aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/misc/dm355evm_keys.c
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2009-04-23 22:25:29 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-04-23 22:29:54 -0400
commiteb990b5533cfbddfac6efe783a349525907d1c26 (patch)
tree9ab99029d79a22f8a140b4d1d4002ad6ed20ec6d /drivers/input/misc/dm355evm_keys.c
parente912a30184b2d7fb3ab881120f2dc3e09bb59e1d (diff)
Input: add dm355evm_keys driver
Simple input driver support for the events reported by the MSP430 firmware on the DM355 EVM. Verified using the RC5 remote included with the kit; docs weren't quite right. Some of the keycode selections might need improvement; they can be remapped, so there's at least a runtime workaround. (I also suspect Linux may someday merit more generic support for RC5 based remote controls.) These events don't distinguish key press vs release events, so this reports both and then skips the next event if it's identical. The RC5 remote codes include a "toggle" bit that can help detect autorepeated keys; but this driver doesn't bother with those nuances. This driver relies on the drivers/mfd/dm355evm_msp.c code for core features, including sharing I2C access to this firmware with GPIO, LED, and RTC support. [dtor@mail.ru: fix error unwindng path in probe()] Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/misc/dm355evm_keys.c')
-rw-r--r--drivers/input/misc/dm355evm_keys.c329
1 files changed, 329 insertions, 0 deletions
diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c
new file mode 100644
index 000000000000..a63315ce4a6c
--- /dev/null
+++ b/drivers/input/misc/dm355evm_keys.c
@@ -0,0 +1,329 @@
1/*
2 * dm355evm_keys.c - support buttons and IR remote on DM355 EVM board
3 *
4 * Copyright (c) 2008 by David Brownell
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/input.h>
14#include <linux/platform_device.h>
15#include <linux/interrupt.h>
16
17#include <linux/i2c/dm355evm_msp.h>
18
19
20/*
21 * The MSP430 firmware on the DM355 EVM monitors on-board pushbuttons
22 * and an IR receptor used for the remote control. When any key is
23 * pressed, or its autorepeat kicks in, an event is sent. This driver
24 * read those events from the small (32 event) queue and reports them.
25 *
26 * Because we communicate with the MSP430 using I2C, and all I2C calls
27 * in Linux sleep, we need to cons up a kind of threaded IRQ handler
28 * using a work_struct. The IRQ is active low, but we use it through
29 * the GPIO controller so we can trigger on falling edges.
30 *
31 * Note that physically there can only be one of these devices.
32 *
33 * This driver was tested with firmware revision A4.
34 */
35struct dm355evm_keys {
36 struct work_struct work;
37 struct input_dev *input;
38 struct device *dev;
39 int irq;
40};
41
42static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
43{
44 struct dm355evm_keys *keys = _keys;
45
46 schedule_work(&keys->work);
47 return IRQ_HANDLED;
48}
49
50/* These initial keycodes can be remapped by dm355evm_setkeycode(). */
51static struct {
52 u16 event;
53 u16 keycode;
54} dm355evm_keys[] = {
55
56 /*
57 * Pushbuttons on the EVM board ... note that the labels for these
58 * are SW10/SW11/etc on the PC board. The left/right orientation
59 * comes only from the firmware's documentation, and presumes the
60 * power connector is immediately in front of you and the IR sensor
61 * is to the right. (That is, rotate the board counter-clockwise
62 * by 90 degrees from the SW10/etc and "DM355 EVM" labels.)
63 */
64 { 0x00d8, KEY_OK, }, /* SW12 */
65 { 0x00b8, KEY_UP, }, /* SW13 */
66 { 0x00e8, KEY_DOWN, }, /* SW11 */
67 { 0x0078, KEY_LEFT, }, /* SW14 */
68 { 0x00f0, KEY_RIGHT, }, /* SW10 */
69
70 /*
71 * IR buttons ... codes assigned to match the universal remote
72 * provided with the EVM (Philips PM4S) using DVD code 0020.
73 *
74 * These event codes match firmware documentation, but other
75 * remote controls could easily send more RC5-encoded events.
76 * The PM4S manual was used in several cases to help select
77 * a keycode reflecting the intended usage.
78 *
79 * RC5 codes are 14 bits, with two start bits (0x3 prefix)
80 * and a toggle bit (masked out below).
81 */
82 { 0x300c, KEY_POWER, }, /* NOTE: docs omit this */
83 { 0x3000, KEY_NUMERIC_0, },
84 { 0x3001, KEY_NUMERIC_1, },
85 { 0x3002, KEY_NUMERIC_2, },
86 { 0x3003, KEY_NUMERIC_3, },
87 { 0x3004, KEY_NUMERIC_4, },
88 { 0x3005, KEY_NUMERIC_5, },
89 { 0x3006, KEY_NUMERIC_6, },
90 { 0x3007, KEY_NUMERIC_7, },
91 { 0x3008, KEY_NUMERIC_8, },
92 { 0x3009, KEY_NUMERIC_9, },
93 { 0x3022, KEY_ENTER, },
94 { 0x30ec, KEY_MODE, }, /* "tv/vcr/..." */
95 { 0x300f, KEY_SELECT, }, /* "info" */
96 { 0x3020, KEY_CHANNELUP, }, /* "up" */
97 { 0x302e, KEY_MENU, }, /* "in/out" */
98 { 0x3011, KEY_VOLUMEDOWN, }, /* "left" */
99 { 0x300d, KEY_MUTE, }, /* "ok" */
100 { 0x3010, KEY_VOLUMEUP, }, /* "right" */
101 { 0x301e, KEY_SUBTITLE, }, /* "cc" */
102 { 0x3021, KEY_CHANNELDOWN, }, /* "down" */
103 { 0x3022, KEY_PREVIOUS, },
104 { 0x3026, KEY_SLEEP, },
105 { 0x3172, KEY_REWIND, }, /* NOTE: docs wrongly say 0x30ca */
106 { 0x3175, KEY_PLAY, },
107 { 0x3174, KEY_FASTFORWARD, },
108 { 0x3177, KEY_RECORD, },
109 { 0x3176, KEY_STOP, },
110 { 0x3169, KEY_PAUSE, },
111};
112
113static void dm355evm_keys_work(struct work_struct *work)
114{
115 struct dm355evm_keys *keys;
116 int status;
117
118 keys = container_of(work, struct dm355evm_keys, work);
119
120 /* For simplicity we ignore INPUT_COUNT and just read
121 * events until we get the "queue empty" indicator.
122 * Reading INPUT_LOW decrements the count.
123 */
124 for (;;) {
125 static u16 last_event;
126 u16 event;
127 int keycode;
128 int i;
129
130 status = dm355evm_msp_read(DM355EVM_MSP_INPUT_HIGH);
131 if (status < 0) {
132 dev_dbg(keys->dev, "input high err %d\n",
133 status);
134 break;
135 }
136 event = status << 8;
137
138 status = dm355evm_msp_read(DM355EVM_MSP_INPUT_LOW);
139 if (status < 0) {
140 dev_dbg(keys->dev, "input low err %d\n",
141 status);
142 break;
143 }
144 event |= status;
145 if (event == 0xdead)
146 break;
147
148 /* Press and release a button: two events, same code.
149 * Press and hold (autorepeat), then release: N events
150 * (N > 2), same code. For RC5 buttons the toggle bits
151 * distinguish (for example) "1-autorepeat" from "1 1";
152 * but PCB buttons don't support that bit.
153 *
154 * So we must synthesize release events. We do that by
155 * mapping events to a press/release event pair; then
156 * to avoid adding extra events, skip the second event
157 * of each pair.
158 */
159 if (event == last_event) {
160 last_event = 0;
161 continue;
162 }
163 last_event = event;
164
165 /* ignore the RC5 toggle bit */
166 event &= ~0x0800;
167
168 /* find the key, or leave it as unknown */
169 keycode = KEY_UNKNOWN;
170 for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) {
171 if (dm355evm_keys[i].event != event)
172 continue;
173 keycode = dm355evm_keys[i].keycode;
174 break;
175 }
176 dev_dbg(keys->dev,
177 "input event 0x%04x--> keycode %d\n",
178 event, keycode);
179
180 /* report press + release */
181 input_report_key(keys->input, keycode, 1);
182 input_sync(keys->input);
183 input_report_key(keys->input, keycode, 0);
184 input_sync(keys->input);
185 }
186}
187
188static int dm355evm_setkeycode(struct input_dev *dev, int index, int keycode)
189{
190 u16 old_keycode;
191 unsigned i;
192
193 if (((unsigned)index) >= ARRAY_SIZE(dm355evm_keys))
194 return -EINVAL;
195
196 old_keycode = dm355evm_keys[index].keycode;
197 dm355evm_keys[index].keycode = keycode;
198 set_bit(keycode, dev->keybit);
199
200 for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) {
201 if (dm355evm_keys[index].keycode == old_keycode)
202 goto done;
203 }
204 clear_bit(old_keycode, dev->keybit);
205done:
206 return 0;
207}
208
209static int dm355evm_getkeycode(struct input_dev *dev, int index, int *keycode)
210{
211 if (((unsigned)index) >= ARRAY_SIZE(dm355evm_keys))
212 return -EINVAL;
213
214 return dm355evm_keys[index].keycode;
215}
216
217/*----------------------------------------------------------------------*/
218
219static int __devinit dm355evm_keys_probe(struct platform_device *pdev)
220{
221 struct dm355evm_keys *keys;
222 struct input_dev *input;
223 int status;
224 int i;
225
226 /* allocate instance struct and input dev */
227 keys = kzalloc(sizeof *keys, GFP_KERNEL);
228 input = input_allocate_device();
229 if (!keys || !input) {
230 status = -ENOMEM;
231 goto fail1;
232 }
233
234 keys->dev = &pdev->dev;
235 keys->input = input;
236 INIT_WORK(&keys->work, dm355evm_keys_work);
237
238 /* set up "threaded IRQ handler" */
239 status = platform_get_irq(pdev, 0);
240 if (status < 0)
241 goto fail1;
242 keys->irq = status;
243
244 input_set_drvdata(input, keys);
245
246 input->name = "DM355 EVM Controls";
247 input->phys = "dm355evm/input0";
248 input->dev.parent = &pdev->dev;
249
250 input->id.bustype = BUS_I2C;
251 input->id.product = 0x0355;
252 input->id.version = dm355evm_msp_read(DM355EVM_MSP_FIRMREV);
253
254 input->evbit[0] = BIT(EV_KEY);
255 for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++)
256 __set_bit(dm355evm_keys[i].keycode, input->keybit);
257
258 input->setkeycode = dm355evm_setkeycode;
259 input->getkeycode = dm355evm_getkeycode;
260
261 /* REVISIT: flush the event queue? */
262
263 status = request_irq(keys->irq, dm355evm_keys_irq,
264 IRQF_TRIGGER_FALLING,
265 dev_name(&pdev->dev), keys);
266 if (status < 0)
267 goto fail1;
268
269 /* register */
270 status = input_register_device(input);
271 if (status < 0)
272 goto fail2;
273
274 platform_set_drvdata(pdev, keys);
275
276 return 0;
277
278fail2:
279 free_irq(keys->irq, keys);
280fail1:
281 input_free_device(input);
282 kfree(keys);
283 dev_err(&pdev->dev, "can't register, err %d\n", status);
284
285 return status;
286}
287
288static int __devexit dm355evm_keys_remove(struct platform_device *pdev)
289{
290 struct dm355evm_keys *keys = platform_get_drvdata(pdev);
291
292 free_irq(keys->irq, keys);
293 input_unregister_device(keys->input);
294 kfree(keys);
295
296 return 0;
297}
298
299/* REVISIT: add suspend/resume when DaVinci supports it. The IRQ should
300 * be able to wake up the system. When device_may_wakeup(&pdev->dev), call
301 * enable_irq_wake() on suspend, and disable_irq_wake() on resume.
302 */
303
304/*
305 * I2C is used to talk to the MSP430, but this platform device is
306 * exposed by an MFD driver that manages I2C communications.
307 */
308static struct platform_driver dm355evm_keys_driver = {
309 .probe = dm355evm_keys_probe,
310 .remove = __devexit_p(dm355evm_keys_remove),
311 .driver = {
312 .owner = THIS_MODULE,
313 .name = "dm355evm_keys",
314 },
315};
316
317static int __init dm355evm_keys_init(void)
318{
319 return platform_driver_register(&dm355evm_keys_driver);
320}
321module_init(dm355evm_keys_init);
322
323static void __exit dm355evm_keys_exit(void)
324{
325 platform_driver_unregister(&dm355evm_keys_driver);
326}
327module_exit(dm355evm_keys_exit);
328
329MODULE_LICENSE("GPL");