diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-27 08:44:20 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-27 08:44:20 +0200 |
commit | 396e6e49c58bb23d1814d3c240c736c9f01523c5 (patch) | |
tree | a6ec8dac896c3ea3ac7b1bb0dce8728766afcf91 /drivers/input/keyboard | |
parent | 18974369cfe23acf16d0fb79e0d1fba7a9a95ec0 (diff) | |
parent | 6ad390a25a9d1d8606b9b826878f0a30639dc2b3 (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: (68 commits)
Input: adp5589-keys - add support for the ADP5585 derivatives
Input: imx_keypad - add pm suspend and resume support
Input: force feedback - potential integer wrap in input_ff_create()
Input: tsc2007 - make sure that X plate resistance is specified
Input: serio_raw - fix memory leak when closing char device
Input: serio_raw - kick clients when disconnecting port
Input: serio_raw - explicitly mark disconnected ports as dead
Input: serio_raw - fix coding style issues
Input: serio_raw - use dev_*() for messages
Input: serio_raw - use bool for boolean data
Input: serio_raw - perform proper locking when adding clients to list
Input: serio_raw - rename serio_raw_list to serio_raw_client
Input: serio_raw - use kref instead of rolling out its own refcounting
Input: psmouse - switch to using dev_*() for messages
Input: wacom - correct max Y value on medium bamboos
Input: wacom - add ABS_DISTANCE to Bamboo Pen reports
Input: wacom - remove unneeded touch pressure initialization
Input: lm8323 - wrap suspend and resume in CONFIG_PM_SLEEP
Input: ad7879-i2c - wrap suspend and resume in CONFIG_PM_SLEEP
Input: synaptics_i2c - wrap suspend and resume in CONFIG_PM_SLEEP
...
Diffstat (limited to 'drivers/input/keyboard')
-rw-r--r-- | drivers/input/keyboard/Kconfig | 4 | ||||
-rw-r--r-- | drivers/input/keyboard/adp5588-keys.c | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/adp5589-keys.c | 609 | ||||
-rw-r--r-- | drivers/input/keyboard/davinci_keyscan.c | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/ep93xx_keypad.c | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/gpio_keys.c | 24 | ||||
-rw-r--r-- | drivers/input/keyboard/imx_keypad.c | 46 | ||||
-rw-r--r-- | drivers/input/keyboard/jornada720_kbd.c | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/lm8323.c | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/matrix_keypad.c | 1 | ||||
-rw-r--r-- | drivers/input/keyboard/pxa27x_keypad.c | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/pxa930_rotary.c | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/tc3589x-keypad.c | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/tegra-kbc.c | 85 | ||||
-rw-r--r-- | drivers/input/keyboard/w90p910_keypad.c | 2 |
15 files changed, 604 insertions, 183 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index b4dee9d5a055..615c21f2a553 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -33,10 +33,10 @@ config KEYBOARD_ADP5588 module will be called adp5588-keys. config KEYBOARD_ADP5589 - tristate "ADP5589 I2C QWERTY Keypad and IO Expander" + tristate "ADP5585/ADP5589 I2C QWERTY Keypad and IO Expander" depends on I2C help - Say Y here if you want to use a ADP5589 attached to your + Say Y here if you want to use a ADP5585/ADP5589 attached to your system I2C bus. To compile this driver as a module, choose M here: the diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index e34eeb8ae371..4a7f534cf64b 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -550,7 +550,7 @@ static int __devinit adp5588_probe(struct i2c_client *client, } error = request_irq(client->irq, adp5588_irq, - IRQF_TRIGGER_FALLING | IRQF_DISABLED, + IRQF_TRIGGER_FALLING, client->dev.driver->name, kpad); if (error) { dev_err(&client->dev, "irq %d busy?\n", client->irq); diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index c7708263051b..02b5d53031bf 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -1,5 +1,5 @@ /* - * Description: keypad driver for ADP5589 + * Description: keypad driver for ADP5589, ADP5585 * I2C QWERTY Keypad and IO Expander * Bugs: Enter bugs at http://blackfin.uclinux.org/ * @@ -22,35 +22,165 @@ #include <linux/input/adp5589.h> +/* ADP5589/ADP5585 Common Registers */ +#define ADP5589_5_ID 0x00 +#define ADP5589_5_INT_STATUS 0x01 +#define ADP5589_5_STATUS 0x02 +#define ADP5589_5_FIFO_1 0x03 +#define ADP5589_5_FIFO_2 0x04 +#define ADP5589_5_FIFO_3 0x05 +#define ADP5589_5_FIFO_4 0x06 +#define ADP5589_5_FIFO_5 0x07 +#define ADP5589_5_FIFO_6 0x08 +#define ADP5589_5_FIFO_7 0x09 +#define ADP5589_5_FIFO_8 0x0A +#define ADP5589_5_FIFO_9 0x0B +#define ADP5589_5_FIFO_10 0x0C +#define ADP5589_5_FIFO_11 0x0D +#define ADP5589_5_FIFO_12 0x0E +#define ADP5589_5_FIFO_13 0x0F +#define ADP5589_5_FIFO_14 0x10 +#define ADP5589_5_FIFO_15 0x11 +#define ADP5589_5_FIFO_16 0x12 +#define ADP5589_5_GPI_INT_STAT_A 0x13 +#define ADP5589_5_GPI_INT_STAT_B 0x14 + +/* ADP5589 Registers */ +#define ADP5589_GPI_INT_STAT_C 0x15 +#define ADP5589_GPI_STATUS_A 0x16 +#define ADP5589_GPI_STATUS_B 0x17 +#define ADP5589_GPI_STATUS_C 0x18 +#define ADP5589_RPULL_CONFIG_A 0x19 +#define ADP5589_RPULL_CONFIG_B 0x1A +#define ADP5589_RPULL_CONFIG_C 0x1B +#define ADP5589_RPULL_CONFIG_D 0x1C +#define ADP5589_RPULL_CONFIG_E 0x1D +#define ADP5589_GPI_INT_LEVEL_A 0x1E +#define ADP5589_GPI_INT_LEVEL_B 0x1F +#define ADP5589_GPI_INT_LEVEL_C 0x20 +#define ADP5589_GPI_EVENT_EN_A 0x21 +#define ADP5589_GPI_EVENT_EN_B 0x22 +#define ADP5589_GPI_EVENT_EN_C 0x23 +#define ADP5589_GPI_INTERRUPT_EN_A 0x24 +#define ADP5589_GPI_INTERRUPT_EN_B 0x25 +#define ADP5589_GPI_INTERRUPT_EN_C 0x26 +#define ADP5589_DEBOUNCE_DIS_A 0x27 +#define ADP5589_DEBOUNCE_DIS_B 0x28 +#define ADP5589_DEBOUNCE_DIS_C 0x29 +#define ADP5589_GPO_DATA_OUT_A 0x2A +#define ADP5589_GPO_DATA_OUT_B 0x2B +#define ADP5589_GPO_DATA_OUT_C 0x2C +#define ADP5589_GPO_OUT_MODE_A 0x2D +#define ADP5589_GPO_OUT_MODE_B 0x2E +#define ADP5589_GPO_OUT_MODE_C 0x2F +#define ADP5589_GPIO_DIRECTION_A 0x30 +#define ADP5589_GPIO_DIRECTION_B 0x31 +#define ADP5589_GPIO_DIRECTION_C 0x32 +#define ADP5589_UNLOCK1 0x33 +#define ADP5589_UNLOCK2 0x34 +#define ADP5589_EXT_LOCK_EVENT 0x35 +#define ADP5589_UNLOCK_TIMERS 0x36 +#define ADP5589_LOCK_CFG 0x37 +#define ADP5589_RESET1_EVENT_A 0x38 +#define ADP5589_RESET1_EVENT_B 0x39 +#define ADP5589_RESET1_EVENT_C 0x3A +#define ADP5589_RESET2_EVENT_A 0x3B +#define ADP5589_RESET2_EVENT_B 0x3C +#define ADP5589_RESET_CFG 0x3D +#define ADP5589_PWM_OFFT_LOW 0x3E +#define ADP5589_PWM_OFFT_HIGH 0x3F +#define ADP5589_PWM_ONT_LOW 0x40 +#define ADP5589_PWM_ONT_HIGH 0x41 +#define ADP5589_PWM_CFG 0x42 +#define ADP5589_CLOCK_DIV_CFG 0x43 +#define ADP5589_LOGIC_1_CFG 0x44 +#define ADP5589_LOGIC_2_CFG 0x45 +#define ADP5589_LOGIC_FF_CFG 0x46 +#define ADP5589_LOGIC_INT_EVENT_EN 0x47 +#define ADP5589_POLL_PTIME_CFG 0x48 +#define ADP5589_PIN_CONFIG_A 0x49 +#define ADP5589_PIN_CONFIG_B 0x4A +#define ADP5589_PIN_CONFIG_C 0x4B +#define ADP5589_PIN_CONFIG_D 0x4C +#define ADP5589_GENERAL_CFG 0x4D +#define ADP5589_INT_EN 0x4E + +/* ADP5585 Registers */ +#define ADP5585_GPI_STATUS_A 0x15 +#define ADP5585_GPI_STATUS_B 0x16 +#define ADP5585_RPULL_CONFIG_A 0x17 +#define ADP5585_RPULL_CONFIG_B 0x18 +#define ADP5585_RPULL_CONFIG_C 0x19 +#define ADP5585_RPULL_CONFIG_D 0x1A +#define ADP5585_GPI_INT_LEVEL_A 0x1B +#define ADP5585_GPI_INT_LEVEL_B 0x1C +#define ADP5585_GPI_EVENT_EN_A 0x1D +#define ADP5585_GPI_EVENT_EN_B 0x1E +#define ADP5585_GPI_INTERRUPT_EN_A 0x1F +#define ADP5585_GPI_INTERRUPT_EN_B 0x20 +#define ADP5585_DEBOUNCE_DIS_A 0x21 +#define ADP5585_DEBOUNCE_DIS_B 0x22 +#define ADP5585_GPO_DATA_OUT_A 0x23 +#define ADP5585_GPO_DATA_OUT_B 0x24 +#define ADP5585_GPO_OUT_MODE_A 0x25 +#define ADP5585_GPO_OUT_MODE_B 0x26 +#define ADP5585_GPIO_DIRECTION_A 0x27 +#define ADP5585_GPIO_DIRECTION_B 0x28 +#define ADP5585_RESET1_EVENT_A 0x29 +#define ADP5585_RESET1_EVENT_B 0x2A +#define ADP5585_RESET1_EVENT_C 0x2B +#define ADP5585_RESET2_EVENT_A 0x2C +#define ADP5585_RESET2_EVENT_B 0x2D +#define ADP5585_RESET_CFG 0x2E +#define ADP5585_PWM_OFFT_LOW 0x2F +#define ADP5585_PWM_OFFT_HIGH 0x30 +#define ADP5585_PWM_ONT_LOW 0x31 +#define ADP5585_PWM_ONT_HIGH 0x32 +#define ADP5585_PWM_CFG 0x33 +#define ADP5585_LOGIC_CFG 0x34 +#define ADP5585_LOGIC_FF_CFG 0x35 +#define ADP5585_LOGIC_INT_EVENT_EN 0x36 +#define ADP5585_POLL_PTIME_CFG 0x37 +#define ADP5585_PIN_CONFIG_A 0x38 +#define ADP5585_PIN_CONFIG_B 0x39 +#define ADP5585_PIN_CONFIG_D 0x3A +#define ADP5585_GENERAL_CFG 0x3B +#define ADP5585_INT_EN 0x3C + +/* ID Register */ +#define ADP5589_5_DEVICE_ID_MASK 0xF +#define ADP5589_5_MAN_ID_MASK 0xF +#define ADP5589_5_MAN_ID_SHIFT 4 +#define ADP5589_5_MAN_ID 0x02 + /* 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 LCK_TRK_LOGIC (1 << 4) /* ADP5589 only */ +#define LCK_TRK_GPI (1 << 3) /* ADP5589 only */ #define INT_CFG (1 << 1) #define RST_CFG (1 << 0) /* INT_EN Register */ -#define LOGIC2_IEN (1 << 5) +#define LOGIC2_IEN (1 << 5) /* ADP5589 only */ #define LOGIC1_IEN (1 << 4) -#define LOCK_IEN (1 << 3) +#define LOCK_IEN (1 << 3) /* ADP5589 only */ #define OVRFLOW_IEN (1 << 2) #define GPI_IEN (1 << 1) #define EVENT_IEN (1 << 0) /* Interrupt Status Register */ -#define LOGIC2_INT (1 << 5) +#define LOGIC2_INT (1 << 5) /* ADP5589 only */ #define LOGIC1_INT (1 << 4) -#define LOCK_INT (1 << 3) +#define LOCK_INT (1 << 3) /* ADP5589 only */ #define OVRFLOW_INT (1 << 2) #define GPI_INT (1 << 1) #define EVENT_INT (1 << 0) /* STATUS Register */ - -#define LOGIC2_STAT (1 << 7) +#define LOGIC2_STAT (1 << 7) /* ADP5589 only */ #define LOGIC1_STAT (1 << 6) -#define LOCK_STAT (1 << 5) +#define LOCK_STAT (1 << 5) /* ADP5589 only */ #define KEC 0xF /* PIN_CONFIG_D Register */ @@ -61,27 +191,54 @@ #define LOCK_EN (1 << 0) #define PTIME_MASK 0x3 -#define LTIME_MASK 0x3 +#define LTIME_MASK 0x3 /* ADP5589 only */ /* Key Event Register xy */ #define KEY_EV_PRESSED (1 << 7) #define KEY_EV_MASK (0x7F) #define KEYP_MAX_EVENT 16 +#define ADP5589_MAXGPIO 19 +#define ADP5585_MAXGPIO 11 /* 10 on the ADP5585-01, 11 on ADP5585-02 */ -#define MAXGPIO 19 -#define ADP_BANK(offs) ((offs) >> 3) -#define ADP_BIT(offs) (1u << ((offs) & 0x7)) +enum { + ADP5589, + ADP5585_01, + ADP5585_02 +}; + +struct adp_constants { + u8 maxgpio; + u8 keymapsize; + u8 gpi_pin_row_base; + u8 gpi_pin_row_end; + u8 gpi_pin_col_base; + u8 gpi_pin_base; + u8 gpi_pin_end; + u8 gpimapsize_max; + u8 max_row_num; + u8 max_col_num; + u8 row_mask; + u8 col_mask; + u8 col_shift; + u8 c4_extend_cfg; + u8 (*bank) (u8 offset); + u8 (*bit) (u8 offset); + u8 (*reg) (u8 reg); +}; struct adp5589_kpad { struct i2c_client *client; struct input_dev *input; + const struct adp_constants *var; unsigned short keycode[ADP5589_KEYMAPSIZE]; const struct adp5589_gpi_map *gpimap; unsigned short gpimapsize; unsigned extend_cfg; + bool is_adp5585; + bool adp5585_support_row5; #ifdef CONFIG_GPIOLIB - unsigned char gpiomap[MAXGPIO]; + unsigned char gpiomap[ADP5589_MAXGPIO]; bool export_gpio; struct gpio_chip gc; struct mutex gpio_lock; /* Protect cached dir, dat_out */ @@ -90,6 +247,129 @@ struct adp5589_kpad { #endif }; +/* + * ADP5589 / ADP5585 derivative / variant handling + */ + + +/* ADP5589 */ + +static unsigned char adp5589_bank(unsigned char offset) +{ + return offset >> 3; +} + +static unsigned char adp5589_bit(unsigned char offset) +{ + return 1u << (offset & 0x7); +} + +static unsigned char adp5589_reg(unsigned char reg) +{ + return reg; +} + +static const struct adp_constants const_adp5589 = { + .maxgpio = ADP5589_MAXGPIO, + .keymapsize = ADP5589_KEYMAPSIZE, + .gpi_pin_row_base = ADP5589_GPI_PIN_ROW_BASE, + .gpi_pin_row_end = ADP5589_GPI_PIN_ROW_END, + .gpi_pin_col_base = ADP5589_GPI_PIN_COL_BASE, + .gpi_pin_base = ADP5589_GPI_PIN_BASE, + .gpi_pin_end = ADP5589_GPI_PIN_END, + .gpimapsize_max = ADP5589_GPIMAPSIZE_MAX, + .c4_extend_cfg = 12, + .max_row_num = ADP5589_MAX_ROW_NUM, + .max_col_num = ADP5589_MAX_COL_NUM, + .row_mask = ADP5589_ROW_MASK, + .col_mask = ADP5589_COL_MASK, + .col_shift = ADP5589_COL_SHIFT, + .bank = adp5589_bank, + .bit = adp5589_bit, + .reg = adp5589_reg, +}; + +/* ADP5585 */ + +static unsigned char adp5585_bank(unsigned char offset) +{ + return offset > ADP5585_MAX_ROW_NUM; +} + +static unsigned char adp5585_bit(unsigned char offset) +{ + return (offset > ADP5585_MAX_ROW_NUM) ? + 1u << (offset - ADP5585_COL_SHIFT) : 1u << offset; +} + +static const unsigned char adp5585_reg_lut[] = { + [ADP5589_GPI_STATUS_A] = ADP5585_GPI_STATUS_A, + [ADP5589_GPI_STATUS_B] = ADP5585_GPI_STATUS_B, + [ADP5589_RPULL_CONFIG_A] = ADP5585_RPULL_CONFIG_A, + [ADP5589_RPULL_CONFIG_B] = ADP5585_RPULL_CONFIG_B, + [ADP5589_RPULL_CONFIG_C] = ADP5585_RPULL_CONFIG_C, + [ADP5589_RPULL_CONFIG_D] = ADP5585_RPULL_CONFIG_D, + [ADP5589_GPI_INT_LEVEL_A] = ADP5585_GPI_INT_LEVEL_A, + [ADP5589_GPI_INT_LEVEL_B] = ADP5585_GPI_INT_LEVEL_B, + [ADP5589_GPI_EVENT_EN_A] = ADP5585_GPI_EVENT_EN_A, + [ADP5589_GPI_EVENT_EN_B] = ADP5585_GPI_EVENT_EN_B, + [ADP5589_GPI_INTERRUPT_EN_A] = ADP5585_GPI_INTERRUPT_EN_A, + [ADP5589_GPI_INTERRUPT_EN_B] = ADP5585_GPI_INTERRUPT_EN_B, + [ADP5589_DEBOUNCE_DIS_A] = ADP5585_DEBOUNCE_DIS_A, + [ADP5589_DEBOUNCE_DIS_B] = ADP5585_DEBOUNCE_DIS_B, + [ADP5589_GPO_DATA_OUT_A] = ADP5585_GPO_DATA_OUT_A, + [ADP5589_GPO_DATA_OUT_B] = ADP5585_GPO_DATA_OUT_B, + [ADP5589_GPO_OUT_MODE_A] = ADP5585_GPO_OUT_MODE_A, + [ADP5589_GPO_OUT_MODE_B] = ADP5585_GPO_OUT_MODE_B, + [ADP5589_GPIO_DIRECTION_A] = ADP5585_GPIO_DIRECTION_A, + [ADP5589_GPIO_DIRECTION_B] = ADP5585_GPIO_DIRECTION_B, + [ADP5589_RESET1_EVENT_A] = ADP5585_RESET1_EVENT_A, + [ADP5589_RESET1_EVENT_B] = ADP5585_RESET1_EVENT_B, + [ADP5589_RESET1_EVENT_C] = ADP5585_RESET1_EVENT_C, + [ADP5589_RESET2_EVENT_A] = ADP5585_RESET2_EVENT_A, + [ADP5589_RESET2_EVENT_B] = ADP5585_RESET2_EVENT_B, + [ADP5589_RESET_CFG] = ADP5585_RESET_CFG, + [ADP5589_PWM_OFFT_LOW] = ADP5585_PWM_OFFT_LOW, + [ADP5589_PWM_OFFT_HIGH] = ADP5585_PWM_OFFT_HIGH, + [ADP5589_PWM_ONT_LOW] = ADP5585_PWM_ONT_LOW, + [ADP5589_PWM_ONT_HIGH] = ADP5585_PWM_ONT_HIGH, + [ADP5589_PWM_CFG] = ADP5585_PWM_CFG, + [ADP5589_LOGIC_1_CFG] = ADP5585_LOGIC_CFG, + [ADP5589_LOGIC_FF_CFG] = ADP5585_LOGIC_FF_CFG, + [ADP5589_LOGIC_INT_EVENT_EN] = ADP5585_LOGIC_INT_EVENT_EN, + [ADP5589_POLL_PTIME_CFG] = ADP5585_POLL_PTIME_CFG, + [ADP5589_PIN_CONFIG_A] = ADP5585_PIN_CONFIG_A, + [ADP5589_PIN_CONFIG_B] = ADP5585_PIN_CONFIG_B, + [ADP5589_PIN_CONFIG_D] = ADP5585_PIN_CONFIG_D, + [ADP5589_GENERAL_CFG] = ADP5585_GENERAL_CFG, + [ADP5589_INT_EN] = ADP5585_INT_EN, +}; + +static unsigned char adp5585_reg(unsigned char reg) +{ + return adp5585_reg_lut[reg]; +} + +static const struct adp_constants const_adp5585 = { + .maxgpio = ADP5585_MAXGPIO, + .keymapsize = ADP5585_KEYMAPSIZE, + .gpi_pin_row_base = ADP5585_GPI_PIN_ROW_BASE, + .gpi_pin_row_end = ADP5585_GPI_PIN_ROW_END, + .gpi_pin_col_base = ADP5585_GPI_PIN_COL_BASE, + .gpi_pin_base = ADP5585_GPI_PIN_BASE, + .gpi_pin_end = ADP5585_GPI_PIN_END, + .gpimapsize_max = ADP5585_GPIMAPSIZE_MAX, + .c4_extend_cfg = 10, + .max_row_num = ADP5585_MAX_ROW_NUM, + .max_col_num = ADP5585_MAX_COL_NUM, + .row_mask = ADP5585_ROW_MASK, + .col_mask = ADP5585_COL_MASK, + .col_shift = ADP5585_COL_SHIFT, + .bank = adp5585_bank, + .bit = adp5585_bit, + .reg = adp5585_reg, +}; + static int adp5589_read(struct i2c_client *client, u8 reg) { int ret = i2c_smbus_read_byte_data(client, reg); @@ -109,19 +389,20 @@ static int adp5589_write(struct i2c_client *client, u8 reg, u8 val) 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]); + unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); + unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); - return !!(adp5589_read(kpad->client, ADP5589_GPI_STATUS_A + bank) & - bit); + return !!(adp5589_read(kpad->client, + kpad->var->reg(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]); + unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); + unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); mutex_lock(&kpad->gpio_lock); @@ -130,8 +411,8 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip, else kpad->dat_out[bank] &= ~bit; - adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank, - kpad->dat_out[bank]); + adp5589_write(kpad->client, kpad->var->reg(ADP5589_GPO_DATA_OUT_A) + + bank, kpad->dat_out[bank]); mutex_unlock(&kpad->gpio_lock); } @@ -139,14 +420,15 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip, 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]); + unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); + unsigned int bit = kpad->var->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, + ret = adp5589_write(kpad->client, + kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank, kpad->dir[bank]); mutex_unlock(&kpad->gpio_lock); @@ -158,8 +440,8 @@ 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]); + unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); + unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); int ret; mutex_lock(&kpad->gpio_lock); @@ -171,9 +453,10 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip, 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, + ret = adp5589_write(kpad->client, kpad->var->reg(ADP5589_GPO_DATA_OUT_A) + + bank, kpad->dat_out[bank]); + ret |= adp5589_write(kpad->client, + kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank, kpad->dir[bank]); mutex_unlock(&kpad->gpio_lock); @@ -184,26 +467,29 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip, static int __devinit adp5589_build_gpiomap(struct adp5589_kpad *kpad, const struct adp5589_kpad_platform_data *pdata) { - bool pin_used[MAXGPIO]; + bool pin_used[ADP5589_MAXGPIO]; int n_unused = 0; int i; memset(pin_used, false, sizeof(pin_used)); - for (i = 0; i < MAXGPIO; i++) + for (i = 0; i < kpad->var->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; + pin_used[kpad->gpimap[i].pin - kpad->var->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; + pin_used[kpad->var->c4_extend_cfg] = true; + + if (!kpad->adp5585_support_row5) + pin_used[5] = true; - for (i = 0; i < MAXGPIO; i++) + for (i = 0; i < kpad->var->maxgpio; i++) if (!pin_used[i]) kpad->gpiomap[n_unused++] = i; @@ -246,11 +532,11 @@ static int __devinit adp5589_gpio_add(struct adp5589_kpad *kpad) 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); + for (i = 0; i <= kpad->var->bank(kpad->var->maxgpio); i++) { + kpad->dat_out[i] = adp5589_read(kpad->client, kpad->var->reg( + ADP5589_GPO_DATA_OUT_A) + i); + kpad->dir[i] = adp5589_read(kpad->client, kpad->var->reg( + ADP5589_GPIO_DIRECTION_A) + i); } if (gpio_data->setup) { @@ -317,11 +603,11 @@ 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 = adp5589_read(kpad->client, ADP5589_5_FIFO_1 + i); int key_val = key & KEY_EV_MASK; - if (key_val >= ADP5589_GPI_PIN_BASE && - key_val <= ADP5589_GPI_PIN_END) { + if (key_val >= kpad->var->gpi_pin_base && + key_val <= kpad->var->gpi_pin_end) { adp5589_report_switches(kpad, key, key_val); } else { input_report_key(kpad->input, @@ -337,29 +623,30 @@ static irqreturn_t adp5589_irq(int irq, void *handle) struct i2c_client *client = kpad->client; int status, ev_cnt; - status = adp5589_read(client, ADP5589_INT_STATUS); + status = adp5589_read(client, ADP5589_5_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; + ev_cnt = adp5589_read(client, ADP5589_5_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 */ + adp5589_write(client, ADP5589_5_INT_STATUS, status); /* Status is W1C */ return IRQ_HANDLED; } -static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad, unsigned short key) +static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad, + unsigned short key) { int i; - for (i = 0; i < ADP5589_KEYMAPSIZE; i++) + for (i = 0; i < kpad->var->keymapsize; i++) if (key == kpad->keycode[i]) return (i + 1) | KEY_EV_PRESSED; @@ -372,19 +659,23 @@ 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; + client->dev.platform_data; + u8 (*reg) (u8) = kpad->var->reg; unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0; unsigned char pull_mask = 0; + int i, ret; + + ret = adp5589_write(client, reg(ADP5589_PIN_CONFIG_A), + pdata->keypad_en_mask & kpad->var->row_mask); + ret |= adp5589_write(client, reg(ADP5589_PIN_CONFIG_B), + (pdata->keypad_en_mask >> kpad->var->col_shift) & + kpad->var->col_mask); - 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 (!kpad->is_adp5585) + ret |= adp5589_write(client, ADP5589_PIN_CONFIG_C, + (pdata->keypad_en_mask >> 16) & 0xFF); - if (pdata->en_keylock) { + if (!kpad->is_adp5585 && pdata->en_keylock) { ret |= adp5589_write(client, ADP5589_UNLOCK1, pdata->unlock_key1); ret |= adp5589_write(client, ADP5589_UNLOCK2, @@ -395,96 +686,130 @@ static int __devinit adp5589_setup(struct adp5589_kpad *kpad) } for (i = 0; i < KEYP_MAX_EVENT; i++) - ret |= adp5589_read(client, ADP5589_FIFO_1 + i); + ret |= adp5589_read(client, ADP5589_5_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)); + if (pin <= kpad->var->gpi_pin_row_end) { + evt_mode1 |= (1 << (pin - kpad->var->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); + ((1 << (pin - kpad->var->gpi_pin_col_base)) & 0xFF); + if (!kpad->is_adp5585) + evt_mode3 |= ((1 << (pin - + kpad->var->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); + ret |= adp5589_write(client, reg(ADP5589_GPI_EVENT_EN_A), + evt_mode1); + ret |= adp5589_write(client, reg(ADP5589_GPI_EVENT_EN_B), + evt_mode2); + if (!kpad->is_adp5585) + ret |= adp5589_write(client, + reg(ADP5589_GPI_EVENT_EN_C), + evt_mode3); } if (pdata->pull_dis_mask & pdata->pullup_en_100k & - pdata->pullup_en_300k & pdata->pulldown_en_300k) + 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; + for (i = 0; i <= kpad->var->max_row_num; i++) { + unsigned val = 0, bit = (1 << i); + if (pdata->pullup_en_300k & bit) + val = 0; + else if (pdata->pulldown_en_300k & bit) + val = 1; + else if (pdata->pullup_en_100k & bit) + val = 2; + else if (pdata->pull_dis_mask & bit) + val = 3; + + pull_mask |= val << (2 * (i & 0x3)); + + if (i == 3 || i == kpad->var->max_row_num) { + ret |= adp5589_write(client, reg(ADP5585_RPULL_CONFIG_A) + + (i >> 2), pull_mask); + pull_mask = 0; + } + } - if (pdata->pullup_en_300k & (1 << i)) + for (i = 0; i <= kpad->var->max_col_num; i++) { + unsigned val = 0, bit = 1 << (i + kpad->var->col_shift); + if (pdata->pullup_en_300k & bit) val = 0; - else if (pdata->pulldown_en_300k & (1 << i)) + else if (pdata->pulldown_en_300k & bit) val = 1; - else if (pdata->pullup_en_100k & (1 << i)) + else if (pdata->pullup_en_100k & bit) val = 2; - else if (pdata->pull_dis_mask & (1 << i)) + else if (pdata->pull_dis_mask & bit) val = 3; pull_mask |= val << (2 * (i & 0x3)); - if ((i & 0x3) == 0x3 || i == MAXGPIO - 1) { + if (i == 3 || i == kpad->var->max_col_num) { ret |= adp5589_write(client, - ADP5589_RPULL_CONFIG_A + (i >> 2), - pull_mask); + reg(ADP5585_RPULL_CONFIG_C) + + (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, + ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_A), adp5589_get_evcode(kpad, pdata->reset1_key_1)); - ret |= adp5589_write(client, ADP5589_RESET1_EVENT_B, + ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_B), adp5589_get_evcode(kpad, pdata->reset1_key_2)); - ret |= adp5589_write(client, ADP5589_RESET1_EVENT_C, + ret |= adp5589_write(client, reg(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, + ret |= adp5589_write(client, reg(ADP5589_RESET2_EVENT_A), adp5589_get_evcode(kpad, pdata->reset2_key_1)); - ret |= adp5589_write(client, ADP5589_RESET2_EVENT_B, + ret |= adp5589_write(client, reg(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, + ret |= adp5589_write(client, reg(ADP5589_RESET_CFG), pdata->reset_cfg); - ret |= adp5589_write(client, ADP5589_PIN_CONFIG_D, + ret |= adp5589_write(client, reg(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, reg(ADP5589_DEBOUNCE_DIS_A), + pdata->debounce_dis_mask & kpad->var->row_mask); - ret |= adp5589_write(client, ADP5589_POLL_PTIME_CFG, + ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_B), + (pdata->debounce_dis_mask >> kpad->var->col_shift) + & kpad->var->col_mask); + + if (!kpad->is_adp5585) + ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_C), + (pdata->debounce_dis_mask >> 16) & 0xFF); + + ret |= adp5589_write(client, reg(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 | + ret |= adp5589_write(client, ADP5589_5_INT_STATUS, + (kpad->is_adp5585 ? 0 : LOGIC2_INT) | + LOGIC1_INT | OVRFLOW_INT | + (kpad->is_adp5585 ? 0 : LOCK_INT) | GPI_INT | EVENT_INT); /* Status is W1C */ - ret |= adp5589_write(client, ADP5589_GENERAL_CFG, + ret |= adp5589_write(client, reg(ADP5589_GENERAL_CFG), INT_CFG | OSC_EN | CORE_CLK(3)); - ret |= adp5589_write(client, ADP5589_INT_EN, + ret |= adp5589_write(client, reg(ADP5589_INT_EN), OVRFLOW_IEN | GPI_IEN | EVENT_IEN); if (ret < 0) { @@ -497,30 +822,33 @@ static int __devinit adp5589_setup(struct adp5589_kpad *kpad) 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; + int gpi_stat1 = adp5589_read(kpad->client, + kpad->var->reg(ADP5589_GPI_STATUS_A)); + int gpi_stat2 = adp5589_read(kpad->client, + kpad->var->reg(ADP5589_GPI_STATUS_B)); + int gpi_stat3 = !kpad->is_adp5585 ? + adp5589_read(kpad->client, ADP5589_GPI_STATUS_C) : 0; for (i = 0; i < kpad->gpimapsize; i++) { unsigned short pin = kpad->gpimap[i].pin; - if (pin <= ADP5589_GPI_PIN_ROW_END) { + if (pin <= kpad->var->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) { + pin_loc = pin - kpad->var->gpi_pin_row_base; + } else if ((pin - kpad->var->gpi_pin_col_base) < 8) { gpi_stat_tmp = gpi_stat2; - pin_loc = pin - ADP5589_GPI_PIN_COL_BASE; + pin_loc = pin - kpad->var->gpi_pin_col_base; } else { gpi_stat_tmp = gpi_stat3; - pin_loc = pin - ADP5589_GPI_PIN_COL_BASE - 8; + pin_loc = pin - kpad->var->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); + "Can't read GPIO_DAT_STAT switch %d, default to OFF\n", + pin); gpi_stat_tmp = 0; } @@ -536,7 +864,8 @@ 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; + const struct adp5589_kpad_platform_data *pdata = + client->dev.platform_data; struct input_dev *input; unsigned int revid; int ret, i; @@ -548,56 +877,79 @@ static int __devinit adp5589_probe(struct i2c_client *client, 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) { + kpad = kzalloc(sizeof(*kpad), GFP_KERNEL); + if (!kpad) + return -ENOMEM; + + switch (id->driver_data) { + case ADP5585_02: + kpad->adp5585_support_row5 = true; + case ADP5585_01: + kpad->is_adp5585 = true; + kpad->var = &const_adp5585; + break; + case ADP5589: + kpad->var = &const_adp5589; + break; + } + + if (!((pdata->keypad_en_mask & kpad->var->row_mask) && + (pdata->keypad_en_mask >> kpad->var->col_shift)) || + !pdata->keymap) { dev_err(&client->dev, "no rows, cols or keymap from pdata\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } - if (pdata->keymapsize != ADP5589_KEYMAPSIZE) { + if (pdata->keymapsize != kpad->var->keymapsize) { dev_err(&client->dev, "invalid keymapsize\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } if (!pdata->gpimap && pdata->gpimapsize) { dev_err(&client->dev, "invalid gpimap from pdata\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } - if (pdata->gpimapsize > ADP5589_GPIMAPSIZE_MAX) { + if (pdata->gpimapsize > kpad->var->gpimapsize_max) { dev_err(&client->dev, "invalid gpimapsize\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } 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) { + if (pin < kpad->var->gpi_pin_base || + pin > kpad->var->gpi_pin_end) { dev_err(&client->dev, "invalid gpi pin data\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } - if ((1 << (pin - ADP5589_GPI_PIN_ROW_BASE)) & + if ((1 << (pin - kpad->var->gpi_pin_row_base)) & pdata->keypad_en_mask) { dev_err(&client->dev, "invalid gpi row/col data\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } } if (!client->irq) { dev_err(&client->dev, "no IRQ?\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } - kpad = kzalloc(sizeof(*kpad), GFP_KERNEL); input = input_allocate_device(); - if (!kpad || !input) { + if (!input) { error = -ENOMEM; goto err_free_mem; } @@ -605,13 +957,13 @@ static int __devinit adp5589_probe(struct i2c_client *client, kpad->client = client; kpad->input = input; - ret = adp5589_read(client, ADP5589_ID); + ret = adp5589_read(client, ADP5589_5_ID); if (ret < 0) { error = ret; - goto err_free_mem; + goto err_free_input; } - revid = (u8) ret & ADP5589_DEVICE_ID_MASK; + revid = (u8) ret & ADP5589_5_DEVICE_ID_MASK; input->name = client->name; input->phys = "adp5589-keys/input0"; @@ -652,7 +1004,7 @@ static int __devinit adp5589_probe(struct i2c_client *client, error = input_register_device(input); if (error) { dev_err(&client->dev, "unable to register input device\n"); - goto err_free_mem; + goto err_free_input; } error = request_threaded_irq(client->irq, NULL, adp5589_irq, @@ -685,8 +1037,9 @@ err_free_irq: err_unreg_dev: input_unregister_device(input); input = NULL; -err_free_mem: +err_free_input: input_free_device(input); +err_free_mem: kfree(kpad); return error; @@ -696,7 +1049,7 @@ static int __devexit adp5589_remove(struct i2c_client *client) { struct adp5589_kpad *kpad = i2c_get_clientdata(client); - adp5589_write(client, ADP5589_GENERAL_CFG, 0); + adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0); free_irq(client->irq, kpad); input_unregister_device(kpad->input); adp5589_gpio_remove(kpad); @@ -736,7 +1089,9 @@ static int adp5589_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(adp5589_dev_pm_ops, adp5589_suspend, adp5589_resume); static const struct i2c_device_id adp5589_id[] = { - {"adp5589-keys", 0}, + {"adp5589-keys", ADP5589}, + {"adp5585-keys", ADP5585_01}, + {"adp5585-02-keys", ADP5585_02}, /* Adds ROW5 to ADP5585 */ {} }; @@ -767,4 +1122,4 @@ module_exit(adp5589_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); -MODULE_DESCRIPTION("ADP5589 Keypad driver"); +MODULE_DESCRIPTION("ADP5589/ADP5585 Keypad driver"); diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c index cd89d17162a3..9d82b3aeff5e 100644 --- a/drivers/input/keyboard/davinci_keyscan.c +++ b/drivers/input/keyboard/davinci_keyscan.c @@ -271,7 +271,7 @@ static int __init davinci_ks_probe(struct platform_device *pdev) } error = request_irq(davinci_ks->irq, davinci_ks_interrupt, - IRQF_DISABLED, pdev->name, davinci_ks); + 0, pdev->name, davinci_ks); if (error < 0) { dev_err(dev, "unable to register davinci key scan interrupt\n"); goto fail5; diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index aa17e024d803..4662c5da8018 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -323,7 +323,7 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) platform_set_drvdata(pdev, keypad); err = request_irq(keypad->irq, ep93xx_keypad_irq_handler, - IRQF_DISABLED, pdev->name, keypad); + 0, pdev->name, keypad); if (err) goto failed_free_dev; diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 67df91af8424..ed1ed469d085 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -461,8 +461,7 @@ static int gpio_keys_get_devtree_pdata(struct device *dev, struct device_node *node, *pp; int i; struct gpio_keys_button *buttons; - const u32 *reg; - int len; + u32 reg; node = dev->of_node; if (node == NULL) @@ -470,7 +469,7 @@ static int gpio_keys_get_devtree_pdata(struct device *dev, memset(pdata, 0, sizeof *pdata); - pdata->rep = !!of_get_property(node, "autorepeat", &len); + pdata->rep = !!of_get_property(node, "autorepeat", NULL); /* First count the subnodes */ pdata->nbuttons = 0; @@ -498,22 +497,25 @@ static int gpio_keys_get_devtree_pdata(struct device *dev, buttons[i].gpio = of_get_gpio_flags(pp, 0, &flags); buttons[i].active_low = flags & OF_GPIO_ACTIVE_LOW; - reg = of_get_property(pp, "linux,code", &len); - if (!reg) { + if (of_property_read_u32(pp, "linux,code", ®)) { dev_err(dev, "Button without keycode: 0x%x\n", buttons[i].gpio); goto out_fail; } - buttons[i].code = be32_to_cpup(reg); + buttons[i].code = reg; - buttons[i].desc = of_get_property(pp, "label", &len); + buttons[i].desc = of_get_property(pp, "label", NULL); - reg = of_get_property(pp, "linux,input-type", &len); - buttons[i].type = reg ? be32_to_cpup(reg) : EV_KEY; + if (of_property_read_u32(pp, "linux,input-type", ®) == 0) + buttons[i].type = reg; + else + buttons[i].type = EV_KEY; buttons[i].wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL); - reg = of_get_property(pp, "debounce-interval", &len); - buttons[i].debounce_interval = reg ? be32_to_cpup(reg) : 5; + if (of_property_read_u32(pp, "debounce-interval", ®) == 0) + buttons[i].debounce_interval = reg; + else + buttons[i].debounce_interval = 5; i++; } diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index d92c15c39e68..ccebd2d09151 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -510,7 +510,7 @@ static int __devinit imx_keypad_probe(struct platform_device *pdev) /* Ensure that the keypad will stay dormant until opened */ imx_keypad_inhibit(keypad); - error = request_irq(irq, imx_keypad_irq_handler, IRQF_DISABLED, + error = request_irq(irq, imx_keypad_irq_handler, 0, pdev->name, keypad); if (error) { dev_err(&pdev->dev, "failed to request IRQ\n"); @@ -567,10 +567,54 @@ static int __devexit imx_keypad_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int imx_kbd_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_keypad *kbd = platform_get_drvdata(pdev); + struct input_dev *input_dev = kbd->input_dev; + + /* imx kbd can wake up system even clock is disabled */ + mutex_lock(&input_dev->mutex); + + if (input_dev->users) + clk_disable(kbd->clk); + + mutex_unlock(&input_dev->mutex); + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(kbd->irq); + + return 0; +} + +static int imx_kbd_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_keypad *kbd = platform_get_drvdata(pdev); + struct input_dev *input_dev = kbd->input_dev; + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(kbd->irq); + + mutex_lock(&input_dev->mutex); + + if (input_dev->users) + clk_enable(kbd->clk); + + mutex_unlock(&input_dev->mutex); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(imx_kbd_pm_ops, imx_kbd_suspend, imx_kbd_resume); + static struct platform_driver imx_keypad_driver = { .driver = { .name = "imx-keypad", .owner = THIS_MODULE, + .pm = &imx_kbd_pm_ops, }, .probe = imx_keypad_probe, .remove = __devexit_p(imx_keypad_remove), diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index 2cd3e1d56ea4..0aa6740e60d0 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -129,7 +129,7 @@ static int __devinit jornada720_kbd_probe(struct platform_device *pdev) err = request_irq(IRQ_GPIO0, jornada720_kbd_interrupt, - IRQF_DISABLED | IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_FALLING, "jornadakbd", pdev); if (err) { printk(KERN_INFO "jornadakbd720_kbd: Unable to grab IRQ\n"); diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 756348a7f93a..82d1dc8badd5 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -788,7 +788,7 @@ static int __devexit lm8323_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP /* * We don't need to explicitly suspend the chip, as it already switches off * when there's no activity. diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index b02e4268e18f..e2ae657717ea 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -343,7 +343,6 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev, for (i = 0; i < pdata->num_row_gpios; i++) { err = request_irq(gpio_to_irq(pdata->row_gpios[i]), matrix_keypad_interrupt, - IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "matrix-keypad", keypad); diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 4b0ec35259a1..eca6ae63de14 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -535,7 +535,7 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) input_dev->evbit[0] |= BIT_MASK(EV_REL); } - error = request_irq(irq, pxa27x_keypad_irq_handler, IRQF_DISABLED, + error = request_irq(irq, pxa27x_keypad_irq_handler, 0, pdev->name, keypad); if (error) { dev_err(&pdev->dev, "failed to request IRQ\n"); diff --git a/drivers/input/keyboard/pxa930_rotary.c b/drivers/input/keyboard/pxa930_rotary.c index b7123a44b6ec..35451bf780c7 100644 --- a/drivers/input/keyboard/pxa930_rotary.c +++ b/drivers/input/keyboard/pxa930_rotary.c @@ -148,7 +148,7 @@ static int __devinit pxa930_rotary_probe(struct platform_device *pdev) r->input_dev = input_dev; input_set_drvdata(input_dev, r); - err = request_irq(irq, rotary_irq, IRQF_DISABLED, + err = request_irq(irq, rotary_irq, 0, "enhanced rotary", r); if (err) { dev_err(&pdev->dev, "failed to request IRQ\n"); diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c index 99122f59e988..f60c9e82f204 100644 --- a/drivers/input/keyboard/tc3589x-keypad.c +++ b/drivers/input/keyboard/tc3589x-keypad.c @@ -90,7 +90,7 @@ struct tc_keypad { bool keypad_stopped; }; -static int __devinit tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad) +static int tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad) { int ret; struct tc3589x *tc3589x = keypad->tc3589x; diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index a5a77915c650..cf3228b0ab90 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -55,6 +55,7 @@ #define KBC_ROW_CFG0_0 0x8 #define KBC_COL_CFG0_0 0x18 +#define KBC_TO_CNT_0 0x24 #define KBC_INIT_DLY_0 0x28 #define KBC_RPT_DLY_0 0x2c #define KBC_KP_ENT0_0 0x30 @@ -70,6 +71,7 @@ struct tegra_kbc { spinlock_t lock; unsigned int repoll_dly; unsigned long cp_dly_jiffies; + unsigned int cp_to_wkup_dly; bool use_fn_map; bool use_ghost_filter; const struct tegra_kbc_platform_data *pdata; @@ -258,12 +260,10 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc) u32 val = 0; unsigned int i; 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++) { if ((i % 4) == 0) val = readl(kbc->mmio + KBC_KP_ENT0_0 + i); @@ -292,7 +292,7 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc) * 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)) { + if (kbc->use_ghost_filter && num_down >= 3) { for (i = 0; i < num_down; i++) { unsigned int j; u8 curr_col = scancodes[i] & 0x07; @@ -325,8 +325,6 @@ 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; @@ -341,6 +339,18 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc) kbc->num_pressed_keys = num_down; } +static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable) +{ + u32 val; + + val = readl(kbc->mmio + KBC_CONTROL_0); + if (enable) + val |= KBC_CONTROL_FIFO_CNT_INT_EN; + else + val &= ~KBC_CONTROL_FIFO_CNT_INT_EN; + writel(val, kbc->mmio + KBC_CONTROL_0); +} + static void tegra_kbc_keypress_timer(unsigned long data) { struct tegra_kbc *kbc = (struct tegra_kbc *)data; @@ -348,6 +358,8 @@ static void tegra_kbc_keypress_timer(unsigned long data) u32 val; unsigned int i; + spin_lock_irqsave(&kbc->lock, flags); + val = (readl(kbc->mmio + KBC_INT_0) >> 4) & 0xf; if (val) { unsigned long dly; @@ -369,26 +381,19 @@ static void tegra_kbc_keypress_timer(unsigned long data) kbc->num_pressed_keys = 0; /* All keys are released so enable the keypress interrupt */ - spin_lock_irqsave(&kbc->lock, flags); - val = readl(kbc->mmio + KBC_CONTROL_0); - val |= KBC_CONTROL_FIFO_CNT_INT_EN; - writel(val, kbc->mmio + KBC_CONTROL_0); - spin_unlock_irqrestore(&kbc->lock, flags); + tegra_kbc_set_fifo_interrupt(kbc, true); } + + spin_unlock_irqrestore(&kbc->lock, flags); } static irqreturn_t tegra_kbc_isr(int irq, void *args) { struct tegra_kbc *kbc = args; - u32 val, ctl; + unsigned long flags; + u32 val; - /* - * Until all keys are released, defer further processing to - * the polling loop in tegra_kbc_keypress_timer - */ - ctl = readl(kbc->mmio + KBC_CONTROL_0); - ctl &= ~KBC_CONTROL_FIFO_CNT_INT_EN; - writel(ctl, kbc->mmio + KBC_CONTROL_0); + spin_lock_irqsave(&kbc->lock, flags); /* * Quickly bail out & reenable interrupts if the fifo threshold @@ -399,15 +404,15 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args) if (val & KBC_INT_FIFO_CNT_INT_STATUS) { /* - * Schedule timer to run when hardware is in continuous - * polling mode. + * Until all keys are released, defer further processing to + * the polling loop in tegra_kbc_keypress_timer. */ + tegra_kbc_set_fifo_interrupt(kbc, false); mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies); - } else { - ctl |= KBC_CONTROL_FIFO_CNT_INT_EN; - writel(ctl, kbc->mmio + KBC_CONTROL_0); } + spin_unlock_irqrestore(&kbc->lock, flags); + return IRQ_HANDLED; } @@ -455,7 +460,6 @@ static void tegra_kbc_config_pins(struct tegra_kbc *kbc) static int tegra_kbc_start(struct tegra_kbc *kbc) { const struct tegra_kbc_platform_data *pdata = kbc->pdata; - unsigned long flags; unsigned int debounce_cnt; u32 val = 0; @@ -493,7 +497,6 @@ static int tegra_kbc_start(struct tegra_kbc *kbc) * Atomically clear out any remaining entries in the key FIFO * and enable keyboard interrupts. */ - spin_lock_irqsave(&kbc->lock, flags); while (1) { val = readl(kbc->mmio + KBC_INT_0); val >>= 4; @@ -504,7 +507,6 @@ static int tegra_kbc_start(struct tegra_kbc *kbc) val = readl(kbc->mmio + KBC_KP_ENT1_0); } writel(0x7, kbc->mmio + KBC_INT_0); - spin_unlock_irqrestore(&kbc->lock, flags); enable_irq(kbc->irq); @@ -734,18 +736,30 @@ static int tegra_kbc_suspend(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct tegra_kbc *kbc = platform_get_drvdata(pdev); + mutex_lock(&kbc->idev->mutex); if (device_may_wakeup(&pdev->dev)) { - tegra_kbc_setup_wakekeys(kbc, true); - enable_irq_wake(kbc->irq); + disable_irq(kbc->irq); + del_timer_sync(&kbc->timer); + tegra_kbc_set_fifo_interrupt(kbc, false); + /* Forcefully clear the interrupt status */ writel(0x7, kbc->mmio + KBC_INT_0); + /* + * Store the previous resident time of continuous polling mode. + * Force the keyboard into interrupt mode. + */ + kbc->cp_to_wkup_dly = readl(kbc->mmio + KBC_TO_CNT_0); + writel(0, kbc->mmio + KBC_TO_CNT_0); + + tegra_kbc_setup_wakekeys(kbc, true); msleep(30); + + enable_irq_wake(kbc->irq); } else { - mutex_lock(&kbc->idev->mutex); if (kbc->idev->users) tegra_kbc_stop(kbc); - mutex_unlock(&kbc->idev->mutex); } + mutex_unlock(&kbc->idev->mutex); return 0; } @@ -756,15 +770,22 @@ static int tegra_kbc_resume(struct device *dev) struct tegra_kbc *kbc = platform_get_drvdata(pdev); int err = 0; + mutex_lock(&kbc->idev->mutex); if (device_may_wakeup(&pdev->dev)) { disable_irq_wake(kbc->irq); tegra_kbc_setup_wakekeys(kbc, false); + + /* Restore the resident time of continuous polling mode. */ + writel(kbc->cp_to_wkup_dly, kbc->mmio + KBC_TO_CNT_0); + + tegra_kbc_set_fifo_interrupt(kbc, true); + + enable_irq(kbc->irq); } else { - mutex_lock(&kbc->idev->mutex); if (kbc->idev->users) err = tegra_kbc_start(kbc); - mutex_unlock(&kbc->idev->mutex); } + mutex_unlock(&kbc->idev->mutex); return err; } diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c index ee2bf6bcf291..318586dadacf 100644 --- a/drivers/input/keyboard/w90p910_keypad.c +++ b/drivers/input/keyboard/w90p910_keypad.c @@ -203,7 +203,7 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev) input_dev->keycode, input_dev->keybit); error = request_irq(keypad->irq, w90p910_keypad_irq_handler, - IRQF_DISABLED, pdev->name, keypad); + 0, pdev->name, keypad); if (error) { dev_err(&pdev->dev, "failed to request IRQ\n"); goto failed_put_clk; |