/* * The matrix is stable only if no changes are detected after * IMX_KEYPAD_SCANS_FOR_STABILITY scans
*/ #define IMX_KEYPAD_SCANS_FOR_STABILITY 3 int stable_count;
bool enabled;
/* Masks for enabled rows/cols */ unsignedshort rows_en_mask; unsignedshort cols_en_mask;
unsignedshort keycodes[MAX_MATRIX_KEY_NUM];
/* * Matrix states: * -stable: achieved after a complete debounce process. * -unstable: used in the debouncing process.
*/ unsignedshort matrix_stable_state[MAX_MATRIX_KEY_COLS]; unsignedshort matrix_unstable_state[MAX_MATRIX_KEY_COLS];
};
/* Scan the matrix and return the new state in *matrix_volatile_state. */ staticvoid imx_keypad_scan_matrix(struct imx_keypad *keypad, unsignedshort *matrix_volatile_state)
{ int col; unsignedshort reg_val;
for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) { if ((keypad->cols_en_mask & (1 << col)) == 0) continue; /* * Discharge keypad capacitance: * 2. write 1s on column data. * 3. configure columns as totem-pole to discharge capacitance. * 4. configure columns as open-drain.
*/
reg_val = readw(keypad->mmio_base + KPDR);
reg_val |= 0xff00;
writew(reg_val, keypad->mmio_base + KPDR);
/* * Compare the new matrix state (volatile) with the stable one stored in * keypad->matrix_stable_state and fire events if changes are detected.
*/ staticvoid imx_keypad_fire_events(struct imx_keypad *keypad, unsignedshort *matrix_volatile_state)
{ struct input_dev *input_dev = keypad->input_dev; int row, col;
for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) { unsignedshort bits_changed; int code;
if ((keypad->cols_en_mask & (1 << col)) == 0) continue; /* Column is not enabled */
/* * If the matrix state is changed from the previous scan * (Re)Begin the debouncing process, saving the new state in * keypad->matrix_unstable_state. * else * Increase the count of number of scans with a stable state.
*/ if (state_changed) {
memcpy(keypad->matrix_unstable_state, matrix_volatile_state, sizeof(matrix_volatile_state));
keypad->stable_count = 0;
} else
keypad->stable_count++;
/* * If the matrix is not as stable as we want reschedule scan * in the near future.
*/ if (keypad->stable_count < IMX_KEYPAD_SCANS_FOR_STABILITY) {
mod_timer(&keypad->check_matrix_timer,
jiffies + msecs_to_jiffies(10)); return;
}
/* * If the matrix state is stable, fire the events and save the new * stable state. Note, if the matrix is kept stable for longer * (keypad->stable_count > IMX_KEYPAD_SCANS_FOR_STABILITY) all * events have already been generated.
*/ if (keypad->stable_count == IMX_KEYPAD_SCANS_FOR_STABILITY) {
imx_keypad_fire_events(keypad, matrix_volatile_state);
is_zero_matrix = true; for (i = 0; i < MAX_MATRIX_KEY_COLS; i++) { if (matrix_volatile_state[i] != 0) {
is_zero_matrix = false; break;
}
}
if (is_zero_matrix) { /* * All keys have been released. Enable only the KDI * interrupt for future key presses (clear the KDI * status bit and its sync chain before that).
*/
reg_val = readw(keypad->mmio_base + KPSR);
reg_val |= KBD_STAT_KPKD | KBD_STAT_KDSC;
writew(reg_val, keypad->mmio_base + KPSR);
reg_val = readw(keypad->mmio_base + KPSR);
reg_val |= KBD_STAT_KDIE;
reg_val &= ~KBD_STAT_KRIE;
writew(reg_val, keypad->mmio_base + KPSR);
} else { /* * Some keys are still pressed. Schedule a rescan in * attempt to detect multiple key presses and enable * the KRI interrupt to react quickly to key release * event.
*/
mod_timer(&keypad->check_matrix_timer,
jiffies + msecs_to_jiffies(60));
/* Enable the kpp clock */
error = clk_prepare_enable(keypad->clk); if (error) return error;
/* We became active from now */
keypad->enabled = true;
imx_keypad_config(keypad);
/* Sanity control, not all the rows must be actived now. */ if ((readw(keypad->mmio_base + KPDR) & keypad->rows_en_mask) == 0) {
dev_err(&dev->dev, "too many keys pressed, control pins initialisation\n"); goto open_err;
}
/* Ensure that the keypad will stay dormant until opened */
error = clk_prepare_enable(keypad->clk); if (error) return error;
imx_keypad_inhibit(keypad);
clk_disable_unprepare(keypad->clk);
error = devm_request_irq(&pdev->dev, irq, imx_keypad_irq_handler, 0,
pdev->name, keypad); if (error) {
dev_err(&pdev->dev, "failed to request IRQ\n"); return error;
}
/* Register the input device */
error = input_register_device(input_dev); if (error) {
dev_err(&pdev->dev, "failed to register input device\n"); return error;
}
scoped_guard(mutex, &input_dev->mutex) { /* imx kbd can wake up system even clock is disabled */ if (input_device_enabled(input_dev))
clk_disable_unprepare(kbd->clk);
}
if (device_may_wakeup(&pdev->dev)) { if (reg_val & KBD_STAT_KPKD)
reg_val |= KBD_STAT_KRIE; if (reg_val & KBD_STAT_KPKR)
reg_val |= KBD_STAT_KDIE;
writew(reg_val, kbd->mmio_base + KPSR);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.