aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/omap24xx/patches-3.1/200-omap-platform.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/omap24xx/patches-3.1/200-omap-platform.patch')
-rw-r--r--target/linux/omap24xx/patches-3.1/200-omap-platform.patch897
1 files changed, 0 insertions, 897 deletions
diff --git a/target/linux/omap24xx/patches-3.1/200-omap-platform.patch b/target/linux/omap24xx/patches-3.1/200-omap-platform.patch
deleted file mode 100644
index 9a2e9436fa..0000000000
--- a/target/linux/omap24xx/patches-3.1/200-omap-platform.patch
+++ /dev/null
@@ -1,897 +0,0 @@
---- /dev/null
-+++ b/arch/arm/plat-omap/bootreason.c
-@@ -0,0 +1,79 @@
-+/*
-+ * linux/arch/arm/plat-omap/bootreason.c
-+ *
-+ * OMAP Bootreason passing
-+ *
-+ * Copyright (c) 2004 Nokia
-+ *
-+ * Written by David Weinehall <david.weinehall@nokia.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
-+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ *
-+ * You should have received a copy of the GNU General Public License along
-+ * with this program; if not, write to the Free Software Foundation, Inc.,
-+ * 675 Mass Ave, Cambridge, MA 02139, USA.
-+ */
-+#include <linux/proc_fs.h>
-+#include <linux/errno.h>
-+#include <plat/board.h>
-+
-+static char boot_reason[16];
-+
-+static int omap_bootreason_read_proc(char *page, char **start, off_t off,
-+ int count, int *eof, void *data)
-+{
-+ int len = 0;
-+
-+ len += sprintf(page + len, "%s\n", boot_reason);
-+
-+ *start = page + off;
-+
-+ if (len > off)
-+ len -= off;
-+ else
-+ len = 0;
-+
-+ return len < count ? len : count;
-+}
-+
-+static int __init bootreason_init(void)
-+{
-+ const struct omap_boot_reason_config *cfg;
-+ int reason_valid = 0;
-+
-+ cfg = omap_get_config(OMAP_TAG_BOOT_REASON, struct omap_boot_reason_config);
-+ if (cfg != NULL) {
-+ strncpy(boot_reason, cfg->reason_str, sizeof(cfg->reason_str));
-+ boot_reason[sizeof(cfg->reason_str)] = 0;
-+ reason_valid = 1;
-+ } else {
-+ /* Read the boot reason from the OMAP registers */
-+ }
-+
-+ if (!reason_valid)
-+ return -ENOENT;
-+
-+ printk(KERN_INFO "Bootup reason: %s\n", boot_reason);
-+
-+ if (!create_proc_read_entry("bootreason", S_IRUGO, NULL,
-+ omap_bootreason_read_proc, NULL))
-+ return -ENOMEM;
-+
-+ return 0;
-+}
-+
-+late_initcall(bootreason_init);
---- a/arch/arm/plat-omap/common.c
-+++ b/arch/arm/plat-omap/common.c
-@@ -21,18 +21,90 @@
- #include <plat/vram.h>
- #include <plat/dsp.h>
-
-+#include <asm/setup.h>
-+
-
- #define NO_LENGTH_CHECK 0xffffffff
-
- struct omap_board_config_kernel *omap_board_config __initdata;
- int omap_board_config_size;
-
-+unsigned char omap_bootloader_tag[1024];
-+int omap_bootloader_tag_len;
-+
-+/* used by omap-smp.c and board-4430sdp.c */
-+void __iomem *gic_cpu_base_addr;
-+
-+#ifdef CONFIG_OMAP_BOOT_TAG
-+
-+static int __init parse_tag_omap(const struct tag *tag)
-+{
-+ u32 size = tag->hdr.size - (sizeof(tag->hdr) >> 2);
-+
-+ size <<= 2;
-+ if (size > sizeof(omap_bootloader_tag))
-+ return -1;
-+
-+ memcpy(omap_bootloader_tag, tag->u.omap.data, size);
-+ omap_bootloader_tag_len = size;
-+
-+ return 0;
-+}
-+
-+__tagtable(ATAG_BOARD, parse_tag_omap);
-+
-+#endif
-+
- static const void *__init get_config(u16 tag, size_t len,
- int skip, size_t *len_out)
- {
- struct omap_board_config_kernel *kinfo = NULL;
- int i;
-
-+#ifdef CONFIG_OMAP_BOOT_TAG
-+ struct omap_board_config_entry *info = NULL;
-+
-+ if (omap_bootloader_tag_len > 4)
-+ info = (struct omap_board_config_entry *) omap_bootloader_tag;
-+ while (info != NULL) {
-+ u8 *next;
-+
-+ if (info->tag == tag) {
-+ if (skip == 0)
-+ break;
-+ skip--;
-+ }
-+
-+ if ((info->len & 0x03) != 0) {
-+ /* We bail out to avoid an alignment fault */
-+ printk(KERN_ERR "OMAP peripheral config: Length (%d) not word-aligned (tag %04x)\n",
-+ info->len, info->tag);
-+ return NULL;
-+ }
-+ next = (u8 *) info + sizeof(*info) + info->len;
-+ if (next >= omap_bootloader_tag + omap_bootloader_tag_len)
-+ info = NULL;
-+ else
-+ info = (struct omap_board_config_entry *) next;
-+ }
-+ if (info != NULL) {
-+ /* Check the length as a lame attempt to check for
-+ * binary inconsistency. */
-+ if (len != NO_LENGTH_CHECK) {
-+ /* Word-align len */
-+ if (len & 0x03)
-+ len = (len + 3) & ~0x03;
-+ if (info->len != len) {
-+ printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n",
-+ tag, len, info->len);
-+ return NULL;
-+ }
-+ }
-+ if (len_out != NULL)
-+ *len_out = info->len;
-+ return info->data;
-+ }
-+#endif
- /* Try to find the config from the board-specific structures
- * in the kernel. */
- for (i = 0; i < omap_board_config_size; i++) {
---- /dev/null
-+++ b/arch/arm/plat-omap/component-version.c
-@@ -0,0 +1,64 @@
-+/*
-+ * linux/arch/arm/plat-omap/component-version.c
-+ *
-+ * Copyright (C) 2005 Nokia Corporation
-+ * Written by Juha Yrjölä <juha.yrjola@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/init.h>
-+#include <linux/module.h>
-+#include <linux/err.h>
-+#include <linux/proc_fs.h>
-+#include <plat/board.h>
-+
-+static int component_version_read_proc(char *page, char **start, off_t off,
-+ int count, int *eof, void *data)
-+{
-+ int len, i;
-+ const struct omap_version_config *ver;
-+ char *p;
-+
-+ i = 0;
-+ p = page;
-+ while ((ver = omap_get_nr_config(OMAP_TAG_VERSION_STR,
-+ struct omap_version_config, i)) != NULL) {
-+ p += sprintf(p, "%-12s%s\n", ver->component, ver->version);
-+ i++;
-+ }
-+
-+ len = (p - page) - off;
-+ if (len < 0)
-+ len = 0;
-+
-+ *eof = (len <= count) ? 1 : 0;
-+ *start = page + off;
-+
-+ return len;
-+}
-+
-+static int __init component_version_init(void)
-+{
-+ if (omap_get_config(OMAP_TAG_VERSION_STR, struct omap_version_config) == NULL)
-+ return -ENODEV;
-+ if (!create_proc_read_entry("component_version", S_IRUGO, NULL,
-+ component_version_read_proc, NULL))
-+ return -ENOMEM;
-+
-+ return 0;
-+}
-+
-+static void __exit component_version_exit(void)
-+{
-+ remove_proc_entry("component_version", NULL);
-+}
-+
-+late_initcall(component_version_init);
-+module_exit(component_version_exit);
-+
-+MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>");
-+MODULE_DESCRIPTION("Component version driver");
-+MODULE_LICENSE("GPL");
---- a/arch/arm/plat-omap/Kconfig
-+++ b/arch/arm/plat-omap/Kconfig
-@@ -82,6 +82,38 @@ config OMAP_RESET_CLOCKS
- probably do not want this option enabled until your
- device drivers work properly.
-
-+config OMAP_BOOT_TAG
-+ bool "OMAP bootloader information passing"
-+ depends on ARCH_OMAP
-+ default n
-+ help
-+ Say Y, if you have a bootloader which passes information
-+ about your board and its peripheral configuration.
-+
-+config OMAP_BOOT_REASON
-+ bool "Support for boot reason"
-+ depends on OMAP_BOOT_TAG
-+ default n
-+ help
-+ Say Y, if you want to have a procfs entry for reading the boot
-+ reason in user-space.
-+
-+config OMAP_COMPONENT_VERSION
-+ bool "Support for component version display"
-+ depends on OMAP_BOOT_TAG && PROC_FS
-+ default n
-+ 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
---- a/arch/arm/plat-omap/Makefile
-+++ b/arch/arm/plat-omap/Makefile
-@@ -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
---- a/arch/arm/include/asm/setup.h
-+++ b/arch/arm/include/asm/setup.h
-@@ -136,6 +136,13 @@ struct tag_acorn {
- __u8 adfsdrives;
- };
-
-+/* TI OMAP specific information */
-+#define ATAG_BOARD 0x414f4d50
-+
-+struct tag_omap {
-+ u8 data[0];
-+};
-+
- /* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */
- #define ATAG_MEMCLK 0x41000402
-
-@@ -162,6 +169,11 @@ struct tag {
- struct tag_acorn acorn;
-
- /*
-+ * OMAP specific
-+ */
-+ struct tag_omap omap;
-+
-+ /*
- * DC21285 specific
- */
- struct tag_memclk memclk;
---- /dev/null
-+++ b/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))
-+ irq_set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQ_TYPE_EDGE_FALLING);
-+ else
-+ irq_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");
---- a/arch/arm/plat-omap/include/plat/board.h
-+++ b/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 *__init __omap_get_config(u16 tag, size_t len, int nr);
-
- #define omap_get_config(tag, type) \