1 Index: linux-2.6.38-rc6/arch/arm/plat-omap/bootreason.c
2 ===================================================================
3 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
4 +++ linux-2.6.38-rc6/arch/arm/plat-omap/bootreason.c 2011-02-25 01:11:27.298563256 +0100
7 + * linux/arch/arm/plat-omap/bootreason.c
9 + * OMAP Bootreason passing
11 + * Copyright (c) 2004 Nokia
13 + * Written by David Weinehall <david.weinehall@nokia.com>
15 + * This program is free software; you can redistribute it and/or modify it
16 + * under the terms of the GNU General Public License as published by the
17 + * Free Software Foundation; either version 2 of the License, or (at your
18 + * option) any later version.
20 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
21 + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
23 + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27 + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 + * You should have received a copy of the GNU General Public License along
32 + * with this program; if not, write to the Free Software Foundation, Inc.,
33 + * 675 Mass Ave, Cambridge, MA 02139, USA.
35 +#include <linux/proc_fs.h>
36 +#include <linux/errno.h>
37 +#include <plat/board.h>
39 +static char boot_reason[16];
41 +static int omap_bootreason_read_proc(char *page, char **start, off_t off,
42 + int count, int *eof, void *data)
46 + len += sprintf(page + len, "%s\n", boot_reason);
48 + *start = page + off;
55 + return len < count ? len : count;
58 +static int __init bootreason_init(void)
60 + const struct omap_boot_reason_config *cfg;
61 + int reason_valid = 0;
63 + cfg = omap_get_config(OMAP_TAG_BOOT_REASON, struct omap_boot_reason_config);
65 + strncpy(boot_reason, cfg->reason_str, sizeof(cfg->reason_str));
66 + boot_reason[sizeof(cfg->reason_str)] = 0;
69 + /* Read the boot reason from the OMAP registers */
75 + printk(KERN_INFO "Bootup reason: %s\n", boot_reason);
77 + if (!create_proc_read_entry("bootreason", S_IRUGO, NULL,
78 + omap_bootreason_read_proc, NULL))
84 +late_initcall(bootreason_init);
85 Index: linux-2.6.38-rc6/arch/arm/plat-omap/common.c
86 ===================================================================
87 --- linux-2.6.38-rc6.orig/arch/arm/plat-omap/common.c 2011-02-25 01:10:25.645115298 +0100
88 +++ linux-2.6.38-rc6/arch/arm/plat-omap/common.c 2011-02-25 01:11:27.298563256 +0100
90 #include <plat/vram.h>
93 +#include <asm/setup.h>
96 #define NO_LENGTH_CHECK 0xffffffff
98 struct omap_board_config_kernel *omap_board_config;
99 int omap_board_config_size;
101 +unsigned char omap_bootloader_tag[1024];
102 +int omap_bootloader_tag_len;
104 +/* used by omap-smp.c and board-4430sdp.c */
105 +void __iomem *gic_cpu_base_addr;
107 +#ifdef CONFIG_OMAP_BOOT_TAG
109 +static int __init parse_tag_omap(const struct tag *tag)
111 + u32 size = tag->hdr.size - (sizeof(tag->hdr) >> 2);
114 + if (size > sizeof(omap_bootloader_tag))
117 + memcpy(omap_bootloader_tag, tag->u.omap.data, size);
118 + omap_bootloader_tag_len = size;
123 +__tagtable(ATAG_BOARD, parse_tag_omap);
127 static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
129 struct omap_board_config_kernel *kinfo = NULL;
132 +#ifdef CONFIG_OMAP_BOOT_TAG
133 + struct omap_board_config_entry *info = NULL;
135 + if (omap_bootloader_tag_len > 4)
136 + info = (struct omap_board_config_entry *) omap_bootloader_tag;
137 + while (info != NULL) {
140 + if (info->tag == tag) {
146 + if ((info->len & 0x03) != 0) {
147 + /* We bail out to avoid an alignment fault */
148 + printk(KERN_ERR "OMAP peripheral config: Length (%d) not word-aligned (tag %04x)\n",
149 + info->len, info->tag);
152 + next = (u8 *) info + sizeof(*info) + info->len;
153 + if (next >= omap_bootloader_tag + omap_bootloader_tag_len)
156 + info = (struct omap_board_config_entry *) next;
158 + if (info != NULL) {
159 + /* Check the length as a lame attempt to check for
160 + * binary inconsistency. */
161 + if (len != NO_LENGTH_CHECK) {
162 + /* Word-align len */
164 + len = (len + 3) & ~0x03;
165 + if (info->len != len) {
166 + printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n",
167 + tag, len, info->len);
171 + if (len_out != NULL)
172 + *len_out = info->len;
176 /* Try to find the config from the board-specific structures
178 for (i = 0; i < omap_board_config_size; i++) {
179 Index: linux-2.6.38-rc6/arch/arm/plat-omap/component-version.c
180 ===================================================================
181 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
182 +++ linux-2.6.38-rc6/arch/arm/plat-omap/component-version.c 2011-02-25 01:11:27.299563117 +0100
185 + * linux/arch/arm/plat-omap/component-version.c
187 + * Copyright (C) 2005 Nokia Corporation
188 + * Written by Juha Yrjölä <juha.yrjola@nokia.com>
190 + * This program is free software; you can redistribute it and/or modify
191 + * it under the terms of the GNU General Public License version 2 as
192 + * published by the Free Software Foundation.
195 +#include <linux/init.h>
196 +#include <linux/module.h>
197 +#include <linux/err.h>
198 +#include <linux/proc_fs.h>
199 +#include <plat/board.h>
201 +static int component_version_read_proc(char *page, char **start, off_t off,
202 + int count, int *eof, void *data)
205 + const struct omap_version_config *ver;
210 + while ((ver = omap_get_nr_config(OMAP_TAG_VERSION_STR,
211 + struct omap_version_config, i)) != NULL) {
212 + p += sprintf(p, "%-12s%s\n", ver->component, ver->version);
216 + len = (p - page) - off;
220 + *eof = (len <= count) ? 1 : 0;
221 + *start = page + off;
226 +static int __init component_version_init(void)
228 + if (omap_get_config(OMAP_TAG_VERSION_STR, struct omap_version_config) == NULL)
230 + if (!create_proc_read_entry("component_version", S_IRUGO, NULL,
231 + component_version_read_proc, NULL))
237 +static void __exit component_version_exit(void)
239 + remove_proc_entry("component_version", NULL);
242 +late_initcall(component_version_init);
243 +module_exit(component_version_exit);
245 +MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>");
246 +MODULE_DESCRIPTION("Component version driver");
247 +MODULE_LICENSE("GPL");
248 Index: linux-2.6.38-rc6/arch/arm/plat-omap/Kconfig
249 ===================================================================
250 --- linux-2.6.38-rc6.orig/arch/arm/plat-omap/Kconfig 2011-02-25 01:10:25.621118611 +0100
251 +++ linux-2.6.38-rc6/arch/arm/plat-omap/Kconfig 2011-02-25 01:11:27.299563117 +0100
253 probably do not want this option enabled until your
254 device drivers work properly.
256 +config OMAP_BOOT_TAG
257 + bool "OMAP bootloader information passing"
258 + depends on ARCH_OMAP
261 + Say Y, if you have a bootloader which passes information
262 + about your board and its peripheral configuration.
264 +config OMAP_BOOT_REASON
265 + bool "Support for boot reason"
266 + depends on OMAP_BOOT_TAG
269 + Say Y, if you want to have a procfs entry for reading the boot
270 + reason in user-space.
272 +config OMAP_COMPONENT_VERSION
273 + bool "Support for component version display"
274 + depends on OMAP_BOOT_TAG && PROC_FS
277 + Say Y, if you want to have a procfs entry for reading component
278 + versions (supplied by the bootloader) in user-space.
280 +config OMAP_GPIO_SWITCH
281 + bool "GPIO switch support"
283 + Say Y, if you want to have support for reporting of GPIO
284 + switches (e.g. cover switches) via sysfs. Your bootloader has
285 + to provide information about the switches to the kernel via the
286 + ATAG_BOARD mechanism if they're not defined by the board config.
289 bool "OMAP multiplexing support"
291 Index: linux-2.6.38-rc6/arch/arm/plat-omap/Makefile
292 ===================================================================
293 --- linux-2.6.38-rc6.orig/arch/arm/plat-omap/Makefile 2011-02-25 01:10:25.604120958 +0100
294 +++ linux-2.6.38-rc6/arch/arm/plat-omap/Makefile 2011-02-25 01:11:27.299563117 +0100
297 obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
298 obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
299 +obj-$(CONFIG_OMAP_BOOT_REASON) += bootreason.o
300 +obj-$(CONFIG_OMAP_COMPONENT_VERSION) += component-version.o
301 +obj-$(CONFIG_OMAP_GPIO_SWITCH) += gpio-switch.o
302 obj-$(CONFIG_OMAP_DEBUG_DEVICES) += debug-devices.o
303 obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o
304 i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o
305 Index: linux-2.6.38-rc6/arch/arm/include/asm/setup.h
306 ===================================================================
307 --- linux-2.6.38-rc6.orig/arch/arm/include/asm/setup.h 2011-02-25 01:10:25.523132140 +0100
308 +++ linux-2.6.38-rc6/arch/arm/include/asm/setup.h 2011-02-25 01:11:27.300562978 +0100
313 +/* TI OMAP specific information */
314 +#define ATAG_BOARD 0x414f4d50
320 /* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */
321 #define ATAG_MEMCLK 0x41000402
324 struct tag_acorn acorn;
329 + struct tag_omap omap;
334 struct tag_memclk memclk;
335 Index: linux-2.6.38-rc6/arch/arm/plat-omap/gpio-switch.c
336 ===================================================================
337 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
338 +++ linux-2.6.38-rc6/arch/arm/plat-omap/gpio-switch.c 2011-02-25 01:11:27.301562839 +0100
341 + * linux/arch/arm/plat-omap/gpio-switch.c
343 + * Copyright (C) 2004-2006 Nokia Corporation
344 + * Written by Juha Yrjölä <juha.yrjola@nokia.com>
345 + * and Paul Mundt <paul.mundt@nokia.com>
347 + * This program is free software; you can redistribute it and/or modify
348 + * it under the terms of the GNU General Public License version 2 as
349 + * published by the Free Software Foundation.
352 +#include <linux/sched.h>
353 +#include <linux/init.h>
354 +#include <linux/list.h>
355 +#include <linux/irq.h>
356 +#include <linux/interrupt.h>
357 +#include <linux/module.h>
358 +#include <linux/platform_device.h>
359 +#include <linux/timer.h>
360 +#include <linux/err.h>
361 +#include <linux/slab.h>
362 +#include <linux/gpio.h>
363 +#include <plat/hardware.h>
364 +#include <plat/irqs.h>
365 +#include <plat/mux.h>
366 +#include <plat/board.h>
367 +#include <plat/gpio-switch.h>
369 +struct gpio_switch {
375 + unsigned both_edges:1;
377 + u16 debounce_rising;
378 + u16 debounce_falling;
380 + void (* notify)(void *data, int state);
383 + struct work_struct work;
384 + struct timer_list timer;
385 + struct platform_device pdev;
387 + struct list_head node;
390 +static LIST_HEAD(gpio_switches);
391 +static struct platform_device *gpio_sw_platform_dev;
392 +static struct platform_driver gpio_sw_driver;
394 +static const struct omap_gpio_switch *board_gpio_sw_table;
395 +static int board_gpio_sw_count;
397 +static const char *cover_str[2] = { "open", "closed" };
398 +static const char *connection_str[2] = { "disconnected", "connected" };
399 +static const char *activity_str[2] = { "inactive", "active" };
402 + * GPIO switch state default debounce delay in ms
404 +#define OMAP_GPIO_SW_DEFAULT_DEBOUNCE 10
406 +static const char **get_sw_str(struct gpio_switch *sw)
408 + switch (sw->type) {
409 + case OMAP_GPIO_SWITCH_TYPE_COVER:
411 + case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
412 + return connection_str;
413 + case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
414 + return activity_str;
421 +static const char *get_sw_type(struct gpio_switch *sw)
423 + switch (sw->type) {
424 + case OMAP_GPIO_SWITCH_TYPE_COVER:
426 + case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
427 + return "connection";
428 + case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
436 +static void print_sw_state(struct gpio_switch *sw, int state)
440 + str = get_sw_str(sw);
442 + printk(KERN_INFO "%s (GPIO %d) is now %s\n", sw->name, sw->gpio, str[state]);
445 +static int gpio_sw_get_state(struct gpio_switch *sw)
449 + state = gpio_get_value(sw->gpio);
450 + if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
456 +static ssize_t gpio_sw_state_store(struct device *dev,
457 + struct device_attribute *attr,
461 + struct gpio_switch *sw = dev_get_drvdata(dev);
466 + if (!(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT))
469 + if (sscanf(buf, "%15s", state) != 1)
472 + str = get_sw_str(sw);
473 + if (strcmp(state, str[0]) == 0)
474 + sw->state = enable = 0;
475 + else if (strcmp(state, str[1]) == 0)
476 + sw->state = enable = 1;
480 + if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
482 + gpio_set_value(sw->gpio, enable);
487 +static ssize_t gpio_sw_state_show(struct device *dev,
488 + struct device_attribute *attr,
491 + struct gpio_switch *sw = dev_get_drvdata(dev);
494 + str = get_sw_str(sw);
495 + return sprintf(buf, "%s\n", str[sw->state]);
498 +static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, gpio_sw_state_show,
499 + gpio_sw_state_store);
501 +static ssize_t gpio_sw_type_show(struct device *dev,
502 + struct device_attribute *attr,
505 + struct gpio_switch *sw = dev_get_drvdata(dev);
507 + return sprintf(buf, "%s\n", get_sw_type(sw));
510 +static DEVICE_ATTR(type, S_IRUGO, gpio_sw_type_show, NULL);
512 +static ssize_t gpio_sw_direction_show(struct device *dev,
513 + struct device_attribute *attr,
516 + struct gpio_switch *sw = dev_get_drvdata(dev);
519 + is_output = sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT;
520 + return sprintf(buf, "%s\n", is_output ? "output" : "input");
523 +static DEVICE_ATTR(direction, S_IRUGO, gpio_sw_direction_show, NULL);
526 +static irqreturn_t gpio_sw_irq_handler(int irq, void *arg)
528 + struct gpio_switch *sw = arg;
529 + unsigned long timeout;
532 + if (!sw->both_edges) {
533 + if (gpio_get_value(sw->gpio))
534 + set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQ_TYPE_EDGE_FALLING);
536 + set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQ_TYPE_EDGE_RISING);
539 + state = gpio_sw_get_state(sw);
540 + if (sw->state == state)
541 + return IRQ_HANDLED;
544 + timeout = sw->debounce_rising;
546 + timeout = sw->debounce_falling;
548 + schedule_work(&sw->work);
550 + mod_timer(&sw->timer, jiffies + msecs_to_jiffies(timeout));
552 + return IRQ_HANDLED;
555 +static void gpio_sw_timer(unsigned long arg)
557 + struct gpio_switch *sw = (struct gpio_switch *) arg;
559 + schedule_work(&sw->work);
562 +static void gpio_sw_handler(struct work_struct *work)
564 + struct gpio_switch *sw = container_of(work, struct gpio_switch, work);
567 + state = gpio_sw_get_state(sw);
568 + if (sw->state == state)
572 + if (sw->notify != NULL)
573 + sw->notify(sw->notify_data, state);
574 + sysfs_notify(&sw->pdev.dev.kobj, NULL, "state");
575 + print_sw_state(sw, state);
578 +static int __init can_do_both_edges(struct gpio_switch *sw)
580 + if (!cpu_class_is_omap1())
582 + if (OMAP_GPIO_IS_MPUIO(sw->gpio))
588 +static void gpio_sw_release(struct device *dev)
592 +static int __init new_switch(struct gpio_switch *sw)
594 + int r, direction, trigger;
596 + switch (sw->type) {
597 + case OMAP_GPIO_SWITCH_TYPE_COVER:
598 + case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
599 + case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
602 + printk(KERN_ERR "invalid GPIO switch type: %d\n", sw->type);
606 + sw->pdev.name = sw->name;
609 + sw->pdev.dev.parent = &gpio_sw_platform_dev->dev;
610 + sw->pdev.dev.driver = &gpio_sw_driver.driver;
611 + sw->pdev.dev.release = gpio_sw_release;
613 + r = platform_device_register(&sw->pdev);
615 + printk(KERN_ERR "gpio-switch: platform device registration "
616 + "failed for %s", sw->name);
619 + dev_set_drvdata(&sw->pdev.dev, sw);
621 + r = gpio_request(sw->gpio, "gpio-switch");
623 + platform_device_unregister(&sw->pdev);
627 + /* input: 1, output: 0 */
628 + direction = !(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT);
630 + gpio_direction_input(sw->gpio);
632 + gpio_direction_output(sw->gpio, 0);
634 + sw->state = gpio_sw_get_state(sw);
637 + r |= device_create_file(&sw->pdev.dev, &dev_attr_state);
638 + r |= device_create_file(&sw->pdev.dev, &dev_attr_type);
639 + r |= device_create_file(&sw->pdev.dev, &dev_attr_direction);
641 + printk(KERN_ERR "gpio-switch: attribute file creation "
642 + "failed for %s\n", sw->name);
647 + if (can_do_both_edges(sw)) {
648 + trigger = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
649 + sw->both_edges = 1;
651 + if (gpio_get_value(sw->gpio))
652 + trigger = IRQF_TRIGGER_FALLING;
654 + trigger = IRQF_TRIGGER_RISING;
656 + r = request_irq(OMAP_GPIO_IRQ(sw->gpio), gpio_sw_irq_handler,
657 + IRQF_SHARED | trigger, sw->name, sw);
659 + printk(KERN_ERR "gpio-switch: request_irq() failed "
660 + "for GPIO %d\n", sw->gpio);
661 + platform_device_unregister(&sw->pdev);
662 + gpio_free(sw->gpio);
666 + INIT_WORK(&sw->work, gpio_sw_handler);
667 + init_timer(&sw->timer);
669 + sw->timer.function = gpio_sw_timer;
670 + sw->timer.data = (unsigned long)sw;
672 + list_add(&sw->node, &gpio_switches);
677 +static int __init add_atag_switches(void)
679 + const struct omap_gpio_switch_config *cfg;
680 + struct gpio_switch *sw;
683 + for (i = 0; ; i++) {
684 + cfg = omap_get_nr_config(OMAP_TAG_GPIO_SWITCH,
685 + struct omap_gpio_switch_config, i);
688 + sw = kzalloc(sizeof(*sw), GFP_KERNEL);
690 + printk(KERN_ERR "gpio-switch: kmalloc failed\n");
693 + strncpy(sw->name, cfg->name, sizeof(cfg->name));
694 + sw->gpio = cfg->gpio;
695 + sw->flags = cfg->flags;
696 + sw->type = cfg->type;
697 + sw->debounce_rising = OMAP_GPIO_SW_DEFAULT_DEBOUNCE;
698 + sw->debounce_falling = OMAP_GPIO_SW_DEFAULT_DEBOUNCE;
699 + if ((r = new_switch(sw)) < 0) {
707 +static struct gpio_switch * __init find_switch(int gpio, const char *name)
709 + struct gpio_switch *sw;
711 + list_for_each_entry(sw, &gpio_switches, node) {
712 + if ((gpio < 0 || sw->gpio != gpio) &&
713 + (name == NULL || strcmp(sw->name, name) != 0))
716 + if (gpio < 0 || name == NULL)
719 + if (strcmp(sw->name, name) != 0)
720 + printk("gpio-switch: name mismatch for %d (%s, %s)\n",
721 + gpio, name, sw->name);
722 + else if (sw->gpio != gpio)
723 + printk("gpio-switch: GPIO mismatch for %s (%d, %d)\n",
724 + name, gpio, sw->gpio);
731 +static int __init add_board_switches(void)
735 + for (i = 0; i < board_gpio_sw_count; i++) {
736 + const struct omap_gpio_switch *cfg;
737 + struct gpio_switch *sw;
740 + cfg = board_gpio_sw_table + i;
741 + if (strlen(cfg->name) > sizeof(sw->name) - 1)
743 + /* Check whether we only update an existing switch
744 + * or add a new switch. */
745 + sw = find_switch(cfg->gpio, cfg->name);
747 + sw->debounce_rising = cfg->debounce_rising;
748 + sw->debounce_falling = cfg->debounce_falling;
749 + sw->notify = cfg->notify;
750 + sw->notify_data = cfg->notify_data;
753 + if (cfg->gpio < 0 || cfg->name == NULL) {
754 + printk("gpio-switch: required switch not "
755 + "found (%d, %s)\n", cfg->gpio,
760 + sw = kzalloc(sizeof(*sw), GFP_KERNEL);
762 + printk(KERN_ERR "gpio-switch: kmalloc failed\n");
765 + strlcpy(sw->name, cfg->name, sizeof(sw->name));
766 + sw->gpio = cfg->gpio;
767 + sw->flags = cfg->flags;
768 + sw->type = cfg->type;
769 + sw->debounce_rising = cfg->debounce_rising;
770 + sw->debounce_falling = cfg->debounce_falling;
771 + sw->notify = cfg->notify;
772 + sw->notify_data = cfg->notify_data;
773 + if ((r = new_switch(sw)) < 0) {
781 +static void gpio_sw_cleanup(void)
783 + struct gpio_switch *sw = NULL, *old = NULL;
785 + list_for_each_entry(sw, &gpio_switches, node) {
788 + flush_scheduled_work();
789 + del_timer_sync(&sw->timer);
791 + free_irq(OMAP_GPIO_IRQ(sw->gpio), sw);
793 + device_remove_file(&sw->pdev.dev, &dev_attr_state);
794 + device_remove_file(&sw->pdev.dev, &dev_attr_type);
795 + device_remove_file(&sw->pdev.dev, &dev_attr_direction);
797 + platform_device_unregister(&sw->pdev);
798 + gpio_free(sw->gpio);
804 +static void __init report_initial_state(void)
806 + struct gpio_switch *sw;
808 + list_for_each_entry(sw, &gpio_switches, node) {
811 + state = gpio_get_value(sw->gpio);
812 + if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
814 + if (sw->notify != NULL)
815 + sw->notify(sw->notify_data, state);
816 + print_sw_state(sw, state);
820 +static int gpio_sw_remove(struct platform_device *dev)
825 +static struct platform_driver gpio_sw_driver = {
826 + .remove = gpio_sw_remove,
828 + .name = "gpio-switch",
832 +void __init omap_register_gpio_switches(const struct omap_gpio_switch *tbl,
835 + BUG_ON(board_gpio_sw_table != NULL);
837 + board_gpio_sw_table = tbl;
838 + board_gpio_sw_count = count;
841 +static int __init gpio_sw_init(void)
845 + printk(KERN_INFO "OMAP GPIO switch handler initializing\n");
847 + r = platform_driver_register(&gpio_sw_driver);
851 + gpio_sw_platform_dev = platform_device_register_simple("gpio-switch",
853 + if (IS_ERR(gpio_sw_platform_dev)) {
854 + r = PTR_ERR(gpio_sw_platform_dev);
858 + r = add_atag_switches();
862 + r = add_board_switches();
866 + report_initial_state();
871 + platform_device_unregister(gpio_sw_platform_dev);
873 + platform_driver_unregister(&gpio_sw_driver);
877 +static void __exit gpio_sw_exit(void)
880 + platform_device_unregister(gpio_sw_platform_dev);
881 + platform_driver_unregister(&gpio_sw_driver);
885 +late_initcall(gpio_sw_init);
887 +module_init(gpio_sw_init);
889 +module_exit(gpio_sw_exit);
891 +MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>, Paul Mundt <paul.mundt@nokia.com");
892 +MODULE_DESCRIPTION("GPIO switch driver");
893 +MODULE_LICENSE("GPL");
894 Index: linux-2.6.38-rc6/arch/arm/plat-omap/include/plat/board.h
895 ===================================================================
896 --- linux-2.6.38-rc6.orig/arch/arm/plat-omap/include/plat/board.h 2011-02-25 01:10:25.553127998 +0100
897 +++ linux-2.6.38-rc6/arch/arm/plat-omap/include/plat/board.h 2011-02-25 01:11:27.301562839 +0100
902 +struct omap_gpio_switch_config {
907 + int key_code:24; /* Linux key code */
910 extern const void *__omap_get_config(u16 tag, size_t len, int nr);
912 #define omap_get_config(tag, type) \