diff options
Diffstat (limited to 'drivers/input')
58 files changed, 1603 insertions, 841 deletions
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index f3135ae22df4..abd18f31b24f 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -22,7 +22,6 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/mm.h> -#include <linux/miscdevice.h> #include <linux/module.h> #include <linux/poll.h> #include <linux/init.h> diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 83af17ad0f1f..c7d5b2b643d1 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -134,6 +134,7 @@ static const struct xpad_device { { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE }, { 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", 0, XTYPE_XBOXONE }, + { 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, @@ -1044,9 +1045,9 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect packet->data[7] = 0x00; packet->data[8] = strong / 512; /* left actuator */ packet->data[9] = weak / 512; /* right actuator */ - packet->data[10] = 0xFF; - packet->data[11] = 0x00; - packet->data[12] = 0x00; + packet->data[10] = 0xFF; /* on period */ + packet->data[11] = 0x00; /* off period */ + packet->data[12] = 0xFF; /* repeat count */ packet->len = 13; packet->pending = true; break; @@ -1376,6 +1377,12 @@ static int xpad_init_input(struct usb_xpad *xpad) input_dev->name = xpad->name; input_dev->phys = xpad->phys; usb_to_input_id(xpad->udev, &input_dev->id); + + if (xpad->xtype == XTYPE_XBOX360W) { + /* x360w controllers and the receiver have different ids */ + input_dev->id.product = 0x02a1; + } + input_dev->dev.parent = &xpad->intf->dev; input_set_drvdata(input_dev, xpad); diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 509608c95994..cbd75cf44739 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -12,6 +12,21 @@ menuconfig INPUT_KEYBOARD if INPUT_KEYBOARD +config KEYBOARD_ADC + tristate "ADC Ladder Buttons" + depends on IIO + select INPUT_POLLDEV + help + This driver implements support for buttons connected + to an ADC using a resistor ladder. + + Say Y here if your device has such buttons connected to an ADC. Your + board-specific setup logic must also provide a configuration data + for mapping voltages to buttons. + + To compile this driver as a module, choose M here: the + module will be called adc_keys. + config KEYBOARD_ADP5520 tristate "Keypad Support for ADP5520 PMIC" depends on PMIC_ADP5520 diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 1d416ddf84e4..d9f4cfcf3410 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -4,6 +4,7 @@ # Each configuration option enables a list of files. +obj-$(CONFIG_KEYBOARD_ADC) += adc-keys.o obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c new file mode 100644 index 000000000000..f8cf2ccacefd --- /dev/null +++ b/drivers/input/keyboard/adc-keys.c @@ -0,0 +1,210 @@ +/* + * Input driver for resistor ladder connected on ADC + * + * Copyright (c) 2016 Alexandre Belloni + * + * 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/err.h> +#include <linux/iio/consumer.h> +#include <linux/iio/types.h> +#include <linux/input.h> +#include <linux/input-polldev.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/slab.h> + +struct adc_keys_button { + u32 voltage; + u32 keycode; +}; + +struct adc_keys_state { + struct iio_channel *channel; + u32 num_keys; + u32 last_key; + u32 keyup_voltage; + const struct adc_keys_button *map; +}; + +static void adc_keys_poll(struct input_polled_dev *dev) +{ + struct adc_keys_state *st = dev->private; + int i, value, ret; + u32 diff, closest = 0xffffffff; + int keycode = 0; + + ret = iio_read_channel_processed(st->channel, &value); + if (unlikely(ret < 0)) { + /* Forcibly release key if any was pressed */ + value = st->keyup_voltage; + } else { + for (i = 0; i < st->num_keys; i++) { + diff = abs(st->map[i].voltage - value); + if (diff < closest) { + closest = diff; + keycode = st->map[i].keycode; + } + } + } + + if (abs(st->keyup_voltage - value) < closest) + keycode = 0; + + if (st->last_key && st->last_key != keycode) + input_report_key(dev->input, st->last_key, 0); + + if (keycode) + input_report_key(dev->input, keycode, 1); + + input_sync(dev->input); + st->last_key = keycode; +} + +static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st) +{ + struct adc_keys_button *map; + struct fwnode_handle *child; + int i; + + st->num_keys = device_get_child_node_count(dev); + if (st->num_keys == 0) { + dev_err(dev, "keymap is missing\n"); + return -EINVAL; + } + + map = devm_kmalloc_array(dev, st->num_keys, sizeof(*map), GFP_KERNEL); + if (!map) + return -ENOMEM; + + i = 0; + device_for_each_child_node(dev, child) { + if (fwnode_property_read_u32(child, "press-threshold-microvolt", + &map[i].voltage)) { + dev_err(dev, "Key with invalid or missing voltage\n"); + fwnode_handle_put(child); + return -EINVAL; + } + map[i].voltage /= 1000; + + if (fwnode_property_read_u32(child, "linux,code", + &map[i].keycode)) { + dev_err(dev, "Key with invalid or missing linux,code\n"); + fwnode_handle_put(child); + return -EINVAL; + } + + i++; + } + + st->map = map; + return 0; +} + +static int adc_keys_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct adc_keys_state *st; + struct input_polled_dev *poll_dev; + struct input_dev *input; + enum iio_chan_type type; + int i, value; + int error; + + st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); + if (!st) + return -ENOMEM; + + st->channel = devm_iio_channel_get(dev, "buttons"); + if (IS_ERR(st->channel)) + return PTR_ERR(st->channel); + + if (!st->channel->indio_dev) + return -ENXIO; + + error = iio_get_channel_type(st->channel, &type); + if (error < 0) + return error; + + if (type != IIO_VOLTAGE) { + dev_err(dev, "Incompatible channel type %d\n", type); + return -EINVAL; + } + + if (device_property_read_u32(dev, "keyup-threshold-microvolt", + &st->keyup_voltage)) { + dev_err(dev, "Invalid or missing keyup voltage\n"); + return -EINVAL; + } + st->keyup_voltage /= 1000; + + error = adc_keys_load_keymap(dev, st); + if (error) + return error; + + platform_set_drvdata(pdev, st); + + poll_dev = devm_input_allocate_polled_device(dev); + if (!poll_dev) { + dev_err(dev, "failed to allocate input device\n"); + return -ENOMEM; + } + + if (!device_property_read_u32(dev, "poll-interval", &value)) + poll_dev->poll_interval = value; + + poll_dev->poll = adc_keys_poll; + poll_dev->private = st; + + input = poll_dev->input; + + input->name = pdev->name; + input->phys = "adc-keys/input0"; + + input->id.bustype = BUS_HOST; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0100; + + __set_bit(EV_KEY, input->evbit); + for (i = 0; i < st->num_keys; i++) + __set_bit(st->map[i].keycode, input->keybit); + + if (device_property_read_bool(dev, "autorepeat")) + __set_bit(EV_REP, input->evbit); + + error = input_register_polled_device(poll_dev); + if (error) { + dev_err(dev, "Unable to register input device: %d\n", error); + return error; + } + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id adc_keys_of_match[] = { + { .compatible = "adc-keys", }, + { } +}; +MODULE_DEVICE_TABLE(of, adc_keys_of_match); +#endif + +static struct platform_driver __refdata adc_keys_driver = { + .driver = { + .name = "adc_keys", + .of_match_table = of_match_ptr(adc_keys_of_match), + }, + .probe = adc_keys_probe, +}; +module_platform_driver(adc_keys_driver); + +MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>"); +MODULE_DESCRIPTION("Input driver for resistor ladder connected on ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 29093657f2ef..582462d0af75 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -26,15 +26,15 @@ #include <linux/gpio_keys.h> #include <linux/workqueue.h> #include <linux/gpio.h> +#include <linux/gpio/consumer.h> #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 { const struct gpio_keys_button *button; struct input_dev *input; + struct gpio_desc *gpiod; struct timer_list release_timer; unsigned int release_delay; /* in msecs, for IRQ-only buttons */ @@ -140,7 +140,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata) */ disable_irq(bdata->irq); - if (gpio_is_valid(bdata->button->gpio)) + if (bdata->gpiod) cancel_delayed_work_sync(&bdata->work); else del_timer_sync(&bdata->release_timer); @@ -358,19 +358,20 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) const struct gpio_keys_button *button = bdata->button; struct input_dev *input = bdata->input; unsigned int type = button->type ?: EV_KEY; - int state = gpio_get_value_cansleep(button->gpio); + int state; + state = gpiod_get_value_cansleep(bdata->gpiod); if (state < 0) { - dev_err(input->dev.parent, "failed to get gpio state\n"); + dev_err(input->dev.parent, + "failed to get gpio state: %d\n", state); return; } - state = (state ? 1 : 0) ^ button->active_low; if (type == EV_ABS) { if (state) input_event(input, type, button->code, button->value); } else { - input_event(input, type, button->code, !!state); + input_event(input, type, button->code, state); } input_sync(input); } @@ -456,7 +457,7 @@ static void gpio_keys_quiesce_key(void *data) { struct gpio_button_data *bdata = data; - if (gpio_is_valid(bdata->button->gpio)) + if (bdata->gpiod) cancel_delayed_work_sync(&bdata->work); else del_timer_sync(&bdata->release_timer); @@ -465,7 +466,8 @@ static void gpio_keys_quiesce_key(void *data) static int gpio_keys_setup_key(struct platform_device *pdev, struct input_dev *input, struct gpio_button_data *bdata, - const struct gpio_keys_button *button) + const struct gpio_keys_button *button, + struct fwnode_handle *child) { const char *desc = button->desc ? button->desc : "gpio_keys"; struct device *dev = &pdev->dev; @@ -478,18 +480,56 @@ static int gpio_keys_setup_key(struct platform_device *pdev, bdata->button = button; spin_lock_init(&bdata->lock); - if (gpio_is_valid(button->gpio)) { + if (child) { + bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, child); + if (IS_ERR(bdata->gpiod)) { + error = PTR_ERR(bdata->gpiod); + if (error == -ENOENT) { + /* + * GPIO is optional, we may be dealing with + * purely interrupt-driven setup. + */ + bdata->gpiod = NULL; + } else { + if (error != -EPROBE_DEFER) + dev_err(dev, "failed to get gpio: %d\n", + error); + return error; + } + } else { + error = gpiod_direction_input(bdata->gpiod); + if (error) { + dev_err(dev, "Failed to configure GPIO %d as input: %d\n", + desc_to_gpio(bdata->gpiod), error); + return error; + } + } + } else if (gpio_is_valid(button->gpio)) { + /* + * Legacy GPIO number, so request the GPIO here and + * convert it to descriptor. + */ + unsigned flags = GPIOF_IN; + + if (button->active_low) + flags |= GPIOF_ACTIVE_LOW; - error = devm_gpio_request_one(&pdev->dev, button->gpio, - GPIOF_IN, desc); + error = devm_gpio_request_one(&pdev->dev, button->gpio, flags, + desc); if (error < 0) { dev_err(dev, "Failed to request GPIO %d, error %d\n", button->gpio, error); return error; } + bdata->gpiod = gpio_to_desc(button->gpio); + if (!bdata->gpiod) + return -EINVAL; + } + + if (bdata->gpiod) { if (button->debounce_interval) { - error = gpio_set_debounce(button->gpio, + error = gpiod_set_debounce(bdata->gpiod, button->debounce_interval * 1000); /* use timer if gpiolib doesn't provide debounce */ if (error < 0) @@ -500,7 +540,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev, if (button->irq) { bdata->irq = button->irq; } else { - irq = gpio_to_irq(button->gpio); + irq = gpiod_to_irq(bdata->gpiod); if (irq < 0) { error = irq; dev_err(dev, @@ -518,9 +558,10 @@ static int gpio_keys_setup_key(struct platform_device *pdev, } else { if (!button->irq) { - dev_err(dev, "No IRQ specified\n"); + dev_err(dev, "Found button without gpio or irq\n"); return -EINVAL; } + bdata->irq = button->irq; if (button->type && button->type != EV_KEY) { @@ -575,7 +616,7 @@ static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata) for (i = 0; i < ddata->pdata->nbuttons; i++) { struct gpio_button_data *bdata = &ddata->data[i]; - if (gpio_is_valid(bdata->button->gpio)) + if (bdata->gpiod) gpio_keys_gpio_report_event(bdata); } input_sync(input); @@ -612,25 +653,18 @@ static void gpio_keys_close(struct input_dev *input) * Handlers for alternative sources of platform_data */ -#ifdef CONFIG_OF /* - * Translate OpenFirmware node properties into platform_data + * Translate properties into platform_data */ static struct gpio_keys_platform_data * gpio_keys_get_devtree_pdata(struct device *dev) { - struct device_node *node, *pp; struct gpio_keys_platform_data *pdata; struct gpio_keys_button *button; - int error; + struct fwnode_handle *child; int nbuttons; - int i; - node = dev->of_node; - if (!node) - return ERR_PTR(-ENODEV); - - nbuttons = of_get_available_child_count(node); + nbuttons = device_get_child_node_count(dev); if (nbuttons == 0) return ERR_PTR(-ENODEV); @@ -640,64 +674,47 @@ gpio_keys_get_devtree_pdata(struct device *dev) if (!pdata) return ERR_PTR(-ENOMEM); - pdata->buttons = (struct gpio_keys_button *)(pdata + 1); - pdata->nbuttons = nbuttons; - - pdata->rep = !!of_get_property(node, "autorepeat", NULL); - - of_property_read_string(node, "label", &pdata->name); - - i = 0; - for_each_available_child_of_node(node, pp) { - enum of_gpio_flags flags; + button = (struct gpio_keys_button *)(pdata + 1); - button = &pdata->buttons[i++]; + pdata->buttons = button; + pdata->nbuttons = nbuttons; - button->gpio = of_get_gpio_flags(pp, 0, &flags); - if (button->gpio < 0) { - error = button->gpio; - if (error != -ENOENT) { - if (error != -EPROBE_DEFER) - dev_err(dev, - "Failed to get gpio flags, error: %d\n", - error); - return ERR_PTR(error); - } - } else { - button->active_low = flags & OF_GPIO_ACTIVE_LOW; - } + pdata->rep = device_property_read_bool(dev, "autorepeat"); - button->irq = irq_of_parse_and_map(pp, 0); + device_property_read_string(dev, "label", &pdata->name); - if (!gpio_is_valid(button->gpio) && !button->irq) { - dev_err(dev, "Found button without gpios or irqs\n"); - return ERR_PTR(-EINVAL); - } + device_for_each_child_node(dev, child) { + if (is_of_node(child)) + button->irq = + irq_of_parse_and_map(to_of_node(child), 0); - if (of_property_read_u32(pp, "linux,code", &button->code)) { - dev_err(dev, "Button without keycode: 0x%x\n", - button->gpio); + if (fwnode_property_read_u32(child, "linux,code", + &button->code)) { + dev_err(dev, "Button without keycode\n"); + fwnode_handle_put(child); return ERR_PTR(-EINVAL); } - button->desc = of_get_property(pp, "label", NULL); + fwnode_property_read_string(child, "label", &button->desc); - if (of_property_read_u32(pp, "linux,input-type", &button->type)) + if (fwnode_property_read_u32(child, "linux,input-type", + &button->type)) button->type = EV_KEY; - button->wakeup = of_property_read_bool(pp, "wakeup-source") || - /* legacy name */ - of_property_read_bool(pp, "gpio-key,wakeup"); + button->wakeup = + fwnode_property_read_bool(child, "wakeup-source") || + /* legacy name */ + fwnode_property_read_bool(child, "gpio-key,wakeup"); - button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL); + button->can_disable = + fwnode_property_read_bool(child, "linux,can-disable"); - if (of_property_read_u32(pp, "debounce-interval", + if (fwnode_property_read_u32(child, "debounce-interval", &button->debounce_interval)) button->debounce_interval = 5; - } - if (pdata->nbuttons == 0) - return ERR_PTR(-EINVAL); + button++; + } return pdata; } @@ -708,20 +725,11 @@ static const struct of_device_id gpio_keys_of_match[] = { }; MODULE_DEVICE_TABLE(of, gpio_keys_of_match); -#else - -static inline struct gpio_keys_platform_data * -gpio_keys_get_devtree_pdata(struct device *dev) -{ - return ERR_PTR(-ENODEV); -} - -#endif - static int gpio_keys_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev); + struct fwnode_handle *child = NULL; struct gpio_keys_drvdata *ddata; struct input_dev *input; size_t size; @@ -774,14 +782,28 @@ static int gpio_keys_probe(struct platform_device *pdev) const struct gpio_keys_button *button = &pdata->buttons[i]; struct gpio_button_data *bdata = &ddata->data[i]; - error = gpio_keys_setup_key(pdev, input, bdata, button); - if (error) + if (!dev_get_platdata(dev)) { + child = device_get_next_child_node(&pdev->dev, child); + if (!child) { + dev_err(&pdev->dev, + "missing child device node for entry %d\n", + i); + return -EINVAL; + } + } + + error = gpio_keys_setup_key(pdev, input, bdata, button, child); + if (error) { + fwnode_handle_put(child); return error; + } if (button->wakeup) wakeup = 1; } + fwnode_handle_put(child); + error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group); if (error) { dev_err(dev, "Unable to export keys/switches, error: %d\n", @@ -814,8 +836,7 @@ static int gpio_keys_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int gpio_keys_suspend(struct device *dev) +static int __maybe_unused gpio_keys_suspend(struct device *dev) { struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); struct input_dev *input = ddata->input; @@ -837,7 +858,7 @@ static int gpio_keys_suspend(struct device *dev) return 0; } -static int gpio_keys_resume(struct device *dev) +static int __maybe_unused gpio_keys_resume(struct device *dev) { struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); struct input_dev *input = ddata->input; @@ -863,7 +884,6 @@ static int gpio_keys_resume(struct device *dev) gpio_keys_report_state(ddata); return 0; } -#endif static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume); @@ -873,7 +893,7 @@ static struct platform_driver gpio_keys_device_driver = { .driver = { .name = "gpio-keys", .pm = &gpio_keys_pm_ops, - .of_match_table = of_match_ptr(gpio_keys_of_match), + .of_match_table = gpio_keys_of_match, } }; diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 62bdb1d48c49..bed4f2086158 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -30,10 +30,10 @@ #define DRV_NAME "gpio-keys-polled" struct gpio_keys_button_data { + struct gpio_desc *gpiod; int last_state; int count; int threshold; - int can_sleep; }; struct gpio_keys_polled_dev { @@ -46,7 +46,7 @@ struct gpio_keys_polled_dev { }; static void gpio_keys_button_event(struct input_polled_dev *dev, - struct gpio_keys_button *button, + const struct gpio_keys_button *button, int state) { struct gpio_keys_polled_dev *bdev = dev->private; @@ -70,21 +70,22 @@ static void gpio_keys_button_event(struct input_polled_dev *dev, } static void gpio_keys_polled_check_state(struct input_polled_dev *dev, - struct gpio_keys_button *button, + const struct gpio_keys_button *button, struct gpio_keys_button_data *bdata) { int state; - if (bdata->can_sleep) - state = !!gpiod_get_value_cansleep(button->gpiod); - else - state = !!gpiod_get_value(button->gpiod); - - gpio_keys_button_event(dev, button, state); + state = gpiod_get_value_cansleep(bdata->gpiod); + if (state < 0) { + dev_err(dev->input->dev.parent, + "failed to get gpio state: %d\n", state); + } else { + gpio_keys_button_event(dev, button, state); - if (state != bdata->last_state) { - bdata->count = 0; - bdata->last_state = state; + if (state != bdata->last_state) { + bdata->count = 0; + bdata->last_state = state; + } } } @@ -142,48 +143,35 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev) pdata->disable(bdev->dev); } -static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev) +static struct gpio_keys_platform_data * +gpio_keys_polled_get_devtree_pdata(struct device *dev) { struct gpio_keys_platform_data *pdata; struct gpio_keys_button *button; struct fwnode_handle *child; - int error; int nbuttons; nbuttons = device_get_child_node_count(dev); if (nbuttons == 0) - return NULL; + return ERR_PTR(-EINVAL); pdata = devm_kzalloc(dev, sizeof(*pdata) + nbuttons * sizeof(*button), GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); - pdata->buttons = (struct gpio_keys_button *)(pdata + 1); + button = (struct gpio_keys_button *)(pdata + 1); + + pdata->buttons = button; + pdata->nbuttons = nbuttons; pdata->rep = device_property_present(dev, "autorepeat"); device_property_read_u32(dev, "poll-interval", &pdata->poll_interval); device_for_each_child_node(dev, child) { - struct gpio_desc *desc; - - desc = devm_get_gpiod_from_child(dev, NULL, child); - if (IS_ERR(desc)) { - error = PTR_ERR(desc); - if (error != -EPROBE_DEFER) - dev_err(dev, - "Failed to get gpio flags, error: %d\n", - error); - fwnode_handle_put(child); - return ERR_PTR(error); - } - - button = &pdata->buttons[pdata->nbuttons++]; - button->gpiod = desc; - - if (fwnode_property_read_u32(child, "linux,code", &button->code)) { - dev_err(dev, "Button without keycode: %d\n", - pdata->nbuttons - 1); + if (fwnode_property_read_u32(child, "linux,code", + &button->code)) { + dev_err(dev, "button without keycode\n"); fwnode_handle_put(child); return ERR_PTR(-EINVAL); } @@ -206,10 +194,9 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct if (fwnode_property_read_u32(child, "debounce-interval", &button->debounce_interval)) button->debounce_interval = 5; - } - if (pdata->nbuttons == 0) - return ERR_PTR(-EINVAL); + button++; + } return pdata; } @@ -220,7 +207,7 @@ static void gpio_keys_polled_set_abs_params(struct input_dev *input, int i, min = 0, max = 0; for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; + const struct gpio_keys_button *button = &pdata->buttons[i]; if (button->type != EV_ABS || button->code != code) continue; @@ -230,6 +217,7 @@ static void gpio_keys_polled_set_abs_params(struct input_dev *input, if (button->value > max) max = button->value; } + input_set_abs_params(input, code, min, max, 0, 0); } @@ -242,6 +230,7 @@ MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match); static int gpio_keys_polled_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct fwnode_handle *child = NULL; const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev); struct gpio_keys_polled_dev *bdev; struct input_polled_dev *poll_dev; @@ -254,10 +243,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) pdata = gpio_keys_polled_get_devtree_pdata(dev); if (IS_ERR(pdata)) return PTR_ERR(pdata); - if (!pdata) { - dev_err(dev, "missing platform data\n"); - return -EINVAL; - } } if (!pdata->poll_interval) { @@ -300,20 +285,48 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) __set_bit(EV_REP, input->evbit); for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; + const struct gpio_keys_button *button = &pdata->buttons[i]; struct gpio_keys_button_data *bdata = &bdev->data[i]; unsigned int type = button->type ?: EV_KEY; if (button->wakeup) { dev_err(dev, DRV_NAME " does not support wakeup\n"); + fwnode_handle_put(child); return -EINVAL; } - /* - * Legacy GPIO number so request the GPIO here and - * convert it to descriptor. - */ - if (!button->gpiod && gpio_is_valid(button->gpio)) { + if (!dev_get_platdata(dev)) { + /* No legacy static platform data */ + child = device_get_next_child_node(dev, child); + if (!child) { + dev_err(dev, "missing child device node\n"); + return -EINVAL; + } + + bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, + child); + if (IS_ERR(bdata->gpiod)) { + error = PTR_ERR(bdata->gpiod); + if (error != -EPROBE_DEFER) + dev_err(dev, + "failed to get gpio: %d\n", + error); + fwnode_handle_put(child); + return error; + } + + error = gpiod_direction_input(bdata->gpiod); + if (error) { + dev_err(dev, "Failed to configure GPIO %d as input: %d\n", + desc_to_gpio(bdata->gpiod), error); + fwnode_handle_put(child); + return error; + } + } else if (gpio_is_valid(button->gpio)) { + /* + * Legacy GPIO number so request the GPIO here and + * convert it to descriptor. + */ unsigned flags = GPIOF_IN; if (button->active_low) @@ -322,18 +335,21 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) error = devm_gpio_request_one(&pdev->dev, button->gpio, flags, button->desc ? : DRV_NAME); if (error) { - dev_err(dev, "unable to claim gpio %u, err=%d\n", + dev_err(dev, + "unable to claim gpio %u, err=%d\n", button->gpio, error); return error; } - button->gpiod = gpio_to_desc(button->gpio); + bdata->gpiod = gpio_to_desc(button->gpio); + if (!bdata->gpiod) { + dev_err(dev, + "unable to convert gpio %u to descriptor\n", + button->gpio); + return -EINVAL; + } } - if (IS_ERR(button->gpiod)) - return PTR_ERR(button->gpiod); - - bdata->can_sleep = gpiod_cansleep(button->gpiod); bdata->last_state = -1; bdata->threshold = DIV_ROUND_UP(button->debounce_interval, pdata->poll_interval); @@ -344,6 +360,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) button->code); } + fwnode_handle_put(child); + bdev->poll_dev = poll_dev; bdev->dev = dev; bdev->pdata = pdata; diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index 421d9c55b0e8..1277c39f9482 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -25,8 +25,6 @@ #include <linux/slab.h> #include <mach/jornada720.h> -#include <mach/hardware.h> -#include <mach/irqs.h> MODULE_AUTHOR("Kristoffer Ericson <Kristoffer.Ericson@gmail.com>"); MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver"); @@ -66,10 +64,8 @@ static irqreturn_t jornada720_kbd_interrupt(int irq, void *dev_id) jornada_ssp_start(); if (jornada_ssp_inout(GETSCANKEYCODE) != TXDUMMY) { - printk(KERN_DEBUG - "jornada720_kbd: " - "GetKeycode command failed with ETIMEDOUT, " - "flushed bus\n"); + dev_dbg(&pdev->dev, + "GetKeycode command failed with ETIMEDOUT, flushed bus\n"); } else { /* How many keycodes are waiting for us? */ count = jornada_ssp_byte(TXDUMMY); @@ -97,14 +93,16 @@ static int jornada720_kbd_probe(struct platform_device *pdev) { struct jornadakbd *jornadakbd; struct input_dev *input_dev; - int i, err; + int i, err, irq; - jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!jornadakbd || !input_dev) { - err = -ENOMEM; - goto fail1; - } + irq = platform_get_irq(pdev, 0); + if (irq <= 0) + return irq < 0 ? irq : -EINVAL; + + jornadakbd = devm_kzalloc(&pdev->dev, sizeof(*jornadakbd), GFP_KERNEL); + input_dev = devm_input_allocate_device(&pdev->dev); + if (!jornadakbd || !input_dev) + return -ENOMEM; platform_set_drvdata(pdev, jornadakbd); @@ -127,40 +125,16 @@ static int jornada720_kbd_probe(struct platform_device *pdev) input_set_capability(input_dev, EV_MSC, MSC_SCAN); - err = request_irq(IRQ_GPIO0, - jornada720_kbd_interrupt, - IRQF_TRIGGER_FALLING, - "jornadakbd", pdev); + err = devm_request_irq(&pdev->dev, irq, jornada720_kbd_interrupt, + IRQF_TRIGGER_FALLING, "jornadakbd", pdev); if (err) { - printk(KERN_INFO "jornadakbd720_kbd: Unable to grab IRQ\n"); - goto fail1; + dev_err(&pdev->dev, "unable to grab IRQ%d: %d\n", irq, err); + return err; } - err = input_register_device(jornadakbd->input); - if (err) - goto fail2; - - return 0; - - fail2: /* IRQ, DEVICE, MEMORY */ - free_irq(IRQ_GPIO0, pdev); - fail1: /* DEVICE, MEMORY */ - input_free_device(input_dev); - kfree(jornadakbd); - return err; + return input_register_device(jornadakbd->input); }; -static int jornada720_kbd_remove(struct platform_device *pdev) -{ - struct jornadakbd *jornadakbd = platform_get_drvdata(pdev); - - free_irq(IRQ_GPIO0, pdev); - input_unregister_device(jornadakbd->input); - kfree(jornadakbd); - - return 0; -} - /* work with hotplug and coldplug */ MODULE_ALIAS("platform:jornada720_kbd"); @@ -169,6 +143,5 @@ static struct platform_driver jornada720_kbd_driver = { .name = "jornada720_kbd", }, .probe = jornada720_kbd_probe, - .remove = jornada720_kbd_remove, }; module_platform_driver(jornada720_kbd_driver); diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c index 265d641c40e2..632523d4f5dc 100644 --- a/drivers/input/keyboard/lpc32xx-keys.c +++ b/drivers/input/keyboard/lpc32xx-keys.c @@ -182,7 +182,7 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0 || irq >= NR_IRQS) { + if (irq < 0) { dev_err(&pdev->dev, "failed to get platform irq\n"); return -EINVAL; } diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index fcef5d1365e2..e24443376e75 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -316,7 +316,7 @@ static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad) error = of_property_read_u32(np, "marvell,debounce-interval", &pdata->debounce_interval); if (error) { - dev_err(dev, "failed to parse debpunce-interval\n"); + dev_err(dev, "failed to parse debounce-interval\n"); return error; } diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c index 24a9f599082f..7544888c4749 100644 --- a/drivers/input/keyboard/snvs_pwrkey.c +++ b/drivers/input/keyboard/snvs_pwrkey.c @@ -168,7 +168,6 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) error = input_register_device(input); if (error < 0) { dev_err(&pdev->dev, "failed to register input device\n"); - input_free_device(input); return error; } diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 9002298698fc..3048ef3e3e16 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -164,11 +164,18 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data) int error, col, row; u8 reg, state, code; - /* Initial read of the key event FIFO */ - error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, ®); + do { + error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, ®); + if (error < 0) { + dev_err(&keypad_data->client->dev, + "unable to read REG_KEY_EVENT_A\n"); + break; + } + + /* Assume that key code 0 signifies empty FIFO */ + if (reg <= 0) + break; - /* Assume that key code 0 signifies empty FIFO */ - while (error >= 0 && reg > 0) { state = reg & KEY_EVENT_VALUE; code = reg & KEY_EVENT_CODE; @@ -184,11 +191,7 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data) /* Read for next loop */ error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, ®); - } - - if (error < 0) - dev_err(&keypad_data->client->dev, - "unable to read REG_KEY_EVENT_A\n"); + } while (1); input_sync(input); } diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index efb0ca871327..1ae4d9617ff8 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -292,6 +292,18 @@ config INPUT_GPIO_TILT_POLLED To compile this driver as a module, choose M here: the module will be called gpio_tilt_polled. +config INPUT_GPIO_DECODER + tristate "Polled GPIO Decoder Input driver" + depends on GPIOLIB || COMPILE_TEST + select INPUT_POLLDEV + help + Say Y here if you want driver to read status of multiple GPIO + lines and report the encoded value as an absolute integer to + input subsystem. + + To compile this driver as a module, choose M here: the module + will be called gpio_decoder. + config INPUT_IXP4XX_BEEPER tristate "IXP4XX Beeper support" depends on ARCH_IXP4XX @@ -454,10 +466,10 @@ config INPUT_RETU_PWRBUTTON config INPUT_TPS65218_PWRBUTTON tristate "TPS65218 Power button driver" - depends on MFD_TPS65218 + depends on (MFD_TPS65217 || MFD_TPS65218) help Say Y here if you want to enable power buttong reporting for - the TPS65218 Power Management IC device. + TPS65217 and TPS65218 Power Management IC devices. To compile this driver as a module, choose M here. The module will be called tps65218-pwrbutton. @@ -613,11 +625,12 @@ config INPUT_DA9055_ONKEY will be called da9055_onkey. config INPUT_DA9063_ONKEY - tristate "Dialog DA9062/63 OnKey" + tristate "Dialog DA9063/62/61 OnKey" depends on MFD_DA9063 || MFD_DA9062 help - Support the ONKEY of Dialog DA9063 and DA9062 Power Management ICs - as an input device capable of reporting the power button status. + Support the ONKEY of Dialog DA9063, DA9062 and DA9061 Power + Management ICs as an input device capable of reporting the + power button status. To compile this driver as a module, choose M here: the module will be called da9063_onkey. diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 6a1e5e20fc1c..0b6d025f0487 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o +obj-$(CONFIG_INPUT_GPIO_DECODER) += gpio_decoder.o obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c index b0d445390ee4..2124390ec38c 100644 --- a/drivers/input/misc/bma150.c +++ b/drivers/input/misc/bma150.c @@ -538,8 +538,13 @@ static int bma150_probe(struct i2c_client *client, return -EIO; } + /* + * Note if the IIO CONFIG_BMA180 driver is enabled we want to fail + * the probe for the bma180 as the iio driver is preferred. + */ chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG); - if (chip_id != BMA150_CHIP_ID && chip_id != BMA180_CHIP_ID) { + if (chip_id != BMA150_CHIP_ID && + (IS_ENABLED(CONFIG_BMA180) || chip_id != BMA180_CHIP_ID)) { dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id); return -EINVAL; } @@ -643,7 +648,9 @@ static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL); static const struct i2c_device_id bma150_id[] = { { "bma150", 0 }, +#if !IS_ENABLED(CONFIG_BMA180) { "bma180", 0 }, +#endif { "smb380", 0 }, { "bma023", 0 }, { } diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c index bb863e062b03..b4ff1e86d3d3 100644 --- a/drivers/input/misc/da9063_onkey.c +++ b/drivers/input/misc/da9063_onkey.c @@ -1,5 +1,5 @@ /* - * OnKey device driver for DA9063 and DA9062 PMICs + * OnKey device driver for DA9063, DA9062 and DA9061 PMICs * Copyright (C) 2015 Dialog Semiconductor Ltd. * * This program is free software; you can redistribute it and/or @@ -87,6 +87,7 @@ static const struct of_device_id da9063_compatible_reg_id_table[] = { { .compatible = "dlg,da9062-onkey", .data = &da9062_regs }, { }, }; +MODULE_DEVICE_TABLE(of, da9063_compatible_reg_id_table); static void da9063_poll_on(struct work_struct *work) { @@ -149,13 +150,13 @@ static void da9063_poll_on(struct work_struct *work) * and then send shutdown command */ dev_dbg(&onkey->input->dev, - "Sending SHUTDOWN to DA9063 ...\n"); + "Sending SHUTDOWN to PMIC ...\n"); error = regmap_write(onkey->regmap, config->onkey_shutdown, config->onkey_shutdown_mask); if (error) dev_err(&onkey->input->dev, - "Cannot SHUTDOWN DA9063: %d\n", + "Cannot SHUTDOWN PMIC: %d\n", error); } } @@ -300,6 +301,6 @@ static struct platform_driver da9063_onkey_driver = { module_platform_driver(da9063_onkey_driver); MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>"); -MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063 and DA9062"); +MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063, DA9062 and DA9061"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY); diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index 2adfd86c869a..0a2b865b1000 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -18,8 +18,6 @@ #include <linux/i2c.h> #include <linux/input.h> #include <linux/module.h> -#include <linux/of_gpio.h> -#include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/delay.h> @@ -27,7 +25,6 @@ #include <linux/regulator/consumer.h> #include <dt-bindings/input/ti-drv260x.h> -#include <linux/platform_data/drv260x-pdata.h> #define DRV260X_STATUS 0x0 #define DRV260X_MODE 0x1 @@ -468,90 +465,39 @@ static const struct regmap_config drv260x_regmap_config = { .cache_type = REGCACHE_NONE, }; -#ifdef CONFIG_OF -static int drv260x_parse_dt(struct device *dev, - struct drv260x_data *haptics) -{ - struct device_node *np = dev->of_node; - unsigned int voltage; - int error; - - error = of_property_read_u32(np, "mode", &haptics->mode); - if (error) { - dev_err(dev, "%s: No entry for mode\n", __func__); - return error; - } - - error = of_property_read_u32(np, "library-sel", &haptics->library); - if (error) { - dev_err(dev, "%s: No entry for library selection\n", - __func__); - return error; - } - - error = of_property_read_u32(np, "vib-rated-mv", &voltage); - if (!error) - haptics->rated_voltage = drv260x_calculate_voltage(voltage); - - - error = of_property_read_u32(np, "vib-overdrive-mv", &voltage); - if (!error) - haptics->overdrive_voltage = drv260x_calculate_voltage(voltage); - - return 0; -} -#else -static inline int drv260x_parse_dt(struct device *dev, - struct drv260x_data *haptics) -{ - dev_err(dev, "no platform data defined\n"); - - return -EINVAL; -} -#endif - static int drv260x_probe(struct i2c_client *client, const struct i2c_device_id *id) { - const struct drv260x_platform_data *pdata = dev_get_platdata(&client->dev); + struct device *dev = &client->dev; struct drv260x_data *haptics; + u32 voltage; int error; - haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL); + haptics = devm_kzalloc(dev, sizeof(*haptics), GFP_KERNEL); if (!haptics) return -ENOMEM; - haptics->rated_voltage = DRV260X_DEF_OD_CLAMP_VOLT; - haptics->rated_voltage = DRV260X_DEF_RATED_VOLT; - - if (pdata) { - haptics->mode = pdata->mode; - haptics->library = pdata->library_selection; - if (pdata->vib_overdrive_voltage) - haptics->overdrive_voltage = drv260x_calculate_voltage(pdata->vib_overdrive_voltage); - if (pdata->vib_rated_voltage) - haptics->rated_voltage = drv260x_calculate_voltage(pdata->vib_rated_voltage); - } else if (client->dev.of_node) { - error = drv260x_parse_dt(&client->dev, haptics); - if (error) - return error; - } else { - dev_err(&client->dev, "Platform data not set\n"); - return -ENODEV; + error = device_property_read_u32(dev, "mode", &haptics->mode); + if (error) { + dev_err(dev, "Can't fetch 'mode' property: %d\n", error); + return error; } - if (haptics->mode < DRV260X_LRA_MODE || haptics->mode > DRV260X_ERM_MODE) { - dev_err(&client->dev, - "Vibrator mode is invalid: %i\n", - haptics->mode); + dev_err(dev, "Vibrator mode is invalid: %i\n", haptics->mode); return -EINVAL; } + error = device_property_read_u32(dev, "library-sel", &haptics->library); + if (error) { + dev_err(dev, "Can't fetch 'library-sel' property: %d\n", error); + return error; + } + if (haptics->library < DRV260X_LIB_EMPTY || haptics->library > DRV260X_ERM_LIB_F) { - dev_err(&client->dev, + dev_err(dev, "Library value is invalid: %i\n", haptics->library); return -EINVAL; } @@ -559,40 +505,44 @@ static int drv260x_probe(struct i2c_client *client, if (haptics->mode == DRV260X_LRA_MODE && haptics->library != DRV260X_LIB_EMPTY && haptics->library != DRV260X_LIB_LRA) { - dev_err(&client->dev, - "LRA Mode with ERM Library mismatch\n"); + dev_err(dev, "LRA Mode with ERM Library mismatch\n"); return -EINVAL; } if (haptics->mode == DRV260X_ERM_MODE && (haptics->library == DRV260X_LIB_EMPTY || haptics->library == DRV260X_LIB_LRA)) { - dev_err(&client->dev, - "ERM Mode with LRA Library mismatch\n"); + dev_err(dev, "ERM Mode with LRA Library mismatch\n"); return -EINVAL; } - haptics->regulator = devm_regulator_get(&client->dev, "vbat"); + error = device_property_read_u32(dev, "vib-rated-mv", &voltage); + haptics->rated_voltage = error ? DRV260X_DEF_RATED_VOLT : + drv260x_calculate_voltage(voltage); + + error = device_property_read_u32(dev, "vib-overdrive-mv", &voltage); + haptics->overdrive_voltage = error ? DRV260X_DEF_OD_CLAMP_VOLT : + drv260x_calculate_voltage(voltage); + + haptics->regulator = devm_regulator_get(dev, "vbat"); if (IS_ERR(haptics->regulator)) { error = PTR_ERR(haptics->regulator); - dev_err(&client->dev, - "unable to get regulator, error: %d\n", error); + dev_err(dev, "unable to get regulator, error: %d\n", error); return error; } - haptics->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", + haptics->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); if (IS_ERR(haptics->enable_gpio)) return PTR_ERR(haptics->enable_gpio); - haptics->input_dev = devm_input_allocate_device(&client->dev); + haptics->input_dev = devm_input_allocate_device(dev); if (!haptics->input_dev) { dev_err(&client->dev, "Failed to allocate input device\n"); return -ENOMEM; } haptics->input_dev->name = "drv260x:haptics"; - haptics->input_dev->dev.parent = client->dev.parent; haptics->input_dev->close = drv260x_close; input_set_drvdata(haptics->input_dev, haptics); input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE); @@ -600,8 +550,7 @@ static int drv260x_probe(struct i2c_client *client, error = input_ff_create_memless(haptics->input_dev, NULL, drv260x_haptics_play); if (error) { - dev_err(&client->dev, "input_ff_create() failed: %d\n", - error); + dev_err(dev, "input_ff_create() failed: %d\n", error); return error; } @@ -613,21 +562,19 @@ static int drv260x_probe(struct i2c_client *client, haptics->regmap = devm_regmap_init_i2c(client, &drv260x_regmap_config); if (IS_ERR(haptics->regmap)) { error = PTR_ERR(haptics->regmap); - dev_err(&client->dev, "Failed to allocate register map: %d\n", - error); + dev_err(dev, "Failed to allocate register map: %d\n", error); return error; } error = drv260x_init(haptics); if (error) { - dev_err(&client->dev, "Device init failed: %d\n", error); + dev_err(dev, "Device init failed: %d\n", error); return error; } error = input_register_device(haptics->input_dev); if (error) { - dev_err(&client->dev, "couldn't register input device: %d\n", - error); + dev_err(dev, "couldn't register input device: %d\n", error); return error; } diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c index ef9bc12b3be3..dcb6d8e94b11 100644 --- a/drivers/input/misc/drv2665.c +++ b/drivers/input/misc/drv2665.c @@ -125,8 +125,8 @@ static void drv2665_close(struct input_dev *input) cancel_work_sync(&haptics->work); - error = regmap_update_bits(haptics->regmap, - DRV2665_CTRL_2, DRV2665_STANDBY, 1); + error = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2, + DRV2665_STANDBY, DRV2665_STANDBY); if (error) dev_err(&haptics->client->dev, "Failed to enter standby mode: %d\n", error); @@ -240,7 +240,7 @@ static int __maybe_unused drv2665_suspend(struct device *dev) if (haptics->input_dev->users) { ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2, - DRV2665_STANDBY, 1); + DRV2665_STANDBY, DRV2665_STANDBY); if (ret) { dev_err(dev, "Failed to set standby mode\n"); regulator_disable(haptics->regulator); diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index d5ba7481328c..2849bb6906a8 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c @@ -256,7 +256,7 @@ static void drv2667_close(struct input_dev *input) cancel_work_sync(&haptics->work); error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, - DRV2667_STANDBY, 1); + DRV2667_STANDBY, DRV2667_STANDBY); if (error) dev_err(&haptics->client->dev, "Failed to enter standby mode: %d\n", error); @@ -415,7 +415,7 @@ static int __maybe_unused drv2667_suspend(struct device *dev) if (haptics->input_dev->users) { ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, - DRV2667_STANDBY, 1); + DRV2667_STANDBY, DRV2667_STANDBY); if (ret) { dev_err(dev, "Failed to set standby mode\n"); regulator_disable(haptics->regulator); diff --git a/drivers/input/misc/gpio_decoder.c b/drivers/input/misc/gpio_decoder.c new file mode 100644 index 000000000000..ca7e0bacb2d8 --- /dev/null +++ b/drivers/input/misc/gpio_decoder.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * A generic driver to read multiple gpio lines and translate the + * encoded numeric value into an input event. + */ + +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <linux/input.h> +#include <linux/input-polldev.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +struct gpio_decoder { + struct input_polled_dev *poll_dev; + struct gpio_descs *input_gpios; + struct device *dev; + u32 axis; + u32 last_stable; +}; + +static int gpio_decoder_get_gpios_state(struct gpio_decoder *decoder) +{ + struct gpio_descs *gpios = decoder->input_gpios; + unsigned int ret = 0; + int i, val; + + for (i = 0; i < gpios->ndescs; i++) { + val = gpiod_get_value_cansleep(gpios->desc[i]); + if (val < 0) { + dev_err(decoder->dev, + "Error reading gpio %d: %d\n", + desc_to_gpio(gpios->desc[i]), val); + return val; + } + + val = !!val; + ret = (ret << 1) | val; + } + + return ret; +} + +static void gpio_decoder_poll_gpios(struct input_polled_dev *poll_dev) +{ + struct gpio_decoder *decoder = poll_dev->private; + int state; + + state = gpio_decoder_get_gpios_state(decoder); + if (state >= 0 && state != decoder->last_stable) { + input_report_abs(poll_dev->input, decoder->axis, state); + input_sync(poll_dev->input); + decoder->last_stable = state; + } +} + +static int gpio_decoder_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct gpio_decoder *decoder; + struct input_polled_dev *poll_dev; + u32 max; + int err; + + decoder = devm_kzalloc(dev, sizeof(struct gpio_decoder), GFP_KERNEL); + if (!decoder) + return -ENOMEM; + + device_property_read_u32(dev, "linux,axis", &decoder->axis); + decoder->input_gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN); + if (IS_ERR(decoder->input_gpios)) { + dev_err(dev, "unable to acquire input gpios\n"); + return PTR_ERR(decoder->input_gpios); + } + if (decoder->input_gpios->ndescs < 2) { + dev_err(dev, "not enough gpios found\n"); + return -EINVAL; + } + + if (device_property_read_u32(dev, "decoder-max-value", &max)) + max = (1U << decoder->input_gpios->ndescs) - 1; + + decoder->dev = dev; + poll_dev = devm_input_allocate_polled_device(decoder->dev); + if (!poll_dev) + return -ENOMEM; + + poll_dev->private = decoder; + poll_dev->poll = gpio_decoder_poll_gpios; + decoder->poll_dev = poll_dev; + + poll_dev->input->name = pdev->name; + poll_dev->input->id.bustype = BUS_HOST; + input_set_abs_params(poll_dev->input, decoder->axis, 0, max, 0, 0); + + err = input_register_polled_device(poll_dev); + if (err) { + dev_err(dev, "failed to register polled device\n"); + return err; + } + platform_set_drvdata(pdev, decoder); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id gpio_decoder_of_match[] = { + { .compatible = "gpio-decoder", }, + { }, +}; +MODULE_DEVICE_TABLE(of, gpio_decoder_of_match); +#endif + +static struct platform_driver gpio_decoder_driver = { + .probe = gpio_decoder_probe, + .driver = { + .name = "gpio-decoder", + .of_match_table = of_match_ptr(gpio_decoder_of_match), + } +}; +module_platform_driver(gpio_decoder_driver); + +MODULE_DESCRIPTION("GPIO decoder input driver"); +MODULE_AUTHOR("Vignesh R <vigneshr@ti.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c index 29ddeb7be84b..46b0f48fbf49 100644 --- a/drivers/input/misc/max77693-haptic.c +++ b/drivers/input/misc/max77693-haptic.c @@ -3,7 +3,7 @@ * * Copyright (C) 2014,2015 Samsung Electronics * Jaewon Kim <jaewon02.kim@samsung.com> - * Krzysztof Kozlowski <k.kozlowski@samsung.com> + * Krzysztof Kozlowski <krzk@kernel.org> * * This program is not provided / owned by Maxim Integrated Products. * @@ -426,7 +426,7 @@ static struct platform_driver max77693_haptic_driver = { module_platform_driver(max77693_haptic_driver); MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>"); -MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>"); +MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>"); MODULE_DESCRIPTION("MAXIM 77693/77843 Haptic driver"); MODULE_ALIAS("platform:max77693-haptic"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c index c14b82709b0f..908b51089dee 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -17,6 +17,7 @@ #include <linux/acpi.h> #include <linux/gpio/consumer.h> #include <linux/gpio_keys.h> +#include <linux/gpio.h> #include <linux/platform_device.h> /* @@ -92,7 +93,7 @@ soc_button_device_create(struct platform_device *pdev, continue; gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index); - if (gpio < 0) + if (!gpio_is_valid(gpio)) continue; gpio_keys[n_buttons].type = info->event_type; @@ -166,6 +167,11 @@ static int soc_button_probe(struct platform_device *pdev) button_info = (struct soc_button_info *)id->driver_data; + if (gpiod_count(&pdev->dev, KBUILD_MODNAME) <= 0) { + dev_dbg(&pdev->dev, "no GPIO attached, ignoring...\n"); + return -ENODEV; + } + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/drivers/input/misc/tps65218-pwrbutton.c b/drivers/input/misc/tps65218-pwrbutton.c index a39b62651a4b..3273217ce80c 100644 --- a/drivers/input/misc/tps65218-pwrbutton.c +++ b/drivers/input/misc/tps65218-pwrbutton.c @@ -1,8 +1,9 @@ /* - * Texas Instruments' TPS65218 Power Button Input Driver + * Texas Instruments' TPS65217 and TPS65218 Power Button Input Driver * * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ * Author: Felipe Balbi <balbi@ti.com> + * Author: Marcin Niestroj <m.niestroj@grinn-global.com> * * 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 @@ -18,31 +19,61 @@ #include <linux/input.h> #include <linux/interrupt.h> #include <linux/kernel.h> +#include <linux/mfd/tps65217.h> #include <linux/mfd/tps65218.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/regmap.h> #include <linux/slab.h> -struct tps65218_pwrbutton { +struct tps6521x_data { + unsigned int reg_status; + unsigned int pb_mask; + const char *name; +}; + +static const struct tps6521x_data tps65217_data = { + .reg_status = TPS65217_REG_STATUS, + .pb_mask = TPS65217_STATUS_PB, + .name = "tps65217_pwrbutton", +}; + +static const struct tps6521x_data tps65218_data = { + .reg_status = TPS65218_REG_STATUS, + .pb_mask = TPS65218_STATUS_PB_STATE, + .name = "tps65218_pwrbutton", +}; + +struct tps6521x_pwrbutton { struct device *dev; - struct tps65218 *tps; + struct regmap *regmap; struct input_dev *idev; + const struct tps6521x_data *data; + char phys[32]; +}; + +static const struct of_device_id of_tps6521x_pb_match[] = { + { .compatible = "ti,tps65217-pwrbutton", .data = &tps65217_data }, + { .compatible = "ti,tps65218-pwrbutton", .data = &tps65218_data }, + { }, }; +MODULE_DEVICE_TABLE(of, of_tps6521x_pb_match); -static irqreturn_t tps65218_pwr_irq(int irq, void *_pwr) +static irqreturn_t tps6521x_pb_irq(int irq, void *_pwr) { - struct tps65218_pwrbutton *pwr = _pwr; + struct tps6521x_pwrbutton *pwr = _pwr; + const struct tps6521x_data *tps_data = pwr->data; unsigned int reg; int error; - error = tps65218_reg_read(pwr->tps, TPS65218_REG_STATUS, ®); + error = regmap_read(pwr->regmap, tps_data->reg_status, ®); if (error) { dev_err(pwr->dev, "can't read register: %d\n", error); goto out; } - if (reg & TPS65218_STATUS_PB_STATE) { + if (reg & tps_data->pb_mask) { input_report_key(pwr->idev, KEY_POWER, 1); pm_wakeup_event(pwr->dev, 0); } else { @@ -55,42 +86,55 @@ out: return IRQ_HANDLED; } -static int tps65218_pwron_probe(struct platform_device *pdev) +static int tps6521x_pb_probe(struct platform_device *pdev) { - struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent); struct device *dev = &pdev->dev; - struct tps65218_pwrbutton *pwr; + struct tps6521x_pwrbutton *pwr; struct input_dev *idev; + const struct of_device_id *match; int error; int irq; + match = of_match_node(of_tps6521x_pb_match, pdev->dev.of_node); + if (!match) + return -ENXIO; + pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL); if (!pwr) return -ENOMEM; + pwr->data = match->data; + idev = devm_input_allocate_device(dev); if (!idev) return -ENOMEM; - idev->name = "tps65218_pwrbutton"; - idev->phys = "tps65218_pwrbutton/input0"; + idev->name = pwr->data->name; + snprintf(pwr->phys, sizeof(pwr->phys), "%s/input0", + pwr->data->name); + idev->phys = pwr->phys; idev->dev.parent = dev; idev->id.bustype = BUS_I2C; input_set_capability(idev, EV_KEY, KEY_POWER); - pwr->tps = tps; + pwr->regmap = dev_get_regmap(pdev->dev.parent, NULL); pwr->dev = dev; pwr->idev = idev; platform_set_drvdata(pdev, pwr); device_init_wakeup(dev, true); irq = platform_get_irq(pdev, 0); - error = devm_request_threaded_irq(dev, irq, NULL, tps65218_pwr_irq, + if (irq < 0) { + dev_err(dev, "No IRQ resource!\n"); + return -EINVAL; + } + + error = devm_request_threaded_irq(dev, irq, NULL, tps6521x_pb_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "tps65218-pwrbutton", pwr); + pwr->data->name, pwr); if (error) { dev_err(dev, "failed to request IRQ #%d: %d\n", irq, error); @@ -106,21 +150,15 @@ static int tps65218_pwron_probe(struct platform_device *pdev) return 0; } -static const struct of_device_id of_tps65218_pwr_match[] = { - { .compatible = "ti,tps65218-pwrbutton" }, - { }, -}; -MODULE_DEVICE_TABLE(of, of_tps65218_pwr_match); - -static struct platform_driver tps65218_pwron_driver = { - .probe = tps65218_pwron_probe, +static struct platform_driver tps6521x_pb_driver = { + .probe = tps6521x_pb_probe, .driver = { - .name = "tps65218_pwrbutton", - .of_match_table = of_tps65218_pwr_match, + .name = "tps6521x_pwrbutton", + .of_match_table = of_tps6521x_pb_match, }, }; -module_platform_driver(tps65218_pwron_driver); +module_platform_driver(tps6521x_pb_driver); -MODULE_DESCRIPTION("TPS65218 Power Button"); +MODULE_DESCRIPTION("TPS6521X Power Button"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 936f07a4e35f..328edc8c8786 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -103,6 +103,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = { 6-byte ALPS packet */ #define ALPS_STICK_BITS 0x100 /* separate stick button bits */ #define ALPS_BUTTONPAD 0x200 /* device is a clickpad */ +#define ALPS_DUALPOINT_WITH_PRESSURE 0x400 /* device can report trackpoint pressure */ static const struct alps_model_info alps_model_data[] = { { { 0x32, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */ @@ -1152,19 +1153,30 @@ static void alps_process_packet_v7(struct psmouse *psmouse) alps_process_touchpad_packet_v7(psmouse); } -static unsigned char alps_get_pkt_id_ss4_v2(unsigned char *byte) +static enum SS4_PACKET_ID alps_get_pkt_id_ss4_v2(unsigned char *byte) { - unsigned char pkt_id = SS4_PACKET_ID_IDLE; + enum SS4_PACKET_ID pkt_id = SS4_PACKET_ID_IDLE; - if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 && - (byte[3] & 0x88) == 0x08 && byte[4] == 0x10 && byte[5] == 0x00) { - pkt_id = SS4_PACKET_ID_IDLE; - } else if (!(byte[3] & 0x10)) { - pkt_id = SS4_PACKET_ID_ONE; - } else if (!(byte[3] & 0x20)) { + switch (byte[3] & 0x30) { + case 0x00: + if (SS4_IS_IDLE_V2(byte)) { + pkt_id = SS4_PACKET_ID_IDLE; + } else { + pkt_id = SS4_PACKET_ID_ONE; + } + break; + case 0x10: + /* two-finger finger positions */ pkt_id = SS4_PACKET_ID_TWO; - } else { + break; + case 0x20: + /* stick pointer */ + pkt_id = SS4_PACKET_ID_STICK; + break; + case 0x30: + /* third and fourth finger positions */ pkt_id = SS4_PACKET_ID_MULTI; + break; } return pkt_id; @@ -1174,7 +1186,7 @@ static int alps_decode_ss4_v2(struct alps_fields *f, unsigned char *p, struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; - unsigned char pkt_id; + enum SS4_PACKET_ID pkt_id; unsigned int no_data_x, no_data_y; pkt_id = alps_get_pkt_id_ss4_v2(p); @@ -1185,7 +1197,13 @@ static int alps_decode_ss4_v2(struct alps_fields *f, f->mt[0].x = SS4_1F_X_V2(p); f->mt[0].y = SS4_1F_Y_V2(p); f->pressure = ((SS4_1F_Z_V2(p)) * 2) & 0x7f; - f->fingers = 1; + /* + * When a button is held the device will give us events + * with x, y, and pressure of 0. This causes annoying jumps + * if a touch is released while the button is held. + * Handle this by claiming zero contacts. + */ + f->fingers = f->pressure > 0 ? 1 : 0; f->first_mp = 0; f->is_mp = 0; break; @@ -1246,16 +1264,34 @@ static int alps_decode_ss4_v2(struct alps_fields *f, } break; + case SS4_PACKET_ID_STICK: + /* + * x, y, and pressure are decoded in + * alps_process_packet_ss4_v2() + */ + f->first_mp = 0; + f->is_mp = 0; + break; + case SS4_PACKET_ID_IDLE: default: memset(f, 0, sizeof(struct alps_fields)); break; } - f->left = !!(SS4_BTN_V2(p) & 0x01); - if (!(priv->flags & ALPS_BUTTONPAD)) { - f->right = !!(SS4_BTN_V2(p) & 0x02); - f->middle = !!(SS4_BTN_V2(p) & 0x04); + /* handle buttons */ + if (pkt_id == SS4_PACKET_ID_STICK) { + f->ts_left = !!(SS4_BTN_V2(p) & 0x01); + if (!(priv->flags & ALPS_BUTTONPAD)) { + f->ts_right = !!(SS4_BTN_V2(p) & 0x02); + f->ts_middle = !!(SS4_BTN_V2(p) & 0x04); + } + } else { + f->left = !!(SS4_BTN_V2(p) & 0x01); + if (!(priv->flags & ALPS_BUTTONPAD)) { + f->right = !!(SS4_BTN_V2(p) & 0x02); + f->middle = !!(SS4_BTN_V2(p) & 0x04); + } } return 0; @@ -1266,6 +1302,7 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse) struct alps_data *priv = psmouse->private; unsigned char *packet = psmouse->packet; struct input_dev *dev = psmouse->dev; + struct input_dev *dev2 = priv->dev2; struct alps_fields *f = &priv->f; memset(f, 0, sizeof(struct alps_fields)); @@ -1301,6 +1338,27 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse) priv->multi_packet = 0; + /* Report trackstick */ + if (alps_get_pkt_id_ss4_v2(packet) == SS4_PACKET_ID_STICK) { + if (!(priv->flags & ALPS_DUALPOINT)) { + psmouse_warn(psmouse, + "Rejected trackstick packet from non DualPoint device"); + return; + } + + input_report_rel(dev2, REL_X, SS4_TS_X_V2(packet)); + input_report_rel(dev2, REL_Y, SS4_TS_Y_V2(packet)); + input_report_abs(dev2, ABS_PRESSURE, SS4_TS_Z_V2(packet)); + + input_report_key(dev2, BTN_LEFT, f->ts_left); + input_report_key(dev2, BTN_RIGHT, f->ts_right); + input_report_key(dev2, BTN_MIDDLE, f->ts_middle); + + input_sync(dev2); + return; + } + + /* Report touchpad */ alps_report_mt_data(psmouse, (f->fingers <= 4) ? f->fingers : 4); input_mt_report_finger_count(dev, f->fingers); @@ -2695,6 +2753,10 @@ static int alps_set_protocol(struct psmouse *psmouse, if (alps_set_defaults_ss4_v2(psmouse, priv)) return -EIO; + if (priv->fw_ver[1] == 0x1) + priv->flags |= ALPS_DUALPOINT | + ALPS_DUALPOINT_WITH_PRESSURE; + break; } @@ -2767,6 +2829,9 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x14 && ec[1] == 0x02) { protocol = &alps_v8_protocol_data; + } else if (e7[0] == 0x73 && e7[1] == 0x03 && + e7[2] == 0x28 && ec[1] == 0x01) { + protocol = &alps_v8_protocol_data; } else { psmouse_dbg(psmouse, "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec); @@ -2949,6 +3014,10 @@ int alps_init(struct psmouse *psmouse) input_set_capability(dev2, EV_REL, REL_X); input_set_capability(dev2, EV_REL, REL_Y); + if (priv->flags & ALPS_DUALPOINT_WITH_PRESSURE) { + input_set_capability(dev2, EV_ABS, ABS_PRESSURE); + input_set_abs_params(dev2, ABS_PRESSURE, 0, 127, 0, 0); + } input_set_capability(dev2, EV_KEY, BTN_LEFT); input_set_capability(dev2, EV_KEY, BTN_RIGHT); input_set_capability(dev2, EV_KEY, BTN_MIDDLE); diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index d37f814dc447..cde6f4bd8ea2 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -37,12 +37,14 @@ * or there's button activities. * SS4_PACKET_ID_TWO: There's two or more fingers on touchpad * SS4_PACKET_ID_MULTI: There's three or more fingers on touchpad + * SS4_PACKET_ID_STICK: A stick pointer packet */ enum SS4_PACKET_ID { SS4_PACKET_ID_IDLE = 0, SS4_PACKET_ID_ONE, SS4_PACKET_ID_TWO, SS4_PACKET_ID_MULTI, + SS4_PACKET_ID_STICK, }; #define SS4_COUNT_PER_ELECTRODE 256 @@ -52,7 +54,15 @@ enum SS4_PACKET_ID { #define SS4_MASK_NORMAL_BUTTONS 0x07 -#define SS4_1F_X_V2(_b) ((_b[0] & 0x0007) | \ +#define SS4_IS_IDLE_V2(_b) (((_b[0]) == 0x18) && \ + ((_b[1]) == 0x10) && \ + ((_b[2]) == 0x00) && \ + ((_b[3] & 0x88) == 0x08) && \ + ((_b[4]) == 0x10) && \ + ((_b[5]) == 0x00) \ + ) + +#define SS4_1F_X_V2(_b) (((_b[0]) & 0x0007) | \ ((_b[1] << 3) & 0x0078) | \ ((_b[1] << 2) & 0x0380) | \ ((_b[2] << 5) & 0x1C00) \ @@ -99,6 +109,18 @@ enum SS4_PACKET_ID { #define SS4_IS_MF_CONTINUE(_b) ((_b[2] & 0x10) == 0x10) #define SS4_IS_5F_DETECTED(_b) ((_b[2] & 0x10) == 0x10) +#define SS4_TS_X_V2(_b) (s8)( \ + ((_b[0] & 0x01) << 7) | \ + (_b[1] & 0x7F) \ + ) + +#define SS4_TS_Y_V2(_b) (s8)( \ + ((_b[3] & 0x01) << 7) | \ + (_b[2] & 0x7F) \ + ) + +#define SS4_TS_Z_V2(_b) (s8)(_b[4] & 0x7F) + #define SS4_MFPACKET_NO_AX 8160 /* X-Coordinate value */ #define SS4_MFPACKET_NO_AY 4080 /* Y-Coordinate value */ @@ -144,7 +166,7 @@ struct alps_protocol_info { * (aka command mode response) identifies the firmware minor version. This * can be used to distinguish different hardware models which are not * uniquely identifiable through their E7 responses. - * @protocol_info: information about protcol used by the device. + * @protocol_info: information about protocol used by the device. * * Many (but not all) ALPS touchpads can be identified by looking at the * values returned in the "E7 report" and/or the "EC report." This table diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index d15b33813021..fa598f7f4372 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1093,19 +1093,18 @@ static int elan_probe(struct i2c_client *client, if (error) return error; + dev_info(&client->dev, + "Elan Touchpad: Module ID: 0x%04x, Firmware: 0x%04x, Sample: 0x%04x, IAP: 0x%04x\n", + data->product_id, + data->fw_version, + data->sm_version, + data->iap_version); + dev_dbg(&client->dev, - "Elan Touchpad Information:\n" - " Module product ID: 0x%04x\n" - " Firmware Version: 0x%04x\n" - " Sample Version: 0x%04x\n" - " IAP Version: 0x%04x\n" + "Elan Touchpad Extra Information:\n" " Max ABS X,Y: %d,%d\n" " Width X,Y: %d,%d\n" " Resolution X,Y: %d,%d (dots/mm)\n", - data->product_id, - data->fw_version, - data->sm_version, - data->iap_version, data->max_x, data->max_y, data->width_x, data->width_y, data->x_res, data->y_res); diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index cb6aecbc1dc2..e23b2495d52e 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -222,11 +222,13 @@ static int elan_smbus_get_checksum(struct i2c_client *client, static int elan_smbus_get_max(struct i2c_client *client, unsigned int *max_x, unsigned int *max_y) { + int ret; int error; u8 val[3]; - error = i2c_smbus_read_block_data(client, ETP_SMBUS_RANGE_CMD, val); - if (error) { + ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RANGE_CMD, val); + if (ret != 3) { + error = ret < 0 ? ret : -EIO; dev_err(&client->dev, "failed to get dimensions: %d\n", error); return error; } @@ -240,12 +242,13 @@ static int elan_smbus_get_max(struct i2c_client *client, static int elan_smbus_get_resolution(struct i2c_client *client, u8 *hw_res_x, u8 *hw_res_y) { + int ret; int error; u8 val[3]; - error = i2c_smbus_read_block_data(client, - ETP_SMBUS_RESOLUTION_CMD, val); - if (error) { + ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RESOLUTION_CMD, val); + if (ret != 3) { + error = ret < 0 ? ret : -EIO; dev_err(&client->dev, "failed to get resolution: %d\n", error); return error; } @@ -260,12 +263,13 @@ static int elan_smbus_get_num_traces(struct i2c_client *client, unsigned int *x_traces, unsigned int *y_traces) { + int ret; int error; u8 val[3]; - error = i2c_smbus_read_block_data(client, - ETP_SMBUS_XY_TRACENUM_CMD, val); - if (error) { + ret = i2c_smbus_read_block_data(client, ETP_SMBUS_XY_TRACENUM_CMD, val); + if (ret != 3) { + error = ret < 0 ? ret : -EIO; dev_err(&client->dev, "failed to get trace info: %d\n", error); return error; } diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 08e252a42480..db7d1d666ac1 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1134,7 +1134,7 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse, * System76 Pangolin 0x250f01 ? 2 hw buttons * (*) + 3 trackpoint buttons * (**) + 0 trackpoint buttons - * Note: Lenovo L430 and Lenovo L430 have the same fw_version/caps + * Note: Lenovo L430 and Lenovo L530 have the same fw_version/caps */ static void elantech_set_buttonpad_prop(struct psmouse *psmouse) { @@ -1159,6 +1159,13 @@ static const struct dmi_system_id elantech_dmi_has_middle_button[] = { DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H730"), }, }, + { + /* Fujitsu H760 also has a middle button */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H760"), + }, + }, #endif { } }; @@ -1503,10 +1510,10 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = { }, }, { - /* Fujitsu LIFEBOOK E554 does not work with crc_enabled == 0 */ + /* Fujitsu H760 does not work with crc_enabled == 0 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), - DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E554"), + DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H760"), }, }, { @@ -1517,6 +1524,20 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = { }, }, { + /* Fujitsu LIFEBOOK E554 does not work with crc_enabled == 0 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E554"), + }, + }, + { + /* Fujitsu LIFEBOOK E556 does not work with crc_enabled == 0 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E556"), + }, + }, + { /* Fujitsu LIFEBOOK U745 does not work with crc_enabled == 0 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c index c8c6a8cc329d..a7d39689bbfb 100644 --- a/drivers/input/mouse/focaltech.c +++ b/drivers/input/mouse/focaltech.c @@ -43,7 +43,7 @@ int focaltech_detect(struct psmouse *psmouse, bool set_properties) if (set_properties) { psmouse->vendor = "FocalTech"; - psmouse->name = "FocalTech Touchpad"; + psmouse->name = "Touchpad"; } return 0; @@ -146,8 +146,8 @@ static void focaltech_report_state(struct psmouse *psmouse) } input_mt_report_pointer_emulation(dev, true); - input_report_key(psmouse->dev, BTN_LEFT, state->pressed); - input_sync(psmouse->dev); + input_report_key(dev, BTN_LEFT, state->pressed); + input_sync(dev); } static void focaltech_process_touch_packet(struct psmouse *psmouse, @@ -390,7 +390,8 @@ static int focaltech_read_size(struct psmouse *psmouse) return 0; } -void focaltech_set_resolution(struct psmouse *psmouse, unsigned int resolution) +static void focaltech_set_resolution(struct psmouse *psmouse, + unsigned int resolution) { /* not supported yet */ } diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 5784e20542a4..bee267424972 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -1115,10 +1115,6 @@ static int psmouse_extensions(struct psmouse *psmouse, if (psmouse_try_protocol(psmouse, PSMOUSE_TOUCHKIT_PS2, &max_proto, set_properties, true)) return PSMOUSE_TOUCHKIT_PS2; - - if (psmouse_try_protocol(psmouse, PSMOUSE_BYD, - &max_proto, set_properties, true)) - return PSMOUSE_BYD; } /* @@ -1916,7 +1912,7 @@ static int __init psmouse_init(void) synaptics_module_init(); hgpk_module_init(); - kpsmoused_wq = create_singlethread_workqueue("kpsmoused"); + kpsmoused_wq = alloc_ordered_workqueue("kpsmoused", 0); if (!kpsmoused_wq) { pr_err("failed to create kpsmoused workqueue\n"); return -ENOMEM; diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index aa7c5da60800..cb2bf203f4ca 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -29,7 +29,7 @@ * after soft reset, we should wait for 1 ms * before the device becomes operational */ -#define SOFT_RESET_DELAY_MS 3 +#define SOFT_RESET_DELAY_US 3000 /* and after hard reset, we should wait for max 500ms */ #define HARD_RESET_DELAY_MS 500 @@ -311,7 +311,7 @@ static int synaptics_i2c_reset_config(struct i2c_client *client) if (ret) { dev_err(&client->dev, "Unable to reset device\n"); } else { - msleep(SOFT_RESET_DELAY_MS); + usleep_range(SOFT_RESET_DELAY_US, SOFT_RESET_DELAY_US + 100); ret = synaptics_i2c_config(client); if (ret) dev_err(&client->dev, "Unable to config device\n"); diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c index 64a548822da4..082306d7c207 100644 --- a/drivers/input/rmi4/rmi_i2c.c +++ b/drivers/input/rmi4/rmi_i2c.c @@ -182,6 +182,21 @@ static const struct of_device_id rmi_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, rmi_i2c_of_match); #endif +static void rmi_i2c_regulator_bulk_disable(void *data) +{ + struct rmi_i2c_xport *rmi_i2c = data; + + regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies), + rmi_i2c->supplies); +} + +static void rmi_i2c_unregister_transport(void *data) +{ + struct rmi_i2c_xport *rmi_i2c = data; + + rmi_unregister_transport_device(&rmi_i2c->xport); +} + static int rmi_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -224,6 +239,12 @@ static int rmi_i2c_probe(struct i2c_client *client, if (retval < 0) return retval; + retval = devm_add_action_or_reset(&client->dev, + rmi_i2c_regulator_bulk_disable, + rmi_i2c); + if (retval) + return retval; + of_property_read_u32(client->dev.of_node, "syna,startup-delay-ms", &rmi_i2c->startup_delay); @@ -254,23 +275,17 @@ static int rmi_i2c_probe(struct i2c_client *client, client->addr); return retval; } + retval = devm_add_action_or_reset(&client->dev, + rmi_i2c_unregister_transport, + rmi_i2c); + if (retval) + return retval; dev_info(&client->dev, "registered rmi i2c driver at %#04x.\n", client->addr); return 0; } -static int rmi_i2c_remove(struct i2c_client *client) -{ - struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client); - - rmi_unregister_transport_device(&rmi_i2c->xport); - regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies), - rmi_i2c->supplies); - - return 0; -} - #ifdef CONFIG_PM_SLEEP static int rmi_i2c_suspend(struct device *dev) { @@ -367,7 +382,6 @@ static struct i2c_driver rmi_i2c_driver = { }, .id_table = rmi_id, .probe = rmi_i2c_probe, - .remove = rmi_i2c_remove, }; module_i2c_driver(rmi_i2c_driver); diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c index f3e9e488635c..69548d7d1f10 100644 --- a/drivers/input/rmi4/rmi_spi.c +++ b/drivers/input/rmi4/rmi_spi.c @@ -358,6 +358,13 @@ static inline int rmi_spi_of_probe(struct spi_device *spi, } #endif +static void rmi_spi_unregister_transport(void *data) +{ + struct rmi_spi_xport *rmi_spi = data; + + rmi_unregister_transport_device(&rmi_spi->xport); +} + static int rmi_spi_probe(struct spi_device *spi) { struct rmi_spi_xport *rmi_spi; @@ -425,20 +432,16 @@ static int rmi_spi_probe(struct spi_device *spi) dev_err(&spi->dev, "failed to register transport.\n"); return retval; } + retval = devm_add_action_or_reset(&spi->dev, + rmi_spi_unregister_transport, + rmi_spi); + if (retval) + return retval; dev_info(&spi->dev, "registered RMI SPI driver\n"); return 0; } -static int rmi_spi_remove(struct spi_device *spi) -{ - struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi); - - rmi_unregister_transport_device(&rmi_spi->xport); - - return 0; -} - #ifdef CONFIG_PM_SLEEP static int rmi_spi_suspend(struct device *dev) { @@ -515,7 +518,6 @@ static struct spi_driver rmi_spi_driver = { }, .id_table = rmi_id, .probe = rmi_spi_probe, - .remove = rmi_spi_remove, }; module_spi_driver(rmi_spi_driver); diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h index a5eed2ade53d..34da81c006b6 100644 --- a/drivers/input/serio/i8042-io.h +++ b/drivers/input/serio/i8042-io.h @@ -81,7 +81,7 @@ static inline int i8042_platform_init(void) return -EBUSY; #endif - i8042_reset = 1; + i8042_reset = I8042_RESET_ALWAYS; return 0; } diff --git a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h index ee1ad27d6ed0..08a1c10a1448 100644 --- a/drivers/input/serio/i8042-ip22io.h +++ b/drivers/input/serio/i8042-ip22io.h @@ -61,7 +61,7 @@ static inline int i8042_platform_init(void) return -EBUSY; #endif - i8042_reset = 1; + i8042_reset = I8042_RESET_ALWAYS; return 0; } diff --git a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h index f708c75d16f1..1aabea43329e 100644 --- a/drivers/input/serio/i8042-ppcio.h +++ b/drivers/input/serio/i8042-ppcio.h @@ -44,7 +44,7 @@ static inline void i8042_write_command(int val) static inline int i8042_platform_init(void) { - i8042_reset = 1; + i8042_reset = I8042_RESET_ALWAYS; return 0; } diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index afcd1c1a05b2..6231d63860ee 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -130,7 +130,7 @@ static int __init i8042_platform_init(void) } } - i8042_reset = 1; + i8042_reset = I8042_RESET_ALWAYS; return 0; } diff --git a/drivers/input/serio/i8042-unicore32io.h b/drivers/input/serio/i8042-unicore32io.h index 73f5cc124a36..455747552f85 100644 --- a/drivers/input/serio/i8042-unicore32io.h +++ b/drivers/input/serio/i8042-unicore32io.h @@ -61,7 +61,7 @@ static inline int i8042_platform_init(void) if (!request_mem_region(I8042_REGION_START, I8042_REGION_SIZE, "i8042")) return -EBUSY; - i8042_reset = 1; + i8042_reset = I8042_RESET_ALWAYS; return 0; } diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 68f5f4a0f1e7..381d802fe853 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -211,6 +211,12 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Rev 1"), }, }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "PEGATRON CORPORATION"), + DMI_MATCH(DMI_PRODUCT_NAME, "C15B"), + }, + }, { } }; @@ -510,6 +516,18 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { { } }; +/* + * On some Asus laptops, just running self tests cause problems. + */ +static const struct dmi_system_id i8042_dmi_noselftest_table[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */ + }, + }, + { } +}; static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { { /* MSI Wind U-100 */ @@ -793,6 +811,13 @@ static const struct dmi_system_id __initconst i8042_dmi_kbdreset_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "P34"), }, }, + { + /* Schenker XMG C504 - Elantech touchpad */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "XMG"), + DMI_MATCH(DMI_PRODUCT_NAME, "C504"), + }, + }, { } }; @@ -1040,10 +1065,10 @@ static int __init i8042_pnp_init(void) return 0; } -#else +#else /* !CONFIG_PNP */ static inline int i8042_pnp_init(void) { return 0; } static inline void i8042_pnp_exit(void) { } -#endif +#endif /* CONFIG_PNP */ static int __init i8042_platform_init(void) { @@ -1072,12 +1097,18 @@ static int __init i8042_platform_init(void) return retval; #if defined(__ia64__) - i8042_reset = true; + i8042_reset = I8042_RESET_ALWAYS; #endif #ifdef CONFIG_X86 - if (dmi_check_system(i8042_dmi_reset_table)) - i8042_reset = true; + /* Honor module parameter when value is not default */ + if (i8042_reset == I8042_RESET_DEFAULT) { + if (dmi_check_system(i8042_dmi_reset_table)) + i8042_reset = I8042_RESET_ALWAYS; + + if (dmi_check_system(i8042_dmi_noselftest_table)) + i8042_reset = I8042_RESET_NEVER; + } if (dmi_check_system(i8042_dmi_noloop_table)) i8042_noloop = true; diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 405252a884dd..62685a768913 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -48,9 +48,39 @@ static bool i8042_unlock; module_param_named(unlock, i8042_unlock, bool, 0); MODULE_PARM_DESC(unlock, "Ignore keyboard lock."); -static bool i8042_reset; -module_param_named(reset, i8042_reset, bool, 0); -MODULE_PARM_DESC(reset, "Reset controller during init and cleanup."); +enum i8042_controller_reset_mode { + I8042_RESET_NEVER, + I8042_RESET_ALWAYS, + I8042_RESET_ON_S2RAM, +#define I8042_RESET_DEFAULT I8042_RESET_ON_S2RAM +}; +static enum i8042_controller_reset_mode i8042_reset = I8042_RESET_DEFAULT; +static int i8042_set_reset(const char *val, const struct kernel_param *kp) +{ + enum i8042_controller_reset_mode *arg = kp->arg; + int error; + bool reset; + + if (val) { + error = kstrtobool(val, &reset); + if (error) + return error; + } else { + reset = true; + } + + *arg = reset ? I8042_RESET_ALWAYS : I8042_RESET_NEVER; + return 0; +} + +static const struct kernel_param_ops param_ops_reset_param = { + .flags = KERNEL_PARAM_OPS_FL_NOARG, + .set = i8042_set_reset, +}; +#define param_check_reset_param(name, p) \ + __param_check(name, p, enum i8042_controller_reset_mode) +module_param_named(reset, i8042_reset, reset_param, 0); +MODULE_PARM_DESC(reset, "Reset controller on resume, cleanup or both"); static bool i8042_direct; module_param_named(direct, i8042_direct, bool, 0); @@ -357,7 +387,7 @@ static int i8042_aux_write(struct serio *serio, unsigned char c) /* - * i8042_aux_close attempts to clear AUX or KBD port state by disabling + * i8042_port_close attempts to clear AUX or KBD port state by disabling * and then re-enabling it. */ @@ -1019,7 +1049,7 @@ static int i8042_controller_init(void) * Reset the controller and reset CRT to the original value set by BIOS. */ -static void i8042_controller_reset(bool force_reset) +static void i8042_controller_reset(bool s2r_wants_reset) { i8042_flush(); @@ -1044,8 +1074,10 @@ static void i8042_controller_reset(bool force_reset) * Reset the controller if requested. */ - if (i8042_reset || force_reset) + if (i8042_reset == I8042_RESET_ALWAYS || + (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) { i8042_controller_selftest(); + } /* * Restore the original control register setting. @@ -1110,7 +1142,7 @@ static void i8042_dritek_enable(void) * before suspending. */ -static int i8042_controller_resume(bool force_reset) +static int i8042_controller_resume(bool s2r_wants_reset) { int error; @@ -1118,7 +1150,8 @@ static int i8042_controller_resume(bool force_reset) if (error) return error; - if (i8042_reset || force_reset) { + if (i8042_reset == I8042_RESET_ALWAYS || + (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) { error = i8042_controller_selftest(); if (error) return error; @@ -1195,7 +1228,7 @@ static int i8042_pm_resume_noirq(struct device *dev) static int i8042_pm_resume(struct device *dev) { - bool force_reset; + bool want_reset; int i; for (i = 0; i < I8042_NUM_PORTS; i++) { @@ -1218,9 +1251,9 @@ static int i8042_pm_resume(struct device *dev) * off control to the platform firmware, otherwise we can simply restore * the mode. */ - force_reset = pm_resume_via_firmware(); + want_reset = pm_resume_via_firmware(); - return i8042_controller_resume(force_reset); + return i8042_controller_resume(want_reset); } static int i8042_pm_thaw(struct device *dev) @@ -1482,7 +1515,7 @@ static int __init i8042_probe(struct platform_device *dev) i8042_platform_device = dev; - if (i8042_reset) { + if (i8042_reset == I8042_RESET_ALWAYS) { error = i8042_controller_selftest(); if (error) return error; diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 9c927d35c1f5..d189843f3727 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -71,10 +71,7 @@ static void serport_serio_close(struct serio *serio) spin_lock_irqsave(&serport->lock, flags); clear_bit(SERPORT_ACTIVE, &serport->flags); - set_bit(SERPORT_DEAD, &serport->flags); spin_unlock_irqrestore(&serport->lock, flags); - - wake_up_interruptible(&serport->wait); } /* @@ -248,6 +245,19 @@ static long serport_ldisc_compat_ioctl(struct tty_struct *tty, } #endif +static int serport_ldisc_hangup(struct tty_struct *tty) +{ + struct serport *serport = (struct serport *) tty->disc_data; + unsigned long flags; + + spin_lock_irqsave(&serport->lock, flags); + set_bit(SERPORT_DEAD, &serport->flags); + spin_unlock_irqrestore(&serport->lock, flags); + + wake_up_interruptible(&serport->wait); + return 0; +} + static void serport_ldisc_write_wakeup(struct tty_struct * tty) { struct serport *serport = (struct serport *) tty->disc_data; @@ -274,6 +284,7 @@ static struct tty_ldisc_ops serport_ldisc = { .compat_ioctl = serport_ldisc_compat_ioctl, #endif .receive_buf = serport_ldisc_receive, + .hangup = serport_ldisc_hangup, .write_wakeup = serport_ldisc_write_wakeup }; diff --git a/drivers/input/tablet/pegasus_notetaker.c b/drivers/input/tablet/pegasus_notetaker.c index 949dacc78664..47de5a81172f 100644 --- a/drivers/input/tablet/pegasus_notetaker.c +++ b/drivers/input/tablet/pegasus_notetaker.c @@ -40,6 +40,7 @@ #include <linux/input.h> #include <linux/usb/input.h> #include <linux/slab.h> +#include <linux/workqueue.h> /* USB HID defines */ #define USB_REQ_GET_REPORT 0x01 diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index ec41df887278..efca0133e266 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -314,19 +314,6 @@ config TOUCHSCREEN_EGALAX_SERIAL To compile this driver as a module, choose M here: the module will be called egalax_ts_serial. -config TOUCHSCREEN_FT6236 - tristate "FT6236 I2C touchscreen" - depends on I2C - depends on GPIOLIB || COMPILE_TEST - help - Say Y here to enable support for the I2C connected FT6x06 and - FT6x36 family of capacitive touchscreen drivers. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called ft6236. - config TOUCHSCREEN_FUJITSU tristate "Fujitsu serial touchscreen" select SERIO @@ -406,6 +393,18 @@ config TOUCHSCREEN_GUNZE To compile this driver as a module, choose M here: the module will be called gunze. +config TOUCHSCREEN_EKTF2127 + tristate "Elan eKTF2127 I2C touchscreen" + depends on I2C + help + Say Y here if you have an Elan eKTF2127 touchscreen + connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called ektf2127. + config TOUCHSCREEN_ELAN tristate "Elan eKTH I2C touchscreen" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index b4373d6be402..81b86451782d 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -32,11 +32,11 @@ obj-$(CONFIG_TOUCHSCREEN_EDT_FT5X06) += edt-ft5x06.o obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o +obj-$(CONFIG_TOUCHSCREEN_EKTF2127) += ektf2127.o obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o -obj-$(CONFIG_TOUCHSCREEN_FT6236) += ft6236.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 703e295a37ed..28466e358fee 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -1063,9 +1063,15 @@ static const struct edt_i2c_chip_data edt_ft5506_data = { .max_support_points = 10, }; +static const struct edt_i2c_chip_data edt_ft6236_data = { + .max_support_points = 2, +}; + static const struct i2c_device_id edt_ft5x06_ts_id[] = { { .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data }, { .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data }, + /* Note no edt- prefix for compatibility with the ft6236.c driver */ + { .name = "ft6236", .driver_data = (long)&edt_ft6236_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id); @@ -1076,6 +1082,8 @@ static const struct of_device_id edt_ft5x06_of_match[] = { { .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data }, { .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data }, { .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data }, + /* Note focaltech vendor prefix for compatibility with ft6236.c */ + { .compatible = "focaltech,ft6236", .data = &edt_ft6236_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); diff --git a/drivers/input/touchscreen/ektf2127.c b/drivers/input/touchscreen/ektf2127.c new file mode 100644 index 000000000000..0ed34ff787ce --- /dev/null +++ b/drivers/input/touchscreen/ektf2127.c @@ -0,0 +1,336 @@ +/* + * Driver for ELAN eKTF2127 i2c touchscreen controller + * + * For this driver the layout of the Chipone icn8318 i2c + * touchscreencontroller is used. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Author: + * Michel Verlaan <michel.verl@gmail.com> + * Siebren Vroegindeweij <siebren.vroegindeweij@hotmail.com> + * + * Original chipone_icn8318 driver: + * Hans de Goede <hdegoede@redhat.com> + */ + +#include <linux/gpio/consumer.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/input/mt.h> +#include <linux/input/touchscreen.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/delay.h> + +/* Packet header defines (first byte of data send / received) */ +#define EKTF2127_NOISE 0x40 +#define EKTF2127_RESPONSE 0x52 +#define EKTF2127_REQUEST 0x53 +#define EKTF2127_HELLO 0x55 +#define EKTF2127_REPORT 0x5d +#define EKTF2127_CALIB_DONE 0x66 + +/* Register defines (second byte of data send / received) */ +#define EKTF2127_ENV_NOISY 0x41 +#define EKTF2127_HEIGHT 0x60 +#define EKTF2127_WIDTH 0x63 + +/* 2 bytes header + 5 * 3 bytes coordinates + 3 bytes pressure info + footer */ +#define EKTF2127_TOUCH_REPORT_SIZE 21 +#define EKTF2127_MAX_TOUCHES 5 + +struct ektf2127_ts { + struct i2c_client *client; + struct input_dev *input; + struct gpio_desc *power_gpios; + struct touchscreen_properties prop; +}; + +static void ektf2127_parse_coordinates(const u8* buf, unsigned int touch_count, + struct input_mt_pos *touches) +{ + int index = 0; + int i; + + for (i = 0; i < touch_count; i++) { + index = 2 + i * 3; + + touches[i].x = (buf[index] & 0x0f); + touches[i].x <<= 8; + touches[i].x |= buf[index + 2]; + + touches[i].y = (buf[index] & 0xf0); + touches[i].y <<= 4; + touches[i].y |= buf[index + 1]; + } +} + +static void ektf2127_report_event(struct ektf2127_ts *ts, const u8 *buf) +{ + struct input_mt_pos touches[EKTF2127_MAX_TOUCHES]; + int slots[EKTF2127_MAX_TOUCHES]; + unsigned int touch_count, i; + + touch_count = buf[1] & 0x07; + if (touch_count > EKTF2127_MAX_TOUCHES) { + dev_err(&ts->client->dev, + "Too many touches %d > %d\n", + touch_count, EKTF2127_MAX_TOUCHES); + touch_count = EKTF2127_MAX_TOUCHES; + } + + ektf2127_parse_coordinates(buf, touch_count, touches); + input_mt_assign_slots(ts->input, slots, touches, + touch_count, 0); + + for (i = 0; i < touch_count; i++) { + input_mt_slot(ts->input, slots[i]); + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true); + touchscreen_report_pos(ts->input, &ts->prop, + touches[i].x, touches[i].y, true); + } + + input_mt_sync_frame(ts->input); + input_sync(ts->input); +} + +static irqreturn_t ektf2127_irq(int irq, void *dev_id) +{ + struct ektf2127_ts *ts = dev_id; + struct device *dev = &ts->client->dev; + char buf[EKTF2127_TOUCH_REPORT_SIZE]; + int ret; + + ret = i2c_master_recv(ts->client, buf, EKTF2127_TOUCH_REPORT_SIZE); + if (ret != EKTF2127_TOUCH_REPORT_SIZE) { + dev_err(dev, "Error reading touch data: %d\n", ret); + goto out; + } + + switch (buf[0]) { + case EKTF2127_REPORT: + ektf2127_report_event(ts, buf); + break; + + case EKTF2127_NOISE: + if (buf[1] == EKTF2127_ENV_NOISY) + dev_dbg(dev, "Environment is electrically noisy\n"); + break; + + case EKTF2127_HELLO: + case EKTF2127_CALIB_DONE: + break; + + default: + dev_err(dev, "Unexpected packet header byte %#02x\n", buf[0]); + break; + } + +out: + return IRQ_HANDLED; +} + +static int ektf2127_start(struct input_dev *dev) +{ + struct ektf2127_ts *ts = input_get_drvdata(dev); + + enable_irq(ts->client->irq); + gpiod_set_value_cansleep(ts->power_gpios, 1); + + return 0; +} + +static void ektf2127_stop(struct input_dev *dev) +{ + struct ektf2127_ts *ts = input_get_drvdata(dev); + + disable_irq(ts->client->irq); + gpiod_set_value_cansleep(ts->power_gpios, 0); +} + +static int __maybe_unused ektf2127_suspend(struct device *dev) +{ + struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev)); + + mutex_lock(&ts->input->mutex); + if (ts->input->users) + ektf2127_stop(ts->input); + mutex_unlock(&ts->input->mutex); + + return 0; +} + +static int __maybe_unused ektf2127_resume(struct device *dev) +{ + struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev)); + + mutex_lock(&ts->input->mutex); + if (ts->input->users) + ektf2127_start(ts->input); + mutex_unlock(&ts->input->mutex); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(ektf2127_pm_ops, ektf2127_suspend, + ektf2127_resume); + +static int ektf2127_query_dimension(struct i2c_client *client, bool width) +{ + struct device *dev = &client->dev; + const char *what = width ? "width" : "height"; + u8 what_code = width ? EKTF2127_WIDTH : EKTF2127_HEIGHT; + u8 buf[4]; + int ret; + int error; + + /* Request dimension */ + buf[0] = EKTF2127_REQUEST; + buf[1] = width ? EKTF2127_WIDTH : EKTF2127_HEIGHT; + buf[2] = 0x00; + buf[3] = 0x00; + ret = i2c_master_send(client, buf, sizeof(buf)); + if (ret != sizeof(buf)) { + error = ret < 0 ? ret : -EIO; + dev_err(dev, "Failed to request %s: %d\n", what, error); + return error; + } + + msleep(20); + + /* Read response */ + ret = i2c_master_recv(client, buf, sizeof(buf)); + if (ret != sizeof(buf)) { + error = ret < 0 ? ret : -EIO; + dev_err(dev, "Failed to receive %s data: %d\n", what, error); + return error; + } + + if (buf[0] != EKTF2127_RESPONSE || buf[1] != what_code) { + dev_err(dev, "Unexpected %s data: %#02x %#02x\n", + what, buf[0], buf[1]); + return -EIO; + } + + return (((buf[3] & 0xf0) << 4) | buf[2]) - 1; +} + +static int ektf2127_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct ektf2127_ts *ts; + struct input_dev *input; + u8 buf[4]; + int max_x, max_y; + int error; + + if (!client->irq) { + dev_err(dev, "Error no irq specified\n"); + return -EINVAL; + } + + ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + /* This requests the gpio *and* turns on the touchscreen controller */ + ts->power_gpios = devm_gpiod_get(dev, "power", GPIOD_OUT_HIGH); + if (IS_ERR(ts->power_gpios)) { + error = PTR_ERR(ts->power_gpios); + if (error != -EPROBE_DEFER) + dev_err(dev, "Error getting power gpio: %d\n", error); + return error; + } + + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + + input->name = client->name; + input->id.bustype = BUS_I2C; + input->open = ektf2127_start; + input->close = ektf2127_stop; + + ts->client = client; + + /* Read hello (ignore result, depends on initial power state) */ + msleep(20); + i2c_master_recv(ts->client, buf, sizeof(buf)); + + /* Read resolution from chip */ + max_x = ektf2127_query_dimension(client, true); + if (max_x < 0) + return max_x; + + max_y = ektf2127_query_dimension(client, false); + if (max_y < 0) + return max_y; + + input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_x, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_y, 0, 0); + touchscreen_parse_properties(input, true, &ts->prop); + + error = input_mt_init_slots(input, EKTF2127_MAX_TOUCHES, + INPUT_MT_DIRECT | + INPUT_MT_DROP_UNUSED | + INPUT_MT_TRACK); + if (error) + return error; + + ts->input = input; + input_set_drvdata(input, ts); + + error = devm_request_threaded_irq(dev, client->irq, + NULL, ektf2127_irq, + IRQF_ONESHOT, client->name, ts); + if (error) { + dev_err(dev, "Error requesting irq: %d\n", error); + return error; + } + + /* Stop device till opened */ + ektf2127_stop(ts->input); + + error = input_register_device(input); + if (error) + return error; + + i2c_set_clientdata(client, ts); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id ektf2127_of_match[] = { + { .compatible = "elan,ektf2127" }, + {} +}; +MODULE_DEVICE_TABLE(of, ektf2127_of_match); +#endif + +static const struct i2c_device_id ektf2127_i2c_id[] = { + { "ektf2127", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ektf2127_i2c_id); + +static struct i2c_driver ektf2127_driver = { + .driver = { + .name = "elan_ektf2127", + .pm = &ektf2127_pm_ops, + .of_match_table = of_match_ptr(ektf2127_of_match), + }, + .probe = ektf2127_probe, + .id_table = ektf2127_i2c_id, +}; +module_i2c_driver(ektf2127_driver); + +MODULE_DESCRIPTION("ELAN eKTF2127 I2C Touchscreen Driver"); +MODULE_AUTHOR("Michel Verlaan, Siebren Vroegindeweij"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index ac09855fa435..02aec284deca 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -298,7 +298,7 @@ static u16 elants_i2c_parse_version(u8 *buf) return get_unaligned_be32(buf) >> 4; } -static int elants_i2c_query_fw_id(struct elants_data *ts) +static int elants_i2c_query_hw_version(struct elants_data *ts) { struct i2c_client *client = ts->client; int error, retry_cnt; @@ -318,8 +318,13 @@ static int elants_i2c_query_fw_id(struct elants_data *ts) error, (int)sizeof(resp), resp); } - dev_err(&client->dev, - "Failed to read fw id or fw id is invalid\n"); + if (error) { + dev_err(&client->dev, + "Failed to read fw id: %d\n", error); + return error; + } + + dev_err(&client->dev, "Invalid fw id: %#04x\n", ts->hw_version); return -EINVAL; } @@ -508,7 +513,7 @@ static int elants_i2c_fastboot(struct i2c_client *client) static int elants_i2c_initialize(struct elants_data *ts) { struct i2c_client *client = ts->client; - int error, retry_cnt; + int error, error2, retry_cnt; const u8 hello_packet[] = { 0x55, 0x55, 0x55, 0x55 }; const u8 recov_packet[] = { 0x55, 0x55, 0x80, 0x80 }; u8 buf[HEADER_SIZE]; @@ -553,18 +558,22 @@ static int elants_i2c_initialize(struct elants_data *ts) } } + /* hw version is available even if device in recovery state */ + error2 = elants_i2c_query_hw_version(ts); if (!error) - error = elants_i2c_query_fw_id(ts); + error = error2; + if (!error) error = elants_i2c_query_fw_version(ts); + if (!error) + error = elants_i2c_query_test_version(ts); + if (!error) + error = elants_i2c_query_bc_version(ts); + if (!error) + error = elants_i2c_query_ts_info(ts); - if (error) { + if (error) ts->iap_mode = ELAN_IAP_RECOVERY; - } else { - elants_i2c_query_test_version(ts); - elants_i2c_query_bc_version(ts); - elants_i2c_query_ts_info(ts); - } return 0; } diff --git a/drivers/input/touchscreen/fsl-imx25-tcq.c b/drivers/input/touchscreen/fsl-imx25-tcq.c index fe9877a6af9e..d50ee490c9cc 100644 --- a/drivers/input/touchscreen/fsl-imx25-tcq.c +++ b/drivers/input/touchscreen/fsl-imx25-tcq.c @@ -55,6 +55,7 @@ static const struct of_device_id mx25_tcq_ids[] = { { .compatible = "fsl,imx25-tcq", }, { /* Sentinel */ } }; +MODULE_DEVICE_TABLE(of, mx25_tcq_ids); #define TSC_4WIRE_PRE_INDEX 0 #define TSC_4WIRE_X_INDEX 1 diff --git a/drivers/input/touchscreen/ft6236.c b/drivers/input/touchscreen/ft6236.c deleted file mode 100644 index d240d2e212bd..000000000000 --- a/drivers/input/touchscreen/ft6236.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * FocalTech FT6236 TouchScreen driver. - * - * Copyright (c) 2010 Focal tech Ltd. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/delay.h> -#include <linux/gpio/consumer.h> -#include <linux/i2c.h> -#include <linux/input.h> -#include <linux/input/mt.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/property.h> - -#define FT6236_MAX_TOUCH_POINTS 2 - -#define FT6236_REG_TH_GROUP 0x80 -#define FT6236_REG_PERIODACTIVE 0x88 -#define FT6236_REG_LIB_VER_H 0xa1 -#define FT6236_REG_LIB_VER_L 0xa2 -#define FT6236_REG_CIPHER 0xa3 -#define FT6236_REG_FIRMID 0xa6 -#define FT6236_REG_FOCALTECH_ID 0xa8 -#define FT6236_REG_RELEASE_CODE_ID 0xaf - -#define FT6236_EVENT_PRESS_DOWN 0 -#define FT6236_EVENT_LIFT_UP 1 -#define FT6236_EVENT_CONTACT 2 -#define FT6236_EVENT_NO_EVENT 3 - -struct ft6236_data { - struct i2c_client *client; - struct input_dev *input; - struct gpio_desc *reset_gpio; - u32 max_x; - u32 max_y; - bool invert_x; - bool invert_y; - bool swap_xy; -}; - -/* - * This struct is a touchpoint as stored in hardware. Note that the id, - * as well as the event, are stored in the upper nybble of the hi byte. - */ -struct ft6236_touchpoint { - union { - u8 xhi; - u8 event; - }; - u8 xlo; - union { - u8 yhi; - u8 id; - }; - u8 ylo; - u8 weight; - u8 misc; -} __packed; - -/* This packet represents the register map as read from offset 0 */ -struct ft6236_packet { - u8 dev_mode; - u8 gest_id; - u8 touches; - struct ft6236_touchpoint points[FT6236_MAX_TOUCH_POINTS]; -} __packed; - -static int ft6236_read(struct i2c_client *client, u8 reg, u8 len, void *data) -{ - int error; - - error = i2c_smbus_read_i2c_block_data(client, reg, len, data); - if (error < 0) - return error; - - if (error != len) - return -EIO; - - return 0; -} - -static irqreturn_t ft6236_interrupt(int irq, void *dev_id) -{ - struct ft6236_data *ft6236 = dev_id; - struct device *dev = &ft6236->client->dev; - struct input_dev *input = ft6236->input; - struct ft6236_packet buf; - u8 touches; - int i, error; - - error = ft6236_read(ft6236->client, 0, sizeof(buf), &buf); - if (error) { - dev_err(dev, "read touchdata failed %d\n", error); - return IRQ_HANDLED; - } - - touches = buf.touches & 0xf; - if (touches > FT6236_MAX_TOUCH_POINTS) { - dev_dbg(dev, - "%d touch points reported, only %d are supported\n", - touches, FT6236_MAX_TOUCH_POINTS); - touches = FT6236_MAX_TOUCH_POINTS; - } - - for (i = 0; i < touches; i++) { - struct ft6236_touchpoint *point = &buf.points[i]; - u16 x = ((point->xhi & 0xf) << 8) | buf.points[i].xlo; - u16 y = ((point->yhi & 0xf) << 8) | buf.points[i].ylo; - u8 event = point->event >> 6; - u8 id = point->id >> 4; - bool act = (event == FT6236_EVENT_PRESS_DOWN || - event == FT6236_EVENT_CONTACT); - - input_mt_slot(input, id); - input_mt_report_slot_state(input, MT_TOOL_FINGER, act); - if (!act) - continue; - - if (ft6236->invert_x) - x = ft6236->max_x - x; - - if (ft6236->invert_y) - y = ft6236->max_y - y; - - if (ft6236->swap_xy) { - input_report_abs(input, ABS_MT_POSITION_X, y); - input_report_abs(input, ABS_MT_POSITION_Y, x); - } else { - input_report_abs(input, ABS_MT_POSITION_X, x); - input_report_abs(input, ABS_MT_POSITION_Y, y); - } - } - - input_mt_sync_frame(input); - input_sync(input); - - return IRQ_HANDLED; -} - -static u8 ft6236_debug_read_byte(struct ft6236_data *ft6236, u8 reg) -{ - struct i2c_client *client = ft6236->client; - u8 val = 0; - int error; - - error = ft6236_read(client, reg, 1, &val); - if (error) - dev_dbg(&client->dev, - "error reading register 0x%02x: %d\n", reg, error); - - return val; -} - -static void ft6236_debug_info(struct ft6236_data *ft6236) -{ - struct device *dev = &ft6236->client->dev; - - dev_dbg(dev, "Touch threshold is %d\n", - ft6236_debug_read_byte(ft6236, FT6236_REG_TH_GROUP) * 4); - dev_dbg(dev, "Report rate is %dHz\n", - ft6236_debug_read_byte(ft6236, FT6236_REG_PERIODACTIVE) * 10); - dev_dbg(dev, "Firmware library version 0x%02x%02x\n", - ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_H), - ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_L)); - dev_dbg(dev, "Firmware version 0x%02x\n", - ft6236_debug_read_byte(ft6236, FT6236_REG_FIRMID)); - dev_dbg(dev, "Chip vendor ID 0x%02x\n", - ft6236_debug_read_byte(ft6236, FT6236_REG_CIPHER)); - dev_dbg(dev, "CTPM vendor ID 0x%02x\n", - ft6236_debug_read_byte(ft6236, FT6236_REG_FOCALTECH_ID)); - dev_dbg(dev, "Release code version 0x%02x\n", - ft6236_debug_read_byte(ft6236, FT6236_REG_RELEASE_CODE_ID)); -} - -static void ft6236_reset(struct ft6236_data *ft6236) -{ - if (!ft6236->reset_gpio) - return; - - gpiod_set_value_cansleep(ft6236->reset_gpio, 1); - usleep_range(5000, 20000); - gpiod_set_value_cansleep(ft6236->reset_gpio, 0); - msleep(300); -} - -static int ft6236_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct device *dev = &client->dev; - struct ft6236_data *ft6236; - struct input_dev *input; - u32 fuzz_x = 0, fuzz_y = 0; - u8 val; - int error; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) - return -ENXIO; - - if (!client->irq) { - dev_err(dev, "irq is missing\n"); - return -EINVAL; - } - - ft6236 = devm_kzalloc(dev, sizeof(*ft6236), GFP_KERNEL); - if (!ft6236) - return -ENOMEM; - - ft6236->client = client; - ft6236->reset_gpio = devm_gpiod_get_optional(dev, "reset", - GPIOD_OUT_LOW); - if (IS_ERR(ft6236->reset_gpio)) { - error = PTR_ERR(ft6236->reset_gpio); - if (error != -EPROBE_DEFER) - dev_err(dev, "error getting reset gpio: %d\n", error); - return error; - } - - ft6236_reset(ft6236); - - /* verify that the controller is present */ - error = ft6236_read(client, 0x00, 1, &val); - if (error) { - dev_err(dev, "failed to read from controller: %d\n", error); - return error; - } - - ft6236_debug_info(ft6236); - - input = devm_input_allocate_device(dev); - if (!input) - return -ENOMEM; - - ft6236->input = input; - input->name = client->name; - input->id.bustype = BUS_I2C; - - if (device_property_read_u32(dev, "touchscreen-size-x", - &ft6236->max_x) || - device_property_read_u32(dev, "touchscreen-size-y", - &ft6236->max_y)) { - dev_err(dev, "touchscreen-size-x and/or -y missing\n"); - return -EINVAL; - } - - device_property_read_u32(dev, "touchscreen-fuzz-x", &fuzz_x); - device_property_read_u32(dev, "touchscreen-fuzz-y", &fuzz_y); - ft6236->invert_x = device_property_read_bool(dev, - "touchscreen-inverted-x"); - ft6236->invert_y = device_property_read_bool(dev, - "touchscreen-inverted-y"); - ft6236->swap_xy = device_property_read_bool(dev, - "touchscreen-swapped-x-y"); - - if (ft6236->swap_xy) { - input_set_abs_params(input, ABS_MT_POSITION_X, 0, - ft6236->max_y, fuzz_y, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, 0, - ft6236->max_x, fuzz_x, 0); - } else { - input_set_abs_params(input, ABS_MT_POSITION_X, 0, - ft6236->max_x, fuzz_x, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, 0, - ft6236->max_y, fuzz_y, 0); - } - - error = input_mt_init_slots(input, FT6236_MAX_TOUCH_POINTS, - INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); - if (error) - return error; - - error = devm_request_threaded_irq(dev, client->irq, NULL, - ft6236_interrupt, IRQF_ONESHOT, - client->name, ft6236); - if (error) { - dev_err(dev, "request irq %d failed: %d\n", client->irq, error); - return error; - } - - error = input_register_device(input); - if (error) { - dev_err(dev, "failed to register input device: %d\n", error); - return error; - } - - return 0; -} - -#ifdef CONFIG_OF -static const struct of_device_id ft6236_of_match[] = { - { .compatible = "focaltech,ft6236", }, - { } -}; -MODULE_DEVICE_TABLE(of, ft6236_of_match); -#endif - -static const struct i2c_device_id ft6236_id[] = { - { "ft6236", }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ft6236_id); - -static struct i2c_driver ft6236_driver = { - .driver = { - .name = "ft6236", - .of_match_table = of_match_ptr(ft6236_of_match), - }, - .probe = ft6236_probe, - .id_table = ft6236_id, -}; -module_i2c_driver(ft6236_driver); - -MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>"); -MODULE_AUTHOR("Noralf Trønnes <noralf@tronnes.org>"); -MODULE_DESCRIPTION("FocalTech FT6236 TouchScreen driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index 8275267eac25..7098e0a47019 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -21,17 +21,25 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/log2.h> /* ADC configuration registers field define */ #define ADC_AIEN (0x1 << 7) #define ADC_CONV_DISABLE 0x1F +#define ADC_AVGE (0x1 << 5) #define ADC_CAL (0x1 << 7) #define ADC_CALF 0x2 #define ADC_12BIT_MODE (0x2 << 2) +#define ADC_CONV_MODE_MASK (0x3 << 2) #define ADC_IPG_CLK 0x00 +#define ADC_INPUT_CLK_MASK 0x3 #define ADC_CLK_DIV_8 (0x03 << 5) +#define ADC_CLK_DIV_MASK (0x3 << 5) #define ADC_SHORT_SAMPLE_MODE (0x0 << 4) +#define ADC_SAMPLE_MODE_MASK (0x1 << 4) #define ADC_HARDWARE_TRIGGER (0x1 << 13) +#define ADC_AVGS_SHIFT 14 +#define ADC_AVGS_MASK (0x3 << 14) #define SELECT_CHANNEL_4 0x04 #define SELECT_CHANNEL_1 0x01 #define DISABLE_CONVERSION_INT (0x0 << 7) @@ -84,8 +92,10 @@ struct imx6ul_tsc { struct clk *adc_clk; struct gpio_desc *xnur_gpio; - int measure_delay_time; - int pre_charge_time; + u32 measure_delay_time; + u32 pre_charge_time; + bool average_enable; + u32 average_select; struct completion completion; }; @@ -96,17 +106,23 @@ struct imx6ul_tsc { */ static int imx6ul_adc_init(struct imx6ul_tsc *tsc) { - int adc_hc = 0; - int adc_gc; - int adc_gs; - int adc_cfg; - int timeout; + u32 adc_hc = 0; + u32 adc_gc; + u32 adc_gs; + u32 adc_cfg; + unsigned long timeout; reinit_completion(&tsc->completion); adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG); + adc_cfg &= ~(ADC_CONV_MODE_MASK | ADC_INPUT_CLK_MASK); adc_cfg |= ADC_12BIT_MODE | ADC_IPG_CLK; + adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE_MASK); adc_cfg |= ADC_CLK_DIV_8 | ADC_SHORT_SAMPLE_MODE; + if (tsc->average_enable) { + adc_cfg &= ~ADC_AVGS_MASK; + adc_cfg |= (tsc->average_select) << ADC_AVGS_SHIFT; + } adc_cfg &= ~ADC_HARDWARE_TRIGGER; writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG); @@ -118,6 +134,8 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc) /* start ADC calibration */ adc_gc = readl(tsc->adc_regs + REG_ADC_GC); adc_gc |= ADC_CAL; + if (tsc->average_enable) + adc_gc |= ADC_AVGE; writel(adc_gc, tsc->adc_regs + REG_ADC_GC); timeout = wait_for_completion_timeout @@ -148,7 +166,7 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc) */ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc) { - int adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4; + u32 adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4; adc_hc0 = DISABLE_CONVERSION_INT; writel(adc_hc0, tsc->adc_regs + REG_ADC_HC0); @@ -173,8 +191,8 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc) */ static void imx6ul_tsc_set(struct imx6ul_tsc *tsc) { - int basic_setting = 0; - int start; + u32 basic_setting = 0; + u32 start; basic_setting |= tsc->measure_delay_time << 8; basic_setting |= DETECT_4_WIRE_MODE | AUTO_MEASURE; @@ -209,8 +227,8 @@ static int imx6ul_tsc_init(struct imx6ul_tsc *tsc) static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc) { - int tsc_flow; - int adc_cfg; + u32 tsc_flow; + u32 adc_cfg; /* TSC controller enters to idle status */ tsc_flow = readl(tsc->tsc_regs + REG_TSC_FLOW_CONTROL); @@ -227,8 +245,8 @@ static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc) static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc) { unsigned long timeout = jiffies + msecs_to_jiffies(2); - int state_machine; - int debug_mode2; + u32 state_machine; + u32 debug_mode2; do { if (time_after(jiffies, timeout)) @@ -246,10 +264,10 @@ static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc) static irqreturn_t tsc_irq_fn(int irq, void *dev_id) { struct imx6ul_tsc *tsc = dev_id; - int status; - int value; - int x, y; - int start; + u32 status; + u32 value; + u32 x, y; + u32 start; status = readl(tsc->tsc_regs + REG_TSC_INT_STATUS); @@ -289,8 +307,8 @@ static irqreturn_t tsc_irq_fn(int irq, void *dev_id) static irqreturn_t adc_irq_fn(int irq, void *dev_id) { struct imx6ul_tsc *tsc = dev_id; - int coco; - int value; + u32 coco; + u32 value; coco = readl(tsc->adc_regs + REG_ADC_HS); if (coco & 0x01) { @@ -346,6 +364,7 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) int err; int tsc_irq; int adc_irq; + u32 average_samples; tsc = devm_kzalloc(&pdev->dev, sizeof(*tsc), GFP_KERNEL); if (!tsc) @@ -450,6 +469,30 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) if (err) tsc->pre_charge_time = 0xfff; + err = of_property_read_u32(np, "touchscreen-average-samples", + &average_samples); + if (err) + average_samples = 1; + + switch (average_samples) { + case 1: + tsc->average_enable = false; + tsc->average_select = 0; /* value unused; initialize anyway */ + break; + case 4: + case 8: + case 16: + case 32: + tsc->average_enable = true; + tsc->average_select = ilog2(average_samples) - 2; + break; + default: + dev_err(&pdev->dev, + "touchscreen-average-samples (%u) must be 1, 4, 8, 16 or 32\n", + average_samples); + return -EINVAL; + } + err = input_register_device(tsc->input); if (err) { dev_err(&pdev->dev, diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c index ea3b6a5b83e6..729b3c89324c 100644 --- a/drivers/input/touchscreen/jornada720_ts.c +++ b/drivers/input/touchscreen/jornada720_ts.c @@ -13,6 +13,7 @@ * HP Jornada 710/720/729 Touchscreen Driver */ +#include <linux/gpio/consumer.h> #include <linux/platform_device.h> #include <linux/input.h> #include <linux/interrupt.h> @@ -20,9 +21,7 @@ #include <linux/slab.h> #include <linux/io.h> -#include <mach/hardware.h> #include <mach/jornada720.h> -#include <mach/irqs.h> MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>"); MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver"); @@ -30,6 +29,7 @@ MODULE_LICENSE("GPL v2"); struct jornada_ts { struct input_dev *dev; + struct gpio_desc *gpio; int x_data[4]; /* X sample values */ int y_data[4]; /* Y sample values */ }; @@ -71,8 +71,8 @@ static irqreturn_t jornada720_ts_interrupt(int irq, void *dev_id) struct input_dev *input = jornada_ts->dev; int x, y; - /* If GPIO_GPIO9 is set to high then report pen up */ - if (GPLR & GPIO_GPIO(9)) { + /* If gpio is high then report pen up */ + if (gpiod_get_value(jornada_ts->gpio)) { input_report_key(input, BTN_TOUCH, 0); input_sync(input); } else { @@ -101,7 +101,7 @@ static int jornada720_ts_probe(struct platform_device *pdev) { struct jornada_ts *jornada_ts; struct input_dev *input_dev; - int error; + int error, irq; jornada_ts = devm_kzalloc(&pdev->dev, sizeof(*jornada_ts), GFP_KERNEL); if (!jornada_ts) @@ -113,6 +113,14 @@ static int jornada720_ts_probe(struct platform_device *pdev) platform_set_drvdata(pdev, jornada_ts); + jornada_ts->gpio = devm_gpiod_get(&pdev->dev, "penup", GPIOD_IN); + if (IS_ERR(jornada_ts->gpio)) + return PTR_ERR(jornada_ts->gpio); + + irq = gpiod_to_irq(jornada_ts->gpio); + if (irq <= 0) + return irq < 0 ? irq : -EINVAL; + jornada_ts->dev = input_dev; input_dev->name = "HP Jornada 7xx Touchscreen"; @@ -125,8 +133,7 @@ static int jornada720_ts_probe(struct platform_device *pdev) input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0); input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0); - error = devm_request_irq(&pdev->dev, IRQ_GPIO9, - jornada720_ts_interrupt, + error = devm_request_irq(&pdev->dev, irq, jornada720_ts_interrupt, IRQF_TRIGGER_RISING, "HP7XX Touchscreen driver", pdev); if (error) { diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c index 913e25a994b4..ef64f36c5ffc 100644 --- a/drivers/input/touchscreen/mc13783_ts.c +++ b/drivers/input/touchscreen/mc13783_ts.c @@ -37,7 +37,6 @@ struct mc13783_ts_priv { struct input_dev *idev; struct mc13xxx *mc13xxx; struct delayed_work work; - struct workqueue_struct *workq; unsigned int sample[4]; struct mc13xxx_ts_platform_data *touch; }; @@ -54,7 +53,7 @@ static irqreturn_t mc13783_ts_handler(int irq, void *data) * be rescheduled for immediate execution here. However the rearm * delay is HZ / 50 which is acceptable. */ - queue_delayed_work(priv->workq, &priv->work, 0); + schedule_delayed_work(&priv->work, 0); return IRQ_HANDLED; } @@ -106,16 +105,18 @@ static void mc13783_ts_report_sample(struct mc13783_ts_priv *priv) dev_dbg(&idev->dev, "report (%d, %d, %d)\n", x1, y1, 0x1000 - cr0); - queue_delayed_work(priv->workq, &priv->work, HZ / 50); - } else + schedule_delayed_work(&priv->work, HZ / 50); + } else { dev_dbg(&idev->dev, "report release\n"); + } input_report_abs(idev, ABS_PRESSURE, cr0 ? 0x1000 - cr0 : cr0); input_report_key(idev, BTN_TOUCH, cr0); input_sync(idev); - } else + } else { dev_dbg(&idev->dev, "discard event\n"); + } } static void mc13783_ts_work(struct work_struct *work) @@ -189,14 +190,6 @@ static int __init mc13783_ts_probe(struct platform_device *pdev) goto err_free_mem; } - /* - * We need separate workqueue because mc13783_adc_do_conversion - * uses keventd and thus would deadlock. - */ - priv->workq = create_singlethread_workqueue("mc13783_ts"); - if (!priv->workq) - goto err_free_mem; - idev->name = MC13783_TS_NAME; idev->dev.parent = &pdev->dev; @@ -215,14 +208,12 @@ static int __init mc13783_ts_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "register input device failed with %d\n", ret); - goto err_destroy_wq; + goto err_free_mem; } platform_set_drvdata(pdev, priv); return 0; -err_destroy_wq: - destroy_workqueue(priv->workq); err_free_mem: input_free_device(idev); kfree(priv); @@ -233,7 +224,6 @@ static int mc13783_ts_remove(struct platform_device *pdev) { struct mc13783_ts_priv *priv = platform_get_drvdata(pdev); - destroy_workqueue(priv->workq); input_unregister_device(priv->idev); kfree(priv); diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index fb5fb9140ca9..703d7f983d0a 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -33,7 +33,7 @@ /***************************************************************** * Protocol - * Version : MIP 4.0 Rev 4.6 + * Version : MIP 4.0 Rev 5.4 *****************************************************************/ /* Address */ @@ -81,6 +81,9 @@ #define MIP4_R1_INFO_IC_HW_CATEGORY 0x77 #define MIP4_R1_INFO_CONTACT_THD_SCR 0x78 #define MIP4_R1_INFO_CONTACT_THD_KEY 0x7A +#define MIP4_R1_INFO_PID 0x7C +#define MIP4_R1_INFO_VID 0x7E +#define MIP4_R1_INFO_SLAVE_ADDR 0x80 #define MIP4_R0_EVENT 0x02 #define MIP4_R1_EVENT_SUPPORTED_FUNC 0x00 @@ -157,6 +160,9 @@ struct mip4_ts { char phys[32]; char product_name[16]; + u16 product_id; + char ic_name[4]; + char fw_name[32]; unsigned int max_x; unsigned int max_y; @@ -263,6 +269,35 @@ static int mip4_query_device(struct mip4_ts *ts) dev_dbg(&ts->client->dev, "product name: %.*s\n", (int)sizeof(ts->product_name), ts->product_name); + /* Product ID */ + cmd[0] = MIP4_R0_INFO; + cmd[1] = MIP4_R1_INFO_PID; + error = mip4_i2c_xfer(ts, cmd, sizeof(cmd), buf, 2); + if (error) { + dev_warn(&ts->client->dev, + "Failed to retrieve product id: %d\n", error); + } else { + ts->product_id = get_unaligned_le16(&buf[0]); + dev_dbg(&ts->client->dev, "product id: %04X\n", ts->product_id); + } + + /* Firmware name */ + snprintf(ts->fw_name, sizeof(ts->fw_name), + "melfas_mip4_%04X.fw", ts->product_id); + dev_dbg(&ts->client->dev, "firmware name: %s\n", ts->fw_name); + + /* IC name */ + cmd[0] = MIP4_R0_INFO; + cmd[1] = MIP4_R1_INFO_IC_NAME; + error = mip4_i2c_xfer(ts, cmd, sizeof(cmd), + ts->ic_name, sizeof(ts->ic_name)); + if (error) + dev_warn(&ts->client->dev, + "Failed to retrieve IC name: %d\n", error); + else + dev_dbg(&ts->client->dev, "IC name: %.*s\n", + (int)sizeof(ts->ic_name), ts->ic_name); + /* Firmware version */ error = mip4_get_fw_version(ts); if (error) @@ -1256,11 +1291,11 @@ static ssize_t mip4_sysfs_fw_update(struct device *dev, const struct firmware *fw; int error; - error = request_firmware(&fw, MIP4_FW_NAME, dev); + error = request_firmware(&fw, ts->fw_name, dev); if (error) { dev_err(&ts->client->dev, "Failed to retrieve firmware %s: %d\n", - MIP4_FW_NAME, error); + ts->fw_name, error); return error; } @@ -1326,7 +1361,7 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev, * paired with current firmware in the chip. */ count = snprintf(buf, PAGE_SIZE, "%.*s\n", - (int)sizeof(ts->product_name), ts->product_name); + (int)sizeof(ts->product_name), ts->product_name); mutex_unlock(&ts->input->mutex); @@ -1335,9 +1370,50 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev, static DEVICE_ATTR(hw_version, S_IRUGO, mip4_sysfs_read_hw_version, NULL); +static ssize_t mip4_sysfs_read_product_id(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mip4_ts *ts = i2c_get_clientdata(client); + size_t count; + + mutex_lock(&ts->input->mutex); + + count = snprintf(buf, PAGE_SIZE, "%04X\n", ts->product_id); + + mutex_unlock(&ts->input->mutex); + + return count; +} + +static DEVICE_ATTR(product_id, S_IRUGO, mip4_sysfs_read_product_id, NULL); + +static ssize_t mip4_sysfs_read_ic_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mip4_ts *ts = i2c_get_clientdata(client); + size_t count; + + mutex_lock(&ts->input->mutex); + + count = snprintf(buf, PAGE_SIZE, "%.*s\n", + (int)sizeof(ts->ic_name), ts->ic_name); + + mutex_unlock(&ts->input->mutex); + + return count; +} + +static DEVICE_ATTR(ic_name, S_IRUGO, mip4_sysfs_read_ic_name, NULL); + static struct attribute *mip4_attrs[] = { &dev_attr_fw_version.attr, &dev_attr_hw_version.attr, + &dev_attr_product_id.attr, + &dev_attr_ic_name.attr, &dev_attr_update_fw.attr, NULL, }; @@ -1401,6 +1477,7 @@ static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id) input->id.bustype = BUS_I2C; input->id.vendor = 0x13c5; + input->id.product = ts->product_id; input->open = mip4_input_open; input->close = mip4_input_close; @@ -1538,6 +1615,6 @@ static struct i2c_driver mip4_driver = { module_i2c_driver(mip4_driver); MODULE_DESCRIPTION("MELFAS MIP4 Touchscreen"); -MODULE_VERSION("2016.03.12"); +MODULE_VERSION("2016.10.31"); MODULE_AUTHOR("Sangwon Jee <jeesw@melfas.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index d159e14f4d20..3bb0637d832e 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/delay.h> @@ -404,7 +400,6 @@ static int __maybe_unused pixcir_i2c_ts_resume(struct device *dev) mutex_lock(&input->mutex); if (device_may_wakeup(&client->dev)) { - if (!input->users) { ret = pixcir_stop(ts); if (ret) { @@ -431,13 +426,7 @@ static const struct of_device_id pixcir_of_match[]; static int pixcir_parse_dt(struct device *dev, struct pixcir_i2c_ts_data *tsdata) { - const struct of_device_id *match; - - match = of_match_device(of_match_ptr(pixcir_of_match), dev); - if (!match) - return -EINVAL; - - tsdata->chip = (const struct pixcir_i2c_chip_data *)match->data; + tsdata->chip = of_device_get_match_data(dev); if (!tsdata->chip) return -EINVAL; diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c index a99fb5cac5a0..2658afa016c9 100644 --- a/drivers/input/touchscreen/raydium_i2c_ts.c +++ b/drivers/input/touchscreen/raydium_i2c_ts.c @@ -669,7 +669,7 @@ static int raydium_i2c_do_update_firmware(struct raydium_data *ts, if (ts->boot_mode == RAYDIUM_TS_MAIN) { dev_err(&client->dev, - "failied to jump to boot loader: %d\n", + "failed to jump to boot loader: %d\n", error); return -EIO; } diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c index f502c8488be8..404830a4a366 100644 --- a/drivers/input/touchscreen/silead.c +++ b/drivers/input/touchscreen/silead.c @@ -29,6 +29,7 @@ #include <linux/input/touchscreen.h> #include <linux/pm.h> #include <linux/irq.h> +#include <linux/regulator/consumer.h> #include <asm/unaligned.h> @@ -73,6 +74,7 @@ struct silead_ts_data { struct i2c_client *client; struct gpio_desc *gpio_power; struct input_dev *input; + struct regulator_bulk_data regulators[2]; char fw_name[64]; struct touchscreen_properties prop; u32 max_fingers; @@ -433,6 +435,13 @@ static int silead_ts_set_default_fw_name(struct silead_ts_data *data, } #endif +static void silead_disable_regulator(void *arg) +{ + struct silead_ts_data *data = arg; + + regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators); +} + static int silead_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -465,6 +474,26 @@ static int silead_ts_probe(struct i2c_client *client, if (client->irq <= 0) return -ENODEV; + data->regulators[0].supply = "vddio"; + data->regulators[1].supply = "avdd"; + error = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->regulators), + data->regulators); + if (error) + return error; + + /* + * Enable regulators at probe and disable them at remove, we need + * to keep the chip powered otherwise it forgets its firmware. + */ + error = regulator_bulk_enable(ARRAY_SIZE(data->regulators), + data->regulators); + if (error) + return error; + + error = devm_add_action_or_reset(dev, silead_disable_regulator, data); + if (error) + return error; + /* Power GPIO pin */ data->gpio_power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW); if (IS_ERR(data->gpio_power)) { diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index 73861ad22df4..a9132603ab34 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -23,7 +23,7 @@ #include <asm/unaligned.h> #define WDT87XX_NAME "wdt87xx_i2c" -#define WDT87XX_DRV_VER "0.9.7" +#define WDT87XX_DRV_VER "0.9.8" #define WDT87XX_FW_NAME "wdt87xx_fw.bin" #define WDT87XX_CFG_NAME "wdt87xx_cfg.bin" @@ -157,6 +157,7 @@ /* Controller requires minimum 300us between commands */ #define WDT_COMMAND_DELAY_MS 2 #define WDT_FLASH_WRITE_DELAY_MS 4 +#define WDT_FLASH_ERASE_DELAY_MS 200 #define WDT_FW_RESET_TIME 2500 struct wdt87xx_sys_param { @@ -726,7 +727,7 @@ static int wdt87xx_write_firmware(struct i2c_client *client, const void *chunk) break; } - msleep(50); + msleep(WDT_FLASH_ERASE_DELAY_MS); error = wdt87xx_write_data(client, data, start_addr, page_size); diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 1534e9b0788c..90d6be3c26cc 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -500,7 +500,7 @@ static int wm97xx_ts_input_open(struct input_dev *idev) { struct wm97xx *wm = input_get_drvdata(idev); - wm->ts_workq = create_singlethread_workqueue("kwm97xx"); + wm->ts_workq = alloc_ordered_workqueue("kwm97xx", 0); if (wm->ts_workq == NULL) { dev_err(wm->dev, "Failed to create workqueue\n"); |