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