kernel: update kernel from 2.6.38.2 to 2.6.38.6 and refresh patches
[15.05/openwrt.git] / target / linux / omap24xx / patches-2.6.38 / 200-omap-platform.patch
1 --- /dev/null
2 +++ b/arch/arm/plat-omap/bootreason.c
3 @@ -0,0 +1,79 @@
4 +/*
5 + * linux/arch/arm/plat-omap/bootreason.c
6 + *
7 + * OMAP Bootreason passing
8 + *
9 + * Copyright (c) 2004 Nokia
10 + *
11 + * Written by David Weinehall <david.weinehall@nokia.com>
12 + *
13 + * This program is free software; you can redistribute it and/or modify it
14 + * under the terms of the GNU General Public License as published by the
15 + * Free Software Foundation; either version 2 of the License, or (at your
16 + * option) any later version.
17 + *
18 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
21 + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24 + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 + *
29 + * You should have received a copy of the GNU General Public License along
30 + * with this program; if not, write to the Free Software Foundation, Inc.,
31 + * 675 Mass Ave, Cambridge, MA 02139, USA.
32 + */
33 +#include <linux/proc_fs.h>
34 +#include <linux/errno.h>
35 +#include <plat/board.h>
36 +
37 +static char boot_reason[16];
38 +
39 +static int omap_bootreason_read_proc(char *page, char **start, off_t off,
40 +                                        int count, int *eof, void *data)
41 +{
42 +       int len = 0;
43 +
44 +       len += sprintf(page + len, "%s\n", boot_reason);
45 +
46 +       *start = page + off;
47 +
48 +       if (len > off)
49 +               len -= off;
50 +       else
51 +               len = 0;
52 +
53 +       return len < count ? len  : count;
54 +}
55 +
56 +static int __init bootreason_init(void)
57 +{
58 +       const struct omap_boot_reason_config *cfg;
59 +       int reason_valid = 0;
60 +
61 +       cfg = omap_get_config(OMAP_TAG_BOOT_REASON, struct omap_boot_reason_config);
62 +       if (cfg != NULL) {
63 +               strncpy(boot_reason, cfg->reason_str, sizeof(cfg->reason_str));
64 +               boot_reason[sizeof(cfg->reason_str)] = 0;
65 +               reason_valid = 1;
66 +       } else {
67 +               /* Read the boot reason from the OMAP registers */
68 +       }
69 +
70 +       if (!reason_valid)
71 +               return -ENOENT;
72 +
73 +       printk(KERN_INFO "Bootup reason: %s\n", boot_reason);
74 +
75 +       if (!create_proc_read_entry("bootreason", S_IRUGO, NULL,
76 +                                       omap_bootreason_read_proc, NULL))
77 +               return -ENOMEM;
78 +
79 +       return 0;
80 +}
81 +
82 +late_initcall(bootreason_init);
83 --- a/arch/arm/plat-omap/common.c
84 +++ b/arch/arm/plat-omap/common.c
85 @@ -21,17 +21,89 @@
86  #include <plat/vram.h>
87  #include <plat/dsp.h>
88  
89 +#include <asm/setup.h>
90 +
91  
92  #define NO_LENGTH_CHECK 0xffffffff
93  
94  struct omap_board_config_kernel *omap_board_config;
95  int omap_board_config_size;
96  
97 +unsigned char omap_bootloader_tag[1024];
98 +int omap_bootloader_tag_len;
99 +
100 +/* used by omap-smp.c and board-4430sdp.c */
101 +void __iomem *gic_cpu_base_addr;
102 +
103 +#ifdef CONFIG_OMAP_BOOT_TAG
104 +
105 +static int __init parse_tag_omap(const struct tag *tag)
106 +{
107 +       u32 size = tag->hdr.size - (sizeof(tag->hdr) >> 2);
108 +
109 +        size <<= 2;
110 +       if (size > sizeof(omap_bootloader_tag))
111 +               return -1;
112 +
113 +       memcpy(omap_bootloader_tag, tag->u.omap.data, size);
114 +       omap_bootloader_tag_len = size;
115 +
116 +        return 0;
117 +}
118 +
119 +__tagtable(ATAG_BOARD, parse_tag_omap);
120 +
121 +#endif
122 +
123  static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
124  {
125         struct omap_board_config_kernel *kinfo = NULL;
126         int i;
127  
128 +#ifdef CONFIG_OMAP_BOOT_TAG
129 +       struct omap_board_config_entry *info = NULL;
130 +
131 +       if (omap_bootloader_tag_len > 4)
132 +               info = (struct omap_board_config_entry *) omap_bootloader_tag;
133 +       while (info != NULL) {
134 +               u8 *next;
135 +
136 +               if (info->tag == tag) {
137 +                       if (skip == 0)
138 +                               break;
139 +                       skip--;
140 +               }
141 +
142 +               if ((info->len & 0x03) != 0) {
143 +                       /* We bail out to avoid an alignment fault */
144 +                       printk(KERN_ERR "OMAP peripheral config: Length (%d) not word-aligned (tag %04x)\n",
145 +                              info->len, info->tag);
146 +                       return NULL;
147 +               }
148 +               next = (u8 *) info + sizeof(*info) + info->len;
149 +               if (next >= omap_bootloader_tag + omap_bootloader_tag_len)
150 +                       info = NULL;
151 +               else
152 +                       info = (struct omap_board_config_entry *) next;
153 +       }
154 +       if (info != NULL) {
155 +               /* Check the length as a lame attempt to check for
156 +                * binary inconsistency. */
157 +               if (len != NO_LENGTH_CHECK) {
158 +                       /* Word-align len */
159 +                       if (len & 0x03)
160 +                               len = (len + 3) & ~0x03;
161 +                       if (info->len != len) {
162 +                               printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n",
163 +                                      tag, len, info->len);
164 +                               return NULL;
165 +                       }
166 +               }
167 +               if (len_out != NULL)
168 +                       *len_out = info->len;
169 +               return info->data;
170 +       }
171 +#endif
172         /* Try to find the config from the board-specific structures
173          * in the kernel. */
174         for (i = 0; i < omap_board_config_size; i++) {
175 --- /dev/null
176 +++ b/arch/arm/plat-omap/component-version.c
177 @@ -0,0 +1,64 @@
178 +/*
179 + *  linux/arch/arm/plat-omap/component-version.c
180 + *
181 + *  Copyright (C) 2005 Nokia Corporation
182 + *  Written by Juha Yrjölä <juha.yrjola@nokia.com>
183 + *
184 + * This program is free software; you can redistribute it and/or modify
185 + * it under the terms of the GNU General Public License version 2 as
186 + * published by the Free Software Foundation.
187 + */
188 +
189 +#include <linux/init.h>
190 +#include <linux/module.h>
191 +#include <linux/err.h>
192 +#include <linux/proc_fs.h>
193 +#include <plat/board.h>
194 +
195 +static int component_version_read_proc(char *page, char **start, off_t off,
196 +                                      int count, int *eof, void *data)
197 +{
198 +       int len, i;
199 +       const struct omap_version_config *ver;
200 +       char *p;
201 +
202 +       i = 0;
203 +       p = page;
204 +       while ((ver = omap_get_nr_config(OMAP_TAG_VERSION_STR,
205 +                                        struct omap_version_config, i)) != NULL) {
206 +               p += sprintf(p, "%-12s%s\n", ver->component, ver->version);
207 +               i++;
208 +       }
209 +
210 +       len = (p - page) - off;
211 +       if (len < 0)
212 +               len = 0;
213 +
214 +       *eof = (len <= count) ? 1 : 0;
215 +       *start = page + off;
216 +
217 +       return len;
218 +}
219 +
220 +static int __init component_version_init(void)
221 +{
222 +       if (omap_get_config(OMAP_TAG_VERSION_STR, struct omap_version_config) == NULL)
223 +               return -ENODEV;
224 +       if (!create_proc_read_entry("component_version", S_IRUGO, NULL,
225 +                                   component_version_read_proc, NULL))
226 +               return -ENOMEM;
227 +
228 +       return 0;
229 +}
230 +
231 +static void __exit component_version_exit(void)
232 +{
233 +       remove_proc_entry("component_version", NULL);
234 +}
235 +
236 +late_initcall(component_version_init);
237 +module_exit(component_version_exit);
238 +
239 +MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>");
240 +MODULE_DESCRIPTION("Component version driver");
241 +MODULE_LICENSE("GPL");
242 --- a/arch/arm/plat-omap/Kconfig
243 +++ b/arch/arm/plat-omap/Kconfig
244 @@ -79,6 +79,38 @@ config OMAP_RESET_CLOCKS
245           probably do not want this option enabled until your
246           device drivers work properly.
247  
248 +config OMAP_BOOT_TAG
249 +       bool "OMAP bootloader information passing"
250 +        depends on ARCH_OMAP
251 +        default n
252 +        help
253 +          Say Y, if you have a bootloader which passes information
254 +          about your board and its peripheral configuration.
255 +
256 +config OMAP_BOOT_REASON
257 +       bool "Support for boot reason"
258 +        depends on OMAP_BOOT_TAG
259 +        default n
260 +        help
261 +          Say Y, if you want to have a procfs entry for reading the boot
262 +          reason in user-space.
263 +
264 +config OMAP_COMPONENT_VERSION
265 +       bool "Support for component version display"
266 +       depends on OMAP_BOOT_TAG && PROC_FS
267 +       default n
268 +       help
269 +         Say Y, if you want to have a procfs entry for reading component
270 +         versions (supplied by the bootloader) in user-space.
271 +
272 +config OMAP_GPIO_SWITCH
273 +       bool "GPIO switch support"
274 +       help
275 +         Say Y, if you want to have support for reporting of GPIO
276 +         switches (e.g. cover switches) via sysfs. Your bootloader has
277 +         to provide information about the switches to the kernel via the
278 +         ATAG_BOARD mechanism if they're not defined by the board config.
279 +
280  config OMAP_MUX
281         bool "OMAP multiplexing support"
282         depends on ARCH_OMAP
283 --- a/arch/arm/plat-omap/Makefile
284 +++ b/arch/arm/plat-omap/Makefile
285 @@ -23,6 +23,9 @@ obj-$(CONFIG_OMAP_IOMMU_DEBUG) += iommu-
286  
287  obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
288  obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
289 +obj-$(CONFIG_OMAP_BOOT_REASON) += bootreason.o
290 +obj-$(CONFIG_OMAP_COMPONENT_VERSION) += component-version.o
291 +obj-$(CONFIG_OMAP_GPIO_SWITCH) += gpio-switch.o
292  obj-$(CONFIG_OMAP_DEBUG_DEVICES) += debug-devices.o
293  obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o
294  i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o
295 --- a/arch/arm/include/asm/setup.h
296 +++ b/arch/arm/include/asm/setup.h
297 @@ -136,6 +136,13 @@ struct tag_acorn {
298         __u8 adfsdrives;
299  };
300  
301 +/* TI OMAP specific information */
302 +#define ATAG_BOARD       0x414f4d50
303 +
304 +struct tag_omap {
305 +       u8 data[0];
306 +};
307 +
308  /* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */
309  #define ATAG_MEMCLK    0x41000402
310  
311 @@ -162,6 +169,11 @@ struct tag {
312                 struct tag_acorn        acorn;
313  
314                 /*
315 +                * OMAP specific
316 +                 */
317 +                struct tag_omap         omap;
318 +
319 +               /*
320                  * DC21285 specific
321                  */
322                 struct tag_memclk       memclk;
323 --- /dev/null
324 +++ b/arch/arm/plat-omap/gpio-switch.c
325 @@ -0,0 +1,554 @@
326 +/*
327 + *  linux/arch/arm/plat-omap/gpio-switch.c
328 + *
329 + *  Copyright (C) 2004-2006 Nokia Corporation
330 + *  Written by Juha Yrjölä <juha.yrjola@nokia.com>
331 + *         and Paul Mundt <paul.mundt@nokia.com>
332 + *
333 + * This program is free software; you can redistribute it and/or modify
334 + * it under the terms of the GNU General Public License version 2 as
335 + * published by the Free Software Foundation.
336 + */
337 +
338 +#include <linux/sched.h>
339 +#include <linux/init.h>
340 +#include <linux/list.h>
341 +#include <linux/irq.h>
342 +#include <linux/interrupt.h>
343 +#include <linux/module.h>
344 +#include <linux/platform_device.h>
345 +#include <linux/timer.h>
346 +#include <linux/err.h>
347 +#include <linux/slab.h>
348 +#include <linux/gpio.h>
349 +#include <plat/hardware.h>
350 +#include <plat/irqs.h>
351 +#include <plat/mux.h>
352 +#include <plat/board.h>
353 +#include <plat/gpio-switch.h>
354 +
355 +struct gpio_switch {
356 +       char            name[14];
357 +       u16             gpio;
358 +       unsigned        flags:4;
359 +       unsigned        type:4;
360 +       unsigned        state:1;
361 +       unsigned        both_edges:1;
362 +
363 +       u16             debounce_rising;
364 +       u16             debounce_falling;
365 +
366 +       void (* notify)(void *data, int state);
367 +       void *notify_data;
368 +
369 +       struct work_struct      work;
370 +       struct timer_list       timer;
371 +       struct platform_device  pdev;
372 +
373 +       struct list_head        node;
374 +};
375 +
376 +static LIST_HEAD(gpio_switches);
377 +static struct platform_device *gpio_sw_platform_dev;
378 +static struct platform_driver gpio_sw_driver;
379 +
380 +static const struct omap_gpio_switch *board_gpio_sw_table;
381 +static int board_gpio_sw_count;
382 +
383 +static const char *cover_str[2] = { "open", "closed" };
384 +static const char *connection_str[2] = { "disconnected", "connected" };
385 +static const char *activity_str[2] = { "inactive", "active" };
386 +
387 +/*
388 + * GPIO switch state default debounce delay in ms
389 + */
390 +#define OMAP_GPIO_SW_DEFAULT_DEBOUNCE          10
391 +
392 +static const char **get_sw_str(struct gpio_switch *sw)
393 +{
394 +       switch (sw->type) {
395 +       case OMAP_GPIO_SWITCH_TYPE_COVER:
396 +               return cover_str;
397 +       case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
398 +               return connection_str;
399 +       case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
400 +               return activity_str;
401 +       default:
402 +               BUG();
403 +               return NULL;
404 +       }
405 +}
406 +
407 +static const char *get_sw_type(struct gpio_switch *sw)
408 +{
409 +       switch (sw->type) {
410 +       case OMAP_GPIO_SWITCH_TYPE_COVER:
411 +               return "cover";
412 +       case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
413 +               return "connection";
414 +       case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
415 +               return "activity";
416 +       default:
417 +               BUG();
418 +               return NULL;
419 +       }
420 +}
421 +
422 +static void print_sw_state(struct gpio_switch *sw, int state)
423 +{
424 +       const char **str;
425 +
426 +       str = get_sw_str(sw);
427 +       if (str != NULL)
428 +               printk(KERN_INFO "%s (GPIO %d) is now %s\n", sw->name, sw->gpio, str[state]);
429 +}
430 +
431 +static int gpio_sw_get_state(struct gpio_switch *sw)
432 +{
433 +       int state;
434 +
435 +       state = gpio_get_value(sw->gpio);
436 +       if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
437 +               state = !state;
438 +
439 +       return state;
440 +}
441 +
442 +static ssize_t gpio_sw_state_store(struct device *dev,
443 +                                  struct device_attribute *attr,
444 +                                  const char *buf,
445 +                                  size_t count)
446 +{
447 +       struct gpio_switch *sw = dev_get_drvdata(dev);
448 +       const char **str;
449 +       char state[16];
450 +       int enable;
451 +
452 +       if (!(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT))
453 +               return -EPERM;
454 +
455 +       if (sscanf(buf, "%15s", state) != 1)
456 +               return -EINVAL;
457 +
458 +       str = get_sw_str(sw);
459 +       if (strcmp(state, str[0]) == 0)
460 +               sw->state = enable = 0;
461 +       else if (strcmp(state, str[1]) == 0)
462 +               sw->state = enable = 1;
463 +       else
464 +               return -EINVAL;
465 +
466 +       if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
467 +               enable = !enable;
468 +       gpio_set_value(sw->gpio, enable);
469 +
470 +       return count;
471 +}
472 +
473 +static ssize_t gpio_sw_state_show(struct device *dev,
474 +                                 struct device_attribute *attr,
475 +                                 char *buf)
476 +{
477 +       struct gpio_switch *sw = dev_get_drvdata(dev);
478 +       const char **str;
479 +
480 +       str = get_sw_str(sw);
481 +       return sprintf(buf, "%s\n", str[sw->state]);
482 +}
483 +
484 +static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, gpio_sw_state_show,
485 +                  gpio_sw_state_store);
486 +
487 +static ssize_t gpio_sw_type_show(struct device *dev,
488 +                                struct device_attribute *attr,
489 +                                char *buf)
490 +{
491 +       struct gpio_switch *sw = dev_get_drvdata(dev);
492 +
493 +       return sprintf(buf, "%s\n", get_sw_type(sw));
494 +}
495 +
496 +static DEVICE_ATTR(type, S_IRUGO, gpio_sw_type_show, NULL);
497 +
498 +static ssize_t gpio_sw_direction_show(struct device *dev,
499 +                                     struct device_attribute *attr,
500 +                                     char *buf)
501 +{
502 +       struct gpio_switch *sw = dev_get_drvdata(dev);
503 +       int is_output;
504 +
505 +       is_output = sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT;
506 +       return sprintf(buf, "%s\n", is_output ? "output" : "input");
507 +}
508 +
509 +static DEVICE_ATTR(direction, S_IRUGO, gpio_sw_direction_show, NULL);
510 +
511 +
512 +static irqreturn_t gpio_sw_irq_handler(int irq, void *arg)
513 +{
514 +       struct gpio_switch *sw = arg;
515 +       unsigned long timeout;
516 +       int state;
517 +
518 +       if (!sw->both_edges) {
519 +               if (gpio_get_value(sw->gpio))
520 +                       set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQ_TYPE_EDGE_FALLING);
521 +               else
522 +                       set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQ_TYPE_EDGE_RISING);
523 +       }
524 +
525 +       state = gpio_sw_get_state(sw);
526 +       if (sw->state == state)
527 +               return IRQ_HANDLED;
528 +
529 +       if (state)
530 +               timeout = sw->debounce_rising;
531 +       else
532 +               timeout = sw->debounce_falling;
533 +       if (!timeout)
534 +               schedule_work(&sw->work);
535 +       else
536 +               mod_timer(&sw->timer, jiffies + msecs_to_jiffies(timeout));
537 +
538 +       return IRQ_HANDLED;
539 +}
540 +
541 +static void gpio_sw_timer(unsigned long arg)
542 +{
543 +       struct gpio_switch *sw = (struct gpio_switch *) arg;
544 +
545 +       schedule_work(&sw->work);
546 +}
547 +
548 +static void gpio_sw_handler(struct work_struct *work)
549 +{
550 +       struct gpio_switch *sw = container_of(work, struct gpio_switch, work);
551 +       int state;
552 +
553 +       state = gpio_sw_get_state(sw);
554 +       if (sw->state == state)
555 +               return;
556 +
557 +       sw->state = state;
558 +       if (sw->notify != NULL)
559 +               sw->notify(sw->notify_data, state);
560 +       sysfs_notify(&sw->pdev.dev.kobj, NULL, "state");
561 +       print_sw_state(sw, state);
562 +}
563 +
564 +static int __init can_do_both_edges(struct gpio_switch *sw)
565 +{
566 +       if (!cpu_class_is_omap1())
567 +               return 1;
568 +       if (OMAP_GPIO_IS_MPUIO(sw->gpio))
569 +               return 0;
570 +       else
571 +               return 1;
572 +}
573 +
574 +static void gpio_sw_release(struct device *dev)
575 +{
576 +}
577 +
578 +static int __init new_switch(struct gpio_switch *sw)
579 +{
580 +       int r, direction, trigger;
581 +
582 +       switch (sw->type) {
583 +       case OMAP_GPIO_SWITCH_TYPE_COVER:
584 +       case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
585 +       case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
586 +               break;
587 +       default:
588 +               printk(KERN_ERR "invalid GPIO switch type: %d\n", sw->type);
589 +               return -EINVAL;
590 +       }
591 +
592 +       sw->pdev.name   = sw->name;
593 +       sw->pdev.id     = -1;
594 +
595 +       sw->pdev.dev.parent = &gpio_sw_platform_dev->dev;
596 +       sw->pdev.dev.driver = &gpio_sw_driver.driver;
597 +       sw->pdev.dev.release = gpio_sw_release;
598 +
599 +       r = platform_device_register(&sw->pdev);
600 +       if (r) {
601 +               printk(KERN_ERR "gpio-switch: platform device registration "
602 +                      "failed for %s", sw->name);
603 +               return r;
604 +       }
605 +       dev_set_drvdata(&sw->pdev.dev, sw);
606 +
607 +       r = gpio_request(sw->gpio, "gpio-switch");
608 +       if (r < 0) {
609 +               platform_device_unregister(&sw->pdev);
610 +               return r;
611 +       }
612 +
613 +       /* input: 1, output: 0 */
614 +       direction = !(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT);
615 +       if (direction)
616 +               gpio_direction_input(sw->gpio);
617 +       else
618 +               gpio_direction_output(sw->gpio, 0);
619 +
620 +       sw->state = gpio_sw_get_state(sw);
621 +
622 +       r = 0;
623 +       r |= device_create_file(&sw->pdev.dev, &dev_attr_state);
624 +       r |= device_create_file(&sw->pdev.dev, &dev_attr_type);
625 +       r |= device_create_file(&sw->pdev.dev, &dev_attr_direction);
626 +       if (r)
627 +               printk(KERN_ERR "gpio-switch: attribute file creation "
628 +                      "failed for %s\n", sw->name);
629 +
630 +       if (!direction)
631 +               return 0;
632 +
633 +       if (can_do_both_edges(sw)) {
634 +               trigger = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
635 +               sw->both_edges = 1;
636 +       } else {
637 +               if (gpio_get_value(sw->gpio))
638 +                       trigger = IRQF_TRIGGER_FALLING;
639 +               else
640 +                       trigger = IRQF_TRIGGER_RISING;
641 +       }
642 +       r = request_irq(OMAP_GPIO_IRQ(sw->gpio), gpio_sw_irq_handler,
643 +                       IRQF_SHARED | trigger, sw->name, sw);
644 +       if (r < 0) {
645 +               printk(KERN_ERR "gpio-switch: request_irq() failed "
646 +                      "for GPIO %d\n", sw->gpio);
647 +               platform_device_unregister(&sw->pdev);
648 +               gpio_free(sw->gpio);
649 +               return r;
650 +       }
651 +
652 +       INIT_WORK(&sw->work, gpio_sw_handler);
653 +       init_timer(&sw->timer);
654 +
655 +       sw->timer.function = gpio_sw_timer;
656 +       sw->timer.data = (unsigned long)sw;
657 +
658 +       list_add(&sw->node, &gpio_switches);
659 +
660 +       return 0;
661 +}
662 +
663 +static int __init add_atag_switches(void)
664 +{
665 +       const struct omap_gpio_switch_config *cfg;
666 +       struct gpio_switch *sw;
667 +       int i, r;
668 +
669 +       for (i = 0; ; i++) {
670 +               cfg = omap_get_nr_config(OMAP_TAG_GPIO_SWITCH,
671 +                                        struct omap_gpio_switch_config, i);
672 +               if (cfg == NULL)
673 +                       break;
674 +               sw = kzalloc(sizeof(*sw), GFP_KERNEL);
675 +               if (sw == NULL) {
676 +                       printk(KERN_ERR "gpio-switch: kmalloc failed\n");
677 +                       return -ENOMEM;
678 +               }
679 +               strncpy(sw->name, cfg->name, sizeof(cfg->name));
680 +               sw->gpio = cfg->gpio;
681 +               sw->flags = cfg->flags;
682 +               sw->type = cfg->type;
683 +               sw->debounce_rising = OMAP_GPIO_SW_DEFAULT_DEBOUNCE;
684 +               sw->debounce_falling = OMAP_GPIO_SW_DEFAULT_DEBOUNCE;
685 +               if ((r = new_switch(sw)) < 0) {
686 +                       kfree(sw);
687 +                       return r;
688 +               }
689 +       }
690 +       return 0;
691 +}
692 +
693 +static struct gpio_switch * __init find_switch(int gpio, const char *name)
694 +{
695 +       struct gpio_switch *sw;
696 +
697 +       list_for_each_entry(sw, &gpio_switches, node) {
698 +               if ((gpio < 0 || sw->gpio != gpio) &&
699 +                   (name == NULL || strcmp(sw->name, name) != 0))
700 +                       continue;
701 +
702 +               if (gpio < 0 || name == NULL)
703 +                       goto no_check;
704 +
705 +               if (strcmp(sw->name, name) != 0)
706 +                       printk("gpio-switch: name mismatch for %d (%s, %s)\n",
707 +                              gpio, name, sw->name);
708 +               else if (sw->gpio != gpio)
709 +                       printk("gpio-switch: GPIO mismatch for %s (%d, %d)\n",
710 +                              name, gpio, sw->gpio);
711 +no_check:
712 +               return sw;
713 +       }
714 +       return NULL;
715 +}
716 +
717 +static int __init add_board_switches(void)
718 +{
719 +       int i;
720 +
721 +       for (i = 0; i < board_gpio_sw_count; i++) {
722 +               const struct omap_gpio_switch *cfg;
723 +               struct gpio_switch *sw;
724 +               int r;
725 +
726 +               cfg = board_gpio_sw_table + i;
727 +               if (strlen(cfg->name) > sizeof(sw->name) - 1)
728 +                       return -EINVAL;
729 +               /* Check whether we only update an existing switch
730 +                * or add a new switch. */
731 +               sw = find_switch(cfg->gpio, cfg->name);
732 +               if (sw != NULL) {
733 +                       sw->debounce_rising = cfg->debounce_rising;
734 +                       sw->debounce_falling = cfg->debounce_falling;
735 +                       sw->notify = cfg->notify;
736 +                       sw->notify_data = cfg->notify_data;
737 +                       continue;
738 +               } else {
739 +                       if (cfg->gpio < 0 || cfg->name == NULL) {
740 +                               printk("gpio-switch: required switch not "
741 +                                      "found (%d, %s)\n", cfg->gpio,
742 +                                      cfg->name);
743 +                               continue;
744 +                       }
745 +               }
746 +               sw = kzalloc(sizeof(*sw), GFP_KERNEL);
747 +               if (sw == NULL) {
748 +                       printk(KERN_ERR "gpio-switch: kmalloc failed\n");
749 +                       return -ENOMEM;
750 +               }
751 +               strlcpy(sw->name, cfg->name, sizeof(sw->name));
752 +               sw->gpio = cfg->gpio;
753 +               sw->flags = cfg->flags;
754 +               sw->type = cfg->type;
755 +               sw->debounce_rising = cfg->debounce_rising;
756 +               sw->debounce_falling = cfg->debounce_falling;
757 +               sw->notify = cfg->notify;
758 +               sw->notify_data = cfg->notify_data;
759 +               if ((r = new_switch(sw)) < 0) {
760 +                       kfree(sw);
761 +                       return r;
762 +               }
763 +       }
764 +       return 0;
765 +}
766 +
767 +static void gpio_sw_cleanup(void)
768 +{
769 +       struct gpio_switch *sw = NULL, *old = NULL;
770 +
771 +       list_for_each_entry(sw, &gpio_switches, node) {
772 +               if (old != NULL)
773 +                       kfree(old);
774 +               flush_scheduled_work();
775 +               del_timer_sync(&sw->timer);
776 +
777 +               free_irq(OMAP_GPIO_IRQ(sw->gpio), sw);
778 +
779 +               device_remove_file(&sw->pdev.dev, &dev_attr_state);
780 +               device_remove_file(&sw->pdev.dev, &dev_attr_type);
781 +               device_remove_file(&sw->pdev.dev, &dev_attr_direction);
782 +
783 +               platform_device_unregister(&sw->pdev);
784 +               gpio_free(sw->gpio);
785 +               old = sw;
786 +       }
787 +       kfree(old);
788 +}
789 +
790 +static void __init report_initial_state(void)
791 +{
792 +       struct gpio_switch *sw;
793 +
794 +       list_for_each_entry(sw, &gpio_switches, node) {
795 +               int state;
796 +
797 +               state = gpio_get_value(sw->gpio);
798 +               if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
799 +                       state = !state;
800 +               if (sw->notify != NULL)
801 +                       sw->notify(sw->notify_data, state);
802 +               print_sw_state(sw, state);
803 +       }
804 +}
805 +
806 +static int gpio_sw_remove(struct platform_device *dev)
807 +{
808 +       return 0;
809 +}
810 +
811 +static struct platform_driver gpio_sw_driver = {
812 +       .remove         = gpio_sw_remove,
813 +       .driver         = {
814 +               .name   = "gpio-switch",
815 +       },
816 +};
817 +
818 +void __init omap_register_gpio_switches(const struct omap_gpio_switch *tbl,
819 +                                       int count)
820 +{
821 +       BUG_ON(board_gpio_sw_table != NULL);
822 +
823 +       board_gpio_sw_table = tbl;
824 +       board_gpio_sw_count = count;
825 +}
826 +
827 +static int __init gpio_sw_init(void)
828 +{
829 +       int r;
830 +
831 +       printk(KERN_INFO "OMAP GPIO switch handler initializing\n");
832 +
833 +       r = platform_driver_register(&gpio_sw_driver);
834 +       if (r)
835 +               return r;
836 +
837 +       gpio_sw_platform_dev = platform_device_register_simple("gpio-switch",
838 +                                                              -1, NULL, 0);
839 +       if (IS_ERR(gpio_sw_platform_dev)) {
840 +               r = PTR_ERR(gpio_sw_platform_dev);
841 +               goto err1;
842 +       }
843 +
844 +       r = add_atag_switches();
845 +       if (r < 0)
846 +               goto err2;
847 +
848 +       r = add_board_switches();
849 +       if (r < 0)
850 +               goto err2;
851 +
852 +       report_initial_state();
853 +
854 +       return 0;
855 +err2:
856 +       gpio_sw_cleanup();
857 +       platform_device_unregister(gpio_sw_platform_dev);
858 +err1:
859 +       platform_driver_unregister(&gpio_sw_driver);
860 +       return r;
861 +}
862 +
863 +static void __exit gpio_sw_exit(void)
864 +{
865 +       gpio_sw_cleanup();
866 +       platform_device_unregister(gpio_sw_platform_dev);
867 +       platform_driver_unregister(&gpio_sw_driver);
868 +}
869 +
870 +#ifndef MODULE
871 +late_initcall(gpio_sw_init);
872 +#else
873 +module_init(gpio_sw_init);
874 +#endif
875 +module_exit(gpio_sw_exit);
876 +
877 +MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>, Paul Mundt <paul.mundt@nokia.com");
878 +MODULE_DESCRIPTION("GPIO switch driver");
879 +MODULE_LICENSE("GPL");
880 --- a/arch/arm/plat-omap/include/plat/board.h
881 +++ b/arch/arm/plat-omap/include/plat/board.h
882 @@ -151,6 +151,14 @@ struct omap_board_config_kernel {
883         const void *data;
884  };
885  
886 +struct omap_gpio_switch_config {
887 +       char name[12];
888 +       u16 gpio;
889 +       int flags:4;
890 +       int type:4;
891 +       int key_code:24; /* Linux key code */
892 +};
893 +
894  extern const void *__omap_get_config(u16 tag, size_t len, int nr);
895  
896  #define omap_get_config(tag, type) \