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/module.h>
14 #include <linux/interrupt.h>
15 #include <linux/platform_device.h>
16 #include <mach/highlander.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 = __raw_readw(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 	__raw_writew(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);
123