aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/keyboard/pxa27x_keypad.c
diff options
context:
space:
mode:
authorEric Miao <eric.y.miao@gmail.com>2008-01-31 00:59:03 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2008-01-31 00:59:03 -0500
commit62059d9e912717abbfb875440621d935d091f289 (patch)
tree574d242a19fd54c5af19faea473448cb4efcf0ec /drivers/input/keyboard/pxa27x_keypad.c
parentd7416f9eaa5427f47648973aac3a65e7a0eeda04 (diff)
Input: pxa27x_keypad - enable rotary encoders and direct keys
1. Rotary encoder events can be configured either as relative events as the legacy code does or as any specified key code, this is useful on some platform which uses the rotary keys as KEY_{UP/DOWN/LEFT/RIGHT} 2. Add support for direct keys, the corresponding keycodes for each direct key can now be specified within the platform data 3. Remove the direct/rotary key detection code from the IRQ handler to dedicated functions to improve readability Signed-off-by: Eric Miao <eric.miao@marvell.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/keyboard/pxa27x_keypad.c')
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c163
1 files changed, 134 insertions, 29 deletions
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index e9d4e227a009..cd25b3414491 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -41,6 +41,9 @@
41#define KPC_MKCN(n) ((((n) & 0x7) - 1) << 23) /* matrix key column number */ 41#define KPC_MKCN(n) ((((n) & 0x7) - 1) << 23) /* matrix key column number */
42#define KPC_DKN(n) ((((n) & 0x7) - 1) << 6) /* direct key number */ 42#define KPC_DKN(n) ((((n) & 0x7) - 1) << 6) /* direct key number */
43 43
44#define KPDK_DKP (0x1 << 31)
45#define KPDK_DK(n) ((n) & 0xff)
46
44#define KPAS_MUKP(n) (((n) >> 26) & 0x1f) 47#define KPAS_MUKP(n) (((n) >> 26) & 0x1f)
45#define KPAS_RP(n) (((n) >> 4) & 0xf) 48#define KPAS_RP(n) (((n) >> 4) & 0xf)
46#define KPAS_CP(n) ((n) & 0xf) 49#define KPAS_CP(n) ((n) & 0xf)
@@ -60,6 +63,13 @@ struct pxa27x_keypad {
60 63
61 /* state row bits of each column scan */ 64 /* state row bits of each column scan */
62 uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS]; 65 uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS];
66 uint32_t direct_key_state;
67
68 unsigned int direct_key_mask;
69
70 int rotary_rel_code[2];
71 int rotary_up_key[2];
72 int rotary_down_key[2];
63}; 73};
64 74
65static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) 75static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
@@ -78,6 +88,25 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
78 keypad->matrix_keycodes[(row << 3) + col] = code; 88 keypad->matrix_keycodes[(row << 3) + col] = code;
79 set_bit(code, input_dev->keybit); 89 set_bit(code, input_dev->keybit);
80 } 90 }
91
92 keypad->rotary_up_key[0] = pdata->rotary0_up_key;
93 keypad->rotary_up_key[1] = pdata->rotary1_up_key;
94 keypad->rotary_down_key[0] = pdata->rotary0_down_key;
95 keypad->rotary_down_key[1] = pdata->rotary1_down_key;
96 keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
97 keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
98
99 if (pdata->rotary0_up_key && pdata->rotary0_down_key) {
100 set_bit(pdata->rotary0_up_key, input_dev->keybit);
101 set_bit(pdata->rotary0_down_key, input_dev->keybit);
102 } else
103 set_bit(pdata->rotary0_rel_code, input_dev->relbit);
104
105 if (pdata->rotary1_up_key && pdata->rotary1_down_key) {
106 set_bit(pdata->rotary1_up_key, input_dev->keybit);
107 set_bit(pdata->rotary1_down_key, input_dev->keybit);
108 } else
109 set_bit(pdata->rotary1_rel_code, input_dev->relbit);
81} 110}
82 111
83static inline unsigned int lookup_matrix_keycode( 112static inline unsigned int lookup_matrix_keycode(
@@ -151,35 +180,92 @@ scan:
151 180
152#define DEFAULT_KPREC (0x007f007f) 181#define DEFAULT_KPREC (0x007f007f)
153 182
183static inline int rotary_delta(uint32_t kprec)
184{
185 if (kprec & KPREC_OF0)
186 return (kprec & 0xff) + 0x7f;
187 else if (kprec & KPREC_UF0)
188 return (kprec & 0xff) - 0x7f - 0xff;
189 else
190 return (kprec & 0xff) - 0x7f;
191}
192
193static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta)
194{
195 struct input_dev *dev = keypad->input_dev;
196
197 if (delta == 0)
198 return;
199
200 if (keypad->rotary_up_key[r] && keypad->rotary_down_key[r]) {
201 int keycode = (delta > 0) ? keypad->rotary_up_key[r] :
202 keypad->rotary_down_key[r];
203
204 /* simulate a press-n-release */
205 input_report_key(dev, keycode, 1);
206 input_sync(dev);
207 input_report_key(dev, keycode, 0);
208 input_sync(dev);
209 } else {
210 input_report_rel(dev, keypad->rotary_rel_code[r], delta);
211 input_sync(dev);
212 }
213}
214
215static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad)
216{
217 struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
218 uint32_t kprec;
219
220 /* read and reset to default count value */
221 kprec = KPREC;
222 KPREC = DEFAULT_KPREC;
223
224 if (pdata->enable_rotary0)
225 report_rotary_event(keypad, 0, rotary_delta(kprec));
226
227 if (pdata->enable_rotary1)
228 report_rotary_event(keypad, 1, rotary_delta(kprec >> 16));
229}
230
231static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
232{
233 struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
234 unsigned int new_state;
235 uint32_t kpdk, bits_changed;
236 int i;
237
238 kpdk = KPDK;
239
240 if (pdata->enable_rotary0 || pdata->enable_rotary1)
241 pxa27x_keypad_scan_rotary(keypad);
242
243 if (pdata->direct_key_map == NULL)
244 return;
245
246 new_state = KPDK_DK(kpdk) & keypad->direct_key_mask;
247 bits_changed = keypad->direct_key_state ^ new_state;
248
249 if (bits_changed == 0)
250 return;
251
252 for (i = 0; i < pdata->direct_key_num; i++) {
253 if (bits_changed & (1 << i))
254 input_report_key(keypad->input_dev,
255 pdata->direct_key_map[i],
256 (new_state & (1 << i)));
257 }
258 input_sync(keypad->input_dev);
259 keypad->direct_key_state = new_state;
260}
261
154static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id) 262static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id)
155{ 263{
156 struct pxa27x_keypad *keypad = dev_id; 264 struct pxa27x_keypad *keypad = dev_id;
157 struct input_dev *input_dev = keypad->input_dev;
158 unsigned long kpc = KPC; 265 unsigned long kpc = KPC;
159 int rel; 266
160 267 if (kpc & KPC_DI)
161 if (kpc & KPC_DI) { 268 pxa27x_keypad_scan_direct(keypad);
162 unsigned long kpdk = KPDK;
163
164 if (!(kpdk & KPDK_DKP)) {
165 /* better luck next time */
166 } else if (kpc & KPC_REE0) {
167 unsigned long kprec = KPREC;
168 KPREC = 0x7f;
169
170 if (kprec & KPREC_OF0)
171 rel = (kprec & 0xff) + 0x7f;
172 else if (kprec & KPREC_UF0)
173 rel = (kprec & 0xff) - 0x7f - 0xff;
174 else
175 rel = (kprec & 0xff) - 0x7f;
176
177 if (rel) {
178 input_report_rel(input_dev, REL_WHEEL, rel);
179 input_sync(input_dev);
180 }
181 }
182 }
183 269
184 if (kpc & KPC_MI) 270 if (kpc & KPC_MI)
185 pxa27x_keypad_scan_matrix(keypad); 271 pxa27x_keypad_scan_matrix(keypad);
@@ -190,6 +276,7 @@ static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id)
190static void pxa27x_keypad_config(struct pxa27x_keypad *keypad) 276static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
191{ 277{
192 struct pxa27x_keypad_platform_data *pdata = keypad->pdata; 278 struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
279 unsigned int mask = 0, direct_key_num = 0;
193 unsigned long kpc = 0; 280 unsigned long kpc = 0;
194 281
195 /* enable matrix keys with automatic scan */ 282 /* enable matrix keys with automatic scan */
@@ -199,10 +286,29 @@ static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
199 KPC_MKCN(pdata->matrix_key_cols); 286 KPC_MKCN(pdata->matrix_key_cols);
200 } 287 }
201 288
202 /* FIXME: hardcoded to enable rotary 0 _only_ */ 289 /* enable rotary key, debounce interval same as direct keys */
203 kpc |= KPC_DKN(2) | KPC_REE0 | KPC_DI | KPC_DIE; 290 if (pdata->enable_rotary0) {
291 mask |= 0x03;
292 direct_key_num = 2;
293 kpc |= KPC_REE0;
294 }
295
296 if (pdata->enable_rotary1) {
297 mask |= 0x0c;
298 direct_key_num = 4;
299 kpc |= KPC_REE1;
300 }
301
302 if (pdata->direct_key_num > direct_key_num)
303 direct_key_num = pdata->direct_key_num;
304
305 keypad->direct_key_mask = ((2 << direct_key_num) - 1) & ~mask;
306
307 /* enable direct key */
308 if (direct_key_num)
309 kpc |= KPC_DE | KPC_DIE | KPC_DKN(direct_key_num);
204 310
205 KPC = kpc; 311 KPC = kpc | KPC_RE_ZERO_DEB;
206 KPREC = DEFAULT_KPREC; 312 KPREC = DEFAULT_KPREC;
207} 313}
208 314
@@ -301,7 +407,6 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
301 407
302 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | 408 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
303 BIT_MASK(EV_REL); 409 BIT_MASK(EV_REL);
304 input_dev->relbit[BIT_WORD(REL_WHEEL)] = BIT_MASK(REL_WHEEL);
305 410
306 pxa27x_keypad_build_keycode(keypad); 411 pxa27x_keypad_build_keycode(keypad);
307 412