sh: R7780RP push-switch support.
[linux-2.6.git] / arch / sh / boards / renesas / r7780rp / psw.c
1 /*
2  * arch/sh/boards/renesas/r7780rp/psw.c
3  *
4  * push switch support for RDBRP-1/RDBREVRP-1 debug boards.
5  *
6  * Copyright (C) 2006  Paul Mundt
7  *
8  * This file is subject to the terms and conditions of the GNU General Public
9  * License.  See the file "COPYING" in the main directory of this archive
10  * for more details.
11  */
12 #include <linux/io.h>
13 #include <linux/init.h>
14 #include <linux/interrupt.h>
15 #include <linux/platform_device.h>
16 #include <asm/mach/r7780rp.h>
17 #include <asm/push-switch.h>
18
19 static irqreturn_t psw_irq_handler(int irq, void *arg)
20 {
21         struct platform_device *pdev = arg;
22         struct push_switch *psw = platform_get_drvdata(pdev);
23         struct push_switch_platform_info *psw_info = pdev->dev.platform_data;
24         unsigned int l, mask;
25         int ret = 0;
26
27         l = ctrl_inw(PA_DBSW);
28
29         /* Nothing to do if there's no state change */
30         if (psw->state) {
31                 ret = 1;
32                 goto out;
33         }
34
35         mask = l & 0x70;
36         /* Figure out who raised it */
37         if (mask & (1 << psw_info->bit)) {
38                 psw->state = !!(mask & (1 << psw_info->bit));
39                 if (psw->state) /* debounce */
40                         mod_timer(&psw->debounce, jiffies + 50);
41
42                 ret = 1;
43         }
44
45 out:
46         /* Clear the switch IRQs */
47         l |= (0x7 << 12);
48         ctrl_outw(l, PA_DBSW);
49
50         return IRQ_RETVAL(ret);
51 }
52
53 static struct resource psw_resources[] = {
54         [0] = {
55                 .start  = IRQ_PSW,
56                 .flags  = IORESOURCE_IRQ,
57         },
58 };
59
60 static struct push_switch_platform_info s2_platform_data = {
61         .name           = "s2",
62         .bit            = 6,
63         .irq_flags      = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
64                           IRQF_SHARED,
65         .irq_handler    = psw_irq_handler,
66 };
67
68 static struct platform_device s2_switch_device = {
69         .name           = "push-switch",
70         .id             = 0,
71         .num_resources  = ARRAY_SIZE(psw_resources),
72         .resource       = psw_resources,
73         .dev            = {
74                 .platform_data = &s2_platform_data,
75         },
76 };
77
78 static struct push_switch_platform_info s3_platform_data = {
79         .name           = "s3",
80         .bit            = 5,
81         .irq_flags      = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
82                           IRQF_SHARED,
83         .irq_handler    = psw_irq_handler,
84 };
85
86 static struct platform_device s3_switch_device = {
87         .name           = "push-switch",
88         .id             = 1,
89         .num_resources  = ARRAY_SIZE(psw_resources),
90         .resource       = psw_resources,
91         .dev            = {
92                 .platform_data = &s3_platform_data,
93         },
94 };
95
96 static struct push_switch_platform_info s4_platform_data = {
97         .name           = "s4",
98         .bit            = 4,
99         .irq_flags      = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
100                           IRQF_SHARED,
101         .irq_handler    = psw_irq_handler,
102 };
103
104 static struct platform_device s4_switch_device = {
105         .name           = "push-switch",
106         .id             = 2,
107         .num_resources  = ARRAY_SIZE(psw_resources),
108         .resource       = psw_resources,
109         .dev            = {
110                 .platform_data = &s4_platform_data,
111         },
112 };
113
114 static struct platform_device *psw_devices[] = {
115         &s2_switch_device, &s3_switch_device, &s4_switch_device,
116 };
117
118 static int __init psw_init(void)
119 {
120         return platform_add_devices(psw_devices, ARRAY_SIZE(psw_devices));
121 }
122 module_init(psw_init);