diff options
author | Phil Sutter <n0-1@freewrt.org> | 2009-03-05 02:27:15 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2009-03-09 23:10:12 -0400 |
commit | d9bdffd2102404e8ea5f71c5b88dad890984164d (patch) | |
tree | c8deba7479dc3ba6140dd6c55742dbb16f819db7 | |
parent | 73969ff0eda233f140bcbed1251431387b43f383 (diff) |
Input: add driver for S1 button of rb532
Mikrotik's Routerboard 532 has two builtin buttons, from which one
triggers a hardware reset. The other one is accessible through GPIO
pin 1. Sadly, this pin is being multiplexed with UART0 input, so
enabling it as interrupt source (as implied by the gpio-keys driver)
is not possible unless UART0 has been turned off. The later one though
is a rather bad idea as the Routerboard is an embedded device with
only a single serial port, so it's almost always used as serial
console device.
This patch adds a driver based on INPUT_POLLDEV, which disables the
UART and reconfigures GPIO pin 1 temporarily while reading the button
state. This procedure works fine and has been tested as part of
another, unpublished driver for this device.
Signed-off-by: Phil Sutter <n0-1@freewrt.org>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r-- | arch/mips/include/asm/mach-rc32434/gpio.h | 3 | ||||
-rw-r--r-- | arch/mips/rb532/devices.c | 19 | ||||
-rw-r--r-- | drivers/input/misc/Kconfig | 12 | ||||
-rw-r--r-- | drivers/input/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/misc/rb532_button.c | 120 |
5 files changed, 137 insertions, 18 deletions
diff --git a/arch/mips/include/asm/mach-rc32434/gpio.h b/arch/mips/include/asm/mach-rc32434/gpio.h index 3cb50d17b62d..12ee8d510160 100644 --- a/arch/mips/include/asm/mach-rc32434/gpio.h +++ b/arch/mips/include/asm/mach-rc32434/gpio.h | |||
@@ -80,6 +80,9 @@ struct rb532_gpio_reg { | |||
80 | /* Compact Flash GPIO pin */ | 80 | /* Compact Flash GPIO pin */ |
81 | #define CF_GPIO_NUM 13 | 81 | #define CF_GPIO_NUM 13 |
82 | 82 | ||
83 | /* S1 button GPIO (shared with UART0_SIN) */ | ||
84 | #define GPIO_BTN_S1 1 | ||
85 | |||
83 | extern void rb532_gpio_set_ilevel(int bit, unsigned gpio); | 86 | extern void rb532_gpio_set_ilevel(int bit, unsigned gpio); |
84 | extern void rb532_gpio_set_istat(int bit, unsigned gpio); | 87 | extern void rb532_gpio_set_istat(int bit, unsigned gpio); |
85 | extern void rb532_gpio_set_func(unsigned gpio); | 88 | extern void rb532_gpio_set_func(unsigned gpio); |
diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c index 4a5f05b662ae..9f40e1ff9b4f 100644 --- a/arch/mips/rb532/devices.c +++ b/arch/mips/rb532/devices.c | |||
@@ -200,26 +200,9 @@ static struct platform_device rb532_led = { | |||
200 | .id = -1, | 200 | .id = -1, |
201 | }; | 201 | }; |
202 | 202 | ||
203 | static struct gpio_keys_button rb532_gpio_btn[] = { | ||
204 | { | ||
205 | .gpio = 1, | ||
206 | .code = BTN_0, | ||
207 | .desc = "S1", | ||
208 | .active_low = 1, | ||
209 | } | ||
210 | }; | ||
211 | |||
212 | static struct gpio_keys_platform_data rb532_gpio_btn_data = { | ||
213 | .buttons = rb532_gpio_btn, | ||
214 | .nbuttons = ARRAY_SIZE(rb532_gpio_btn), | ||
215 | }; | ||
216 | |||
217 | static struct platform_device rb532_button = { | 203 | static struct platform_device rb532_button = { |
218 | .name = "gpio-keys", | 204 | .name = "rb532-button", |
219 | .id = -1, | 205 | .id = -1, |
220 | .dev = { | ||
221 | .platform_data = &rb532_gpio_btn_data, | ||
222 | } | ||
223 | }; | 206 | }; |
224 | 207 | ||
225 | static struct resource rb532_wdt_res[] = { | 208 | static struct resource rb532_wdt_res[] = { |
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 806d2e66d249..203abac1e23e 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
@@ -238,4 +238,16 @@ config INPUT_GPIO_ROTARY_ENCODER | |||
238 | To compile this driver as a module, choose M here: the | 238 | To compile this driver as a module, choose M here: the |
239 | module will be called rotary_encoder. | 239 | module will be called rotary_encoder. |
240 | 240 | ||
241 | config INPUT_RB532_BUTTON | ||
242 | tristate "Mikrotik Routerboard 532 button interface" | ||
243 | depends on MIKROTIK_RB532 | ||
244 | depends on GPIOLIB && GENERIC_GPIO | ||
245 | select INPUT_POLLDEV | ||
246 | help | ||
247 | Say Y here if you want support for the S1 button built into | ||
248 | Mikrotik's Routerboard 532. | ||
249 | |||
250 | To compile this driver as a module, choose M here: the | ||
251 | module will be called rb532_button. | ||
252 | |||
241 | endif | 253 | endif |
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index e86cee66c914..e94cfd9be6cc 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile | |||
@@ -23,4 +23,5 @@ obj-$(CONFIG_INPUT_APANEL) += apanel.o | |||
23 | obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o | 23 | obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o |
24 | obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o | 24 | obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o |
25 | obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o | 25 | obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o |
26 | obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o | ||
26 | 27 | ||
diff --git a/drivers/input/misc/rb532_button.c b/drivers/input/misc/rb532_button.c new file mode 100644 index 000000000000..e2c7f622a0b5 --- /dev/null +++ b/drivers/input/misc/rb532_button.c | |||
@@ -0,0 +1,120 @@ | |||
1 | /* | ||
2 | * Support for the S1 button on Routerboard 532 | ||
3 | * | ||
4 | * Copyright (C) 2009 Phil Sutter <n0-1@freewrt.org> | ||
5 | */ | ||
6 | |||
7 | #include <linux/input-polldev.h> | ||
8 | #include <linux/module.h> | ||
9 | #include <linux/platform_device.h> | ||
10 | |||
11 | #include <asm/mach-rc32434/gpio.h> | ||
12 | #include <asm/mach-rc32434/rb.h> | ||
13 | |||
14 | #define DRV_NAME "rb532-button" | ||
15 | |||
16 | #define RB532_BTN_RATE 100 /* msec */ | ||
17 | #define RB532_BTN_KSYM BTN_0 | ||
18 | |||
19 | /* The S1 button state is provided by GPIO pin 1. But as this | ||
20 | * pin is also used for uart input as alternate function, the | ||
21 | * operational modes must be switched first: | ||
22 | * 1) disable uart using set_latch_u5() | ||
23 | * 2) turn off alternate function implicitly through | ||
24 | * gpio_direction_input() | ||
25 | * 3) read the GPIO's current value | ||
26 | * 4) undo step 2 by enabling alternate function (in this | ||
27 | * mode the GPIO direction is fixed, so no change needed) | ||
28 | * 5) turn on uart again | ||
29 | * The GPIO value occurs to be inverted, so pin high means | ||
30 | * button is not pressed. | ||
31 | */ | ||
32 | static bool rb532_button_pressed(void) | ||
33 | { | ||
34 | int val; | ||
35 | |||
36 | set_latch_u5(0, LO_FOFF); | ||
37 | gpio_direction_input(GPIO_BTN_S1); | ||
38 | |||
39 | val = gpio_get_value(GPIO_BTN_S1); | ||
40 | |||
41 | rb532_gpio_set_func(GPIO_BTN_S1); | ||
42 | set_latch_u5(LO_FOFF, 0); | ||
43 | |||
44 | return !val; | ||
45 | } | ||
46 | |||
47 | static void rb532_button_poll(struct input_polled_dev *poll_dev) | ||
48 | { | ||
49 | input_report_key(poll_dev->input, RB532_BTN_KSYM, | ||
50 | rb532_button_pressed()); | ||
51 | input_sync(poll_dev->input); | ||
52 | } | ||
53 | |||
54 | static int __devinit rb532_button_probe(struct platform_device *pdev) | ||
55 | { | ||
56 | struct input_polled_dev *poll_dev; | ||
57 | int error; | ||
58 | |||
59 | poll_dev = input_allocate_polled_device(); | ||
60 | if (!poll_dev) | ||
61 | return -ENOMEM; | ||
62 | |||
63 | poll_dev->poll = rb532_button_poll; | ||
64 | poll_dev->poll_interval = RB532_BTN_RATE; | ||
65 | |||
66 | poll_dev->input->name = "rb532 button"; | ||
67 | poll_dev->input->phys = "rb532/button0"; | ||
68 | poll_dev->input->id.bustype = BUS_HOST; | ||
69 | poll_dev->input->dev.parent = &pdev->dev; | ||
70 | |||
71 | dev_set_drvdata(&pdev->dev, poll_dev); | ||
72 | |||
73 | input_set_capability(poll_dev->input, EV_KEY, RB532_BTN_KSYM); | ||
74 | |||
75 | error = input_register_polled_device(poll_dev); | ||
76 | if (error) { | ||
77 | input_free_polled_device(poll_dev); | ||
78 | return error; | ||
79 | } | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int __devexit rb532_button_remove(struct platform_device *pdev) | ||
85 | { | ||
86 | struct input_polled_dev *poll_dev = dev_get_drvdata(&pdev->dev); | ||
87 | |||
88 | input_unregister_polled_device(poll_dev); | ||
89 | input_free_polled_device(poll_dev); | ||
90 | dev_set_drvdata(&pdev->dev, NULL); | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static struct platform_driver rb532_button_driver = { | ||
96 | .probe = rb532_button_probe, | ||
97 | .remove = __devexit_p(rb532_button_remove), | ||
98 | .driver = { | ||
99 | .name = DRV_NAME, | ||
100 | .owner = THIS_MODULE, | ||
101 | }, | ||
102 | }; | ||
103 | |||
104 | static int __init rb532_button_init(void) | ||
105 | { | ||
106 | return platform_driver_register(&rb532_button_driver); | ||
107 | } | ||
108 | |||
109 | static void __exit rb532_button_exit(void) | ||
110 | { | ||
111 | platform_driver_unregister(&rb532_button_driver); | ||
112 | } | ||
113 | |||
114 | module_init(rb532_button_init); | ||
115 | module_exit(rb532_button_exit); | ||
116 | |||
117 | MODULE_AUTHOR("Phil Sutter <n0-1@freewrt.org>"); | ||
118 | MODULE_LICENSE("GPL"); | ||
119 | MODULE_DESCRIPTION("Support for S1 button on Routerboard 532"); | ||
120 | MODULE_ALIAS("platform:" DRV_NAME); | ||