summaryrefslogtreecommitdiff
path: root/drivers/input/keyboard
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-05-24 11:58:49 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-24 11:58:49 -0700
commit4637f40f200063973553ce3c4c1ac6c247e4535c (patch)
treeff317a0dfb67cae313a208d120edd5102730044d /drivers/input/keyboard
parent5129df03d0c44b2d5a5f9d7d52f3b079706b9a8f (diff)
parentb73077eb03f510a84b102fb97640e595a958403c (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (40 commits) Input: ADP5589 - new driver for I2C Keypad Decoder and I/O Expander Input: tsc2007 - add X, Y and Z fuzz factors to platform data Input: tsc2007 - add poll_period parameter to platform data Input: tsc2007 - add poll_delay parameter to platform data Input: tsc2007 - add max_rt parameter to platform data Input: tsc2007 - debounce pressure measurement Input: ad714x - fix captouch wheel option algorithm Input: ad714x - allow platform code to specify irqflags Input: ad714x - fix threshold and completion interrupt masks Input: ad714x - fix up input configuration Input: elantech - remove support for proprietary X driver Input: elantech - report multitouch with proper ABS_MT messages Input: elantech - export pressure and width when supported Input: elantech - describe further the protocol Input: atmel_tsadcc - correct call to input_free_device Input: add driver FSL MPR121 capacitive touch sensor Input: remove useless synchronize_rcu() calls Input: ads7846 - fix gpio_pendown configuration Input: ads7846 - add possibility to use external vref on ads7846 Input: rotary-encoder - add support for half-period encoders ...
Diffstat (limited to 'drivers/input/keyboard')
-rw-r--r--drivers/input/keyboard/Kconfig22
-rw-r--r--drivers/input/keyboard/Makefile2
-rw-r--r--drivers/input/keyboard/adp5589-keys.c771
-rw-r--r--drivers/input/keyboard/gpio_keys.c11
-rw-r--r--drivers/input/keyboard/mpr121_touchkey.c339
-rw-r--r--drivers/input/keyboard/omap-keypad.c6
-rw-r--r--drivers/input/keyboard/qt1070.c1
-rw-r--r--drivers/input/keyboard/sh_keysc.c53
-rw-r--r--drivers/input/keyboard/tegra-kbc.c60
9 files changed, 1206 insertions, 59 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index b16bed038f72..69badb4e06aa 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -32,6 +32,16 @@ config KEYBOARD_ADP5588
To compile this driver as a module, choose M here: the
module will be called adp5588-keys.
+config KEYBOARD_ADP5589
+ tristate "ADP5589 I2C QWERTY Keypad and IO Expander"
+ depends on I2C
+ help
+ Say Y here if you want to use a ADP5589 attached to your
+ system I2C bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called adp5589-keys.
+
config KEYBOARD_AMIGA
tristate "Amiga keyboard"
depends on AMIGA
@@ -325,6 +335,18 @@ config KEYBOARD_MCS
To compile this driver as a module, choose M here: the
module will be called mcs_touchkey.
+config KEYBOARD_MPR121
+ tristate "Freescale MPR121 Touchkey"
+ depends on I2C
+ help
+ Say Y here if you have Freescale MPR121 touchkey controller
+ chip in your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mpr121_touchkey.
+
config KEYBOARD_IMX
tristate "IMX keypad support"
depends on ARCH_MXC
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 878e6c20deb0..c49cf8e04cd7 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o
obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o
+obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
@@ -27,6 +28,7 @@ obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o
obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o
obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o
+obj-$(CONFIG_KEYBOARD_MPR121) += mpr121_touchkey.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c
new file mode 100644
index 000000000000..631598663aab
--- /dev/null
+++ b/drivers/input/keyboard/adp5589-keys.c
@@ -0,0 +1,771 @@
+/*
+ * Description: keypad driver for ADP5589
+ * I2C QWERTY Keypad and IO Expander
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2010-2011 Analog Devices Inc.
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <linux/input/adp5589.h>
+
+/* GENERAL_CFG Register */
+#define OSC_EN (1 << 7)
+#define CORE_CLK(x) (((x) & 0x3) << 5)
+#define LCK_TRK_LOGIC (1 << 4)
+#define LCK_TRK_GPI (1 << 3)
+#define INT_CFG (1 << 1)
+#define RST_CFG (1 << 0)
+
+/* INT_EN Register */
+#define LOGIC2_IEN (1 << 5)
+#define LOGIC1_IEN (1 << 4)
+#define LOCK_IEN (1 << 3)
+#define OVRFLOW_IEN (1 << 2)
+#define GPI_IEN (1 << 1)
+#define EVENT_IEN (1 << 0)
+
+/* Interrupt Status Register */
+#define LOGIC2_INT (1 << 5)
+#define LOGIC1_INT (1 << 4)
+#define LOCK_INT (1 << 3)
+#define OVRFLOW_INT (1 << 2)
+#define GPI_INT (1 << 1)
+#define EVENT_INT (1 << 0)
+
+/* STATUS Register */
+
+#define LOGIC2_STAT (1 << 7)
+#define LOGIC1_STAT (1 << 6)
+#define LOCK_STAT (1 << 5)
+#define KEC 0xF
+
+/* PIN_CONFIG_D Register */
+#define C4_EXTEND_CFG (1 << 6) /* RESET2 */
+#define R4_EXTEND_CFG (1 << 5) /* RESET1 */
+
+/* LOCK_CFG */
+#define LOCK_EN (1 << 0)
+
+#define PTIME_MASK 0x3
+#define LTIME_MASK 0x3
+
+/* Key Event Register xy */
+#define KEY_EV_PRESSED (1 << 7)
+#define KEY_EV_MASK (0x7F)
+
+#define KEYP_MAX_EVENT 16
+
+#define MAXGPIO 19
+#define ADP_BANK(offs) ((offs) >> 3)
+#define ADP_BIT(offs) (1u << ((offs) & 0x7))
+
+struct adp5589_kpad {
+ struct i2c_client *client;
+ struct input_dev *input;
+ unsigned short keycode[ADP5589_KEYMAPSIZE];
+ const struct adp5589_gpi_map *gpimap;
+ unsigned short gpimapsize;
+ unsigned extend_cfg;
+#ifdef CONFIG_GPIOLIB
+ unsigned char gpiomap[MAXGPIO];
+ bool export_gpio;
+ struct gpio_chip gc;
+ struct mutex gpio_lock; /* Protect cached dir, dat_out */
+ u8 dat_out[3];
+ u8 dir[3];
+#endif
+};
+
+static int adp5589_read(struct i2c_client *client, u8 reg)
+{
+ int ret = i2c_smbus_read_byte_data(client, reg);
+
+ if (ret < 0)
+ dev_err(&client->dev, "Read Error\n");
+
+ return ret;
+}
+
+static int adp5589_write(struct i2c_client *client, u8 reg, u8 val)
+{
+ return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+#ifdef CONFIG_GPIOLIB
+static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off)
+{
+ struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+ unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+ unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+
+ return !!(adp5589_read(kpad->client, ADP5589_GPI_STATUS_A + bank) &
+ bit);
+}
+
+static void adp5589_gpio_set_value(struct gpio_chip *chip,
+ unsigned off, int val)
+{
+ struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+ unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+ unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+
+ mutex_lock(&kpad->gpio_lock);
+
+ if (val)
+ kpad->dat_out[bank] |= bit;
+ else
+ kpad->dat_out[bank] &= ~bit;
+
+ adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank,
+ kpad->dat_out[bank]);
+
+ mutex_unlock(&kpad->gpio_lock);
+}
+
+static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off)
+{
+ struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+ unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+ unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+ int ret;
+
+ mutex_lock(&kpad->gpio_lock);
+
+ kpad->dir[bank] &= ~bit;
+ ret = adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank,
+ kpad->dir[bank]);
+
+ mutex_unlock(&kpad->gpio_lock);
+
+ return ret;
+}
+
+static int adp5589_gpio_direction_output(struct gpio_chip *chip,
+ unsigned off, int val)
+{
+ struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+ unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+ unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+ int ret;
+
+ mutex_lock(&kpad->gpio_lock);
+
+ kpad->dir[bank] |= bit;
+
+ if (val)
+ kpad->dat_out[bank] |= bit;
+ else
+ kpad->dat_out[bank] &= ~bit;
+
+ ret = adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank,
+ kpad->dat_out[bank]);
+ ret |= adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank,
+ kpad->dir[bank]);
+
+ mutex_unlock(&kpad->gpio_lock);
+
+ return ret;
+}
+
+static int __devinit adp5589_build_gpiomap(struct adp5589_kpad *kpad,
+ const struct adp5589_kpad_platform_data *pdata)
+{
+ bool pin_used[MAXGPIO];
+ int n_unused = 0;
+ int i;
+
+ memset(pin_used, false, sizeof(pin_used));
+
+ for (i = 0; i < MAXGPIO; i++)
+ if (pdata->keypad_en_mask & (1 << i))
+ pin_used[i] = true;
+
+ for (i = 0; i < kpad->gpimapsize; i++)
+ pin_used[kpad->gpimap[i].pin - ADP5589_GPI_PIN_BASE] = true;
+
+ if (kpad->extend_cfg & R4_EXTEND_CFG)
+ pin_used[4] = true;
+
+ if (kpad->extend_cfg & C4_EXTEND_CFG)
+ pin_used[12] = true;
+
+ for (i = 0; i < MAXGPIO; i++)
+ if (!pin_used[i])
+ kpad->gpiomap[n_unused++] = i;
+
+ return n_unused;
+}
+
+static int __devinit adp5589_gpio_add(struct adp5589_kpad *kpad)
+{
+ struct device *dev = &kpad->client->dev;
+ const struct adp5589_kpad_platform_data *pdata = dev->platform_data;
+ const struct adp5589_gpio_platform_data *gpio_data = pdata->gpio_data;
+ int i, error;
+
+ if (!gpio_data)
+ return 0;
+
+ kpad->gc.ngpio = adp5589_build_gpiomap(kpad, pdata);
+ if (kpad->gc.ngpio == 0) {
+ dev_info(dev, "No unused gpios left to export\n");
+ return 0;
+ }
+
+ kpad->export_gpio = true;
+
+ kpad->gc.direction_input = adp5589_gpio_direction_input;
+ kpad->gc.direction_output = adp5589_gpio_direction_output;
+ kpad->gc.get = adp5589_gpio_get_value;
+ kpad->gc.set = adp5589_gpio_set_value;
+ kpad->gc.can_sleep = 1;
+
+ kpad->gc.base = gpio_data->gpio_start;
+ kpad->gc.label = kpad->client->name;
+ kpad->gc.owner = THIS_MODULE;
+
+ mutex_init(&kpad->gpio_lock);
+
+ error = gpiochip_add(&kpad->gc);
+ if (error) {
+ dev_err(dev, "gpiochip_add failed, err: %d\n", error);
+ return error;
+ }
+
+ for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+ kpad->dat_out[i] = adp5589_read(kpad->client,
+ ADP5589_GPO_DATA_OUT_A + i);
+ kpad->dir[i] = adp5589_read(kpad->client,
+ ADP5589_GPIO_DIRECTION_A + i);
+ }
+
+ if (gpio_data->setup) {
+ error = gpio_data->setup(kpad->client,
+ kpad->gc.base, kpad->gc.ngpio,
+ gpio_data->context);
+ if (error)
+ dev_warn(dev, "setup failed, %d\n", error);
+ }
+
+ return 0;
+}
+
+static void __devexit adp5589_gpio_remove(struct adp5589_kpad *kpad)
+{
+ struct device *dev = &kpad->client->dev;
+ const struct adp5589_kpad_platform_data *pdata = dev->platform_data;
+ const struct adp5589_gpio_platform_data *gpio_data = pdata->gpio_data;
+ int error;
+
+ if (!kpad->export_gpio)
+ return;
+
+ if (gpio_data->teardown) {
+ error = gpio_data->teardown(kpad->client,
+ kpad->gc.base, kpad->gc.ngpio,
+ gpio_data->context);
+ if (error)
+ dev_warn(dev, "teardown failed %d\n", error);
+ }
+
+ error = gpiochip_remove(&kpad->gc);
+ if (error)
+ dev_warn(dev, "gpiochip_remove failed %d\n", error);
+}
+#else
+static inline int adp5589_gpio_add(struct adp5589_kpad *kpad)
+{
+ return 0;
+}
+
+static inline void adp5589_gpio_remove(struct adp5589_kpad *kpad)
+{
+}
+#endif
+
+static void adp5589_report_switches(struct adp5589_kpad *kpad,
+ int key, int key_val)
+{
+ int i;
+
+ for (i = 0; i < kpad->gpimapsize; i++) {
+ if (key_val == kpad->gpimap[i].pin) {
+ input_report_switch(kpad->input,
+ kpad->gpimap[i].sw_evt,
+ key & KEY_EV_PRESSED);
+ break;
+ }
+ }
+}
+
+static void adp5589_report_events(struct adp5589_kpad *kpad, int ev_cnt)
+{
+ int i;
+
+ for (i = 0; i < ev_cnt; i++) {
+ int key = adp5589_read(kpad->client, ADP5589_FIFO_1 + i);
+ int key_val = key & KEY_EV_MASK;
+
+ if (key_val >= ADP5589_GPI_PIN_BASE &&
+ key_val <= ADP5589_GPI_PIN_END) {
+ adp5589_report_switches(kpad, key, key_val);
+ } else {
+ input_report_key(kpad->input,
+ kpad->keycode[key_val - 1],
+ key & KEY_EV_PRESSED);
+ }
+ }
+}
+
+static irqreturn_t adp5589_irq(int irq, void *handle)
+{
+ struct adp5589_kpad *kpad = handle;
+ struct i2c_client *client = kpad->client;
+ int status, ev_cnt;
+
+ status = adp5589_read(client, ADP5589_INT_STATUS);
+
+ if (status & OVRFLOW_INT) /* Unlikely and should never happen */
+ dev_err(&client->dev, "Event Overflow Error\n");
+
+ if (status & EVENT_INT) {
+ ev_cnt = adp5589_read(client, ADP5589_STATUS) & KEC;
+ if (ev_cnt) {
+ adp5589_report_events(kpad, ev_cnt);
+ input_sync(kpad->input);
+ }
+ }
+
+ adp5589_write(client, ADP5589_INT_STATUS, status); /* Status is W1C */
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad, unsigned short key)
+{
+ int i;
+
+ for (i = 0; i < ADP5589_KEYMAPSIZE; i++)
+ if (key == kpad->keycode[i])
+ return (i + 1) | KEY_EV_PRESSED;
+
+ dev_err(&kpad->client->dev, "RESET/UNLOCK key not in keycode map\n");
+
+ return -EINVAL;
+}
+
+static int __devinit adp5589_setup(struct adp5589_kpad *kpad)
+{
+ struct i2c_client *client = kpad->client;
+ const struct adp5589_kpad_platform_data *pdata =
+ client->dev.platform_data;
+ int i, ret;
+ unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;
+ unsigned char pull_mask = 0;
+
+ ret = adp5589_write(client, ADP5589_PIN_CONFIG_A,
+ pdata->keypad_en_mask & 0xFF);
+ ret |= adp5589_write(client, ADP5589_PIN_CONFIG_B,
+ (pdata->keypad_en_mask >> 8) & 0xFF);
+ ret |= adp5589_write(client, ADP5589_PIN_CONFIG_C,
+ (pdata->keypad_en_mask >> 16) & 0xFF);
+
+ if (pdata->en_keylock) {
+ ret |= adp5589_write(client, ADP5589_UNLOCK1,
+ pdata->unlock_key1);
+ ret |= adp5589_write(client, ADP5589_UNLOCK2,
+ pdata->unlock_key2);
+ ret |= adp5589_write(client, ADP5589_UNLOCK_TIMERS,
+ pdata->unlock_timer & LTIME_MASK);
+ ret |= adp5589_write(client, ADP5589_LOCK_CFG, LOCK_EN);
+ }
+
+ for (i = 0; i < KEYP_MAX_EVENT; i++)
+ ret |= adp5589_read(client, ADP5589_FIFO_1 + i);
+
+ for (i = 0; i < pdata->gpimapsize; i++) {
+ unsigned short pin = pdata->gpimap[i].pin;
+
+ if (pin <= ADP5589_GPI_PIN_ROW_END) {
+ evt_mode1 |= (1 << (pin - ADP5589_GPI_PIN_ROW_BASE));
+ } else {
+ evt_mode2 |=
+ ((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) & 0xFF);
+ evt_mode3 |=
+ ((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) >> 8);
+ }
+ }
+
+ if (pdata->gpimapsize) {
+ ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_A, evt_mode1);
+ ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_B, evt_mode2);
+ ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_C, evt_mode3);
+ }
+
+ if (pdata->pull_dis_mask & pdata->pullup_en_100k &
+ pdata->pullup_en_300k & pdata->pulldown_en_300k)
+ dev_warn(&client->dev, "Conflicting pull resistor config\n");
+
+ for (i = 0; i < MAXGPIO; i++) {
+ unsigned val = 0;
+
+ if (pdata->pullup_en_300k & (1 << i))
+ val = 0;
+ else if (pdata->pulldown_en_300k & (1 << i))
+ val = 1;
+ else if (pdata->pullup_en_100k & (1 << i))
+ val = 2;
+ else if (pdata->pull_dis_mask & (1 << i))
+ val = 3;
+
+ pull_mask |= val << (2 * (i & 0x3));
+
+ if ((i & 0x3) == 0x3 || i == MAXGPIO - 1) {
+ ret |= adp5589_write(client,
+ ADP5589_RPULL_CONFIG_A + (i >> 2),
+ pull_mask);
+ pull_mask = 0;
+ }
+ }
+
+ if (pdata->reset1_key_1 && pdata->reset1_key_2 && pdata->reset1_key_3) {
+ ret |= adp5589_write(client, ADP5589_RESET1_EVENT_A,
+ adp5589_get_evcode(kpad,
+ pdata->reset1_key_1));
+ ret |= adp5589_write(client, ADP5589_RESET1_EVENT_B,
+ adp5589_get_evcode(kpad,
+ pdata->reset1_key_2));
+ ret |= adp5589_write(client, ADP5589_RESET1_EVENT_C,
+ adp5589_get_evcode(kpad,
+ pdata->reset1_key_3));
+ kpad->extend_cfg |= R4_EXTEND_CFG;
+ }
+
+ if (pdata->reset2_key_1 && pdata->reset2_key_2) {
+ ret |= adp5589_write(client, ADP5589_RESET2_EVENT_A,
+ adp5589_get_evcode(kpad,
+ pdata->reset2_key_1));
+ ret |= adp5589_write(client, ADP5589_RESET2_EVENT_B,
+ adp5589_get_evcode(kpad,
+ pdata->reset2_key_2));
+ kpad->extend_cfg |= C4_EXTEND_CFG;
+ }
+
+ if (kpad->extend_cfg) {
+ ret |= adp5589_write(client, ADP5589_RESET_CFG,
+ pdata->reset_cfg);
+ ret |= adp5589_write(client, ADP5589_PIN_CONFIG_D,
+ kpad->extend_cfg);
+ }
+
+ for (i = 0; i <= ADP_BANK(MAXGPIO); i++)
+ ret |= adp5589_write(client, ADP5589_DEBOUNCE_DIS_A + i,
+ pdata->debounce_dis_mask >> (i * 8));
+
+ ret |= adp5589_write(client, ADP5589_POLL_PTIME_CFG,
+ pdata->scan_cycle_time & PTIME_MASK);
+ ret |= adp5589_write(client, ADP5589_INT_STATUS, LOGIC2_INT |
+ LOGIC1_INT | OVRFLOW_INT | LOCK_INT |
+ GPI_INT | EVENT_INT); /* Status is W1C */
+
+ ret |= adp5589_write(client, ADP5589_GENERAL_CFG,
+ INT_CFG | OSC_EN | CORE_CLK(3));
+ ret |= adp5589_write(client, ADP5589_INT_EN,
+ OVRFLOW_IEN | GPI_IEN | EVENT_IEN);
+
+ if (ret < 0) {
+ dev_err(&client->dev, "Write Error\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __devinit adp5589_report_switch_state(struct adp5589_kpad *kpad)
+{
+ int gpi_stat1 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_A);
+ int gpi_stat2 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_B);
+ int gpi_stat3 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_C);
+ int gpi_stat_tmp, pin_loc;
+ int i;
+
+ for (i = 0; i < kpad->gpimapsize; i++) {
+ unsigned short pin = kpad->gpimap[i].pin;
+
+ if (pin <= ADP5589_GPI_PIN_ROW_END) {
+ gpi_stat_tmp = gpi_stat1;
+ pin_loc = pin - ADP5589_GPI_PIN_ROW_BASE;
+ } else if ((pin - ADP5589_GPI_PIN_COL_BASE) < 8) {
+ gpi_stat_tmp = gpi_stat2;
+ pin_loc = pin - ADP5589_GPI_PIN_COL_BASE;
+ } else {
+ gpi_stat_tmp = gpi_stat3;
+ pin_loc = pin - ADP5589_GPI_PIN_COL_BASE - 8;
+ }
+
+ if (gpi_stat_tmp < 0) {
+ dev_err(&kpad->client->dev,
+ "Can't read GPIO_DAT_STAT switch"
+ " %d default to OFF\n", pin);
+ gpi_stat_tmp = 0;
+ }
+
+ input_report_switch(kpad->input,
+ kpad->gpimap[i].sw_evt,
+ !(gpi_stat_tmp & (1 << pin_loc)));
+ }
+
+ input_sync(kpad->input);
+}
+
+static int __devinit adp5589_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adp5589_kpad *kpad;
+ const struct adp5589_kpad_platform_data *pdata;
+ struct input_dev *input;
+ unsigned int revid;
+ int ret, i;
+ int error;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
+ return -EIO;
+ }
+
+ pdata = client->dev.platform_data;
+ if (!pdata) {
+ dev_err(&client->dev, "no platform data?\n");
+ return -EINVAL;
+ }
+
+ if (!((pdata->keypad_en_mask & 0xFF) &&
+ (pdata->keypad_en_mask >> 8)) || !pdata->keymap) {
+ dev_err(&client->dev, "no rows, cols or keymap from pdata\n");
+ return -EINVAL;
+ }
+
+ if (pdata->keymapsize != ADP5589_KEYMAPSIZE) {
+ dev_err(&client->dev, "invalid keymapsize\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->gpimap && pdata->gpimapsize) {
+ dev_err(&client->dev, "invalid gpimap from pdata\n");
+ return -EINVAL;
+ }
+
+ if (pdata->gpimapsize > ADP5589_GPIMAPSIZE_MAX) {
+ dev_err(&client->dev, "invalid gpimapsize\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < pdata->gpimapsize; i++) {
+ unsigned short pin = pdata->gpimap[i].pin;
+
+ if (pin < ADP5589_GPI_PIN_BASE || pin > ADP5589_GPI_PIN_END) {
+ dev_err(&client->dev, "invalid gpi pin data\n");
+ return -EINVAL;
+ }
+
+ if ((1 << (pin - ADP5589_GPI_PIN_ROW_BASE)) &
+ pdata->keypad_en_mask) {
+ dev_err(&client->dev, "invalid gpi row/col data\n");
+ return -EINVAL;
+ }
+ }
+
+ if (!client->irq) {
+ dev_err(&client->dev, "no IRQ?\n");
+ return -EINVAL;
+ }
+
+ kpad = kzalloc(sizeof(*kpad), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!kpad || !input) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ kpad->client = client;
+ kpad->input = input;
+
+ ret = adp5589_read(client, ADP5589_ID);
+ if (ret < 0) {
+ error = ret;
+ goto err_free_mem;
+ }
+
+ revid = (u8) ret & ADP5589_DEVICE_ID_MASK;
+
+ input->name = client->name;
+ input->phys = "adp5589-keys/input0";
+ input->dev.parent = &client->dev;
+
+ input_set_drvdata(input, kpad);
+
+ input->id.bustype = BUS_I2C;
+ input->id.vendor = 0x0001;
+ input->id.product = 0x0001;
+ input->id.version = revid;
+
+ input->keycodesize = sizeof(kpad->keycode[0]);
+ input->keycodemax = pdata->keymapsize;
+ input->keycode = kpad->keycode;
+
+ memcpy(kpad->keycode, pdata->keymap,
+ pdata->keymapsize * input->keycodesize);
+
+ kpad->gpimap = pdata->gpimap;
+ kpad->gpimapsize = pdata->gpimapsize;
+
+ /* setup input device */
+ __set_bit(EV_KEY, input->evbit);
+
+ if (pdata->repeat)
+ __set_bit(EV_REP, input->evbit);
+
+ for (i = 0; i < input->keycodemax; i++)
+ __set_bit(kpad->keycode[i] & KEY_MAX, input->keybit);
+ __clear_bit(KEY_RESERVED, input->keybit);
+
+ if (kpad->gpimapsize)
+ __set_bit(EV_SW, input->evbit);
+ for (i = 0; i < kpad->gpimapsize; i++)
+ __set_bit(kpad->gpimap[i].sw_evt, input->swbit);
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(&client->dev, "unable to register input device\n");
+ goto err_free_mem;
+ }
+
+ error = request_threaded_irq(client->irq, NULL, adp5589_irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ client->dev.driver->name, kpad);
+ if (error) {
+ dev_err(&client->dev, "irq %d busy?\n", client->irq);
+ goto err_unreg_dev;
+ }
+
+ error = adp5589_setup(kpad);
+ if (error)
+ goto err_free_irq;
+
+ if (kpad->gpimapsize)
+ adp5589_report_switch_state(kpad);
+
+ error = adp5589_gpio_add(kpad);
+ if (error)
+ goto err_free_irq;
+
+ device_init_wakeup(&client->dev, 1);
+ i2c_set_clientdata(client, kpad);
+
+ dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq);
+ return 0;
+
+err_free_irq:
+ free_irq(client->irq, kpad);
+err_unreg_dev:
+ input_unregister_device(input);
+ input = NULL;
+err_free_mem:
+ input_free_device(input);
+ kfree(kpad);
+
+ return error;
+}
+
+static int __devexit adp5589_remove(struct i2c_client *client)
+{
+ struct adp5589_kpad *kpad = i2c_get_clientdata(client);
+
+ adp5589_write(client, ADP5589_GENERAL_CFG, 0);
+ free_irq(client->irq, kpad);
+ input_unregister_device(kpad->input);
+ adp5589_gpio_remove(kpad);
+ kfree(kpad);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int adp5589_suspend(struct device *dev)
+{
+ struct adp5589_kpad *kpad = dev_get_drvdata(dev);
+ struct i2c_client *client = kpad->client;
+
+ disable_irq(client->irq);
+
+ if (device_may_wakeup(&client->dev))
+ enable_irq_wake(client->irq);
+
+ return 0;
+}
+
+static int adp5589_resume(struct device *dev)
+{
+ struct adp5589_kpad *kpad = dev_get_drvdata(dev);
+ struct i2c_client *client = kpad->client;
+
+ if (device_may_wakeup(&client->dev))
+ disable_irq_wake(client->irq);
+
+ enable_irq(client->irq);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(adp5589_dev_pm_ops, adp5589_suspend, adp5589_resume);
+
+static const struct i2c_device_id adp5589_id[] = {
+ {"adp5589-keys", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, adp5589_id);
+
+static struct i2c_driver adp5589_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .pm = &adp5589_dev_pm_ops,
+ },
+ .probe = adp5589_probe,
+ .remove = __devexit_p(adp5589_remove),
+ .id_table = adp5589_id,
+};
+
+static int __init adp5589_init(void)
+{
+ return i2c_add_driver(&adp5589_driver);
+}
+module_init(adp5589_init);
+
+static void __exit adp5589_exit(void)
+{
+ i2c_del_driver(&adp5589_driver);
+}
+module_exit(adp5589_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADP5589 Keypad driver");
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index eb3006361ee4..6e6145b9a4c1 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -324,7 +324,12 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata)
unsigned int type = button->type ?: EV_KEY;
int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;
- input_event(input, type, button->code, !!state);
+ if (type == EV_ABS) {
+ if (state)
+ input_event(input, type, button->code, button->value);
+ } else {
+ input_event(input, type, button->code, !!state);
+ }
input_sync(input);
}
@@ -363,7 +368,7 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
struct gpio_button_data *bdata,
struct gpio_keys_button *button)
{
- char *desc = button->desc ? button->desc : "gpio_keys";
+ const char *desc = button->desc ? button->desc : "gpio_keys";
struct device *dev = &pdev->dev;
unsigned long irqflags;
int irq, error;
@@ -468,7 +473,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ddata);
input_set_drvdata(input, ddata);
- input->name = pdev->name;
+ input->name = pdata->name ? : pdev->name;
input->phys = "gpio-keys/input0";
input->dev.parent = &pdev->dev;
input->open = gpio_keys_open;
diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c
new file mode 100644
index 000000000000..0a9e81194888
--- /dev/null
+++ b/drivers/input/keyboard/mpr121_touchkey.c
@@ -0,0 +1,339 @@
+/*
+ * Touchkey driver for Freescale MPR121 Controllor
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Author: Zhang Jiejing <jiejing.zhang@freescale.com>
+ *
+ * Based on mcs_touchkey.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/i2c/mpr121_touchkey.h>
+
+/* Register definitions */
+#define ELE_TOUCH_STATUS_0_ADDR 0x0
+#define ELE_TOUCH_STATUS_1_ADDR 0X1
+#define MHD_RISING_ADDR 0x2b
+#define NHD_RISING_ADDR 0x2c
+#define NCL_RISING_ADDR 0x2d
+#define FDL_RISING_ADDR 0x2e
+#define MHD_FALLING_ADDR 0x2f
+#define NHD_FALLING_ADDR 0x30
+#define NCL_FALLING_ADDR 0x31
+#define FDL_FALLING_ADDR 0x32
+#define ELE0_TOUCH_THRESHOLD_ADDR 0x41
+#define ELE0_RELEASE_THRESHOLD_ADDR 0x42
+#define AFE_CONF_ADDR 0x5c
+#define FILTER_CONF_ADDR 0x5d
+
+/*
+ * ELECTRODE_CONF_ADDR: This register configures the number of
+ * enabled capacitance sensing inputs and its run/suspend mode.
+ */
+#define ELECTRODE_CONF_ADDR 0x5e
+#define AUTO_CONFIG_CTRL_ADDR 0x7b
+#define AUTO_CONFIG_USL_ADDR 0x7d
+#define AUTO_CONFIG_LSL_ADDR 0x7e
+#define AUTO_CONFIG_TL_ADDR 0x7f
+
+/* Threshold of touch/release trigger */
+#define TOUCH_THRESHOLD 0x0f
+#define RELEASE_THRESHOLD 0x0a
+/* Masks for touch and release triggers */
+#define TOUCH_STATUS_MASK 0xfff
+/* MPR121 has 12 keys */
+#define MPR121_MAX_KEY_COUNT 12
+
+struct mpr121_touchkey {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ unsigned int key_val;
+ unsigned int statusbits;
+ unsigned int keycount;
+ u16 keycodes[MPR121_MAX_KEY_COUNT];
+};
+
+struct mpr121_init_register {
+ int addr;
+ u8 val;
+};
+
+static const struct mpr121_init_register init_reg_table[] __devinitconst = {
+ { MHD_RISING_ADDR, 0x1 },
+ { NHD_RISING_ADDR, 0x1 },
+ { MHD_FALLING_ADDR, 0x1 },
+ { NHD_FALLING_ADDR, 0x1 },
+ { NCL_FALLING_ADDR, 0xff },
+ { FDL_FALLING_ADDR, 0x02 },
+ { FILTER_CONF_ADDR, 0x04 },
+ { AFE_CONF_ADDR, 0x0b },
+ { AUTO_CONFIG_CTRL_ADDR, 0x0b },
+};
+
+static irqreturn_t mpr_touchkey_interrupt(int irq, void *dev_id)
+{
+ struct mpr121_touchkey *mpr121 = dev_id;
+ struct i2c_client *client = mpr121->client;
+ struct input_dev *input = mpr121->input_dev;
+ unsigned int key_num, key_val, pressed;
+ int reg;
+
+ reg = i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_1_ADDR);
+ if (reg < 0) {
+ dev_err(&client->dev, "i2c read error [%d]\n", reg);
+ goto out;
+ }
+
+ reg <<= 8;
+ reg |= i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_0_ADDR);
+ if (reg < 0) {
+ dev_err(&client->dev, "i2c read error [%d]\n", reg);
+ goto out;
+ }
+
+ reg &= TOUCH_STATUS_MASK;
+ /* use old press bit to figure out which bit changed */
+ key_num = ffs(reg ^ mpr121->statusbits) - 1;
+ pressed = reg & (1 << key_num);
+ mpr121->statusbits = reg;
+
+ key_val = mpr121->keycodes[key_num];
+
+ input_event(input, EV_MSC, MSC_SCAN, key_num);
+ input_report_key(input, key_val, pressed);
+ input_sync(input);
+
+ dev_dbg(&client->dev, "key %d %d %s\n", key_num, key_val,
+ pressed ? "pressed" : "released");
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata,
+ struct mpr121_touchkey *mpr121,
+ struct i2c_client *client)
+{
+ const struct mpr121_init_register *reg;
+ unsigned char usl, lsl, tl;
+ int i, t, vdd, ret;
+
+ /* Set up touch/release threshold for ele0-ele11 */
+ for (i = 0; i <= MPR121_MAX_KEY_COUNT; i++) {
+ t = ELE0_TOUCH_THRESHOLD_ADDR + (i * 2);
+ ret = i2c_smbus_write_byte_data(client, t, TOUCH_THRESHOLD);
+ if (ret < 0)
+ goto err_i2c_write;
+ ret = i2c_smbus_write_byte_data(client, t + 1,
+ RELEASE_THRESHOLD);
+ if (ret < 0)
+ goto err_i2c_write;
+ }
+
+ /* Set up init register */
+ for (i = 0; i < ARRAY_SIZE(init_reg_table); i++) {
+ reg = &init_reg_table[i];
+ ret = i2c_smbus_write_byte_data(client, reg->addr, reg->val);
+ if (ret < 0)
+ goto err_i2c_write;
+ }
+
+
+ /*
+ * Capacitance on sensing input varies and needs to be compensated.
+ * The internal MPR121-auto-configuration can do this if it's
+ * registers are set properly (based on pdata->vdd_uv).
+ */
+ vdd = pdata->vdd_uv / 1000;
+ usl = ((vdd - 700) * 256) / vdd;
+ lsl = (usl * 65) / 100;
+ tl = (usl * 90) / 100;
+ ret = i2c_smbus_write_byte_data(client, AUTO_CONFIG_USL_ADDR, usl);
+ ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_LSL_ADDR, lsl);
+ ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_TL_ADDR, tl);
+ ret |= i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR,
+ mpr121->keycount);
+ if (ret != 0)
+ goto err_i2c_write;
+
+ dev_dbg(&client->dev, "set up with %x keys.\n", mpr121->keycount);
+
+ return 0;
+
+err_i2c_write:
+ dev_err(&client->dev, "i2c write error: %d\n", ret);
+ return ret;
+}
+
+static int __devinit mpr_touchkey_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const struct mpr121_platform_data *pdata = client->dev.platform_data;
+ struct mpr121_touchkey *mpr121;
+ struct input_dev *input_dev;
+ int error;
+ int i;
+
+ if (!pdata) {
+ dev_err(&client->dev, "no platform data defined\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->keymap || !pdata->keymap_size) {
+ dev_err(&client->dev, "missing keymap data\n");
+ return -EINVAL;
+ }
+
+ if (pdata->keymap_size > MPR121_MAX_KEY_COUNT) {
+ dev_err(&client->dev, "too many keys defined\n");
+ return -EINVAL;
+ }
+
+ if (!client->irq) {
+ dev_err(&client->dev, "irq number should not be zero\n");
+ return -EINVAL;
+ }
+
+ mpr121 = kzalloc(sizeof(struct mpr121_touchkey), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!mpr121 || !input_dev) {
+ dev_err(&client->dev, "Failed to allocate memory\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ mpr121->client = client;
+ mpr121->input_dev = input_dev;
+ mpr121->keycount = pdata->keymap_size;
+
+ input_dev->name = "Freescale MPR121 Touchkey";
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->dev.parent = &client->dev;
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+
+ input_dev->keycode = mpr121->keycodes;
+ input_dev->keycodesize = sizeof(mpr121->keycodes[0]);
+ input_dev->keycodemax = mpr121->keycount;
+
+ for (i = 0; i < pdata->keymap_size; i++) {
+ input_set_capability(input_dev, EV_KEY, pdata->keymap[i]);
+ mpr121->keycodes[i] = pdata->keymap[i];
+ }
+
+ error = mpr121_phys_init(pdata, mpr121, client);
+ if (error) {
+ dev_err(&client->dev, "Failed to init register\n");
+ goto err_free_mem;
+ }
+
+ error = request_threaded_irq(client->irq, NULL,
+ mpr_touchkey_interrupt,
+ IRQF_TRIGGER_FALLING,
+ client->dev.driver->name, mpr121);
+ if (error) {
+ dev_err(&client->dev, "Failed to register interrupt\n");
+ goto err_free_mem;
+ }
+
+ error = input_register_device(input_dev);
+ if (error)
+ goto err_free_irq;
+
+ i2c_set_clientdata(client, mpr121);
+ device_init_wakeup(&client->dev, pdata->wakeup);
+
+ return 0;
+
+err_free_irq:
+ free_irq(client->irq, mpr121);
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(mpr121);
+ return error;
+}
+
+static int __devexit mpr_touchkey_remove(struct i2c_client *client)
+{
+ struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client);
+
+ free_irq(client->irq, mpr121);
+ input_unregister_device(mpr121->input_dev);
+ kfree(mpr121);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mpr_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (device_may_wakeup(&client->dev))
+ enable_irq_wake(client->irq);
+
+ i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR, 0x00);
+
+ return 0;
+}
+
+static int mpr_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client);
+
+ if (device_may_wakeup(&client->dev))
+ disable_irq_wake(client->irq);
+
+ i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR,
+ mpr121->keycount);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(mpr121_touchkey_pm_ops, mpr_suspend, mpr_resume);
+
+static const struct i2c_device_id mpr121_id[] = {
+ { "mpr121_touchkey", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mpr121_id);
+
+static struct i2c_driver mpr_touchkey_driver = {
+ .driver = {
+ .name = "mpr121",
+ .owner = THIS_MODULE,
+ .pm = &mpr121_touchkey_pm_ops,
+ },
+ .id_table = mpr121_id,
+ .probe = mpr_touchkey_probe,
+ .remove = __devexit_p(mpr_touchkey_remove),
+};
+
+static int __init mpr_touchkey_init(void)
+{
+ return i2c_add_driver(&mpr_touchkey_driver);
+}
+module_init(mpr_touchkey_init);
+
+static void __exit mpr_touchkey_exit(void)
+{
+ i2c_del_driver(&mpr_touchkey_driver);
+}
+module_exit(mpr_touchkey_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Zhang Jiejing <jiejing.zhang@freescale.com>");
+MODULE_DESCRIPTION("Touch Key driver for Freescale MPR121 Chip");
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index 0e2a19cb43d8..f23a743817db 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -413,7 +413,7 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
return 0;
err5:
for (i = irq_idx - 1; i >=0; i--)
- free_irq(row_gpios[i], NULL);
+ free_irq(row_gpios[i], omap_kp);
err4:
input_unregister_device(omap_kp->input);
input_dev = NULL;
@@ -444,11 +444,11 @@ static int __devexit omap_kp_remove(struct platform_device *pdev)
gpio_free(col_gpios[i]);
for (i = 0; i < omap_kp->rows; i++) {
gpio_free(row_gpios[i]);
- free_irq(gpio_to_irq(row_gpios[i]), NULL);
+ free_irq(gpio_to_irq(row_gpios[i]), omap_kp);
}
} else {
omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
- free_irq(omap_kp->irq, NULL);
+ free_irq(omap_kp->irq, omap_kp);
}
del_timer_sync(&omap_kp->timer);
diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c
index fba8404c7297..ca7b89196ab7 100644
--- a/drivers/input/keyboard/qt1070.c
+++ b/drivers/input/keyboard/qt1070.c
@@ -248,6 +248,7 @@ static const struct i2c_device_id qt1070_id[] = {
{ "qt1070", 0 },
{ },
};
+MODULE_DEVICE_TABLE(i2c, qt1070_id);
static struct i2c_driver qt1070_driver = {
.driver = {
diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c
index d7dafd9425b6..834cf98e7efb 100644
--- a/drivers/input/keyboard/sh_keysc.c
+++ b/drivers/input/keyboard/sh_keysc.c
@@ -20,7 +20,7 @@
#include <linux/input.h>
#include <linux/input/sh_keysc.h>
#include <linux/bitmap.h>
-#include <linux/clk.h>
+#include <linux/pm_runtime.h>
#include <linux/io.h>
#include <linux/slab.h>
@@ -37,7 +37,6 @@ static const struct {
struct sh_keysc_priv {
void __iomem *iomem_base;
- struct clk *clk;
DECLARE_BITMAP(last_keys, SH_KEYSC_MAXKEYS);
struct input_dev *input;
struct sh_keysc_info pdata;
@@ -169,7 +168,6 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
struct sh_keysc_info *pdata;
struct resource *res;
struct input_dev *input;
- char clk_name[8];
int i;
int irq, error;
@@ -210,19 +208,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
goto err1;
}
- snprintf(clk_name, sizeof(clk_name), "keysc%d", pdev->id);
- priv->clk = clk_get(&pdev->dev, clk_name);
- if (IS_ERR(priv->clk)) {
- dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
- error = PTR_ERR(priv->clk);
- goto err2;
- }
-
priv->input = input_allocate_device();
if (!priv->input) {
dev_err(&pdev->dev, "failed to allocate input device\n");
error = -ENOMEM;
- goto err3;
+ goto err2;
}
input = priv->input;
@@ -241,10 +231,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
input->keycodesize = sizeof(pdata->keycodes[0]);
input->keycodemax = ARRAY_SIZE(pdata->keycodes);
- error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev);
+ error = request_threaded_irq(irq, NULL, sh_keysc_isr, IRQF_ONESHOT,
+ dev_name(&pdev->dev), pdev);
if (error) {
dev_err(&pdev->dev, "failed to request IRQ\n");
- goto err4;
+ goto err3;
}
for (i = 0; i < SH_KEYSC_MAXKEYS; i++)
@@ -254,10 +245,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
error = input_register_device(input);
if (error) {
dev_err(&pdev->dev, "failed to register input device\n");
- goto err5;
+ goto err4;
}
- clk_enable(priv->clk);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
sh_keysc_write(priv, KYCR1, (sh_keysc_mode[pdata->mode].kymd << 8) |
pdata->scan_timing);
@@ -267,12 +259,10 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
return 0;
- err5:
- free_irq(irq, pdev);
err4:
- input_free_device(input);
+ free_irq(irq, pdev);
err3:
- clk_put(priv->clk);
+ input_free_device(input);
err2:
iounmap(priv->iomem_base);
err1:
@@ -292,8 +282,8 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
free_irq(platform_get_irq(pdev, 0), pdev);
iounmap(priv->iomem_base);
- clk_disable(priv->clk);
- clk_put(priv->clk);
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
platform_set_drvdata(pdev, NULL);
kfree(priv);
@@ -301,6 +291,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
return 0;
}
+#if CONFIG_PM_SLEEP
static int sh_keysc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -311,14 +302,13 @@ static int sh_keysc_suspend(struct device *dev)
value = sh_keysc_read(priv, KYCR1);
if (device_may_wakeup(dev)) {
- value |= 0x80;
+ sh_keysc_write(priv, KYCR1, value | 0x80);
enable_irq_wake(irq);
} else {
- value &= ~0x80;
+ sh_keysc_write(priv, KYCR1, value & ~0x80);
+ pm_runtime_put_sync(dev);
}
- sh_keysc_write(priv, KYCR1, value);
-
return 0;
}
@@ -329,16 +319,17 @@ static int sh_keysc_resume(struct device *dev)
if (device_may_wakeup(dev))
disable_irq_wake(irq);
+ else
+ pm_runtime_get_sync(dev);
return 0;
}
+#endif
-static const struct dev_pm_ops sh_keysc_dev_pm_ops = {
- .suspend = sh_keysc_suspend,
- .resume = sh_keysc_resume,
-};
+static SIMPLE_DEV_PM_OPS(sh_keysc_dev_pm_ops,
+ sh_keysc_suspend, sh_keysc_resume);
-struct platform_driver sh_keysc_device_driver = {
+static struct platform_driver sh_keysc_device_driver = {
.probe = sh_keysc_probe,
.remove = __devexit_p(sh_keysc_remove),
.driver = {
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index 99ce9032d08c..2b3b73ec6689 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -66,12 +66,11 @@ struct tegra_kbc {
void __iomem *mmio;
struct input_dev *idev;
unsigned int irq;
- unsigned int wake_enable_rows;
- unsigned int wake_enable_cols;
spinlock_t lock;
unsigned int repoll_dly;
unsigned long cp_dly_jiffies;
bool use_fn_map;
+ bool use_ghost_filter;
const struct tegra_kbc_platform_data *pdata;
unsigned short keycode[KBC_MAX_KEY * 2];
unsigned short current_keys[KBC_MAX_KPENT];
@@ -260,6 +259,8 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
unsigned int num_down = 0;
unsigned long flags;
bool fn_keypress = false;
+ bool key_in_same_row = false;
+ bool key_in_same_col = false;
spin_lock_irqsave(&kbc->lock, flags);
for (i = 0; i < KBC_MAX_KPENT; i++) {
@@ -285,6 +286,34 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
}
/*
+ * Matrix keyboard designs are prone to keyboard ghosting.
+ * Ghosting occurs if there are 3 keys such that -
+ * any 2 of the 3 keys share a row, and any 2 of them share a column.
+ * If so ignore the key presses for this iteration.
+ */
+ if ((kbc->use_ghost_filter) && (num_down >= 3)) {
+ for (i = 0; i < num_down; i++) {
+ unsigned int j;
+ u8 curr_col = scancodes[i] & 0x07;
+ u8 curr_row = scancodes[i] >> KBC_ROW_SHIFT;
+
+ /*
+ * Find 2 keys such that one key is in the same row
+ * and the other is in the same column as the i-th key.
+ */
+ for (j = i + 1; j < num_down; j++) {
+ u8 col = scancodes[j] & 0x07;
+ u8 row = scancodes[j] >> KBC_ROW_SHIFT;
+
+ if (col == curr_col)
+ key_in_same_col = true;
+ if (row == curr_row)
+ key_in_same_row = true;
+ }
+ }
+ }
+
+ /*
* If the platform uses Fn keymaps, translate keys on a Fn keypress.
* Function keycodes are KBC_MAX_KEY apart from the plain keycodes.
*/
@@ -297,6 +326,10 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
spin_unlock_irqrestore(&kbc->lock, flags);
+ /* Ignore the key presses for this iteration? */
+ if (key_in_same_col && key_in_same_row)
+ return;
+
tegra_kbc_report_released_keys(kbc->idev,
kbc->current_keys, kbc->num_pressed_keys,
keycodes, num_down);
@@ -383,21 +416,11 @@ static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter)
int i;
unsigned int rst_val;
- BUG_ON(pdata->wake_cnt > KBC_MAX_KEY);
- rst_val = (filter && pdata->wake_cnt) ? ~0 : 0;
+ /* Either mask all keys or none. */
+ rst_val = (filter && !pdata->wakeup) ? ~0 : 0;
for (i = 0; i < KBC_MAX_ROW; i++)
writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4);
-
- if (filter) {
- for (i = 0; i < pdata->wake_cnt; i++) {
- u32 val, addr;
- addr = pdata->wake_cfg[i].row * 4 + KBC_ROW0_MASK_0;
- val = readl(kbc->mmio + addr);
- val &= ~(1 << pdata->wake_cfg[i].col);
- writel(val, kbc->mmio + addr);
- }
- }
}
static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
@@ -559,7 +582,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
struct resource *res;
int irq;
int err;
- int i;
int num_rows = 0;
unsigned int debounce_cnt;
unsigned int scan_time_rows;
@@ -616,13 +638,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
goto err_iounmap;
}
- kbc->wake_enable_rows = 0;
- kbc->wake_enable_cols = 0;
- for (i = 0; i < pdata->wake_cnt; i++) {
- kbc->wake_enable_rows |= (1 << pdata->wake_cfg[i].row);
- kbc->wake_enable_cols |= (1 << pdata->wake_cfg[i].col);
- }
-
/*
* The time delay between two consecutive reads of the FIFO is
* the sum of the repeat time and the time taken for scanning
@@ -652,6 +667,7 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
input_dev->keycodemax *= 2;
kbc->use_fn_map = pdata->use_fn_map;
+ kbc->use_ghost_filter = pdata->use_ghost_filter;
keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data;
matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT,
input_dev->keycode, input_dev->keybit);