Lines Matching +full:matrix +full:- +full:keypad

1 // SPDX-License-Identifier: GPL-2.0
3 // Driver for the IMX keypad port.
23 * Keypad Controller registers (halfword)
25 #define KPCR 0x00 /* Keypad Control Register */
27 #define KPSR 0x02 /* Keypad Status Register */
34 #define KBD_STAT_KPPEN (0x1 << 10) /* Keypad Clock Enable */
36 #define KDDR 0x04 /* Keypad Data Direction Register */
37 #define KPDR 0x06 /* Keypad Data Register */
55 * The matrix is stable only if no changes are detected after
70 * Matrix states:
71 * -stable: achieved after a complete debounce process.
72 * -unstable: used in the debouncing process.
78 /* Scan the matrix and return the new state in *matrix_volatile_state. */
79 static void imx_keypad_scan_matrix(struct imx_keypad *keypad, in imx_keypad_scan_matrix() argument
86 if ((keypad->cols_en_mask & (1 << col)) == 0) in imx_keypad_scan_matrix()
89 * Discharge keypad capacitance: in imx_keypad_scan_matrix()
91 * 3. configure columns as totem-pole to discharge capacitance. in imx_keypad_scan_matrix()
92 * 4. configure columns as open-drain. in imx_keypad_scan_matrix()
94 reg_val = readw(keypad->mmio_base + KPDR); in imx_keypad_scan_matrix()
96 writew(reg_val, keypad->mmio_base + KPDR); in imx_keypad_scan_matrix()
98 reg_val = readw(keypad->mmio_base + KPCR); in imx_keypad_scan_matrix()
99 reg_val &= ~((keypad->cols_en_mask & 0xff) << 8); in imx_keypad_scan_matrix()
100 writew(reg_val, keypad->mmio_base + KPCR); in imx_keypad_scan_matrix()
104 reg_val = readw(keypad->mmio_base + KPCR); in imx_keypad_scan_matrix()
105 reg_val |= (keypad->cols_en_mask & 0xff) << 8; in imx_keypad_scan_matrix()
106 writew(reg_val, keypad->mmio_base + KPCR); in imx_keypad_scan_matrix()
111 * 7. Repeat steps 2 - 6 for remaining columns. in imx_keypad_scan_matrix()
113 reg_val = readw(keypad->mmio_base + KPDR); in imx_keypad_scan_matrix()
115 writew(reg_val, keypad->mmio_base + KPDR); in imx_keypad_scan_matrix()
127 reg_val = readw(keypad->mmio_base + KPDR); in imx_keypad_scan_matrix()
128 matrix_volatile_state[col] = (~reg_val) & keypad->rows_en_mask; in imx_keypad_scan_matrix()
135 reg_val = readw(keypad->mmio_base + KPDR); in imx_keypad_scan_matrix()
137 writew(reg_val, keypad->mmio_base + KPDR); in imx_keypad_scan_matrix()
141 * Compare the new matrix state (volatile) with the stable one stored in
142 * keypad->matrix_stable_state and fire events if changes are detected.
144 static void imx_keypad_fire_events(struct imx_keypad *keypad, in imx_keypad_fire_events() argument
147 struct input_dev *input_dev = keypad->input_dev; in imx_keypad_fire_events()
154 if ((keypad->cols_en_mask & (1 << col)) == 0) in imx_keypad_fire_events()
157 bits_changed = keypad->matrix_stable_state[col] ^ in imx_keypad_fire_events()
164 if ((keypad->rows_en_mask & (1 << row)) == 0) in imx_keypad_fire_events()
171 input_report_key(input_dev, keypad->keycodes[code], in imx_keypad_fire_events()
173 dev_dbg(&input_dev->dev, "Event code: %d, val: %d", in imx_keypad_fire_events()
174 keypad->keycodes[code], in imx_keypad_fire_events()
186 struct imx_keypad *keypad = timer_container_of(keypad, t, in imx_keypad_check_for_events() local
195 imx_keypad_scan_matrix(keypad, matrix_volatile_state); in imx_keypad_check_for_events()
199 if ((keypad->cols_en_mask & (1 << i)) == 0) in imx_keypad_check_for_events()
202 if (keypad->matrix_unstable_state[i] ^ matrix_volatile_state[i]) { in imx_keypad_check_for_events()
209 * If the matrix state is changed from the previous scan in imx_keypad_check_for_events()
211 * keypad->matrix_unstable_state. in imx_keypad_check_for_events()
216 memcpy(keypad->matrix_unstable_state, matrix_volatile_state, in imx_keypad_check_for_events()
218 keypad->stable_count = 0; in imx_keypad_check_for_events()
220 keypad->stable_count++; in imx_keypad_check_for_events()
223 * If the matrix is not as stable as we want reschedule scan in imx_keypad_check_for_events()
226 if (keypad->stable_count < IMX_KEYPAD_SCANS_FOR_STABILITY) { in imx_keypad_check_for_events()
227 mod_timer(&keypad->check_matrix_timer, in imx_keypad_check_for_events()
233 * If the matrix state is stable, fire the events and save the new in imx_keypad_check_for_events()
234 * stable state. Note, if the matrix is kept stable for longer in imx_keypad_check_for_events()
235 * (keypad->stable_count > IMX_KEYPAD_SCANS_FOR_STABILITY) all in imx_keypad_check_for_events()
238 if (keypad->stable_count == IMX_KEYPAD_SCANS_FOR_STABILITY) { in imx_keypad_check_for_events()
239 imx_keypad_fire_events(keypad, matrix_volatile_state); in imx_keypad_check_for_events()
241 memcpy(keypad->matrix_stable_state, matrix_volatile_state, in imx_keypad_check_for_events()
260 reg_val = readw(keypad->mmio_base + KPSR); in imx_keypad_check_for_events()
262 writew(reg_val, keypad->mmio_base + KPSR); in imx_keypad_check_for_events()
264 reg_val = readw(keypad->mmio_base + KPSR); in imx_keypad_check_for_events()
267 writew(reg_val, keypad->mmio_base + KPSR); in imx_keypad_check_for_events()
275 mod_timer(&keypad->check_matrix_timer, in imx_keypad_check_for_events()
278 reg_val = readw(keypad->mmio_base + KPSR); in imx_keypad_check_for_events()
280 writew(reg_val, keypad->mmio_base + KPSR); in imx_keypad_check_for_events()
282 reg_val = readw(keypad->mmio_base + KPSR); in imx_keypad_check_for_events()
285 writew(reg_val, keypad->mmio_base + KPSR); in imx_keypad_check_for_events()
291 struct imx_keypad *keypad = dev_id; in imx_keypad_irq_handler() local
294 reg_val = readw(keypad->mmio_base + KPSR); in imx_keypad_irq_handler()
300 writew(reg_val, keypad->mmio_base + KPSR); in imx_keypad_irq_handler()
302 if (keypad->enabled) { in imx_keypad_irq_handler()
303 /* The matrix is supposed to be changed */ in imx_keypad_irq_handler()
304 keypad->stable_count = 0; in imx_keypad_irq_handler()
307 mod_timer(&keypad->check_matrix_timer, in imx_keypad_irq_handler()
314 static void imx_keypad_config(struct imx_keypad *keypad) in imx_keypad_config() argument
320 * Configure keypad columns as open-drain (KPCR[15:8]) in imx_keypad_config()
322 reg_val = readw(keypad->mmio_base + KPCR); in imx_keypad_config()
323 reg_val |= keypad->rows_en_mask & 0xff; /* rows */ in imx_keypad_config()
324 reg_val |= (keypad->cols_en_mask & 0xff) << 8; /* cols */ in imx_keypad_config()
325 writew(reg_val, keypad->mmio_base + KPCR); in imx_keypad_config()
328 reg_val = readw(keypad->mmio_base + KPDR); in imx_keypad_config()
330 writew(reg_val, keypad->mmio_base + KPDR); in imx_keypad_config()
333 writew(0xff00, keypad->mmio_base + KDDR); in imx_keypad_config()
339 reg_val = readw(keypad->mmio_base + KPSR); in imx_keypad_config()
342 writew(reg_val, keypad->mmio_base + KPSR); in imx_keypad_config()
347 writew(reg_val, keypad->mmio_base + KPSR); in imx_keypad_config()
350 static void imx_keypad_inhibit(struct imx_keypad *keypad) in imx_keypad_inhibit() argument
355 reg_val = readw(keypad->mmio_base + KPSR); in imx_keypad_inhibit()
358 writew(reg_val, keypad->mmio_base + KPSR); in imx_keypad_inhibit()
361 reg_val = (keypad->cols_en_mask & 0xff) << 8; in imx_keypad_inhibit()
362 writew(reg_val, keypad->mmio_base + KPCR); in imx_keypad_inhibit()
367 struct imx_keypad *keypad = input_get_drvdata(dev); in imx_keypad_close() local
369 dev_dbg(&dev->dev, ">%s\n", __func__); in imx_keypad_close()
371 /* Mark keypad as being inactive */ in imx_keypad_close()
372 keypad->enabled = false; in imx_keypad_close()
373 synchronize_irq(keypad->irq); in imx_keypad_close()
374 timer_delete_sync(&keypad->check_matrix_timer); in imx_keypad_close()
376 imx_keypad_inhibit(keypad); in imx_keypad_close()
379 clk_disable_unprepare(keypad->clk); in imx_keypad_close()
384 struct imx_keypad *keypad = input_get_drvdata(dev); in imx_keypad_open() local
387 dev_dbg(&dev->dev, ">%s\n", __func__); in imx_keypad_open()
390 error = clk_prepare_enable(keypad->clk); in imx_keypad_open()
395 keypad->enabled = true; in imx_keypad_open()
397 imx_keypad_config(keypad); in imx_keypad_open()
400 if ((readw(keypad->mmio_base + KPDR) & keypad->rows_en_mask) == 0) { in imx_keypad_open()
401 dev_err(&dev->dev, in imx_keypad_open()
410 return -EIO; in imx_keypad_open()
414 { .compatible = "fsl,imx21-kpp", },
421 struct imx_keypad *keypad; in imx_keypad_probe() local
429 input_dev = devm_input_allocate_device(&pdev->dev); in imx_keypad_probe()
431 dev_err(&pdev->dev, "failed to allocate the input device\n"); in imx_keypad_probe()
432 return -ENOMEM; in imx_keypad_probe()
435 keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL); in imx_keypad_probe()
436 if (!keypad) { in imx_keypad_probe()
437 dev_err(&pdev->dev, "not enough memory for driver data\n"); in imx_keypad_probe()
438 return -ENOMEM; in imx_keypad_probe()
441 keypad->input_dev = input_dev; in imx_keypad_probe()
442 keypad->irq = irq; in imx_keypad_probe()
443 keypad->stable_count = 0; in imx_keypad_probe()
445 timer_setup(&keypad->check_matrix_timer, in imx_keypad_probe()
448 keypad->mmio_base = devm_platform_ioremap_resource(pdev, 0); in imx_keypad_probe()
449 if (IS_ERR(keypad->mmio_base)) in imx_keypad_probe()
450 return PTR_ERR(keypad->mmio_base); in imx_keypad_probe()
452 keypad->clk = devm_clk_get(&pdev->dev, NULL); in imx_keypad_probe()
453 if (IS_ERR(keypad->clk)) { in imx_keypad_probe()
454 dev_err(&pdev->dev, "failed to get keypad clock\n"); in imx_keypad_probe()
455 return PTR_ERR(keypad->clk); in imx_keypad_probe()
459 input_dev->name = pdev->name; in imx_keypad_probe()
460 input_dev->id.bustype = BUS_HOST; in imx_keypad_probe()
461 input_dev->dev.parent = &pdev->dev; in imx_keypad_probe()
462 input_dev->open = imx_keypad_open; in imx_keypad_probe()
463 input_dev->close = imx_keypad_close; in imx_keypad_probe()
468 keypad->keycodes, input_dev); in imx_keypad_probe()
470 dev_err(&pdev->dev, "failed to build keymap\n"); in imx_keypad_probe()
478 if (keypad->keycodes[i] != KEY_RESERVED) { in imx_keypad_probe()
479 keypad->rows_en_mask |= 1 << row; in imx_keypad_probe()
480 keypad->cols_en_mask |= 1 << col; in imx_keypad_probe()
484 dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask); in imx_keypad_probe()
485 dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask); in imx_keypad_probe()
487 __set_bit(EV_REP, input_dev->evbit); in imx_keypad_probe()
489 input_set_drvdata(input_dev, keypad); in imx_keypad_probe()
491 /* Ensure that the keypad will stay dormant until opened */ in imx_keypad_probe()
492 error = clk_prepare_enable(keypad->clk); in imx_keypad_probe()
495 imx_keypad_inhibit(keypad); in imx_keypad_probe()
496 clk_disable_unprepare(keypad->clk); in imx_keypad_probe()
498 error = devm_request_irq(&pdev->dev, irq, imx_keypad_irq_handler, 0, in imx_keypad_probe()
499 pdev->name, keypad); in imx_keypad_probe()
501 dev_err(&pdev->dev, "failed to request IRQ\n"); in imx_keypad_probe()
508 dev_err(&pdev->dev, "failed to register input device\n"); in imx_keypad_probe()
512 platform_set_drvdata(pdev, keypad); in imx_keypad_probe()
513 device_init_wakeup(&pdev->dev, 1); in imx_keypad_probe()
522 struct input_dev *input_dev = kbd->input_dev; in imx_kbd_noirq_suspend()
523 unsigned short reg_val = readw(kbd->mmio_base + KPSR); in imx_kbd_noirq_suspend()
525 scoped_guard(mutex, &input_dev->mutex) { in imx_kbd_noirq_suspend()
528 clk_disable_unprepare(kbd->clk); in imx_kbd_noirq_suspend()
531 if (device_may_wakeup(&pdev->dev)) { in imx_kbd_noirq_suspend()
536 writew(reg_val, kbd->mmio_base + KPSR); in imx_kbd_noirq_suspend()
538 enable_irq_wake(kbd->irq); in imx_kbd_noirq_suspend()
548 struct input_dev *input_dev = kbd->input_dev; in imx_kbd_noirq_resume()
551 if (device_may_wakeup(&pdev->dev)) in imx_kbd_noirq_resume()
552 disable_irq_wake(kbd->irq); in imx_kbd_noirq_resume()
554 guard(mutex)(&input_dev->mutex); in imx_kbd_noirq_resume()
557 error = clk_prepare_enable(kbd->clk); in imx_kbd_noirq_resume()
571 .name = "imx-keypad",
580 MODULE_DESCRIPTION("IMX Keypad Port Driver");
582 MODULE_ALIAS("platform:imx-keypad");