diff options
| -rw-r--r-- | target/linux/omap24xx/config-2.6.36 | 1 | ||||
| -rw-r--r-- | target/linux/omap24xx/patches-2.6.36/200-omap-platform.patch | 602 | 
2 files changed, 598 insertions, 5 deletions
| diff --git a/target/linux/omap24xx/config-2.6.36 b/target/linux/omap24xx/config-2.6.36 index 065f3ecec..d2026fea4 100644 --- a/target/linux/omap24xx/config-2.6.36 +++ b/target/linux/omap24xx/config-2.6.36 @@ -404,6 +404,7 @@ CONFIG_OMAP_BOOT_REASON=y  CONFIG_OMAP_BOOT_TAG=y  CONFIG_OMAP_COMPONENT_VERSION=y  CONFIG_OMAP_DM_TIMER=y +CONFIG_OMAP_GPIO_SWITCH=y  CONFIG_OMAP_MBOX_FWK=y  CONFIG_OMAP_MBOX_KFIFO_SIZE=256  CONFIG_OMAP_MCBSP=y diff --git a/target/linux/omap24xx/patches-2.6.36/200-omap-platform.patch b/target/linux/omap24xx/patches-2.6.36/200-omap-platform.patch index ea90592f2..56165be41 100644 --- a/target/linux/omap24xx/patches-2.6.36/200-omap-platform.patch +++ b/target/linux/omap24xx/patches-2.6.36/200-omap-platform.patch @@ -1,10 +1,11 @@  ---   arch/arm/include/asm/setup.h                      |   12  - arch/arm/plat-omap/Kconfig                        |   24  - arch/arm/plat-omap/Makefile                       |    2  + arch/arm/plat-omap/Kconfig                        |   32 + + arch/arm/plat-omap/Makefile                       |    5    arch/arm/plat-omap/bootreason.c                   |   79 ++   arch/arm/plat-omap/common.c                       |   70 ++   arch/arm/plat-omap/component-version.c            |   64 ++ + arch/arm/plat-omap/gpio-switch.c                  |  554 ++++++++++++++++++   arch/arm/plat-omap/include/mach/blizzard.h        |   12    arch/arm/plat-omap/include/mach/board-ams-delta.h |   76 ++   arch/arm/plat-omap/include/mach/board-sx1.h       |   52 + @@ -75,8 +76,9 @@   arch/arm/plat-omap/include/mach/usb.h             |  162 +++++   arch/arm/plat-omap/include/mach/vram.h            |   62 ++   arch/arm/plat-omap/include/mach/vrfb.h            |   50 + + arch/arm/plat-omap/include/plat/board.h           |    8    arch/arm/plat-omap/include/plat/cbus.h            |   31 + - 77 files changed, 10001 insertions(+) + 79 files changed, 10573 insertions(+), 1 deletion(-)  --- /dev/null  +++ linux-2.6.36-rc4/arch/arm/plat-omap/bootreason.c @@ -10276,7 +10278,7 @@  +#endif /* __PLAT_CBUS_H */  --- linux-2.6.36-rc4.orig/arch/arm/plat-omap/Kconfig  +++ linux-2.6.36-rc4/arch/arm/plat-omap/Kconfig -@@ -47,6 +47,30 @@ config OMAP_RESET_CLOCKS +@@ -47,6 +47,38 @@ config OMAP_RESET_CLOCKS   	  probably do not want this option enabled until your   	  device drivers work properly. @@ -10304,20 +10306,36 @@  +	  Say Y, if you want to have a procfs entry for reading component  +	  versions (supplied by the bootloader) in user-space.  + ++config OMAP_GPIO_SWITCH ++	bool "GPIO switch support" ++	help ++	  Say Y, if you want to have support for reporting of GPIO ++	  switches (e.g. cover switches) via sysfs. Your bootloader has ++	  to provide information about the switches to the kernel via the ++	  ATAG_BOARD mechanism if they're not defined by the board config. ++   config OMAP_MUX   	bool "OMAP multiplexing support"   	depends on ARCH_OMAP  --- linux-2.6.36-rc4.orig/arch/arm/plat-omap/Makefile  +++ linux-2.6.36-rc4/arch/arm/plat-omap/Makefile -@@ -23,6 +23,8 @@ obj-$(CONFIG_OMAP_IOMMU_DEBUG) += iommu- +@@ -23,6 +23,9 @@ obj-$(CONFIG_OMAP_IOMMU_DEBUG) += iommu-   obj-$(CONFIG_CPU_FREQ) += cpu-omap.o   obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o  +obj-$(CONFIG_OMAP_BOOT_REASON) += bootreason.o  +obj-$(CONFIG_OMAP_COMPONENT_VERSION) += component-version.o ++obj-$(CONFIG_OMAP_GPIO_SWITCH) += gpio-switch.o   obj-$(CONFIG_OMAP_DEBUG_DEVICES) += debug-devices.o   obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o   i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o +@@ -31,4 +34,4 @@ obj-y += $(i2c-omap-m) $(i2c-omap-y) + # OMAP mailbox framework + obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o +  +-obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o +\ No newline at end of file ++obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o  --- linux-2.6.36-rc4.orig/arch/arm/include/asm/setup.h  +++ linux-2.6.36-rc4/arch/arm/include/asm/setup.h  @@ -136,6 +136,13 @@ struct tag_acorn { @@ -10346,3 +10364,577 @@   		 * DC21285 specific   		 */   		struct tag_memclk	memclk; +--- /dev/null ++++ linux-2.6.36-rc4/arch/arm/plat-omap/gpio-switch.c +@@ -0,0 +1,554 @@ ++/* ++ *  linux/arch/arm/plat-omap/gpio-switch.c ++ * ++ *  Copyright (C) 2004-2006 Nokia Corporation ++ *  Written by Juha Yrjölä <juha.yrjola@nokia.com> ++ *         and Paul Mundt <paul.mundt@nokia.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/sched.h> ++#include <linux/init.h> ++#include <linux/list.h> ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/timer.h> ++#include <linux/err.h> ++#include <linux/slab.h> ++#include <linux/gpio.h> ++#include <plat/hardware.h> ++#include <plat/irqs.h> ++#include <plat/mux.h> ++#include <plat/board.h> ++#include <plat/gpio-switch.h> ++ ++struct gpio_switch { ++	char		name[14]; ++	u16		gpio; ++	unsigned	flags:4; ++	unsigned	type:4; ++	unsigned	state:1; ++	unsigned	both_edges:1; ++ ++	u16		debounce_rising; ++	u16		debounce_falling; ++ ++	void (* notify)(void *data, int state); ++	void *notify_data; ++ ++	struct work_struct	work; ++	struct timer_list	timer; ++	struct platform_device	pdev; ++ ++	struct list_head	node; ++}; ++ ++static LIST_HEAD(gpio_switches); ++static struct platform_device *gpio_sw_platform_dev; ++static struct platform_driver gpio_sw_driver; ++ ++static const struct omap_gpio_switch *board_gpio_sw_table; ++static int board_gpio_sw_count; ++ ++static const char *cover_str[2] = { "open", "closed" }; ++static const char *connection_str[2] = { "disconnected", "connected" }; ++static const char *activity_str[2] = { "inactive", "active" }; ++ ++/* ++ * GPIO switch state default debounce delay in ms ++ */ ++#define OMAP_GPIO_SW_DEFAULT_DEBOUNCE		10 ++ ++static const char **get_sw_str(struct gpio_switch *sw) ++{ ++	switch (sw->type) { ++	case OMAP_GPIO_SWITCH_TYPE_COVER: ++		return cover_str; ++	case OMAP_GPIO_SWITCH_TYPE_CONNECTION: ++		return connection_str; ++	case OMAP_GPIO_SWITCH_TYPE_ACTIVITY: ++		return activity_str; ++	default: ++		BUG(); ++		return NULL; ++	} ++} ++ ++static const char *get_sw_type(struct gpio_switch *sw) ++{ ++	switch (sw->type) { ++	case OMAP_GPIO_SWITCH_TYPE_COVER: ++		return "cover"; ++	case OMAP_GPIO_SWITCH_TYPE_CONNECTION: ++		return "connection"; ++	case OMAP_GPIO_SWITCH_TYPE_ACTIVITY: ++		return "activity"; ++	default: ++		BUG(); ++		return NULL; ++	} ++} ++ ++static void print_sw_state(struct gpio_switch *sw, int state) ++{ ++	const char **str; ++ ++	str = get_sw_str(sw); ++	if (str != NULL) ++		printk(KERN_INFO "%s (GPIO %d) is now %s\n", sw->name, sw->gpio, str[state]); ++} ++ ++static int gpio_sw_get_state(struct gpio_switch *sw) ++{ ++	int state; ++ ++	state = gpio_get_value(sw->gpio); ++	if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED) ++		state = !state; ++ ++	return state; ++} ++ ++static ssize_t gpio_sw_state_store(struct device *dev, ++				   struct device_attribute *attr, ++				   const char *buf, ++				   size_t count) ++{ ++	struct gpio_switch *sw = dev_get_drvdata(dev); ++	const char **str; ++	char state[16]; ++	int enable; ++ ++	if (!(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT)) ++		return -EPERM; ++ ++	if (sscanf(buf, "%15s", state) != 1) ++		return -EINVAL; ++ ++	str = get_sw_str(sw); ++	if (strcmp(state, str[0]) == 0) ++		sw->state = enable = 0; ++	else if (strcmp(state, str[1]) == 0) ++		sw->state = enable = 1; ++	else ++		return -EINVAL; ++ ++	if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED) ++		enable = !enable; ++	gpio_set_value(sw->gpio, enable); ++ ++	return count; ++} ++ ++static ssize_t gpio_sw_state_show(struct device *dev, ++				  struct device_attribute *attr, ++				  char *buf) ++{ ++	struct gpio_switch *sw = dev_get_drvdata(dev); ++	const char **str; ++ ++	str = get_sw_str(sw); ++	return sprintf(buf, "%s\n", str[sw->state]); ++} ++ ++static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, gpio_sw_state_show, ++		   gpio_sw_state_store); ++ ++static ssize_t gpio_sw_type_show(struct device *dev, ++				 struct device_attribute *attr, ++				 char *buf) ++{ ++	struct gpio_switch *sw = dev_get_drvdata(dev); ++ ++	return sprintf(buf, "%s\n", get_sw_type(sw)); ++} ++ ++static DEVICE_ATTR(type, S_IRUGO, gpio_sw_type_show, NULL); ++ ++static ssize_t gpio_sw_direction_show(struct device *dev, ++				      struct device_attribute *attr, ++				      char *buf) ++{ ++	struct gpio_switch *sw = dev_get_drvdata(dev); ++	int is_output; ++ ++	is_output = sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT; ++	return sprintf(buf, "%s\n", is_output ? "output" : "input"); ++} ++ ++static DEVICE_ATTR(direction, S_IRUGO, gpio_sw_direction_show, NULL); ++ ++ ++static irqreturn_t gpio_sw_irq_handler(int irq, void *arg) ++{ ++	struct gpio_switch *sw = arg; ++	unsigned long timeout; ++	int state; ++ ++	if (!sw->both_edges) { ++		if (gpio_get_value(sw->gpio)) ++			set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQ_TYPE_EDGE_FALLING); ++		else ++			set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQ_TYPE_EDGE_RISING); ++	} ++ ++	state = gpio_sw_get_state(sw); ++	if (sw->state == state) ++		return IRQ_HANDLED; ++ ++	if (state) ++		timeout = sw->debounce_rising; ++	else ++		timeout = sw->debounce_falling; ++	if (!timeout) ++		schedule_work(&sw->work); ++	else ++		mod_timer(&sw->timer, jiffies + msecs_to_jiffies(timeout)); ++ ++	return IRQ_HANDLED; ++} ++ ++static void gpio_sw_timer(unsigned long arg) ++{ ++	struct gpio_switch *sw = (struct gpio_switch *) arg; ++ ++	schedule_work(&sw->work); ++} ++ ++static void gpio_sw_handler(struct work_struct *work) ++{ ++	struct gpio_switch *sw = container_of(work, struct gpio_switch, work); ++	int state; ++ ++	state = gpio_sw_get_state(sw); ++	if (sw->state == state) ++		return; ++ ++	sw->state = state; ++	if (sw->notify != NULL) ++		sw->notify(sw->notify_data, state); ++	sysfs_notify(&sw->pdev.dev.kobj, NULL, "state"); ++	print_sw_state(sw, state); ++} ++ ++static int __init can_do_both_edges(struct gpio_switch *sw) ++{ ++	if (!cpu_class_is_omap1()) ++		return 1; ++	if (OMAP_GPIO_IS_MPUIO(sw->gpio)) ++		return 0; ++	else ++		return 1; ++} ++ ++static void gpio_sw_release(struct device *dev) ++{ ++} ++ ++static int __init new_switch(struct gpio_switch *sw) ++{ ++	int r, direction, trigger; ++ ++	switch (sw->type) { ++	case OMAP_GPIO_SWITCH_TYPE_COVER: ++	case OMAP_GPIO_SWITCH_TYPE_CONNECTION: ++	case OMAP_GPIO_SWITCH_TYPE_ACTIVITY: ++		break; ++	default: ++		printk(KERN_ERR "invalid GPIO switch type: %d\n", sw->type); ++		return -EINVAL; ++	} ++ ++	sw->pdev.name	= sw->name; ++	sw->pdev.id	= -1; ++ ++	sw->pdev.dev.parent = &gpio_sw_platform_dev->dev; ++	sw->pdev.dev.driver = &gpio_sw_driver.driver; ++	sw->pdev.dev.release = gpio_sw_release; ++ ++	r = platform_device_register(&sw->pdev); ++	if (r) { ++		printk(KERN_ERR "gpio-switch: platform device registration " ++		       "failed for %s", sw->name); ++		return r; ++	} ++	dev_set_drvdata(&sw->pdev.dev, sw); ++ ++	r = gpio_request(sw->gpio, "gpio-switch"); ++	if (r < 0) { ++		platform_device_unregister(&sw->pdev); ++		return r; ++	} ++ ++	/* input: 1, output: 0 */ ++	direction = !(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT); ++	if (direction) ++		gpio_direction_input(sw->gpio); ++	else ++		gpio_direction_output(sw->gpio, 0); ++ ++	sw->state = gpio_sw_get_state(sw); ++ ++	r = 0; ++	r |= device_create_file(&sw->pdev.dev, &dev_attr_state); ++	r |= device_create_file(&sw->pdev.dev, &dev_attr_type); ++	r |= device_create_file(&sw->pdev.dev, &dev_attr_direction); ++	if (r) ++		printk(KERN_ERR "gpio-switch: attribute file creation " ++		       "failed for %s\n", sw->name); ++ ++	if (!direction) ++		return 0; ++ ++	if (can_do_both_edges(sw)) { ++		trigger = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING; ++		sw->both_edges = 1; ++	} else { ++		if (gpio_get_value(sw->gpio)) ++			trigger = IRQF_TRIGGER_FALLING; ++		else ++			trigger = IRQF_TRIGGER_RISING; ++	} ++	r = request_irq(OMAP_GPIO_IRQ(sw->gpio), gpio_sw_irq_handler, ++			IRQF_SHARED | trigger, sw->name, sw); ++	if (r < 0) { ++		printk(KERN_ERR "gpio-switch: request_irq() failed " ++		       "for GPIO %d\n", sw->gpio); ++		platform_device_unregister(&sw->pdev); ++		gpio_free(sw->gpio); ++		return r; ++	} ++ ++	INIT_WORK(&sw->work, gpio_sw_handler); ++	init_timer(&sw->timer); ++ ++	sw->timer.function = gpio_sw_timer; ++	sw->timer.data = (unsigned long)sw; ++ ++	list_add(&sw->node, &gpio_switches); ++ ++	return 0; ++} ++ ++static int __init add_atag_switches(void) ++{ ++	const struct omap_gpio_switch_config *cfg; ++	struct gpio_switch *sw; ++	int i, r; ++ ++	for (i = 0; ; i++) { ++		cfg = omap_get_nr_config(OMAP_TAG_GPIO_SWITCH, ++					 struct omap_gpio_switch_config, i); ++		if (cfg == NULL) ++			break; ++		sw = kzalloc(sizeof(*sw), GFP_KERNEL); ++		if (sw == NULL) { ++			printk(KERN_ERR "gpio-switch: kmalloc failed\n"); ++			return -ENOMEM; ++		} ++		strncpy(sw->name, cfg->name, sizeof(cfg->name)); ++		sw->gpio = cfg->gpio; ++		sw->flags = cfg->flags; ++		sw->type = cfg->type; ++		sw->debounce_rising = OMAP_GPIO_SW_DEFAULT_DEBOUNCE; ++		sw->debounce_falling = OMAP_GPIO_SW_DEFAULT_DEBOUNCE; ++		if ((r = new_switch(sw)) < 0) { ++			kfree(sw); ++			return r; ++		} ++	} ++	return 0; ++} ++ ++static struct gpio_switch * __init find_switch(int gpio, const char *name) ++{ ++	struct gpio_switch *sw; ++ ++	list_for_each_entry(sw, &gpio_switches, node) { ++		if ((gpio < 0 || sw->gpio != gpio) && ++		    (name == NULL || strcmp(sw->name, name) != 0)) ++			continue; ++ ++		if (gpio < 0 || name == NULL) ++			goto no_check; ++ ++		if (strcmp(sw->name, name) != 0) ++			printk("gpio-switch: name mismatch for %d (%s, %s)\n", ++			       gpio, name, sw->name); ++		else if (sw->gpio != gpio) ++			printk("gpio-switch: GPIO mismatch for %s (%d, %d)\n", ++			       name, gpio, sw->gpio); ++no_check: ++		return sw; ++	} ++	return NULL; ++} ++ ++static int __init add_board_switches(void) ++{ ++	int i; ++ ++	for (i = 0; i < board_gpio_sw_count; i++) { ++		const struct omap_gpio_switch *cfg; ++		struct gpio_switch *sw; ++		int r; ++ ++		cfg = board_gpio_sw_table + i; ++		if (strlen(cfg->name) > sizeof(sw->name) - 1) ++			return -EINVAL; ++		/* Check whether we only update an existing switch ++		 * or add a new switch. */ ++		sw = find_switch(cfg->gpio, cfg->name); ++		if (sw != NULL) { ++			sw->debounce_rising = cfg->debounce_rising; ++			sw->debounce_falling = cfg->debounce_falling; ++			sw->notify = cfg->notify; ++			sw->notify_data = cfg->notify_data; ++			continue; ++		} else { ++			if (cfg->gpio < 0 || cfg->name == NULL) { ++				printk("gpio-switch: required switch not " ++				       "found (%d, %s)\n", cfg->gpio, ++				       cfg->name); ++				continue; ++			} ++		} ++		sw = kzalloc(sizeof(*sw), GFP_KERNEL); ++		if (sw == NULL) { ++			printk(KERN_ERR "gpio-switch: kmalloc failed\n"); ++			return -ENOMEM; ++		} ++		strlcpy(sw->name, cfg->name, sizeof(sw->name)); ++		sw->gpio = cfg->gpio; ++		sw->flags = cfg->flags; ++		sw->type = cfg->type; ++		sw->debounce_rising = cfg->debounce_rising; ++		sw->debounce_falling = cfg->debounce_falling; ++		sw->notify = cfg->notify; ++		sw->notify_data = cfg->notify_data; ++		if ((r = new_switch(sw)) < 0) { ++			kfree(sw); ++			return r; ++		} ++	} ++	return 0; ++} ++ ++static void gpio_sw_cleanup(void) ++{ ++	struct gpio_switch *sw = NULL, *old = NULL; ++ ++	list_for_each_entry(sw, &gpio_switches, node) { ++		if (old != NULL) ++			kfree(old); ++		flush_scheduled_work(); ++		del_timer_sync(&sw->timer); ++ ++		free_irq(OMAP_GPIO_IRQ(sw->gpio), sw); ++ ++		device_remove_file(&sw->pdev.dev, &dev_attr_state); ++		device_remove_file(&sw->pdev.dev, &dev_attr_type); ++		device_remove_file(&sw->pdev.dev, &dev_attr_direction); ++ ++		platform_device_unregister(&sw->pdev); ++		gpio_free(sw->gpio); ++		old = sw; ++	} ++	kfree(old); ++} ++ ++static void __init report_initial_state(void) ++{ ++	struct gpio_switch *sw; ++ ++	list_for_each_entry(sw, &gpio_switches, node) { ++		int state; ++ ++		state = gpio_get_value(sw->gpio); ++		if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED) ++			state = !state; ++		if (sw->notify != NULL) ++			sw->notify(sw->notify_data, state); ++		print_sw_state(sw, state); ++	} ++} ++ ++static int gpio_sw_remove(struct platform_device *dev) ++{ ++	return 0; ++} ++ ++static struct platform_driver gpio_sw_driver = { ++	.remove		= gpio_sw_remove, ++	.driver		= { ++		.name	= "gpio-switch", ++	}, ++}; ++ ++void __init omap_register_gpio_switches(const struct omap_gpio_switch *tbl, ++					int count) ++{ ++	BUG_ON(board_gpio_sw_table != NULL); ++ ++	board_gpio_sw_table = tbl; ++	board_gpio_sw_count = count; ++} ++ ++static int __init gpio_sw_init(void) ++{ ++	int r; ++ ++	printk(KERN_INFO "OMAP GPIO switch handler initializing\n"); ++ ++	r = platform_driver_register(&gpio_sw_driver); ++	if (r) ++		return r; ++ ++	gpio_sw_platform_dev = platform_device_register_simple("gpio-switch", ++							       -1, NULL, 0); ++	if (IS_ERR(gpio_sw_platform_dev)) { ++		r = PTR_ERR(gpio_sw_platform_dev); ++		goto err1; ++	} ++ ++	r = add_atag_switches(); ++	if (r < 0) ++		goto err2; ++ ++	r = add_board_switches(); ++	if (r < 0) ++		goto err2; ++ ++	report_initial_state(); ++ ++	return 0; ++err2: ++	gpio_sw_cleanup(); ++	platform_device_unregister(gpio_sw_platform_dev); ++err1: ++	platform_driver_unregister(&gpio_sw_driver); ++	return r; ++} ++ ++static void __exit gpio_sw_exit(void) ++{ ++	gpio_sw_cleanup(); ++	platform_device_unregister(gpio_sw_platform_dev); ++	platform_driver_unregister(&gpio_sw_driver); ++} ++ ++#ifndef MODULE ++late_initcall(gpio_sw_init); ++#else ++module_init(gpio_sw_init); ++#endif ++module_exit(gpio_sw_exit); ++ ++MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>, Paul Mundt <paul.mundt@nokia.com"); ++MODULE_DESCRIPTION("GPIO switch driver"); ++MODULE_LICENSE("GPL"); +--- linux-2.6.36-rc4.orig/arch/arm/plat-omap/include/plat/board.h ++++ linux-2.6.36-rc4/arch/arm/plat-omap/include/plat/board.h +@@ -151,6 +151,14 @@ struct omap_board_config_kernel { + 	const void *data; + }; +  ++struct omap_gpio_switch_config { ++	char name[12]; ++	u16 gpio; ++	int flags:4; ++	int type:4; ++	int key_code:24; /* Linux key code */ ++}; ++ + extern const void *__omap_get_config(u16 tag, size_t len, int nr); +  + #define omap_get_config(tag, type) \ | 
