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
19static 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
45out:
46	/* Clear the switch IRQs */
47	l |= (0x7 << 12);
48	__raw_writew(l, PA_DBSW);
49
50	return IRQ_RETVAL(ret);
51}
52
53static struct resource psw_resources[] = {
54	[0] = {
55		.start	= IRQ_PSW,
56		.flags	= IORESOURCE_IRQ,
57	},
58};
59
60static 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
68static 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
78static 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
86static 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
96static 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
104static 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
114static struct platform_device *psw_devices[] = {
115	&s2_switch_device, &s3_switch_device, &s4_switch_device,
116};
117
118static int __init psw_init(void)
119{
120	return platform_add_devices(psw_devices, ARRAY_SIZE(psw_devices));
121}
122module_init(psw_init);
123