1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * OMAP4 Keypad Driver |
4 | * |
5 | * Copyright (C) 2010 Texas Instruments |
6 | * |
7 | * Author: Abraham Arce <x0066660@ti.com> |
8 | * Initial Code: Syed Rafiuddin <rafiuddin.syed@ti.com> |
9 | */ |
10 | |
11 | #include <linux/module.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/errno.h> |
15 | #include <linux/io.h> |
16 | #include <linux/of.h> |
17 | #include <linux/input.h> |
18 | #include <linux/input/matrix_keypad.h> |
19 | #include <linux/slab.h> |
20 | #include <linux/pm_runtime.h> |
21 | #include <linux/pm_wakeirq.h> |
22 | |
23 | /* OMAP4 registers */ |
24 | #define OMAP4_KBD_REVISION 0x00 |
25 | #define OMAP4_KBD_SYSCONFIG 0x10 |
26 | #define OMAP4_KBD_SYSSTATUS 0x14 |
27 | #define OMAP4_KBD_IRQSTATUS 0x18 |
28 | #define OMAP4_KBD_IRQENABLE 0x1C |
29 | #define OMAP4_KBD_WAKEUPENABLE 0x20 |
30 | #define OMAP4_KBD_PENDING 0x24 |
31 | #define OMAP4_KBD_CTRL 0x28 |
32 | #define OMAP4_KBD_DEBOUNCINGTIME 0x2C |
33 | #define OMAP4_KBD_LONGKEYTIME 0x30 |
34 | #define OMAP4_KBD_TIMEOUT 0x34 |
35 | #define OMAP4_KBD_STATEMACHINE 0x38 |
36 | #define OMAP4_KBD_ROWINPUTS 0x3C |
37 | #define OMAP4_KBD_COLUMNOUTPUTS 0x40 |
38 | #define OMAP4_KBD_FULLCODE31_0 0x44 |
39 | #define OMAP4_KBD_FULLCODE63_32 0x48 |
40 | |
41 | /* OMAP4 bit definitions */ |
42 | #define OMAP4_DEF_IRQENABLE_EVENTEN BIT(0) |
43 | #define OMAP4_DEF_IRQENABLE_LONGKEY BIT(1) |
44 | #define OMAP4_DEF_WUP_EVENT_ENA BIT(0) |
45 | #define OMAP4_DEF_WUP_LONG_KEY_ENA BIT(1) |
46 | #define OMAP4_DEF_CTRL_NOSOFTMODE BIT(1) |
47 | #define OMAP4_DEF_CTRL_PTV_SHIFT 2 |
48 | |
49 | /* OMAP4 values */ |
50 | #define OMAP4_VAL_IRQDISABLE 0x0 |
51 | |
52 | /* |
53 | * Errata i689: If a key is released for a time shorter than debounce time, |
54 | * the keyboard will idle and never detect the key release. The workaround |
55 | * is to use at least a 12ms debounce time. See omap5432 TRM chapter |
56 | * "26.4.6.2 Keyboard Controller Timer" for more information. |
57 | */ |
58 | #define OMAP4_KEYPAD_PTV_DIV_128 0x6 |
59 | #define OMAP4_KEYPAD_DEBOUNCINGTIME_MS(dbms, ptv) \ |
60 | ((((dbms) * 1000) / ((1 << ((ptv) + 1)) * (1000000 / 32768))) - 1) |
61 | #define OMAP4_VAL_DEBOUNCINGTIME_16MS \ |
62 | OMAP4_KEYPAD_DEBOUNCINGTIME_MS(16, OMAP4_KEYPAD_PTV_DIV_128) |
63 | #define OMAP4_KEYPAD_AUTOIDLE_MS 50 /* Approximate measured time */ |
64 | #define OMAP4_KEYPAD_IDLE_CHECK_MS (OMAP4_KEYPAD_AUTOIDLE_MS / 2) |
65 | |
66 | enum { |
67 | KBD_REVISION_OMAP4 = 0, |
68 | KBD_REVISION_OMAP5, |
69 | }; |
70 | |
71 | struct omap4_keypad { |
72 | struct input_dev *input; |
73 | |
74 | void __iomem *base; |
75 | unsigned int irq; |
76 | struct mutex lock; /* for key scan */ |
77 | |
78 | unsigned int rows; |
79 | unsigned int cols; |
80 | u32 reg_offset; |
81 | u32 irqreg_offset; |
82 | unsigned int row_shift; |
83 | bool no_autorepeat; |
84 | u64 keys; |
85 | unsigned short *keymap; |
86 | }; |
87 | |
88 | static int kbd_readl(struct omap4_keypad *keypad_data, u32 offset) |
89 | { |
90 | return __raw_readl(addr: keypad_data->base + |
91 | keypad_data->reg_offset + offset); |
92 | } |
93 | |
94 | static void kbd_writel(struct omap4_keypad *keypad_data, u32 offset, u32 value) |
95 | { |
96 | __raw_writel(val: value, |
97 | addr: keypad_data->base + keypad_data->reg_offset + offset); |
98 | } |
99 | |
100 | static int kbd_read_irqreg(struct omap4_keypad *keypad_data, u32 offset) |
101 | { |
102 | return __raw_readl(addr: keypad_data->base + |
103 | keypad_data->irqreg_offset + offset); |
104 | } |
105 | |
106 | static void kbd_write_irqreg(struct omap4_keypad *keypad_data, |
107 | u32 offset, u32 value) |
108 | { |
109 | __raw_writel(val: value, |
110 | addr: keypad_data->base + keypad_data->irqreg_offset + offset); |
111 | } |
112 | |
113 | static int omap4_keypad_report_keys(struct omap4_keypad *keypad_data, |
114 | u64 keys, bool down) |
115 | { |
116 | struct input_dev *input_dev = keypad_data->input; |
117 | unsigned int col, row, code; |
118 | DECLARE_BITMAP(mask, 64); |
119 | unsigned long bit; |
120 | int events = 0; |
121 | |
122 | bitmap_from_u64(dst: mask, mask: keys); |
123 | |
124 | for_each_set_bit(bit, mask, keypad_data->rows * BITS_PER_BYTE) { |
125 | row = bit / BITS_PER_BYTE; |
126 | col = bit % BITS_PER_BYTE; |
127 | code = MATRIX_SCAN_CODE(row, col, keypad_data->row_shift); |
128 | |
129 | input_event(dev: input_dev, EV_MSC, MSC_SCAN, value: code); |
130 | input_report_key(dev: input_dev, code: keypad_data->keymap[code], value: down); |
131 | |
132 | events++; |
133 | } |
134 | |
135 | if (events) |
136 | input_sync(dev: input_dev); |
137 | |
138 | return events; |
139 | } |
140 | |
141 | static void omap4_keypad_scan_keys(struct omap4_keypad *keypad_data, u64 keys) |
142 | { |
143 | u64 changed; |
144 | |
145 | mutex_lock(&keypad_data->lock); |
146 | |
147 | changed = keys ^ keypad_data->keys; |
148 | |
149 | /* |
150 | * Report key up events separately and first. This matters in case we |
151 | * lost key-up interrupt and just now catching up. |
152 | */ |
153 | omap4_keypad_report_keys(keypad_data, keys: changed & ~keys, down: false); |
154 | |
155 | /* Report key down events */ |
156 | omap4_keypad_report_keys(keypad_data, keys: changed & keys, down: true); |
157 | |
158 | keypad_data->keys = keys; |
159 | |
160 | mutex_unlock(lock: &keypad_data->lock); |
161 | } |
162 | |
163 | /* Interrupt handlers */ |
164 | static irqreturn_t omap4_keypad_irq_handler(int irq, void *dev_id) |
165 | { |
166 | struct omap4_keypad *keypad_data = dev_id; |
167 | |
168 | if (kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)) |
169 | return IRQ_WAKE_THREAD; |
170 | |
171 | return IRQ_NONE; |
172 | } |
173 | |
174 | static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id) |
175 | { |
176 | struct omap4_keypad *keypad_data = dev_id; |
177 | struct device *dev = keypad_data->input->dev.parent; |
178 | u32 low, high; |
179 | int error; |
180 | u64 keys; |
181 | |
182 | error = pm_runtime_resume_and_get(dev); |
183 | if (error) |
184 | return IRQ_NONE; |
185 | |
186 | low = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0); |
187 | high = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32); |
188 | keys = low | (u64)high << 32; |
189 | |
190 | omap4_keypad_scan_keys(keypad_data, keys); |
191 | |
192 | /* clear pending interrupts */ |
193 | kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS, |
194 | value: kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)); |
195 | |
196 | pm_runtime_mark_last_busy(dev); |
197 | pm_runtime_put_autosuspend(dev); |
198 | |
199 | return IRQ_HANDLED; |
200 | } |
201 | |
202 | static int omap4_keypad_open(struct input_dev *input) |
203 | { |
204 | struct omap4_keypad *keypad_data = input_get_drvdata(dev: input); |
205 | struct device *dev = input->dev.parent; |
206 | int error; |
207 | |
208 | error = pm_runtime_resume_and_get(dev); |
209 | if (error) |
210 | return error; |
211 | |
212 | disable_irq(irq: keypad_data->irq); |
213 | |
214 | kbd_writel(keypad_data, OMAP4_KBD_CTRL, |
215 | OMAP4_DEF_CTRL_NOSOFTMODE | |
216 | (OMAP4_KEYPAD_PTV_DIV_128 << OMAP4_DEF_CTRL_PTV_SHIFT)); |
217 | kbd_writel(keypad_data, OMAP4_KBD_DEBOUNCINGTIME, |
218 | OMAP4_VAL_DEBOUNCINGTIME_16MS); |
219 | /* clear pending interrupts */ |
220 | kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS, |
221 | value: kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)); |
222 | kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE, |
223 | OMAP4_DEF_IRQENABLE_EVENTEN); |
224 | kbd_writel(keypad_data, OMAP4_KBD_WAKEUPENABLE, |
225 | OMAP4_DEF_WUP_EVENT_ENA); |
226 | |
227 | enable_irq(irq: keypad_data->irq); |
228 | |
229 | pm_runtime_mark_last_busy(dev); |
230 | pm_runtime_put_autosuspend(dev); |
231 | |
232 | return 0; |
233 | } |
234 | |
235 | static void omap4_keypad_stop(struct omap4_keypad *keypad_data) |
236 | { |
237 | /* Disable interrupts and wake-up events */ |
238 | kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE, |
239 | OMAP4_VAL_IRQDISABLE); |
240 | kbd_writel(keypad_data, OMAP4_KBD_WAKEUPENABLE, value: 0); |
241 | |
242 | /* clear pending interrupts */ |
243 | kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS, |
244 | value: kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)); |
245 | } |
246 | |
247 | static void omap4_keypad_close(struct input_dev *input) |
248 | { |
249 | struct omap4_keypad *keypad_data = input_get_drvdata(dev: input); |
250 | struct device *dev = input->dev.parent; |
251 | int error; |
252 | |
253 | error = pm_runtime_resume_and_get(dev); |
254 | if (error) |
255 | dev_err(dev, "%s: pm_runtime_resume_and_get() failed: %d\n" , |
256 | __func__, error); |
257 | |
258 | disable_irq(irq: keypad_data->irq); |
259 | omap4_keypad_stop(keypad_data); |
260 | enable_irq(irq: keypad_data->irq); |
261 | |
262 | pm_runtime_mark_last_busy(dev); |
263 | pm_runtime_put_autosuspend(dev); |
264 | } |
265 | |
266 | static int omap4_keypad_parse_dt(struct device *dev, |
267 | struct omap4_keypad *keypad_data) |
268 | { |
269 | struct device_node *np = dev->of_node; |
270 | int err; |
271 | |
272 | err = matrix_keypad_parse_properties(dev, rows: &keypad_data->rows, |
273 | cols: &keypad_data->cols); |
274 | if (err) |
275 | return err; |
276 | |
277 | keypad_data->no_autorepeat = of_property_read_bool(np, propname: "linux,input-no-autorepeat" ); |
278 | |
279 | return 0; |
280 | } |
281 | |
282 | static int omap4_keypad_check_revision(struct device *dev, |
283 | struct omap4_keypad *keypad_data) |
284 | { |
285 | unsigned int rev; |
286 | |
287 | rev = __raw_readl(addr: keypad_data->base + OMAP4_KBD_REVISION); |
288 | rev &= 0x03 << 30; |
289 | rev >>= 30; |
290 | switch (rev) { |
291 | case KBD_REVISION_OMAP4: |
292 | keypad_data->reg_offset = 0x00; |
293 | keypad_data->irqreg_offset = 0x00; |
294 | break; |
295 | case KBD_REVISION_OMAP5: |
296 | keypad_data->reg_offset = 0x10; |
297 | keypad_data->irqreg_offset = 0x0c; |
298 | break; |
299 | default: |
300 | dev_err(dev, "Keypad reports unsupported revision %d" , rev); |
301 | return -EINVAL; |
302 | } |
303 | |
304 | return 0; |
305 | } |
306 | |
307 | /* |
308 | * Errata ID i689 "1.32 Keyboard Key Up Event Can Be Missed". |
309 | * Interrupt may not happen for key-up events. We must clear stuck |
310 | * key-up events after the keyboard hardware has auto-idled. |
311 | */ |
312 | static int omap4_keypad_runtime_suspend(struct device *dev) |
313 | { |
314 | struct platform_device *pdev = to_platform_device(dev); |
315 | struct omap4_keypad *keypad_data = platform_get_drvdata(pdev); |
316 | u32 active; |
317 | |
318 | active = kbd_readl(keypad_data, OMAP4_KBD_STATEMACHINE); |
319 | if (active) { |
320 | pm_runtime_mark_last_busy(dev); |
321 | return -EBUSY; |
322 | } |
323 | |
324 | omap4_keypad_scan_keys(keypad_data, keys: 0); |
325 | |
326 | return 0; |
327 | } |
328 | |
329 | static const struct dev_pm_ops omap4_keypad_pm_ops = { |
330 | RUNTIME_PM_OPS(omap4_keypad_runtime_suspend, NULL, NULL) |
331 | }; |
332 | |
333 | static void omap4_disable_pm(void *d) |
334 | { |
335 | pm_runtime_dont_use_autosuspend(dev: d); |
336 | pm_runtime_disable(dev: d); |
337 | } |
338 | |
339 | static int omap4_keypad_probe(struct platform_device *pdev) |
340 | { |
341 | struct device *dev = &pdev->dev; |
342 | struct omap4_keypad *keypad_data; |
343 | struct input_dev *input_dev; |
344 | unsigned int max_keys; |
345 | int irq; |
346 | int error; |
347 | |
348 | irq = platform_get_irq(pdev, 0); |
349 | if (irq < 0) |
350 | return irq; |
351 | |
352 | keypad_data = devm_kzalloc(dev, size: sizeof(*keypad_data), GFP_KERNEL); |
353 | if (!keypad_data) { |
354 | dev_err(dev, "keypad_data memory allocation failed\n" ); |
355 | return -ENOMEM; |
356 | } |
357 | |
358 | keypad_data->irq = irq; |
359 | mutex_init(&keypad_data->lock); |
360 | platform_set_drvdata(pdev, data: keypad_data); |
361 | |
362 | error = omap4_keypad_parse_dt(dev, keypad_data); |
363 | if (error) |
364 | return error; |
365 | |
366 | keypad_data->base = devm_platform_ioremap_resource(pdev, index: 0); |
367 | if (IS_ERR(ptr: keypad_data->base)) |
368 | return PTR_ERR(ptr: keypad_data->base); |
369 | |
370 | pm_runtime_use_autosuspend(dev); |
371 | pm_runtime_set_autosuspend_delay(dev, OMAP4_KEYPAD_IDLE_CHECK_MS); |
372 | pm_runtime_enable(dev); |
373 | |
374 | error = devm_add_action_or_reset(dev, omap4_disable_pm, dev); |
375 | if (error) { |
376 | dev_err(dev, "unable to register cleanup action\n" ); |
377 | return error; |
378 | } |
379 | |
380 | /* |
381 | * Enable clocks for the keypad module so that we can read |
382 | * revision register. |
383 | */ |
384 | error = pm_runtime_resume_and_get(dev); |
385 | if (error) { |
386 | dev_err(dev, "pm_runtime_resume_and_get() failed\n" ); |
387 | return error; |
388 | } |
389 | |
390 | error = omap4_keypad_check_revision(dev, keypad_data); |
391 | if (!error) { |
392 | /* Ensure device does not raise interrupts */ |
393 | omap4_keypad_stop(keypad_data); |
394 | } |
395 | |
396 | pm_runtime_mark_last_busy(dev); |
397 | pm_runtime_put_autosuspend(dev); |
398 | if (error) |
399 | return error; |
400 | |
401 | /* input device allocation */ |
402 | keypad_data->input = input_dev = devm_input_allocate_device(dev); |
403 | if (!input_dev) |
404 | return -ENOMEM; |
405 | |
406 | input_dev->name = pdev->name; |
407 | input_dev->id.bustype = BUS_HOST; |
408 | input_dev->id.vendor = 0x0001; |
409 | input_dev->id.product = 0x0001; |
410 | input_dev->id.version = 0x0001; |
411 | |
412 | input_dev->open = omap4_keypad_open; |
413 | input_dev->close = omap4_keypad_close; |
414 | |
415 | input_set_capability(dev: input_dev, EV_MSC, MSC_SCAN); |
416 | if (!keypad_data->no_autorepeat) |
417 | __set_bit(EV_REP, input_dev->evbit); |
418 | |
419 | input_set_drvdata(dev: input_dev, data: keypad_data); |
420 | |
421 | keypad_data->row_shift = get_count_order(count: keypad_data->cols); |
422 | max_keys = keypad_data->rows << keypad_data->row_shift; |
423 | keypad_data->keymap = devm_kcalloc(dev, |
424 | n: max_keys, |
425 | size: sizeof(keypad_data->keymap[0]), |
426 | GFP_KERNEL); |
427 | if (!keypad_data->keymap) { |
428 | dev_err(dev, "Not enough memory for keymap\n" ); |
429 | return -ENOMEM; |
430 | } |
431 | |
432 | error = matrix_keypad_build_keymap(NULL, NULL, |
433 | rows: keypad_data->rows, cols: keypad_data->cols, |
434 | keymap: keypad_data->keymap, input_dev); |
435 | if (error) { |
436 | dev_err(dev, "failed to build keymap\n" ); |
437 | return error; |
438 | } |
439 | |
440 | error = devm_request_threaded_irq(dev, irq: keypad_data->irq, |
441 | handler: omap4_keypad_irq_handler, |
442 | thread_fn: omap4_keypad_irq_thread_fn, |
443 | IRQF_ONESHOT, |
444 | devname: "omap4-keypad" , dev_id: keypad_data); |
445 | if (error) { |
446 | dev_err(dev, "failed to register interrupt\n" ); |
447 | return error; |
448 | } |
449 | |
450 | error = input_register_device(keypad_data->input); |
451 | if (error) { |
452 | dev_err(dev, "failed to register input device\n" ); |
453 | return error; |
454 | } |
455 | |
456 | device_init_wakeup(dev, enable: true); |
457 | error = dev_pm_set_wake_irq(dev, irq: keypad_data->irq); |
458 | if (error) |
459 | dev_warn(dev, "failed to set up wakeup irq: %d\n" , error); |
460 | |
461 | return 0; |
462 | } |
463 | |
464 | static int omap4_keypad_remove(struct platform_device *pdev) |
465 | { |
466 | dev_pm_clear_wake_irq(dev: &pdev->dev); |
467 | |
468 | return 0; |
469 | } |
470 | |
471 | static const struct of_device_id omap_keypad_dt_match[] = { |
472 | { .compatible = "ti,omap4-keypad" }, |
473 | {}, |
474 | }; |
475 | MODULE_DEVICE_TABLE(of, omap_keypad_dt_match); |
476 | |
477 | static struct platform_driver omap4_keypad_driver = { |
478 | .probe = omap4_keypad_probe, |
479 | .remove = omap4_keypad_remove, |
480 | .driver = { |
481 | .name = "omap4-keypad" , |
482 | .of_match_table = omap_keypad_dt_match, |
483 | .pm = pm_ptr(&omap4_keypad_pm_ops), |
484 | }, |
485 | }; |
486 | module_platform_driver(omap4_keypad_driver); |
487 | |
488 | MODULE_AUTHOR("Texas Instruments" ); |
489 | MODULE_DESCRIPTION("OMAP4 Keypad Driver" ); |
490 | MODULE_LICENSE("GPL" ); |
491 | MODULE_ALIAS("platform:omap4-keypad" ); |
492 | |