Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/input/misc/dm355evm_keys.c
15109 views
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/slab.h>
14
#include <linux/input.h>
15
#include <linux/input/sparse-keymap.h>
16
#include <linux/platform_device.h>
17
#include <linux/interrupt.h>
18
19
#include <linux/i2c/dm355evm_msp.h>
20
21
22
/*
23
* The MSP430 firmware on the DM355 EVM monitors on-board pushbuttons
24
* and an IR receptor used for the remote control. When any key is
25
* pressed, or its autorepeat kicks in, an event is sent. This driver
26
* read those events from the small (32 event) queue and reports them.
27
*
28
* Note that physically there can only be one of these devices.
29
*
30
* This driver was tested with firmware revision A4.
31
*/
32
struct dm355evm_keys {
33
struct input_dev *input;
34
struct device *dev;
35
int irq;
36
};
37
38
/* These initial keycodes can be remapped */
39
static const struct key_entry dm355evm_keys[] = {
40
/*
41
* Pushbuttons on the EVM board ... note that the labels for these
42
* are SW10/SW11/etc on the PC board. The left/right orientation
43
* comes only from the firmware's documentation, and presumes the
44
* power connector is immediately in front of you and the IR sensor
45
* is to the right. (That is, rotate the board counter-clockwise
46
* by 90 degrees from the SW10/etc and "DM355 EVM" labels.)
47
*/
48
{ KE_KEY, 0x00d8, { KEY_OK } }, /* SW12 */
49
{ KE_KEY, 0x00b8, { KEY_UP } }, /* SW13 */
50
{ KE_KEY, 0x00e8, { KEY_DOWN } }, /* SW11 */
51
{ KE_KEY, 0x0078, { KEY_LEFT } }, /* SW14 */
52
{ KE_KEY, 0x00f0, { KEY_RIGHT } }, /* SW10 */
53
54
/*
55
* IR buttons ... codes assigned to match the universal remote
56
* provided with the EVM (Philips PM4S) using DVD code 0020.
57
*
58
* These event codes match firmware documentation, but other
59
* remote controls could easily send more RC5-encoded events.
60
* The PM4S manual was used in several cases to help select
61
* a keycode reflecting the intended usage.
62
*
63
* RC5 codes are 14 bits, with two start bits (0x3 prefix)
64
* and a toggle bit (masked out below).
65
*/
66
{ KE_KEY, 0x300c, { KEY_POWER } }, /* NOTE: docs omit this */
67
{ KE_KEY, 0x3000, { KEY_NUMERIC_0 } },
68
{ KE_KEY, 0x3001, { KEY_NUMERIC_1 } },
69
{ KE_KEY, 0x3002, { KEY_NUMERIC_2 } },
70
{ KE_KEY, 0x3003, { KEY_NUMERIC_3 } },
71
{ KE_KEY, 0x3004, { KEY_NUMERIC_4 } },
72
{ KE_KEY, 0x3005, { KEY_NUMERIC_5 } },
73
{ KE_KEY, 0x3006, { KEY_NUMERIC_6 } },
74
{ KE_KEY, 0x3007, { KEY_NUMERIC_7 } },
75
{ KE_KEY, 0x3008, { KEY_NUMERIC_8 } },
76
{ KE_KEY, 0x3009, { KEY_NUMERIC_9 } },
77
{ KE_KEY, 0x3022, { KEY_ENTER } },
78
{ KE_KEY, 0x30ec, { KEY_MODE } }, /* "tv/vcr/..." */
79
{ KE_KEY, 0x300f, { KEY_SELECT } }, /* "info" */
80
{ KE_KEY, 0x3020, { KEY_CHANNELUP } }, /* "up" */
81
{ KE_KEY, 0x302e, { KEY_MENU } }, /* "in/out" */
82
{ KE_KEY, 0x3011, { KEY_VOLUMEDOWN } }, /* "left" */
83
{ KE_KEY, 0x300d, { KEY_MUTE } }, /* "ok" */
84
{ KE_KEY, 0x3010, { KEY_VOLUMEUP } }, /* "right" */
85
{ KE_KEY, 0x301e, { KEY_SUBTITLE } }, /* "cc" */
86
{ KE_KEY, 0x3021, { KEY_CHANNELDOWN } },/* "down" */
87
{ KE_KEY, 0x3022, { KEY_PREVIOUS } },
88
{ KE_KEY, 0x3026, { KEY_SLEEP } },
89
{ KE_KEY, 0x3172, { KEY_REWIND } }, /* NOTE: docs wrongly say 0x30ca */
90
{ KE_KEY, 0x3175, { KEY_PLAY } },
91
{ KE_KEY, 0x3174, { KEY_FASTFORWARD } },
92
{ KE_KEY, 0x3177, { KEY_RECORD } },
93
{ KE_KEY, 0x3176, { KEY_STOP } },
94
{ KE_KEY, 0x3169, { KEY_PAUSE } },
95
};
96
97
/*
98
* Because we communicate with the MSP430 using I2C, and all I2C calls
99
* in Linux sleep, we use a threaded IRQ handler. The IRQ itself is
100
* active low, but we go through the GPIO controller so we can trigger
101
* on falling edges and not worry about enabling/disabling the IRQ in
102
* the keypress handling path.
103
*/
104
static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
105
{
106
static u16 last_event;
107
struct dm355evm_keys *keys = _keys;
108
const struct key_entry *ke;
109
unsigned int keycode;
110
int status;
111
u16 event;
112
113
/* For simplicity we ignore INPUT_COUNT and just read
114
* events until we get the "queue empty" indicator.
115
* Reading INPUT_LOW decrements the count.
116
*/
117
for (;;) {
118
status = dm355evm_msp_read(DM355EVM_MSP_INPUT_HIGH);
119
if (status < 0) {
120
dev_dbg(keys->dev, "input high err %d\n",
121
status);
122
break;
123
}
124
event = status << 8;
125
126
status = dm355evm_msp_read(DM355EVM_MSP_INPUT_LOW);
127
if (status < 0) {
128
dev_dbg(keys->dev, "input low err %d\n",
129
status);
130
break;
131
}
132
event |= status;
133
if (event == 0xdead)
134
break;
135
136
/* Press and release a button: two events, same code.
137
* Press and hold (autorepeat), then release: N events
138
* (N > 2), same code. For RC5 buttons the toggle bits
139
* distinguish (for example) "1-autorepeat" from "1 1";
140
* but PCB buttons don't support that bit.
141
*
142
* So we must synthesize release events. We do that by
143
* mapping events to a press/release event pair; then
144
* to avoid adding extra events, skip the second event
145
* of each pair.
146
*/
147
if (event == last_event) {
148
last_event = 0;
149
continue;
150
}
151
last_event = event;
152
153
/* ignore the RC5 toggle bit */
154
event &= ~0x0800;
155
156
/* find the key, or report it as unknown */
157
ke = sparse_keymap_entry_from_scancode(keys->input, event);
158
keycode = ke ? ke->keycode : KEY_UNKNOWN;
159
dev_dbg(keys->dev,
160
"input event 0x%04x--> keycode %d\n",
161
event, keycode);
162
163
/* report press + release */
164
input_report_key(keys->input, keycode, 1);
165
input_sync(keys->input);
166
input_report_key(keys->input, keycode, 0);
167
input_sync(keys->input);
168
}
169
170
return IRQ_HANDLED;
171
}
172
173
/*----------------------------------------------------------------------*/
174
175
static int __devinit dm355evm_keys_probe(struct platform_device *pdev)
176
{
177
struct dm355evm_keys *keys;
178
struct input_dev *input;
179
int status;
180
181
/* allocate instance struct and input dev */
182
keys = kzalloc(sizeof *keys, GFP_KERNEL);
183
input = input_allocate_device();
184
if (!keys || !input) {
185
status = -ENOMEM;
186
goto fail1;
187
}
188
189
keys->dev = &pdev->dev;
190
keys->input = input;
191
192
/* set up "threaded IRQ handler" */
193
status = platform_get_irq(pdev, 0);
194
if (status < 0)
195
goto fail1;
196
keys->irq = status;
197
198
input_set_drvdata(input, keys);
199
200
input->name = "DM355 EVM Controls";
201
input->phys = "dm355evm/input0";
202
input->dev.parent = &pdev->dev;
203
204
input->id.bustype = BUS_I2C;
205
input->id.product = 0x0355;
206
input->id.version = dm355evm_msp_read(DM355EVM_MSP_FIRMREV);
207
208
status = sparse_keymap_setup(input, dm355evm_keys, NULL);
209
if (status)
210
goto fail1;
211
212
/* REVISIT: flush the event queue? */
213
214
status = request_threaded_irq(keys->irq, NULL, dm355evm_keys_irq,
215
IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), keys);
216
if (status < 0)
217
goto fail2;
218
219
/* register */
220
status = input_register_device(input);
221
if (status < 0)
222
goto fail3;
223
224
platform_set_drvdata(pdev, keys);
225
226
return 0;
227
228
fail3:
229
free_irq(keys->irq, keys);
230
fail2:
231
sparse_keymap_free(input);
232
fail1:
233
input_free_device(input);
234
kfree(keys);
235
dev_err(&pdev->dev, "can't register, err %d\n", status);
236
237
return status;
238
}
239
240
static int __devexit dm355evm_keys_remove(struct platform_device *pdev)
241
{
242
struct dm355evm_keys *keys = platform_get_drvdata(pdev);
243
244
free_irq(keys->irq, keys);
245
sparse_keymap_free(keys->input);
246
input_unregister_device(keys->input);
247
kfree(keys);
248
249
return 0;
250
}
251
252
/* REVISIT: add suspend/resume when DaVinci supports it. The IRQ should
253
* be able to wake up the system. When device_may_wakeup(&pdev->dev), call
254
* enable_irq_wake() on suspend, and disable_irq_wake() on resume.
255
*/
256
257
/*
258
* I2C is used to talk to the MSP430, but this platform device is
259
* exposed by an MFD driver that manages I2C communications.
260
*/
261
static struct platform_driver dm355evm_keys_driver = {
262
.probe = dm355evm_keys_probe,
263
.remove = __devexit_p(dm355evm_keys_remove),
264
.driver = {
265
.owner = THIS_MODULE,
266
.name = "dm355evm_keys",
267
},
268
};
269
270
static int __init dm355evm_keys_init(void)
271
{
272
return platform_driver_register(&dm355evm_keys_driver);
273
}
274
module_init(dm355evm_keys_init);
275
276
static void __exit dm355evm_keys_exit(void)
277
{
278
platform_driver_unregister(&dm355evm_keys_driver);
279
}
280
module_exit(dm355evm_keys_exit);
281
282
MODULE_LICENSE("GPL");
283
284