From 30e135869052e2bc244a10d50a3931e862bdebcd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20B=C3=BCsch?= <mb@bu3sch.de>
Date: Sat, 18 Sep 2010 17:31:00 +0000
Subject: omap24xx: Add support for GPIO switches on the n810

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@23081 3c298f89-4303-0410-b956-a3cf2f4a3e73
---
 target/linux/omap24xx/config-2.6.36                |   1 +
 .../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 065f3ececc..d2026fea4d 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 ea90592f2c..56165be411 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.
  
@@ -10303,21 +10305,37 @@
 +	help
 +	  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) \
-- 
cgit v1.2.3