From: Hiroshi DOYU Date: Sun, 12 Feb 2006 10:50:18 +0000 (+0200) Subject: ARM: OMAP: Update OMAP keypad driver X-Git-Tag: v2.6.16-omap1~65 X-Git-Url: http://www.pilppa.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=83090a6e3e98591f4605ac3f91a1c016ff3310ab;p=linux-2.6-omap-h63xx.git ARM: OMAP: Update OMAP keypad driver - Prevent ghost key presses on OMAP1 - Add sysfs attribute for enabling/disabling the keypad IRQ Signed-off-by: Hiroshi DOYU Signed-off-by: Juha Yrjölä --- diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c index 90f794e7c46..2c583d1949a 100644 --- a/arch/arm/mach-omap1/board-nokia770.c +++ b/arch/arm/mach-omap1/board-nokia770.c @@ -35,17 +35,17 @@ static void __init omap_nokia770_init_irq(void) } static int nokia770_keymap[] = { - KEY(0, 1, KEY_UP), - KEY(0, 2, KEY_F5), - KEY(1, 0, KEY_LEFT), - KEY(1, 1, KEY_ENTER), - KEY(1, 2, KEY_RIGHT), - KEY(2, 0, KEY_ESC), - KEY(2, 1, KEY_DOWN), - KEY(2, 2, KEY_F4), - KEY(3, 0, KEY_F7), - KEY(3, 1, KEY_F8), - KEY(3, 2, KEY_F6), + KEY(0, 1, GROUP_0 | KEY_UP), + KEY(0, 2, GROUP_1 | KEY_F5), + KEY(1, 0, GROUP_0 | KEY_LEFT), + KEY(1, 1, GROUP_0 | KEY_ENTER), + KEY(1, 2, GROUP_0 | KEY_RIGHT), + KEY(2, 0, GROUP_1 | KEY_ESC), + KEY(2, 1, GROUP_0 | KEY_DOWN), + KEY(2, 2, GROUP_1 | KEY_F4), + KEY(3, 0, GROUP_2 | KEY_F7), + KEY(3, 1, GROUP_2 | KEY_F8), + KEY(3, 2, GROUP_2 | KEY_F6), 0 }; diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index 66ee31f277c..1ad96b706cb 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -48,6 +48,9 @@ static void omap_kp_tasklet(unsigned long); static void omap_kp_timer(unsigned long); static unsigned char keypad_state[8]; +static DECLARE_MUTEX(kp_enable_mutex); +static int kp_enable = 1; +static int kp_cur_group = -1; struct omap_kp { struct input_dev *input; @@ -213,6 +216,11 @@ static void omap_kp_tasklet(unsigned long data) continue; } + if (!(kp_cur_group == (key & GROUP_MASK) || + kp_cur_group == -1)) + continue; + + kp_cur_group = key & GROUP_MASK; input_report_key(omap_kp_data->input, key, new_state[col] & (1 << row)); #endif @@ -235,10 +243,43 @@ static void omap_kp_tasklet(unsigned long data) enable_irq(OMAP_GPIO_IRQ(row_gpios[i])); } else { omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + kp_cur_group = -1; } } } +static ssize_t omap_kp_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", kp_enable); +} + +static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int state; + + if (sscanf(buf, "%u", &state) != 1) + return -EINVAL; + + if ((state != 1) && (state != 0)) + return -EINVAL; + + down(&kp_enable_mutex); + if (state != kp_enable) { + if (state) + enable_irq(INT_KEYBOARD); + else + disable_irq(INT_KEYBOARD); + kp_enable = state; + } + up(&kp_enable_mutex); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, omap_kp_enable_show, omap_kp_enable_store); + #ifdef CONFIG_PM static int omap_kp_suspend(struct platform_device *dev, pm_message_t state) { @@ -299,12 +340,6 @@ static int __init omap_kp_probe(struct platform_device *pdev) col_gpios = pdata->col_gpios; } - if (cpu_is_omap24xx() && omap_has_menelaus()) { - row_gpios[5] = 0; - col_gpios[2] = 15; - col_gpios[6] = 18; - } - omap_kp->rows = pdata->rows; omap_kp->cols = pdata->cols; @@ -313,8 +348,8 @@ static int __init omap_kp_probe(struct platform_device *pdev) for (i = 0; i < omap_kp->cols; i++) { if (omap_request_gpio(col_gpios[i]) < 0) { printk(KERN_ERR "Failed to request" - "GPIO%d for keypad\n", - col_gpios[i]); + "GPIO%d for keypad\n", + col_gpios[i]); return -EINVAL; } omap_set_gpio_direction(col_gpios[i], 0); @@ -323,8 +358,8 @@ static int __init omap_kp_probe(struct platform_device *pdev) for (i = 0; i < omap_kp->rows; i++) { if (omap_request_gpio(row_gpios[i]) < 0) { printk(KERN_ERR "Failed to request" - "GPIO%d for keypad\n", - row_gpios[i]); + "GPIO%d for keypad\n", + row_gpios[i]); return -EINVAL; } omap_set_gpio_direction(row_gpios[i], 1); @@ -346,6 +381,8 @@ static int __init omap_kp_probe(struct platform_device *pdev) return -EINVAL; } + device_create_file(&pdev->dev, &dev_attr_enable); + /* setup input device */ set_bit(EV_KEY, input_dev->evbit); for (i = 0; keymap[i] != 0; i++) diff --git a/include/asm-arm/arch-omap/keypad.h b/include/asm-arm/arch-omap/keypad.h index 0d90b4f11ab..548515d503e 100644 --- a/include/asm-arm/arch-omap/keypad.h +++ b/include/asm-arm/arch-omap/keypad.h @@ -20,6 +20,16 @@ struct omap_kp_platform_data { unsigned int *col_gpios; }; +/* Group (0..3) -- when multiple keys are pressed, only the + * keys pressed in the same group are considered as pressed. This is + * in order to workaround certain crappy HW designs that produce ghost + * keypresses. */ +#define GROUP_0 (0 << 10) +#define GROUP_1 (1 << 10) +#define GROUP_2 (2 << 10) +#define GROUP_3 (3 << 10) +#define GROUP_MASK GROUP_3 + #define KEY(col, row, val) (((col) << 28) | ((row) << 24) | (val)) #endif