diff options
Diffstat (limited to 'drivers/input/keyboard')
-rw-r--r-- | drivers/input/keyboard/Kconfig | 8 | ||||
-rw-r--r-- | drivers/input/keyboard/Makefile | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/amikbd.c | 47 | ||||
-rw-r--r-- | drivers/input/keyboard/atkbd.c | 6 | ||||
-rw-r--r-- | drivers/input/keyboard/cap1106.c | 341 | ||||
-rw-r--r-- | drivers/input/keyboard/cap11xx.c | 376 | ||||
-rw-r--r-- | drivers/input/keyboard/gpio_keys.c | 37 | ||||
-rw-r--r-- | drivers/input/keyboard/lm8323.c | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/lpc32xx-keys.c | 92 | ||||
-rw-r--r-- | drivers/input/keyboard/mpr121_touchkey.c | 42 | ||||
-rw-r--r-- | drivers/input/keyboard/pxa27x_keypad.c | 84 |
11 files changed, 490 insertions, 547 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index a3958c63d7d5..96ee26c555e0 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -665,14 +665,14 @@ config KEYBOARD_CROS_EC To compile this driver as a module, choose M here: the module will be called cros_ec_keyb. -config KEYBOARD_CAP1106 - tristate "Microchip CAP1106 touch sensor" +config KEYBOARD_CAP11XX + tristate "Microchip CAP11XX based touch sensors" depends on OF && I2C select REGMAP_I2C help - Say Y here to enable the CAP1106 touch sensor driver. + Say Y here to enable the CAP11XX touch sensor driver. To compile this driver as a module, choose M here: the - module will be called cap1106. + module will be called cap11xx. endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 0a3345634d79..febafa527eb6 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -11,7 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o -obj-$(CONFIG_KEYBOARD_CAP1106) += cap1106.o +obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c index 096d6067ae1f..3196f2d29ade 100644 --- a/drivers/input/keyboard/amikbd.c +++ b/drivers/input/keyboard/amikbd.c @@ -45,6 +45,7 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_DESCRIPTION("Amiga keyboard driver"); MODULE_LICENSE("GPL"); +#ifdef CONFIG_HW_CONSOLE static unsigned char amikbd_keycode[0x78] __initdata = { [0] = KEY_GRAVE, [1] = KEY_1, @@ -144,6 +145,32 @@ static unsigned char amikbd_keycode[0x78] __initdata = { [103] = KEY_RIGHTMETA }; +static void __init amikbd_init_console_keymaps(void) +{ + /* We can spare 512 bytes on stack for temp_map in init path. */ + unsigned short temp_map[NR_KEYS]; + int i, j; + + for (i = 0; i < MAX_NR_KEYMAPS; i++) { + if (!key_maps[i]) + continue; + memset(temp_map, 0, sizeof(temp_map)); + for (j = 0; j < 0x78; j++) { + if (!amikbd_keycode[j]) + continue; + temp_map[j] = key_maps[i][amikbd_keycode[j]]; + } + for (j = 0; j < NR_KEYS; j++) { + if (!temp_map[j]) + temp_map[j] = 0xf200; + } + memcpy(key_maps[i], temp_map, sizeof(temp_map)); + } +} +#else /* !CONFIG_HW_CONSOLE */ +static inline void amikbd_init_console_keymaps(void) {} +#endif /* !CONFIG_HW_CONSOLE */ + static const char *amikbd_messages[8] = { [0] = KERN_ALERT "amikbd: Ctrl-Amiga-Amiga reset warning!!\n", [1] = KERN_WARNING "amikbd: keyboard lost sync\n", @@ -186,7 +213,7 @@ static irqreturn_t amikbd_interrupt(int irq, void *data) static int __init amikbd_probe(struct platform_device *pdev) { struct input_dev *dev; - int i, j, err; + int i, err; dev = input_allocate_device(); if (!dev) { @@ -207,22 +234,8 @@ static int __init amikbd_probe(struct platform_device *pdev) for (i = 0; i < 0x78; i++) set_bit(i, dev->keybit); - for (i = 0; i < MAX_NR_KEYMAPS; i++) { - static u_short temp_map[NR_KEYS] __initdata; - if (!key_maps[i]) - continue; - memset(temp_map, 0, sizeof(temp_map)); - for (j = 0; j < 0x78; j++) { - if (!amikbd_keycode[j]) - continue; - temp_map[j] = key_maps[i][amikbd_keycode[j]]; - } - for (j = 0; j < NR_KEYS; j++) { - if (!temp_map[j]) - temp_map[j] = 0xf200; - } - memcpy(key_maps[i], temp_map, sizeof(temp_map)); - } + amikbd_init_console_keymaps(); + ciaa.cra &= ~0x41; /* serial data in, turn off TA */ err = request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", dev); diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 6f5d79569136..e27a25892db4 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -456,8 +456,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, keycode = atkbd->keycode[code]; - if (keycode != ATKBD_KEY_NULL) - input_event(dev, EV_MSC, MSC_SCAN, code); + if (!(atkbd->release && test_bit(code, atkbd->force_release_mask))) + if (keycode != ATKBD_KEY_NULL) + input_event(dev, EV_MSC, MSC_SCAN, code); switch (keycode) { case ATKBD_KEY_NULL: @@ -511,6 +512,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, input_sync(dev); if (value && test_bit(code, atkbd->force_release_mask)) { + input_event(dev, EV_MSC, MSC_SCAN, code); input_report_key(dev, keycode, 0); input_sync(dev); } diff --git a/drivers/input/keyboard/cap1106.c b/drivers/input/keyboard/cap1106.c deleted file mode 100644 index d70b65a14ced..000000000000 --- a/drivers/input/keyboard/cap1106.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Input driver for Microchip CAP1106, 6 channel capacitive touch sensor - * - * http://www.microchip.com/wwwproducts/Devices.aspx?product=CAP1106 - * - * (c) 2014 Daniel Mack <linux@zonque.org> - * - * 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/kernel.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/input.h> -#include <linux/of_irq.h> -#include <linux/regmap.h> -#include <linux/i2c.h> -#include <linux/gpio/consumer.h> - -#define CAP1106_REG_MAIN_CONTROL 0x00 -#define CAP1106_REG_MAIN_CONTROL_GAIN_SHIFT (6) -#define CAP1106_REG_MAIN_CONTROL_GAIN_MASK (0xc0) -#define CAP1106_REG_MAIN_CONTROL_DLSEEP BIT(4) -#define CAP1106_REG_GENERAL_STATUS 0x02 -#define CAP1106_REG_SENSOR_INPUT 0x03 -#define CAP1106_REG_NOISE_FLAG_STATUS 0x0a -#define CAP1106_REG_SENOR_DELTA(X) (0x10 + (X)) -#define CAP1106_REG_SENSITIVITY_CONTROL 0x1f -#define CAP1106_REG_CONFIG 0x20 -#define CAP1106_REG_SENSOR_ENABLE 0x21 -#define CAP1106_REG_SENSOR_CONFIG 0x22 -#define CAP1106_REG_SENSOR_CONFIG2 0x23 -#define CAP1106_REG_SAMPLING_CONFIG 0x24 -#define CAP1106_REG_CALIBRATION 0x26 -#define CAP1106_REG_INT_ENABLE 0x27 -#define CAP1106_REG_REPEAT_RATE 0x28 -#define CAP1106_REG_MT_CONFIG 0x2a -#define CAP1106_REG_MT_PATTERN_CONFIG 0x2b -#define CAP1106_REG_MT_PATTERN 0x2d -#define CAP1106_REG_RECALIB_CONFIG 0x2f -#define CAP1106_REG_SENSOR_THRESH(X) (0x30 + (X)) -#define CAP1106_REG_SENSOR_NOISE_THRESH 0x38 -#define CAP1106_REG_STANDBY_CHANNEL 0x40 -#define CAP1106_REG_STANDBY_CONFIG 0x41 -#define CAP1106_REG_STANDBY_SENSITIVITY 0x42 -#define CAP1106_REG_STANDBY_THRESH 0x43 -#define CAP1106_REG_CONFIG2 0x44 -#define CAP1106_REG_SENSOR_BASE_CNT(X) (0x50 + (X)) -#define CAP1106_REG_SENSOR_CALIB (0xb1 + (X)) -#define CAP1106_REG_SENSOR_CALIB_LSB1 0xb9 -#define CAP1106_REG_SENSOR_CALIB_LSB2 0xba -#define CAP1106_REG_PRODUCT_ID 0xfd -#define CAP1106_REG_MANUFACTURER_ID 0xfe -#define CAP1106_REG_REVISION 0xff - -#define CAP1106_NUM_CHN 6 -#define CAP1106_PRODUCT_ID 0x55 -#define CAP1106_MANUFACTURER_ID 0x5d - -struct cap1106_priv { - struct regmap *regmap; - struct input_dev *idev; - - /* config */ - unsigned short keycodes[CAP1106_NUM_CHN]; -}; - -static const struct reg_default cap1106_reg_defaults[] = { - { CAP1106_REG_MAIN_CONTROL, 0x00 }, - { CAP1106_REG_GENERAL_STATUS, 0x00 }, - { CAP1106_REG_SENSOR_INPUT, 0x00 }, - { CAP1106_REG_NOISE_FLAG_STATUS, 0x00 }, - { CAP1106_REG_SENSITIVITY_CONTROL, 0x2f }, - { CAP1106_REG_CONFIG, 0x20 }, - { CAP1106_REG_SENSOR_ENABLE, 0x3f }, - { CAP1106_REG_SENSOR_CONFIG, 0xa4 }, - { CAP1106_REG_SENSOR_CONFIG2, 0x07 }, - { CAP1106_REG_SAMPLING_CONFIG, 0x39 }, - { CAP1106_REG_CALIBRATION, 0x00 }, - { CAP1106_REG_INT_ENABLE, 0x3f }, - { CAP1106_REG_REPEAT_RATE, 0x3f }, - { CAP1106_REG_MT_CONFIG, 0x80 }, - { CAP1106_REG_MT_PATTERN_CONFIG, 0x00 }, - { CAP1106_REG_MT_PATTERN, 0x3f }, - { CAP1106_REG_RECALIB_CONFIG, 0x8a }, - { CAP1106_REG_SENSOR_THRESH(0), 0x40 }, - { CAP1106_REG_SENSOR_THRESH(1), 0x40 }, - { CAP1106_REG_SENSOR_THRESH(2), 0x40 }, - { CAP1106_REG_SENSOR_THRESH(3), 0x40 }, - { CAP1106_REG_SENSOR_THRESH(4), 0x40 }, - { CAP1106_REG_SENSOR_THRESH(5), 0x40 }, - { CAP1106_REG_SENSOR_NOISE_THRESH, 0x01 }, - { CAP1106_REG_STANDBY_CHANNEL, 0x00 }, - { CAP1106_REG_STANDBY_CONFIG, 0x39 }, - { CAP1106_REG_STANDBY_SENSITIVITY, 0x02 }, - { CAP1106_REG_STANDBY_THRESH, 0x40 }, - { CAP1106_REG_CONFIG2, 0x40 }, - { CAP1106_REG_SENSOR_CALIB_LSB1, 0x00 }, - { CAP1106_REG_SENSOR_CALIB_LSB2, 0x00 }, -}; - -static bool cap1106_volatile_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case CAP1106_REG_MAIN_CONTROL: - case CAP1106_REG_SENSOR_INPUT: - case CAP1106_REG_SENOR_DELTA(0): - case CAP1106_REG_SENOR_DELTA(1): - case CAP1106_REG_SENOR_DELTA(2): - case CAP1106_REG_SENOR_DELTA(3): - case CAP1106_REG_SENOR_DELTA(4): - case CAP1106_REG_SENOR_DELTA(5): - case CAP1106_REG_PRODUCT_ID: - case CAP1106_REG_MANUFACTURER_ID: - case CAP1106_REG_REVISION: - return true; - } - - return false; -} - -static const struct regmap_config cap1106_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = CAP1106_REG_REVISION, - .reg_defaults = cap1106_reg_defaults, - - .num_reg_defaults = ARRAY_SIZE(cap1106_reg_defaults), - .cache_type = REGCACHE_RBTREE, - .volatile_reg = cap1106_volatile_reg, -}; - -static irqreturn_t cap1106_thread_func(int irq_num, void *data) -{ - struct cap1106_priv *priv = data; - unsigned int status; - int ret, i; - - /* - * Deassert interrupt. This needs to be done before reading the status - * registers, which will not carry valid values otherwise. - */ - ret = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL, 1, 0); - if (ret < 0) - goto out; - - ret = regmap_read(priv->regmap, CAP1106_REG_SENSOR_INPUT, &status); - if (ret < 0) - goto out; - - for (i = 0; i < CAP1106_NUM_CHN; i++) - input_report_key(priv->idev, priv->keycodes[i], - status & (1 << i)); - - input_sync(priv->idev); - -out: - return IRQ_HANDLED; -} - -static int cap1106_set_sleep(struct cap1106_priv *priv, bool sleep) -{ - return regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL, - CAP1106_REG_MAIN_CONTROL_DLSEEP, - sleep ? CAP1106_REG_MAIN_CONTROL_DLSEEP : 0); -} - -static int cap1106_input_open(struct input_dev *idev) -{ - struct cap1106_priv *priv = input_get_drvdata(idev); - - return cap1106_set_sleep(priv, false); -} - -static void cap1106_input_close(struct input_dev *idev) -{ - struct cap1106_priv *priv = input_get_drvdata(idev); - - cap1106_set_sleep(priv, true); -} - -static int cap1106_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) -{ - struct device *dev = &i2c_client->dev; - struct cap1106_priv *priv; - struct device_node *node; - int i, error, irq, gain = 0; - unsigned int val, rev; - u32 gain32, keycodes[CAP1106_NUM_CHN]; - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->regmap = devm_regmap_init_i2c(i2c_client, &cap1106_regmap_config); - if (IS_ERR(priv->regmap)) - return PTR_ERR(priv->regmap); - - error = regmap_read(priv->regmap, CAP1106_REG_PRODUCT_ID, &val); - if (error) - return error; - - if (val != CAP1106_PRODUCT_ID) { - dev_err(dev, "Product ID: Got 0x%02x, expected 0x%02x\n", - val, CAP1106_PRODUCT_ID); - return -ENODEV; - } - - error = regmap_read(priv->regmap, CAP1106_REG_MANUFACTURER_ID, &val); - if (error) - return error; - - if (val != CAP1106_MANUFACTURER_ID) { - dev_err(dev, "Manufacturer ID: Got 0x%02x, expected 0x%02x\n", - val, CAP1106_MANUFACTURER_ID); - return -ENODEV; - } - - error = regmap_read(priv->regmap, CAP1106_REG_REVISION, &rev); - if (error < 0) - return error; - - dev_info(dev, "CAP1106 detected, revision 0x%02x\n", rev); - i2c_set_clientdata(i2c_client, priv); - node = dev->of_node; - - if (!of_property_read_u32(node, "microchip,sensor-gain", &gain32)) { - if (is_power_of_2(gain32) && gain32 <= 8) - gain = ilog2(gain32); - else - dev_err(dev, "Invalid sensor-gain value %d\n", gain32); - } - - BUILD_BUG_ON(ARRAY_SIZE(keycodes) != ARRAY_SIZE(priv->keycodes)); - - /* Provide some useful defaults */ - for (i = 0; i < ARRAY_SIZE(keycodes); i++) - keycodes[i] = KEY_A + i; - - of_property_read_u32_array(node, "linux,keycodes", - keycodes, ARRAY_SIZE(keycodes)); - - for (i = 0; i < ARRAY_SIZE(keycodes); i++) - priv->keycodes[i] = keycodes[i]; - - error = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL, - CAP1106_REG_MAIN_CONTROL_GAIN_MASK, - gain << CAP1106_REG_MAIN_CONTROL_GAIN_SHIFT); - if (error) - return error; - - /* Disable autorepeat. The Linux input system has its own handling. */ - error = regmap_write(priv->regmap, CAP1106_REG_REPEAT_RATE, 0); - if (error) - return error; - - priv->idev = devm_input_allocate_device(dev); - if (!priv->idev) - return -ENOMEM; - - priv->idev->name = "CAP1106 capacitive touch sensor"; - priv->idev->id.bustype = BUS_I2C; - priv->idev->evbit[0] = BIT_MASK(EV_KEY); - - if (of_property_read_bool(node, "autorepeat")) - __set_bit(EV_REP, priv->idev->evbit); - - for (i = 0; i < CAP1106_NUM_CHN; i++) - __set_bit(priv->keycodes[i], priv->idev->keybit); - - __clear_bit(KEY_RESERVED, priv->idev->keybit); - - priv->idev->keycode = priv->keycodes; - priv->idev->keycodesize = sizeof(priv->keycodes[0]); - priv->idev->keycodemax = ARRAY_SIZE(priv->keycodes); - - priv->idev->id.vendor = CAP1106_MANUFACTURER_ID; - priv->idev->id.product = CAP1106_PRODUCT_ID; - priv->idev->id.version = rev; - - priv->idev->open = cap1106_input_open; - priv->idev->close = cap1106_input_close; - - input_set_drvdata(priv->idev, priv); - - /* - * Put the device in deep sleep mode for now. - * ->open() will bring it back once the it is actually needed. - */ - cap1106_set_sleep(priv, true); - - error = input_register_device(priv->idev); - if (error) - return error; - - irq = irq_of_parse_and_map(node, 0); - if (!irq) { - dev_err(dev, "Unable to parse or map IRQ\n"); - return -ENXIO; - } - - error = devm_request_threaded_irq(dev, irq, NULL, cap1106_thread_func, - IRQF_ONESHOT, dev_name(dev), priv); - if (error) - return error; - - return 0; -} - -static const struct of_device_id cap1106_dt_ids[] = { - { .compatible = "microchip,cap1106", }, - {} -}; -MODULE_DEVICE_TABLE(of, cap1106_dt_ids); - -static const struct i2c_device_id cap1106_i2c_ids[] = { - { "cap1106", 0 }, - {} -}; -MODULE_DEVICE_TABLE(i2c, cap1106_i2c_ids); - -static struct i2c_driver cap1106_i2c_driver = { - .driver = { - .name = "cap1106", - .owner = THIS_MODULE, - .of_match_table = cap1106_dt_ids, - }, - .id_table = cap1106_i2c_ids, - .probe = cap1106_i2c_probe, -}; - -module_i2c_driver(cap1106_i2c_driver); - -MODULE_ALIAS("platform:cap1106"); -MODULE_DESCRIPTION("Microchip CAP1106 driver"); -MODULE_AUTHOR("Daniel Mack <linux@zonque.org>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c new file mode 100644 index 000000000000..4f59f0bab28f --- /dev/null +++ b/drivers/input/keyboard/cap11xx.c @@ -0,0 +1,376 @@ +/* + * Input driver for Microchip CAP11xx based capacitive touch sensors + * + * (c) 2014 Daniel Mack <linux@zonque.org> + * + * 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/kernel.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/of_irq.h> +#include <linux/regmap.h> +#include <linux/i2c.h> +#include <linux/gpio/consumer.h> + +#define CAP11XX_REG_MAIN_CONTROL 0x00 +#define CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT (6) +#define CAP11XX_REG_MAIN_CONTROL_GAIN_MASK (0xc0) +#define CAP11XX_REG_MAIN_CONTROL_DLSEEP BIT(4) +#define CAP11XX_REG_GENERAL_STATUS 0x02 +#define CAP11XX_REG_SENSOR_INPUT 0x03 +#define CAP11XX_REG_NOISE_FLAG_STATUS 0x0a +#define CAP11XX_REG_SENOR_DELTA(X) (0x10 + (X)) +#define CAP11XX_REG_SENSITIVITY_CONTROL 0x1f +#define CAP11XX_REG_CONFIG 0x20 +#define CAP11XX_REG_SENSOR_ENABLE 0x21 +#define CAP11XX_REG_SENSOR_CONFIG 0x22 +#define CAP11XX_REG_SENSOR_CONFIG2 0x23 +#define CAP11XX_REG_SAMPLING_CONFIG 0x24 +#define CAP11XX_REG_CALIBRATION 0x26 +#define CAP11XX_REG_INT_ENABLE 0x27 +#define CAP11XX_REG_REPEAT_RATE 0x28 +#define CAP11XX_REG_MT_CONFIG 0x2a +#define CAP11XX_REG_MT_PATTERN_CONFIG 0x2b +#define CAP11XX_REG_MT_PATTERN 0x2d +#define CAP11XX_REG_RECALIB_CONFIG 0x2f +#define CAP11XX_REG_SENSOR_THRESH(X) (0x30 + (X)) +#define CAP11XX_REG_SENSOR_NOISE_THRESH 0x38 +#define CAP11XX_REG_STANDBY_CHANNEL 0x40 +#define CAP11XX_REG_STANDBY_CONFIG 0x41 +#define CAP11XX_REG_STANDBY_SENSITIVITY 0x42 +#define CAP11XX_REG_STANDBY_THRESH 0x43 +#define CAP11XX_REG_CONFIG2 0x44 +#define CAP11XX_REG_CONFIG2_ALT_POL BIT(6) +#define CAP11XX_REG_SENSOR_BASE_CNT(X) (0x50 + (X)) +#define CAP11XX_REG_SENSOR_CALIB (0xb1 + (X)) +#define CAP11XX_REG_SENSOR_CALIB_LSB1 0xb9 +#define CAP11XX_REG_SENSOR_CALIB_LSB2 0xba +#define CAP11XX_REG_PRODUCT_ID 0xfd +#define CAP11XX_REG_MANUFACTURER_ID 0xfe +#define CAP11XX_REG_REVISION 0xff + +#define CAP11XX_MANUFACTURER_ID 0x5d + +struct cap11xx_priv { + struct regmap *regmap; + struct input_dev *idev; + + /* config */ + u32 keycodes[]; +}; + +struct cap11xx_hw_model { + u8 product_id; + unsigned int num_channels; +}; + +enum { + CAP1106, + CAP1126, + CAP1188, +}; + +static const struct cap11xx_hw_model cap11xx_devices[] = { + [CAP1106] = { .product_id = 0x55, .num_channels = 6 }, + [CAP1126] = { .product_id = 0x53, .num_channels = 6 }, + [CAP1188] = { .product_id = 0x50, .num_channels = 8 }, +}; + +static const struct reg_default cap11xx_reg_defaults[] = { + { CAP11XX_REG_MAIN_CONTROL, 0x00 }, + { CAP11XX_REG_GENERAL_STATUS, 0x00 }, + { CAP11XX_REG_SENSOR_INPUT, 0x00 }, + { CAP11XX_REG_NOISE_FLAG_STATUS, 0x00 }, + { CAP11XX_REG_SENSITIVITY_CONTROL, 0x2f }, + { CAP11XX_REG_CONFIG, 0x20 }, + { CAP11XX_REG_SENSOR_ENABLE, 0x3f }, + { CAP11XX_REG_SENSOR_CONFIG, 0xa4 }, + { CAP11XX_REG_SENSOR_CONFIG2, 0x07 }, + { CAP11XX_REG_SAMPLING_CONFIG, 0x39 }, + { CAP11XX_REG_CALIBRATION, 0x00 }, + { CAP11XX_REG_INT_ENABLE, 0x3f }, + { CAP11XX_REG_REPEAT_RATE, 0x3f }, + { CAP11XX_REG_MT_CONFIG, 0x80 }, + { CAP11XX_REG_MT_PATTERN_CONFIG, 0x00 }, + { CAP11XX_REG_MT_PATTERN, 0x3f }, + { CAP11XX_REG_RECALIB_CONFIG, 0x8a }, + { CAP11XX_REG_SENSOR_THRESH(0), 0x40 }, + { CAP11XX_REG_SENSOR_THRESH(1), 0x40 }, + { CAP11XX_REG_SENSOR_THRESH(2), 0x40 }, + { CAP11XX_REG_SENSOR_THRESH(3), 0x40 }, + { CAP11XX_REG_SENSOR_THRESH(4), 0x40 }, + { CAP11XX_REG_SENSOR_THRESH(5), 0x40 }, + { CAP11XX_REG_SENSOR_NOISE_THRESH, 0x01 }, + { CAP11XX_REG_STANDBY_CHANNEL, 0x00 }, + { CAP11XX_REG_STANDBY_CONFIG, 0x39 }, + { CAP11XX_REG_STANDBY_SENSITIVITY, 0x02 }, + { CAP11XX_REG_STANDBY_THRESH, 0x40 }, + { CAP11XX_REG_CONFIG2, 0x40 }, + { CAP11XX_REG_SENSOR_CALIB_LSB1, 0x00 }, + { CAP11XX_REG_SENSOR_CALIB_LSB2, 0x00 }, +}; + +static bool cap11xx_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CAP11XX_REG_MAIN_CONTROL: + case CAP11XX_REG_SENSOR_INPUT: + case CAP11XX_REG_SENOR_DELTA(0): + case CAP11XX_REG_SENOR_DELTA(1): + case CAP11XX_REG_SENOR_DELTA(2): + case CAP11XX_REG_SENOR_DELTA(3): + case CAP11XX_REG_SENOR_DELTA(4): + case CAP11XX_REG_SENOR_DELTA(5): + case CAP11XX_REG_PRODUCT_ID: + case CAP11XX_REG_MANUFACTURER_ID: + case CAP11XX_REG_REVISION: + return true; + } + + return false; +} + +static const struct regmap_config cap11xx_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = CAP11XX_REG_REVISION, + .reg_defaults = cap11xx_reg_defaults, + + .num_reg_defaults = ARRAY_SIZE(cap11xx_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .volatile_reg = cap11xx_volatile_reg, +}; + +static irqreturn_t cap11xx_thread_func(int irq_num, void *data) +{ + struct cap11xx_priv *priv = data; + unsigned int status; + int ret, i; + + /* + * Deassert interrupt. This needs to be done before reading the status + * registers, which will not carry valid values otherwise. + */ + ret = regmap_update_bits(priv->regmap, CAP11XX_REG_MAIN_CONTROL, 1, 0); + if (ret < 0) + goto out; + + ret = regmap_read(priv->regmap, CAP11XX_REG_SENSOR_INPUT, &status); + if (ret < 0) + goto out; + + for (i = 0; i < priv->idev->keycodemax; i++) + input_report_key(priv->idev, priv->keycodes[i], + status & (1 << i)); + + input_sync(priv->idev); + +out: + return IRQ_HANDLED; +} + +static int cap11xx_set_sleep(struct cap11xx_priv *priv, bool sleep) +{ + return regmap_update_bits(priv->regmap, CAP11XX_REG_MAIN_CONTROL, + CAP11XX_REG_MAIN_CONTROL_DLSEEP, + sleep ? CAP11XX_REG_MAIN_CONTROL_DLSEEP : 0); +} + +static int cap11xx_input_open(struct input_dev *idev) +{ + struct cap11xx_priv *priv = input_get_drvdata(idev); + + return cap11xx_set_sleep(priv, false); +} + +static void cap11xx_input_close(struct input_dev *idev) +{ + struct cap11xx_priv *priv = input_get_drvdata(idev); + + cap11xx_set_sleep(priv, true); +} + +static int cap11xx_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + struct device *dev = &i2c_client->dev; + struct cap11xx_priv *priv; + struct device_node *node; + const struct cap11xx_hw_model *cap; + int i, error, irq, gain = 0; + unsigned int val, rev; + u32 gain32; + + if (id->driver_data >= ARRAY_SIZE(cap11xx_devices)) { + dev_err(dev, "Invalid device ID %lu\n", id->driver_data); + return -EINVAL; + } + + cap = &cap11xx_devices[id->driver_data]; + if (!cap || !cap->num_channels) { + dev_err(dev, "Invalid device configuration\n"); + return -EINVAL; + } + + priv = devm_kzalloc(dev, + sizeof(*priv) + + cap->num_channels * sizeof(priv->keycodes[0]), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regmap = devm_regmap_init_i2c(i2c_client, &cap11xx_regmap_config); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + error = regmap_read(priv->regmap, CAP11XX_REG_PRODUCT_ID, &val); + if (error) + return error; + + if (val != cap->product_id) { + dev_err(dev, "Product ID: Got 0x%02x, expected 0x%02x\n", + val, cap->product_id); + return -ENXIO; + } + + error = regmap_read(priv->regmap, CAP11XX_REG_MANUFACTURER_ID, &val); + if (error) + return error; + + if (val != CAP11XX_MANUFACTURER_ID) { + dev_err(dev, "Manufacturer ID: Got 0x%02x, expected 0x%02x\n", + val, CAP11XX_MANUFACTURER_ID); + return -ENXIO; + } + + error = regmap_read(priv->regmap, CAP11XX_REG_REVISION, &rev); + if (error < 0) + return error; + + dev_info(dev, "CAP11XX detected, revision 0x%02x\n", rev); + i2c_set_clientdata(i2c_client, priv); + node = dev->of_node; + + if (!of_property_read_u32(node, "microchip,sensor-gain", &gain32)) { + if (is_power_of_2(gain32) && gain32 <= 8) + gain = ilog2(gain32); + else + dev_err(dev, "Invalid sensor-gain value %d\n", gain32); + } + + if (of_property_read_bool(node, "microchip,irq-active-high")) { + error = regmap_update_bits(priv->regmap, CAP11XX_REG_CONFIG2, + CAP11XX_REG_CONFIG2_ALT_POL, 0); + if (error) + return error; + } + + /* Provide some useful defaults */ + for (i = 0; i < cap->num_channels; i++) + priv->keycodes[i] = KEY_A + i; + + of_property_read_u32_array(node, "linux,keycodes", + priv->keycodes, cap->num_channels); + + error = regmap_update_bits(priv->regmap, CAP11XX_REG_MAIN_CONTROL, + CAP11XX_REG_MAIN_CONTROL_GAIN_MASK, + gain << CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT); + if (error) + return error; + + /* Disable autorepeat. The Linux input system has its own handling. */ + error = regmap_write(priv->regmap, CAP11XX_REG_REPEAT_RATE, 0); + if (error) + return error; + + priv->idev = devm_input_allocate_device(dev); + if (!priv->idev) + return -ENOMEM; + + priv->idev->name = "CAP11XX capacitive touch sensor"; + priv->idev->id.bustype = BUS_I2C; + priv->idev->evbit[0] = BIT_MASK(EV_KEY); + + if (of_property_read_bool(node, "autorepeat")) + __set_bit(EV_REP, priv->idev->evbit); + + for (i = 0; i < cap->num_channels; i++) + __set_bit(priv->keycodes[i], priv->idev->keybit); + + __clear_bit(KEY_RESERVED, priv->idev->keybit); + + priv->idev->keycode = priv->keycodes; + priv->idev->keycodesize = sizeof(priv->keycodes[0]); + priv->idev->keycodemax = cap->num_channels; + + priv->idev->id.vendor = CAP11XX_MANUFACTURER_ID; + priv->idev->id.product = cap->product_id; + priv->idev->id.version = rev; + + priv->idev->open = cap11xx_input_open; + priv->idev->close = cap11xx_input_close; + + input_set_drvdata(priv->idev, priv); + + /* + * Put the device in deep sleep mode for now. + * ->open() will bring it back once the it is actually needed. + */ + cap11xx_set_sleep(priv, true); + + error = input_register_device(priv->idev); + if (error) + return error; + + irq = irq_of_parse_and_map(node, 0); + if (!irq) { + dev_err(dev, "Unable to parse or map IRQ\n"); + return -ENXIO; + } + + error = devm_request_threaded_irq(dev, irq, NULL, cap11xx_thread_func, + IRQF_ONESHOT, dev_name(dev), priv); + if (error) + return error; + + return 0; +} + +static const struct of_device_id cap11xx_dt_ids[] = { + { .compatible = "microchip,cap1106", }, + { .compatible = "microchip,cap1126", }, + { .compatible = "microchip,cap1188", }, + {} +}; +MODULE_DEVICE_TABLE(of, cap11xx_dt_ids); + +static const struct i2c_device_id cap11xx_i2c_ids[] = { + { "cap1106", CAP1106 }, + { "cap1126", CAP1126 }, + { "cap1188", CAP1188 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, cap11xx_i2c_ids); + +static struct i2c_driver cap11xx_i2c_driver = { + .driver = { + .name = "cap11xx", + .owner = THIS_MODULE, + .of_match_table = cap11xx_dt_ids, + }, + .id_table = cap11xx_i2c_ids, + .probe = cap11xx_i2c_probe, +}; + +module_i2c_driver(cap11xx_i2c_driver); + +MODULE_ALIAS("platform:cap11xx"); +MODULE_DESCRIPTION("Microchip CAP11XX driver"); +MODULE_AUTHOR("Daniel Mack <linux@zonque.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 8c98e97f8e41..f44f05b70ee0 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -29,6 +29,7 @@ #include <linux/of.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> +#include <linux/of_irq.h> #include <linux/spinlock.h> struct gpio_button_data { @@ -617,27 +618,31 @@ gpio_keys_get_devtree_pdata(struct device *dev) i = 0; for_each_child_of_node(node, pp) { - int gpio; + int gpio = -1; enum of_gpio_flags flags; - if (!of_find_property(pp, "gpios", NULL)) { - pdata->nbuttons--; - dev_warn(dev, "Found button without gpios\n"); - continue; - } + button = &pdata->buttons[i++]; - gpio = of_get_gpio_flags(pp, 0, &flags); - if (gpio < 0) { - error = gpio; - if (error != -EPROBE_DEFER) - dev_err(dev, - "Failed to get gpio flags, error: %d\n", - error); - return ERR_PTR(error); + if (!of_find_property(pp, "gpios", NULL)) { + button->irq = irq_of_parse_and_map(pp, 0); + if (button->irq == 0) { + i--; + pdata->nbuttons--; + dev_warn(dev, "Found button without gpios or irqs\n"); + continue; + } + } else { + gpio = of_get_gpio_flags(pp, 0, &flags); + if (gpio < 0) { + error = gpio; + if (error != -EPROBE_DEFER) + dev_err(dev, + "Failed to get gpio flags, error: %d\n", + error); + return ERR_PTR(error); + } } - button = &pdata->buttons[i++]; - button->gpio = gpio; button->active_low = flags & OF_GPIO_ACTIVE_LOW; diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index cb32e2b506b7..21bea52d4365 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -616,6 +616,8 @@ static ssize_t lm8323_set_disable(struct device *dev, unsigned int i; ret = kstrtouint(buf, 10, &i); + if (ret) + return ret; mutex_lock(&lm->lock); lm->kp_enabled = !i; diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c index 8b1b01361ec6..9e9786d576cb 100644 --- a/drivers/input/keyboard/lpc32xx-keys.c +++ b/drivers/input/keyboard/lpc32xx-keys.c @@ -66,7 +66,6 @@ struct lpc32xx_kscan_drv { struct input_dev *input; struct clk *clk; - struct resource *iores; void __iomem *kscan_base; unsigned int irq; @@ -188,32 +187,27 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev) return -EINVAL; } - kscandat = kzalloc(sizeof(struct lpc32xx_kscan_drv), GFP_KERNEL); - if (!kscandat) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + kscandat = devm_kzalloc(&pdev->dev, sizeof(*kscandat), + GFP_KERNEL); + if (!kscandat) return -ENOMEM; - } error = lpc32xx_parse_dt(&pdev->dev, kscandat); if (error) { dev_err(&pdev->dev, "failed to parse device tree\n"); - goto err_free_mem; + return error; } keymap_size = sizeof(kscandat->keymap[0]) * (kscandat->matrix_sz << kscandat->row_shift); - kscandat->keymap = kzalloc(keymap_size, GFP_KERNEL); - if (!kscandat->keymap) { - dev_err(&pdev->dev, "could not allocate memory for keymap\n"); - error = -ENOMEM; - goto err_free_mem; - } + kscandat->keymap = devm_kzalloc(&pdev->dev, keymap_size, GFP_KERNEL); + if (!kscandat->keymap) + return -ENOMEM; - kscandat->input = input = input_allocate_device(); + kscandat->input = input = devm_input_allocate_device(&pdev->dev); if (!input) { dev_err(&pdev->dev, "failed to allocate input device\n"); - error = -ENOMEM; - goto err_free_keymap; + return -ENOMEM; } /* Setup key input */ @@ -234,39 +228,26 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev) kscandat->keymap, kscandat->input); if (error) { dev_err(&pdev->dev, "failed to build keymap\n"); - goto err_free_input; + return error; } input_set_drvdata(kscandat->input, kscandat); - kscandat->iores = request_mem_region(res->start, resource_size(res), - pdev->name); - if (!kscandat->iores) { - dev_err(&pdev->dev, "failed to request I/O memory\n"); - error = -EBUSY; - goto err_free_input; - } - - kscandat->kscan_base = ioremap(kscandat->iores->start, - resource_size(kscandat->iores)); - if (!kscandat->kscan_base) { - dev_err(&pdev->dev, "failed to remap I/O memory\n"); - error = -EBUSY; - goto err_release_memregion; - } + kscandat->kscan_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(kscandat->kscan_base)) + return PTR_ERR(kscandat->kscan_base); /* Get the key scanner clock */ - kscandat->clk = clk_get(&pdev->dev, NULL); + kscandat->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(kscandat->clk)) { dev_err(&pdev->dev, "failed to get clock\n"); - error = PTR_ERR(kscandat->clk); - goto err_unmap; + return PTR_ERR(kscandat->clk); } /* Configure the key scanner */ error = clk_prepare_enable(kscandat->clk); if (error) - goto err_clk_put; + return error; writel(kscandat->deb_clks, LPC32XX_KS_DEB(kscandat->kscan_base)); writel(kscandat->scan_delay, LPC32XX_KS_SCAN_CTL(kscandat->kscan_base)); @@ -277,52 +258,20 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev) writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base)); clk_disable_unprepare(kscandat->clk); - error = request_irq(irq, lpc32xx_kscan_irq, 0, pdev->name, kscandat); + error = devm_request_irq(&pdev->dev, irq, lpc32xx_kscan_irq, 0, + pdev->name, kscandat); if (error) { dev_err(&pdev->dev, "failed to request irq\n"); - goto err_clk_put; + return error; } error = input_register_device(kscandat->input); if (error) { dev_err(&pdev->dev, "failed to register input device\n"); - goto err_free_irq; + return error; } platform_set_drvdata(pdev, kscandat); - return 0; - -err_free_irq: - free_irq(irq, kscandat); -err_clk_put: - clk_put(kscandat->clk); -err_unmap: - iounmap(kscandat->kscan_base); -err_release_memregion: - release_mem_region(kscandat->iores->start, - resource_size(kscandat->iores)); -err_free_input: - input_free_device(kscandat->input); -err_free_keymap: - kfree(kscandat->keymap); -err_free_mem: - kfree(kscandat); - - return error; -} - -static int lpc32xx_kscan_remove(struct platform_device *pdev) -{ - struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev); - - free_irq(platform_get_irq(pdev, 0), kscandat); - clk_put(kscandat->clk); - iounmap(kscandat->kscan_base); - release_mem_region(kscandat->iores->start, - resource_size(kscandat->iores)); - input_unregister_device(kscandat->input); - kfree(kscandat->keymap); - kfree(kscandat); return 0; } @@ -378,7 +327,6 @@ MODULE_DEVICE_TABLE(of, lpc32xx_kscan_match); static struct platform_driver lpc32xx_kscan_driver = { .probe = lpc32xx_kscan_probe, - .remove = lpc32xx_kscan_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index 009c82256e89..3aa2ec45bcab 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -214,13 +214,14 @@ static int mpr_touchkey_probe(struct i2c_client *client, 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 = devm_kzalloc(&client->dev, sizeof(*mpr121), + GFP_KERNEL); + if (!mpr121) + return -ENOMEM; + + input_dev = devm_input_allocate_device(&client->dev); + if (!input_dev) + return -ENOMEM; mpr121->client = client; mpr121->input_dev = input_dev; @@ -243,44 +244,26 @@ static int mpr_touchkey_probe(struct i2c_client *client, error = mpr121_phys_init(pdata, mpr121, client); if (error) { dev_err(&client->dev, "Failed to init register\n"); - goto err_free_mem; + return error; } - error = request_threaded_irq(client->irq, NULL, + error = devm_request_threaded_irq(&client->dev, client->irq, NULL, mpr_touchkey_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->dev.driver->name, mpr121); if (error) { dev_err(&client->dev, "Failed to register interrupt\n"); - goto err_free_mem; + return error; } error = input_register_device(input_dev); if (error) - goto err_free_irq; + return error; 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 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 @@ -327,7 +310,6 @@ static struct i2c_driver mpr_touchkey_driver = { }, .id_table = mpr121_id, .probe = mpr_touchkey_probe, - .remove = mpr_touchkey_remove, }; module_i2c_driver(mpr_touchkey_driver); diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index a15063bea700..e08fc0ae913d 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -741,37 +741,27 @@ static int pxa27x_keypad_probe(struct platform_device *pdev) return -ENXIO; } - keypad = kzalloc(sizeof(struct pxa27x_keypad), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!keypad || !input_dev) { - dev_err(&pdev->dev, "failed to allocate memory\n"); - error = -ENOMEM; - goto failed_free; - } + keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), + GFP_KERNEL); + if (!keypad) + return -ENOMEM; + + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) + return -ENOMEM; keypad->pdata = pdata; keypad->input_dev = input_dev; keypad->irq = irq; - res = request_mem_region(res->start, resource_size(res), pdev->name); - if (res == NULL) { - dev_err(&pdev->dev, "failed to request I/O memory\n"); - error = -EBUSY; - goto failed_free; - } - - keypad->mmio_base = ioremap(res->start, resource_size(res)); - if (keypad->mmio_base == NULL) { - dev_err(&pdev->dev, "failed to remap I/O memory\n"); - error = -ENXIO; - goto failed_free_mem; - } + keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(keypad->mmio_base)) + return PTR_ERR(keypad->mmio_base); - keypad->clk = clk_get(&pdev->dev, NULL); + keypad->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(keypad->clk)) { dev_err(&pdev->dev, "failed to get keypad clock\n"); - error = PTR_ERR(keypad->clk); - goto failed_free_io; + return PTR_ERR(keypad->clk); } input_dev->name = pdev->name; @@ -802,7 +792,7 @@ static int pxa27x_keypad_probe(struct platform_device *pdev) } if (error) { dev_err(&pdev->dev, "failed to build keycode\n"); - goto failed_put_clk; + return error; } keypad->row_shift = get_count_order(pdata->matrix_key_cols); @@ -812,61 +802,26 @@ static int pxa27x_keypad_probe(struct platform_device *pdev) input_dev->evbit[0] |= BIT_MASK(EV_REL); } - error = request_irq(irq, pxa27x_keypad_irq_handler, 0, - pdev->name, keypad); + error = devm_request_irq(&pdev->dev, irq, pxa27x_keypad_irq_handler, + 0, pdev->name, keypad); if (error) { dev_err(&pdev->dev, "failed to request IRQ\n"); - goto failed_put_clk; + return error; } /* Register the input device */ error = input_register_device(input_dev); if (error) { dev_err(&pdev->dev, "failed to register input device\n"); - goto failed_free_irq; + return error; } platform_set_drvdata(pdev, keypad); device_init_wakeup(&pdev->dev, 1); return 0; - -failed_free_irq: - free_irq(irq, keypad); -failed_put_clk: - clk_put(keypad->clk); -failed_free_io: - iounmap(keypad->mmio_base); -failed_free_mem: - release_mem_region(res->start, resource_size(res)); -failed_free: - input_free_device(input_dev); - kfree(keypad); - return error; } -static int pxa27x_keypad_remove(struct platform_device *pdev) -{ - struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); - struct resource *res; - - free_irq(keypad->irq, keypad); - clk_put(keypad->clk); - - input_unregister_device(keypad->input_dev); - iounmap(keypad->mmio_base); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - kfree(keypad); - - return 0; -} - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:pxa27x-keypad"); - #ifdef CONFIG_OF static const struct of_device_id pxa27x_keypad_dt_match[] = { { .compatible = "marvell,pxa27x-keypad" }, @@ -877,7 +832,6 @@ MODULE_DEVICE_TABLE(of, pxa27x_keypad_dt_match); static struct platform_driver pxa27x_keypad_driver = { .probe = pxa27x_keypad_probe, - .remove = pxa27x_keypad_remove, .driver = { .name = "pxa27x-keypad", .of_match_table = of_match_ptr(pxa27x_keypad_dt_match), @@ -889,3 +843,5 @@ module_platform_driver(pxa27x_keypad_driver); MODULE_DESCRIPTION("PXA27x Keypad Controller Driver"); MODULE_LICENSE("GPL"); +/* work with hotplug and coldplug */ +MODULE_ALIAS("platform:pxa27x-keypad"); |