* row lines connected to the gnd (see twl4030_col_xlate()).
*/
#define TWL4030_ROW_SHIFT 4
-#define TWL4030_KEYMAP_SIZE (TWL4030_MAX_ROWS << TWL4030_ROW_SHIFT)
+#define TWL4030_KEYMAP_SIZE ((TWL4030_MAX_ROWS << TWL4030_ROW_SHIFT) * 2)
struct twl4030_keypad {
unsigned short keymap[TWL4030_KEYMAP_SIZE];
unsigned n_cols;
unsigned irq;
+ unsigned fn_down:1;
+ unsigned fn_sticked:1;
+
struct device *dbg_dev;
struct input_dev *input;
};
/* Extra column handles "all gnd" rows */
for (col = 0; col < kp->n_cols + 1; col++) {
- int code;
+ int code, kcode, is_down;
+ int code2;
if (!(changed & (1 << col)))
continue;
"press" : "release");
code = MATRIX_SCAN_CODE(row, col, TWL4030_ROW_SHIFT);
+ kcode = kp->keymap[code];
+ is_down = (new_state[row] & (1 << col)) ? 1 : 0;
+
+ dev_dbg(kp->dbg_dev, "code: %d %d\n", code, kcode);
+ /* Fn handling */
+ if (kcode == KEY_FN) {
+ kp->fn_down = is_down;
+ kp->fn_sticked |= is_down;
+ } else if (kp->fn_down || kp->fn_sticked) {
+ /* make sure other function is up */
+ input_event(input, EV_MSC, MSC_SCAN, code);
+ input_report_key(input, kcode, 0);
+
+ code = MATRIX_SCAN_CODE(row + TWL4030_MAX_ROWS,
+ col, TWL4030_ROW_SHIFT);
+ kcode = kp->keymap[code];
+
+ kp->fn_sticked = 0;
+ } else {
+ code2 = MATRIX_SCAN_CODE(row + TWL4030_MAX_ROWS,
+ col, TWL4030_ROW_SHIFT);
+ input_event(input, EV_MSC, MSC_SCAN, code2);
+ input_report_key(input, kp->keymap[code2], 0);
+ }
+
+ dev_dbg(kp->dbg_dev, "code(fn): %d %d\n", code, kcode);
input_event(input, EV_MSC, MSC_SCAN, code);
- input_report_key(input, kp->keymap[code],
- new_state[row] & (1 << col));
+ input_report_key(input, kcode, is_down);
}
kp->kp_state[row] = new_state[row];
}
input_set_capability(input, EV_MSC, MSC_SCAN);
- input->name = "TWL4030 Keypad";
+ input->name = "keypad";
input->phys = "twl4030_keypad/input0";
input->dev.parent = &pdev->dev;