diff options
author | Jiri Kosina <jkosina@suse.cz> | 2014-11-20 16:42:02 +0300 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2014-11-20 16:42:02 +0300 |
commit | a02001086bbfb4da35d1228bebc2f1b442db455f (patch) | |
tree | 62ab47936cef06fd08657ca5b6cd1df98c19be57 /drivers/input/keyboard | |
parent | eff264efeeb0898408e8c9df72d8a32621035bed (diff) | |
parent | fc14f9c1272f62c3e8d01300f52467c0d9af50f9 (diff) | |
download | linux-a02001086bbfb4da35d1228bebc2f1b442db455f.tar.xz |
Merge Linus' tree to be be to apply submitted patches to newer code than
current trivial.git base
Diffstat (limited to 'drivers/input/keyboard')
-rw-r--r-- | drivers/input/keyboard/Kconfig | 10 | ||||
-rw-r--r-- | drivers/input/keyboard/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/keyboard/adp5588-keys.c | 5 | ||||
-rw-r--r-- | drivers/input/keyboard/adp5589-keys.c | 4 | ||||
-rw-r--r-- | drivers/input/keyboard/atkbd.c | 8 | ||||
-rw-r--r-- | drivers/input/keyboard/cap1106.c | 341 | ||||
-rw-r--r-- | drivers/input/keyboard/cros_ec_keyb.c | 165 | ||||
-rw-r--r-- | drivers/input/keyboard/imx_keypad.c | 6 | ||||
-rw-r--r-- | drivers/input/keyboard/lm8323.c | 22 | ||||
-rw-r--r-- | drivers/input/keyboard/matrix_keypad.c | 9 | ||||
-rw-r--r-- | drivers/input/keyboard/max7359_keypad.c | 45 | ||||
-rw-r--r-- | drivers/input/keyboard/opencores-kbd.c | 72 | ||||
-rw-r--r-- | drivers/input/keyboard/stmpe-keypad.c | 2 |
13 files changed, 503 insertions, 187 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index f7e79b481349..a3958c63d7d5 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -665,4 +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" + depends on OF && I2C + select REGMAP_I2C + help + Say Y here to enable the CAP1106 touch sensor driver. + + To compile this driver as a module, choose M here: the + module will be called cap1106. + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 7504ae19049d..0a3345634d79 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -11,6 +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_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/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 5ef7fcf0e250..21a62d0fa764 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -251,9 +251,7 @@ static void adp5588_gpio_remove(struct adp5588_kpad *kpad) dev_warn(dev, "teardown failed %d\n", error); } - error = gpiochip_remove(&kpad->gc); - if (error) - dev_warn(dev, "gpiochip_remove failed %d\n", error); + gpiochip_remove(&kpad->gc); } #else static inline int adp5588_gpio_add(struct adp5588_kpad *kpad) @@ -589,6 +587,7 @@ static int adp5588_probe(struct i2c_client *client, err_free_irq: free_irq(client->irq, kpad); + cancel_delayed_work_sync(&kpad->work); err_unreg_dev: input_unregister_device(input); input = NULL; diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 6329549bf6ad..a45267729dfc 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -567,9 +567,7 @@ static void adp5589_gpio_remove(struct adp5589_kpad *kpad) dev_warn(dev, "teardown failed %d\n", error); } - error = gpiochip_remove(&kpad->gc); - if (error) - dev_warn(dev, "gpiochip_remove failed %d\n", error); + gpiochip_remove(&kpad->gc); } #else static inline int adp5589_gpio_add(struct adp5589_kpad *kpad) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 2dd1d0dd4f7d..6f5d79569136 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -1791,14 +1791,6 @@ static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = { { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), - DMI_MATCH(DMI_PRODUCT_NAME, "LW25-B7HV"), - }, - .callback = atkbd_deactivate_fixup, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), - DMI_MATCH(DMI_PRODUCT_NAME, "P1-J273B"), }, .callback = atkbd_deactivate_fixup, }, diff --git a/drivers/input/keyboard/cap1106.c b/drivers/input/keyboard/cap1106.c new file mode 100644 index 000000000000..d70b65a14ced --- /dev/null +++ b/drivers/input/keyboard/cap1106.c @@ -0,0 +1,341 @@ +/* + * 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/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index 408379669d3c..ffa989f2c785 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -22,10 +22,11 @@ */ #include <linux/module.h> +#include <linux/bitops.h> #include <linux/i2c.h> #include <linux/input.h> +#include <linux/interrupt.h> #include <linux/kernel.h> -#include <linux/notifier.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/input/matrix_keypad.h> @@ -38,11 +39,11 @@ * @row_shift: log2 or number of rows, rounded up * @keymap_data: Matrix keymap data used to convert to keyscan values * @ghost_filter: true to enable the matrix key-ghosting filter + * @valid_keys: bitmap of existing keys for each matrix column * @old_kb_state: bitmap of keys pressed last scan * @dev: Device pointer * @idev: Input device * @ec: Top level ChromeOS device to use to talk to EC - * @event_notifier: interrupt event notifier for transport devices */ struct cros_ec_keyb { unsigned int rows; @@ -50,48 +51,24 @@ struct cros_ec_keyb { int row_shift; const struct matrix_keymap_data *keymap_data; bool ghost_filter; + uint8_t *valid_keys; uint8_t *old_kb_state; struct device *dev; struct input_dev *idev; struct cros_ec_device *ec; - struct notifier_block notifier; }; -static bool cros_ec_keyb_row_has_ghosting(struct cros_ec_keyb *ckdev, - uint8_t *buf, int row) -{ - int pressed_in_row = 0; - int row_has_teeth = 0; - int col, mask; - - mask = 1 << row; - for (col = 0; col < ckdev->cols; col++) { - if (buf[col] & mask) { - pressed_in_row++; - row_has_teeth |= buf[col] & ~mask; - if (pressed_in_row > 1 && row_has_teeth) { - /* ghosting */ - dev_dbg(ckdev->dev, - "ghost found at: r%d c%d, pressed %d, teeth 0x%x\n", - row, col, pressed_in_row, - row_has_teeth); - return true; - } - } - } - - return false; -} - /* * Returns true when there is at least one combination of pressed keys that * results in ghosting. */ static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf) { - int row; + int col1, col2, buf1, buf2; + struct device *dev = ckdev->dev; + uint8_t *valid_keys = ckdev->valid_keys; /* * Ghosting happens if for any pressed key X there are other keys @@ -105,27 +82,23 @@ static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf) * * In this case only X, Y, and Z are pressed, but g appears to be * pressed too (see Wikipedia). - * - * We can detect ghosting in a single pass (*) over the keyboard state - * by maintaining two arrays. pressed_in_row counts how many pressed - * keys we have found in a row. row_has_teeth is true if any of the - * pressed keys for this row has other pressed keys in its column. If - * at any point of the scan we find that a row has multiple pressed - * keys, and at least one of them is at the intersection with a column - * with multiple pressed keys, we're sure there is ghosting. - * Conversely, if there is ghosting, we will detect such situation for - * at least one key during the pass. - * - * (*) This looks linear in the number of keys, but it's not. We can - * cheat because the number of rows is small. */ - for (row = 0; row < ckdev->rows; row++) - if (cros_ec_keyb_row_has_ghosting(ckdev, buf, row)) - return true; + for (col1 = 0; col1 < ckdev->cols; col1++) { + buf1 = buf[col1] & valid_keys[col1]; + for (col2 = col1 + 1; col2 < ckdev->cols; col2++) { + buf2 = buf[col2] & valid_keys[col2]; + if (hweight8(buf1 & buf2) > 1) { + dev_dbg(dev, "ghost found at: B[%02d]:0x%02x & B[%02d]:0x%02x", + col1, buf1, col2, buf2); + return true; + } + } + } return false; } + /* * Compares the new keyboard state to the old one and produces key * press/release events accordingly. The keyboard state is 13 bytes (one byte @@ -173,41 +146,79 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, input_sync(ckdev->idev); } -static int cros_ec_keyb_open(struct input_dev *dev) +static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state) { - struct cros_ec_keyb *ckdev = input_get_drvdata(dev); + struct cros_ec_command msg = { + .version = 0, + .command = EC_CMD_MKBP_STATE, + .outdata = NULL, + .outsize = 0, + .indata = kb_state, + .insize = ckdev->cols, + }; + + return cros_ec_cmd_xfer(ckdev->ec, &msg); +} + +static irqreturn_t cros_ec_keyb_irq(int irq, void *data) +{ + struct cros_ec_keyb *ckdev = data; + struct cros_ec_device *ec = ckdev->ec; + int ret; + uint8_t kb_state[ckdev->cols]; + + if (device_may_wakeup(ec->dev)) + pm_wakeup_event(ec->dev, 0); + + ret = cros_ec_keyb_get_state(ckdev, kb_state); + if (ret >= 0) + cros_ec_keyb_process(ckdev, kb_state, ret); + else + dev_err(ec->dev, "failed to get keyboard state: %d\n", ret); - return blocking_notifier_chain_register(&ckdev->ec->event_notifier, - &ckdev->notifier); + return IRQ_HANDLED; } -static void cros_ec_keyb_close(struct input_dev *dev) +static int cros_ec_keyb_open(struct input_dev *dev) { struct cros_ec_keyb *ckdev = input_get_drvdata(dev); + struct cros_ec_device *ec = ckdev->ec; - blocking_notifier_chain_unregister(&ckdev->ec->event_notifier, - &ckdev->notifier); + return request_threaded_irq(ec->irq, NULL, cros_ec_keyb_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "cros_ec_keyb", ckdev); } -static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state) +static void cros_ec_keyb_close(struct input_dev *dev) { - return ckdev->ec->command_recv(ckdev->ec, EC_CMD_MKBP_STATE, - kb_state, ckdev->cols); + struct cros_ec_keyb *ckdev = input_get_drvdata(dev); + struct cros_ec_device *ec = ckdev->ec; + + free_irq(ec->irq, ckdev); } -static int cros_ec_keyb_work(struct notifier_block *nb, - unsigned long state, void *_notify) +/* + * Walks keycodes flipping bit in buffer COLUMNS deep where bit is ROW. Used by + * ghosting logic to ignore NULL or virtual keys. + */ +static void cros_ec_keyb_compute_valid_keys(struct cros_ec_keyb *ckdev) { - int ret; - struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb, - notifier); - uint8_t kb_state[ckdev->cols]; + int row, col; + int row_shift = ckdev->row_shift; + unsigned short *keymap = ckdev->idev->keycode; + unsigned short code; - ret = cros_ec_keyb_get_state(ckdev, kb_state); - if (ret >= 0) - cros_ec_keyb_process(ckdev, kb_state, ret); + BUG_ON(ckdev->idev->keycodesize != sizeof(*keymap)); - return NOTIFY_DONE; + for (col = 0; col < ckdev->cols; col++) { + for (row = 0; row < ckdev->rows; row++) { + code = keymap[MATRIX_SCAN_CODE(row, col, row_shift)]; + if (code && (code != KEY_BATTERY)) + ckdev->valid_keys[col] |= 1 << row; + } + dev_dbg(ckdev->dev, "valid_keys[%02d] = 0x%02x\n", + col, ckdev->valid_keys[col]); + } } static int cros_ec_keyb_probe(struct platform_device *pdev) @@ -230,6 +241,11 @@ static int cros_ec_keyb_probe(struct platform_device *pdev) &ckdev->cols); if (err) return err; + + ckdev->valid_keys = devm_kzalloc(&pdev->dev, ckdev->cols, GFP_KERNEL); + if (!ckdev->valid_keys) + return -ENOMEM; + ckdev->old_kb_state = devm_kzalloc(&pdev->dev, ckdev->cols, GFP_KERNEL); if (!ckdev->old_kb_state) return -ENOMEM; @@ -238,8 +254,12 @@ static int cros_ec_keyb_probe(struct platform_device *pdev) if (!idev) return -ENOMEM; + if (!ec->irq) { + dev_err(dev, "no EC IRQ specified\n"); + return -EINVAL; + } + ckdev->ec = ec; - ckdev->notifier.notifier_call = cros_ec_keyb_work; ckdev->dev = dev; dev_set_drvdata(&pdev->dev, ckdev); @@ -269,6 +289,8 @@ static int cros_ec_keyb_probe(struct platform_device *pdev) input_set_capability(idev, EV_MSC, MSC_SCAN); input_set_drvdata(idev, ckdev); ckdev->idev = idev; + cros_ec_keyb_compute_valid_keys(ckdev); + err = input_register_device(ckdev->idev); if (err) { dev_err(dev, "cannot register input device\n"); @@ -326,10 +348,19 @@ static int cros_ec_keyb_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume); +#ifdef CONFIG_OF +static const struct of_device_id cros_ec_keyb_of_match[] = { + { .compatible = "google,cros-ec-keyb" }, + {}, +}; +MODULE_DEVICE_TABLE(of, cros_ec_keyb_of_match); +#endif + static struct platform_driver cros_ec_keyb_driver = { .probe = cros_ec_keyb_probe, .driver = { .name = "cros-ec-keyb", + .of_match_table = of_match_ptr(cros_ec_keyb_of_match), .pm = &cros_ec_keyb_pm_ops, }, }; diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index 8280cb16260b..20a99c368d16 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -531,8 +531,7 @@ static int imx_keypad_probe(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int imx_kbd_suspend(struct device *dev) +static int __maybe_unused imx_kbd_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct imx_keypad *kbd = platform_get_drvdata(pdev); @@ -552,7 +551,7 @@ static int imx_kbd_suspend(struct device *dev) return 0; } -static int imx_kbd_resume(struct device *dev) +static int __maybe_unused imx_kbd_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct imx_keypad *kbd = platform_get_drvdata(pdev); @@ -575,7 +574,6 @@ err_clk: return ret; } -#endif static SIMPLE_DEV_PM_OPS(imx_kbd_pm_ops, imx_kbd_suspend, imx_kbd_resume); diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 0b42118cbf8f..cb32e2b506b7 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -558,6 +558,12 @@ static ssize_t lm8323_pwm_store_time(struct device *dev, } static DEVICE_ATTR(time, 0644, lm8323_pwm_show_time, lm8323_pwm_store_time); +static struct attribute *lm8323_pwm_attrs[] = { + &dev_attr_time.attr, + NULL +}; +ATTRIBUTE_GROUPS(lm8323_pwm); + static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev, const char *name) { @@ -580,16 +586,11 @@ static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev, if (name) { pwm->cdev.name = name; pwm->cdev.brightness_set = lm8323_pwm_set_brightness; + pwm->cdev.groups = lm8323_pwm_groups; if (led_classdev_register(dev, &pwm->cdev) < 0) { dev_err(dev, "couldn't register PWM %d\n", id); return -1; } - if (device_create_file(pwm->cdev.dev, - &dev_attr_time) < 0) { - dev_err(dev, "couldn't register time attribute\n"); - led_classdev_unregister(&pwm->cdev); - return -1; - } pwm->enabled = true; } @@ -753,11 +754,8 @@ fail3: device_remove_file(&client->dev, &dev_attr_disable_kp); fail2: while (--pwm >= 0) - if (lm->pwm[pwm].enabled) { - device_remove_file(lm->pwm[pwm].cdev.dev, - &dev_attr_time); + if (lm->pwm[pwm].enabled) led_classdev_unregister(&lm->pwm[pwm].cdev); - } fail1: input_free_device(idev); kfree(lm); @@ -777,10 +775,8 @@ static int lm8323_remove(struct i2c_client *client) device_remove_file(&lm->client->dev, &dev_attr_disable_kp); for (i = 0; i < 3; i++) - if (lm->pwm[i].enabled) { - device_remove_file(lm->pwm[i].cdev.dev, &dev_attr_time); + if (lm->pwm[i].enabled) led_classdev_unregister(&lm->pwm[i].cdev); - } kfree(lm); diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 8d2e19e81e1e..e651fa692afe 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -332,23 +332,24 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev, } if (pdata->clustered_irq > 0) { - err = request_irq(pdata->clustered_irq, + err = request_any_context_irq(pdata->clustered_irq, matrix_keypad_interrupt, pdata->clustered_irq_flags, "matrix-keypad", keypad); - if (err) { + if (err < 0) { dev_err(&pdev->dev, "Unable to acquire clustered interrupt\n"); goto err_free_rows; } } else { for (i = 0; i < pdata->num_row_gpios; i++) { - err = request_irq(gpio_to_irq(pdata->row_gpios[i]), + err = request_any_context_irq( + gpio_to_irq(pdata->row_gpios[i]), matrix_keypad_interrupt, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "matrix-keypad", keypad); - if (err) { + if (err < 0) { dev_err(&pdev->dev, "Unable to acquire interrupt for GPIO line %i\n", pdata->row_gpios[i]); diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c index 430b54539720..faa6da53eba8 100644 --- a/drivers/input/keyboard/max7359_keypad.c +++ b/drivers/input/keyboard/max7359_keypad.c @@ -203,12 +203,17 @@ static int max7359_probe(struct i2c_client *client, dev_dbg(&client->dev, "keys FIFO is 0x%02x\n", ret); - keypad = kzalloc(sizeof(struct max7359_keypad), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!keypad || !input_dev) { + keypad = devm_kzalloc(&client->dev, sizeof(struct max7359_keypad), + GFP_KERNEL); + if (!keypad) { dev_err(&client->dev, "failed to allocate memory\n"); - error = -ENOMEM; - goto failed_free_mem; + return -ENOMEM; + } + + input_dev = devm_input_allocate_device(&client->dev); + if (!input_dev) { + dev_err(&client->dev, "failed to allocate input device\n"); + return -ENOMEM; } keypad->client = client; @@ -230,19 +235,20 @@ static int max7359_probe(struct i2c_client *client, max7359_build_keycode(keypad, keymap_data); - error = request_threaded_irq(client->irq, NULL, max7359_interrupt, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - client->name, keypad); + error = devm_request_threaded_irq(&client->dev, client->irq, NULL, + max7359_interrupt, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + client->name, keypad); if (error) { dev_err(&client->dev, "failed to register interrupt\n"); - goto failed_free_mem; + return error; } /* Register the input device */ error = input_register_device(input_dev); if (error) { dev_err(&client->dev, "failed to register input device\n"); - goto failed_free_irq; + return error; } /* Initialize MAX7359 */ @@ -252,24 +258,6 @@ static int max7359_probe(struct i2c_client *client, device_init_wakeup(&client->dev, 1); return 0; - -failed_free_irq: - free_irq(client->irq, keypad); -failed_free_mem: - input_free_device(input_dev); - kfree(keypad); - return error; -} - -static int max7359_remove(struct i2c_client *client) -{ - struct max7359_keypad *keypad = i2c_get_clientdata(client); - - free_irq(client->irq, keypad); - input_unregister_device(keypad->input_dev); - kfree(keypad); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -313,7 +301,6 @@ static struct i2c_driver max7359_i2c_driver = { .pm = &max7359_pm, }, .probe = max7359_probe, - .remove = max7359_remove, .id_table = max7359_ids, }; diff --git a/drivers/input/keyboard/opencores-kbd.c b/drivers/input/keyboard/opencores-kbd.c index 7b9b44158ad1..f8502bb29176 100644 --- a/drivers/input/keyboard/opencores-kbd.c +++ b/drivers/input/keyboard/opencores-kbd.c @@ -18,7 +18,6 @@ struct opencores_kbd { struct input_dev *input; - struct resource *addr_res; void __iomem *addr; int irq; unsigned short keycodes[128]; @@ -56,35 +55,25 @@ static int opencores_kbd_probe(struct platform_device *pdev) return -EINVAL; } - opencores_kbd = kzalloc(sizeof(*opencores_kbd), GFP_KERNEL); - input = input_allocate_device(); - if (!opencores_kbd || !input) { - dev_err(&pdev->dev, "failed to allocate device structures\n"); - error = -ENOMEM; - goto err_free_mem; - } - - opencores_kbd->addr_res = res; - res = request_mem_region(res->start, resource_size(res), pdev->name); - if (!res) { - dev_err(&pdev->dev, "failed to request I/O memory\n"); - error = -EBUSY; - goto err_free_mem; - } + opencores_kbd = devm_kzalloc(&pdev->dev, sizeof(*opencores_kbd), + GFP_KERNEL); + if (!opencores_kbd) + return -ENOMEM; - opencores_kbd->addr = ioremap(res->start, resource_size(res)); - if (!opencores_kbd->addr) { - dev_err(&pdev->dev, "failed to remap I/O memory\n"); - error = -ENXIO; - goto err_rel_mem; + input = devm_input_allocate_device(&pdev->dev); + if (!input) { + dev_err(&pdev->dev, "failed to allocate input device\n"); + return -ENOMEM; } opencores_kbd->input = input; - opencores_kbd->irq = irq; + + opencores_kbd->addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(opencores_kbd->addr)) + return PTR_ERR(opencores_kbd->addr); input->name = pdev->name; input->phys = "opencores-kbd/input0"; - input->dev.parent = &pdev->dev; input_set_drvdata(input, opencores_kbd); @@ -109,54 +98,27 @@ static int opencores_kbd_probe(struct platform_device *pdev) } __clear_bit(KEY_RESERVED, input->keybit); - error = request_irq(irq, &opencores_kbd_isr, - IRQF_TRIGGER_RISING, pdev->name, opencores_kbd); + error = devm_request_irq(&pdev->dev, irq, &opencores_kbd_isr, + IRQF_TRIGGER_RISING, + pdev->name, opencores_kbd); if (error) { dev_err(&pdev->dev, "unable to claim irq %d\n", irq); - goto err_unmap_mem; + return error; } error = input_register_device(input); if (error) { dev_err(&pdev->dev, "unable to register input device\n"); - goto err_free_irq; + return error; } platform_set_drvdata(pdev, opencores_kbd); return 0; - - err_free_irq: - free_irq(irq, opencores_kbd); - err_unmap_mem: - iounmap(opencores_kbd->addr); - err_rel_mem: - release_mem_region(res->start, resource_size(res)); - err_free_mem: - input_free_device(input); - kfree(opencores_kbd); - - return error; -} - -static int opencores_kbd_remove(struct platform_device *pdev) -{ - struct opencores_kbd *opencores_kbd = platform_get_drvdata(pdev); - - free_irq(opencores_kbd->irq, opencores_kbd); - - iounmap(opencores_kbd->addr); - release_mem_region(opencores_kbd->addr_res->start, - resource_size(opencores_kbd->addr_res)); - input_unregister_device(opencores_kbd->input); - kfree(opencores_kbd); - - return 0; } static struct platform_driver opencores_kbd_device_driver = { .probe = opencores_kbd_probe, - .remove = opencores_kbd_remove, .driver = { .name = "opencores-kbd", }, diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c index c6727dda68f2..ef5e67fb567e 100644 --- a/drivers/input/keyboard/stmpe-keypad.c +++ b/drivers/input/keyboard/stmpe-keypad.c @@ -86,7 +86,7 @@ static const struct stmpe_keypad_variant stmpe_keypad_variants[] = { .max_cols = 8, .max_rows = 12, .col_gpios = 0x0000ff, /* GPIO 0 - 7*/ - .row_gpios = 0x1fef00, /* GPIO 8-14, 16-20 */ + .row_gpios = 0x1f7f00, /* GPIO 8-14, 16-20 */ }, [STMPE2403] = { .auto_increment = true, |