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

Archive Download this file



interactive