From 42beaccb2a66d7dc4a051a686122ed41c9a2ce1a Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 17 Nov 2015 09:33:14 -0800 Subject: Input: db9 - clear unused function pointers db9_parport_cb is a local uninitialized structure and the member function pointers will be pointing to arbitrary locations unless they are cleared. Fixes: 2260c419b52b ("Input: db9 - use parallel port device model") Signed-off-by: Sudip Mukherjee Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/db9.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input') diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c index 932d07307454..da326090c2b0 100644 --- a/drivers/input/joystick/db9.c +++ b/drivers/input/joystick/db9.c @@ -592,6 +592,7 @@ static void db9_attach(struct parport *pp) return; } + memset(&db9_parport_cb, 0, sizeof(db9_parport_cb)); db9_parport_cb.flags = PARPORT_FLAG_EXCL; pd = parport_register_dev_model(pp, "db9", &db9_parport_cb, port_idx); -- cgit v1.3 From eb12a5f51f4332bd75a9d35caa4d79e8300af3a7 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 17 Nov 2015 09:33:29 -0800 Subject: Input: gamecon - clear unused function pointers gc_parport_cb is a local uninitialized structure and the member function pointers will be pointing to arbitrary locations unless they are cleared. Fixes: a517e87c3dfc ("Input: gamecon - use parallel port device model") Signed-off-by: Sudip Mukherjee Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/gamecon.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input') diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index 5a672dcac0d8..eae14d512353 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -951,6 +951,7 @@ static void gc_attach(struct parport *pp) pads = gc_cfg[port_idx].args + 1; n_pads = gc_cfg[port_idx].nargs - 1; + memset(&gc_parport_cb, 0, sizeof(gc_parport_cb)); gc_parport_cb.flags = PARPORT_FLAG_EXCL; pd = parport_register_dev_model(pp, "gamecon", &gc_parport_cb, -- cgit v1.3 From 3855e9e4d30ed5207319fb5ef8b0fb416d873cbf Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 17 Nov 2015 09:33:41 -0800 Subject: Input: turbografx - clear unused function pointers tgfx_parport_cb is a local uninitialized structure and the member function pointers will be pointing to arbitrary locations unless they are cleared. Fixes: 4de27a638a99 ("Input: turbografx - use parallel port device model") Signed-off-by: Sudip Mukherjee Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/turbografx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input') diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index 9f5bca26bd2f..77f575dd0901 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -181,6 +181,7 @@ static void tgfx_attach(struct parport *pp) n_buttons = tgfx_cfg[port_idx].args + 1; n_devs = tgfx_cfg[port_idx].nargs - 1; + memset(&tgfx_parport_cb, 0, sizeof(tgfx_parport_cb)); tgfx_parport_cb.flags = PARPORT_FLAG_EXCL; pd = parport_register_dev_model(pp, "turbografx", &tgfx_parport_cb, -- cgit v1.3 From d1f2a031ab902020393dc1dc2d721ea95578b5a8 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 17 Nov 2015 09:33:48 -0800 Subject: Input: walkera0701 - clear unused function pointers walkera0701_parport_cb is a local uninitialized structure and the member function pointers will be pointing to arbitrary locations unless they are cleared. Fixes: 221bcb24c653 ("Input: walkera0701 - use parallel port device model") Signed-off-by: Sudip Mukherjee Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/walkera0701.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input') diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c index d88f5dd3c9d9..413e343f55f7 100644 --- a/drivers/input/joystick/walkera0701.c +++ b/drivers/input/joystick/walkera0701.c @@ -218,6 +218,7 @@ static void walkera0701_attach(struct parport *pp) w->parport = pp; + memset(&walkera0701_parport_cb, 0, sizeof(walkera0701_parport_cb)); walkera0701_parport_cb.flags = PARPORT_FLAG_EXCL; walkera0701_parport_cb.irq_func = walkera0701_irq_handler; walkera0701_parport_cb.private = w; -- cgit v1.3 From 0c6da0733bff3bc7aaa1dcd63fefdbbca5a7a5f8 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 17 Nov 2015 09:33:58 -0800 Subject: Input: parkbd - clear unused function pointers parkbd_parport_cb is a local uninitialized structure and the member function pointers will be pointing to arbitrary locations unless they are cleared. Fixes: 33ca8ab97cbb ("Input: parkbd - use parallel port device model") Signed-off-by: Sudip Mukherjee Signed-off-by: Dmitry Torokhov --- drivers/input/serio/parkbd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input') diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c index 92c31b8f8fb4..1edfac78d4ac 100644 --- a/drivers/input/serio/parkbd.c +++ b/drivers/input/serio/parkbd.c @@ -145,6 +145,7 @@ static int parkbd_getport(struct parport *pp) { struct pardev_cb parkbd_parport_cb; + memset(&parkbd_parport_cb, 0, sizeof(parkbd_parport_cb)); parkbd_parport_cb.irq_func = parkbd_interrupt; parkbd_parport_cb.flags = PARPORT_FLAG_EXCL; -- cgit v1.3 From c67566c6a1dc0dd0309a54e63656e57050cbb9fe Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 20 Nov 2015 10:58:07 -0800 Subject: Input: atmel_mxt_ts - add generic platform data for Chromebooks Apparently people are installing generic Linux distributions not only on Pixels but also on other Chromebooks. Unfortunately on all of them Atmel parts assigned names ATML0000 and ATML0001, and do not carry any other configuration data. So let's create generic instance of platform data that should cover most of them (we assume that they will not be using T100 objects, since with those Google mapped BTN_LEFT onto a different GPIO, so slightly different keymap would be needed, but I think we used parts with T100 on ARM devices where we thankfully have DTS and can describe the devices better). Tested-by: Rich K Reviewed-by: Javier Martinez Canillas Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index c5622058c22b..159120be9614 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -2487,6 +2487,31 @@ static struct mxt_acpi_platform_data samus_platform_data[] = { { } }; +static unsigned int chromebook_tp_buttons[] = { + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + BTN_LEFT +}; + +static struct mxt_acpi_platform_data chromebook_platform_data[] = { + { + /* Touchpad */ + .hid = "ATML0000", + .pdata = { + .t19_num_keys = ARRAY_SIZE(chromebook_tp_buttons), + .t19_keymap = chromebook_tp_buttons, + }, + }, + { + /* Touchscreen */ + .hid = "ATML0001", + }, + { } +}; + static const struct dmi_system_id mxt_dmi_table[] = { { /* 2015 Google Pixel */ @@ -2497,6 +2522,14 @@ static const struct dmi_system_id mxt_dmi_table[] = { }, .driver_data = samus_platform_data, }, + { + /* Other Google Chromebooks */ + .ident = "Chromebook", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), + }, + .driver_data = chromebook_platform_data, + }, { } }; -- cgit v1.3 From 8e20cf2bce122ce9262d6034ee5d5b76fbb92f96 Mon Sep 17 00:00:00 2001 From: Vladis Dronov Date: Tue, 1 Dec 2015 13:09:17 -0800 Subject: Input: aiptek - fix crash on detecting device without endpoints The aiptek driver crashes in aiptek_probe() when a specially crafted USB device without endpoints is detected. This fix adds a check that the device has proper configuration expected by the driver. Also an error return value is changed to more matching one in one of the error paths. Reported-by: Ralf Spenneberg Signed-off-by: Vladis Dronov Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/aiptek.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index e7f966da6efa..78ca44840d60 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -1819,6 +1819,14 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0); + /* Verify that a device really has an endpoint */ + if (intf->altsetting[0].desc.bNumEndpoints < 1) { + dev_err(&intf->dev, + "interface has %d endpoints, but must have minimum 1\n", + intf->altsetting[0].desc.bNumEndpoints); + err = -EINVAL; + goto fail3; + } endpoint = &intf->altsetting[0].endpoint[0].desc; /* Go set up our URB, which is called when the tablet receives @@ -1861,6 +1869,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) if (i == ARRAY_SIZE(speeds)) { dev_info(&intf->dev, "Aiptek tried all speeds, no sane response\n"); + err = -EINVAL; goto fail3; } -- cgit v1.3 From 1cf44efa1e4f0adc6998ad3087fa5220b682743c Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 2 Dec 2015 16:13:54 -0800 Subject: Input: arizona-haptic - fix disabling of haptics device A small copy and paste error was preventing the haptics device being disabled. This patch corrects the value written on disable. Signed-off-by: Charles Keepax Signed-off-by: Dmitry Torokhov --- drivers/input/misc/arizona-haptics.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c index 4bf678541496..d5994a745ffa 100644 --- a/drivers/input/misc/arizona-haptics.c +++ b/drivers/input/misc/arizona-haptics.c @@ -97,8 +97,7 @@ static void arizona_haptics_work(struct work_struct *work) ret = regmap_update_bits(arizona->regmap, ARIZONA_HAPTICS_CONTROL_1, - ARIZONA_HAP_CTRL_MASK, - 1 << ARIZONA_HAP_CTRL_SHIFT); + ARIZONA_HAP_CTRL_MASK, 0); if (ret != 0) { dev_err(arizona->dev, "Failed to stop haptics: %d\n", ret); -- cgit v1.3 From b7d21058b40bff47e69a9af7f00c90942ddfbd4f Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 11 Dec 2015 13:22:39 -0800 Subject: Input: atmel_mxt_ts - add maxtouch to I2C table for module autoload The Atmel maxtouch DT binding documents that the compatible string for the device is "atmel,maxtouch" and the I2C core always reports a module alias of the form i2c:alias where alias is the compatible string model: $ grep MODALIAS /sys/devices/platform/12e00000.i2c/i2c-8/8-004b/uevent MODALIAS=i2c:maxtouch But there isn't maxtouch entry in the I2C device ID table so when the i2c:maxtouch MODALIAS uevent is reported, kmod is not able to match the alias with a module to load: $ modinfo atmel_mxt_ts | grep alias alias: of:N*T*Catmel,maxtouch alias: i2c:mXT224 alias: i2c:atmel_mxt_tp alias: i2c:atmel_mxt_ts alias: i2c:qt602240_ts So add the maxtouch entry to the I2C device ID table to allow the module to be autoloaded when the device is registered via OF. Signed-off-by: Javier Martinez Canillas Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 159120be9614..2d5794ec338b 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -2734,6 +2734,7 @@ static const struct i2c_device_id mxt_id[] = { { "qt602240_ts", 0 }, { "atmel_mxt_ts", 0 }, { "atmel_mxt_tp", 0 }, + { "maxtouch", 0 }, { "mXT224", 0 }, { } }; -- cgit v1.3 From 3eab4588c958205451fd80dfd219955c5e91c18b Mon Sep 17 00:00:00 2001 From: Charlie Mooney Date: Tue, 15 Dec 2015 11:32:10 -0800 Subject: Input: elan_i2c - set input device's vendor and product IDs Previously the "vendor" and "product" IDs for the elan_i2c driver simply reported 0000. This patch modifies the elan_i2c driver to include the Elan vendor ID and the touchpad's product id under input/input*/{vendor,product}. Specifically, this is to allow us to apply a generic Elan gestures config that will apply to all Elan touchpads on ChromeOS. These configs match to input devices in various ways, but one major way is by matching on vendor ID. Adding this patch allows the default Elan touchpad config to be applied to Elan touchpads in this kernel by matching on devices that have vendor ID 04f3. Note that product ID is also available via custom sysfs entry "product_id" as well. Signed-off-by: Charlie Mooney Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 5e1665bbaa0b..2f589857a039 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -41,6 +41,7 @@ #define DRIVER_NAME "elan_i2c" #define ELAN_DRIVER_VERSION "1.6.1" +#define ELAN_VENDOR_ID 0x04f3 #define ETP_MAX_PRESSURE 255 #define ETP_FWIDTH_REDUCE 90 #define ETP_FINGER_WIDTH 15 @@ -914,6 +915,8 @@ static int elan_setup_input_device(struct elan_tp_data *data) input->name = "Elan Touchpad"; input->id.bustype = BUS_I2C; + input->id.vendor = ELAN_VENDOR_ID; + input->id.product = data->product_id; input_set_drvdata(input, data); error = input_mt_init_slots(input, ETP_MAX_FINGERS, -- cgit v1.3 From 478e5ed1c3f6928ece7fffd712ba728b1f92217d Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 18 Dec 2015 15:51:48 -0800 Subject: Input: elants_i2c - fix wake-on-touch When sending "SLEEP" command to the controller it ceases scanning completely and is unable to wake the system up from sleep, so if it is configured as a wakeup source we should simply configure interrupt for wakeup and rely on idle logic within the controller to reduce power consumption while it is not used. Signed-off-by: James Chen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/elants_i2c.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 17cc20ef4923..ac09855fa435 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -1316,7 +1316,13 @@ static int __maybe_unused elants_i2c_suspend(struct device *dev) disable_irq(client->irq); - if (device_may_wakeup(dev) || ts->keep_power_in_suspend) { + if (device_may_wakeup(dev)) { + /* + * The device will automatically enter idle mode + * that has reduced power consumption. + */ + ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0); + } else if (ts->keep_power_in_suspend) { for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { error = elants_i2c_send(client, set_sleep_cmd, sizeof(set_sleep_cmd)); @@ -1326,10 +1332,6 @@ static int __maybe_unused elants_i2c_suspend(struct device *dev) dev_err(&client->dev, "suspend command failed: %d\n", error); } - - if (device_may_wakeup(dev)) - ts->wake_irq_enabled = - (enable_irq_wake(client->irq) == 0); } else { elants_i2c_power_off(ts); } @@ -1345,10 +1347,11 @@ static int __maybe_unused elants_i2c_resume(struct device *dev) int retry_cnt; int error; - if (device_may_wakeup(dev) && ts->wake_irq_enabled) - disable_irq_wake(client->irq); - - if (ts->keep_power_in_suspend) { + if (device_may_wakeup(dev)) { + if (ts->wake_irq_enabled) + disable_irq_wake(client->irq); + elants_i2c_sw_reset(client); + } else if (ts->keep_power_in_suspend) { for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { error = elants_i2c_send(client, set_active_cmd, sizeof(set_active_cmd)); -- cgit v1.3 From d9202af2ffa083f096684fd5f4b530aebbc07439 Mon Sep 17 00:00:00 2001 From: Timo Teräs Date: Sat, 16 Jan 2016 20:22:07 -0800 Subject: Input: rotary_encoder - convert to devm-* api MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use managed resource API for simplifying error paths. Signed-off-by: Timo Teräs Signed-off-by: Dmitry Torokhov --- drivers/input/misc/rotary_encoder.c | 86 +++++++++++-------------------------- 1 file changed, 25 insertions(+), 61 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 8aee71986430..ebbadf3f0579 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -211,8 +211,8 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic if (!of_id || !np) return NULL; - pdata = kzalloc(sizeof(struct rotary_encoder_platform_data), - GFP_KERNEL); + pdata = devm_kzalloc(dev, sizeof(struct rotary_encoder_platform_data), + GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); @@ -277,12 +277,13 @@ static int rotary_encoder_probe(struct platform_device *pdev) } } - encoder = kzalloc(sizeof(struct rotary_encoder), GFP_KERNEL); - input = input_allocate_device(); - if (!encoder || !input) { - err = -ENOMEM; - goto exit_free_mem; - } + encoder = devm_kzalloc(dev, sizeof(struct rotary_encoder), GFP_KERNEL); + if (!encoder) + return -ENOMEM; + + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; encoder->input = input; encoder->pdata = pdata; @@ -301,16 +302,18 @@ static int rotary_encoder_probe(struct platform_device *pdev) } /* request the GPIOs */ - err = gpio_request_one(pdata->gpio_a, GPIOF_IN, dev_name(dev)); + err = devm_gpio_request_one(dev, pdata->gpio_a, GPIOF_IN, + dev_name(dev)); if (err) { dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_a); - goto exit_free_mem; + return err; } - err = gpio_request_one(pdata->gpio_b, GPIOF_IN, dev_name(dev)); + err = devm_gpio_request_one(dev, pdata->gpio_b, GPIOF_IN, + dev_name(dev)); if (err) { dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_b); - goto exit_free_gpio_a; + return err; } encoder->irq_a = gpio_to_irq(pdata->gpio_a); @@ -331,30 +334,29 @@ static int rotary_encoder_probe(struct platform_device *pdev) default: dev_err(dev, "'%d' is not a valid steps-per-period value\n", pdata->steps_per_period); - err = -EINVAL; - goto exit_free_gpio_b; + return -EINVAL; } - err = request_irq(encoder->irq_a, handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - DRV_NAME, encoder); + err = devm_request_irq(dev, encoder->irq_a, handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + DRV_NAME, encoder); if (err) { dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a); - goto exit_free_gpio_b; + return err; } - err = request_irq(encoder->irq_b, handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - DRV_NAME, encoder); + err = devm_request_irq(dev, encoder->irq_b, handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + DRV_NAME, encoder); if (err) { dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b); - goto exit_free_irq_a; + return err; } err = input_register_device(input); if (err) { dev_err(dev, "failed to register input device\n"); - goto exit_free_irq_b; + return err; } device_init_wakeup(&pdev->dev, pdata->wakeup_source); @@ -362,43 +364,6 @@ static int rotary_encoder_probe(struct platform_device *pdev) platform_set_drvdata(pdev, encoder); return 0; - -exit_free_irq_b: - free_irq(encoder->irq_b, encoder); -exit_free_irq_a: - free_irq(encoder->irq_a, encoder); -exit_free_gpio_b: - gpio_free(pdata->gpio_b); -exit_free_gpio_a: - gpio_free(pdata->gpio_a); -exit_free_mem: - input_free_device(input); - kfree(encoder); - if (!dev_get_platdata(&pdev->dev)) - kfree(pdata); - - return err; -} - -static int rotary_encoder_remove(struct platform_device *pdev) -{ - struct rotary_encoder *encoder = platform_get_drvdata(pdev); - const struct rotary_encoder_platform_data *pdata = encoder->pdata; - - device_init_wakeup(&pdev->dev, false); - - free_irq(encoder->irq_a, encoder); - free_irq(encoder->irq_b, encoder); - gpio_free(pdata->gpio_a); - gpio_free(pdata->gpio_b); - - input_unregister_device(encoder->input); - kfree(encoder); - - if (!dev_get_platdata(&pdev->dev)) - kfree(pdata); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -432,7 +397,6 @@ static SIMPLE_DEV_PM_OPS(rotary_encoder_pm_ops, static struct platform_driver rotary_encoder_driver = { .probe = rotary_encoder_probe, - .remove = rotary_encoder_remove, .driver = { .name = DRV_NAME, .pm = &rotary_encoder_pm_ops, -- cgit v1.3 From dee520e368f54e1bc0e387bfda7ef4e0676e248b Mon Sep 17 00:00:00 2001 From: Timo Teräs Date: Sat, 16 Jan 2016 20:46:24 -0800 Subject: Input: rotary_encoder - use threaded irqs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert to use threaded IRQs to support GPIOs that can sleep. Protect the irq handler with mutex as it can be triggered from two different irq lines accessing the same state. This allows using GPIO expanders behind I2C or SPI bus. Signed-off-by: Timo Teräs Signed-off-by: Dmitry Torokhov --- drivers/input/misc/rotary_encoder.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index ebbadf3f0579..aeeaaea69610 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -33,6 +33,7 @@ struct rotary_encoder { struct input_dev *input; const struct rotary_encoder_platform_data *pdata; + struct mutex access_mutex; unsigned int axis; unsigned int pos; @@ -48,8 +49,8 @@ struct rotary_encoder { static int rotary_encoder_get_state(const struct rotary_encoder_platform_data *pdata) { - int a = !!gpio_get_value(pdata->gpio_a); - int b = !!gpio_get_value(pdata->gpio_b); + int a = !!gpio_get_value_cansleep(pdata->gpio_a); + int b = !!gpio_get_value_cansleep(pdata->gpio_b); a ^= pdata->inverted_a; b ^= pdata->inverted_b; @@ -94,6 +95,8 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) struct rotary_encoder *encoder = dev_id; int state; + mutex_lock(&encoder->access_mutex); + state = rotary_encoder_get_state(encoder->pdata); switch (state) { @@ -115,6 +118,8 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) break; } + mutex_unlock(&encoder->access_mutex); + return IRQ_HANDLED; } @@ -123,6 +128,8 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) struct rotary_encoder *encoder = dev_id; int state; + mutex_lock(&encoder->access_mutex); + state = rotary_encoder_get_state(encoder->pdata); switch (state) { @@ -140,6 +147,8 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) break; } + mutex_unlock(&encoder->access_mutex); + return IRQ_HANDLED; } @@ -149,6 +158,8 @@ static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id) unsigned char sum; int state; + mutex_lock(&encoder->access_mutex); + state = rotary_encoder_get_state(encoder->pdata); /* @@ -189,6 +200,8 @@ static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id) out: encoder->last_stable = state; + mutex_unlock(&encoder->access_mutex); + return IRQ_HANDLED; } @@ -285,6 +298,8 @@ static int rotary_encoder_probe(struct platform_device *pdev) if (!input) return -ENOMEM; + mutex_init(&encoder->access_mutex); + encoder->input = input; encoder->pdata = pdata; @@ -337,17 +352,19 @@ static int rotary_encoder_probe(struct platform_device *pdev) return -EINVAL; } - err = devm_request_irq(dev, encoder->irq_a, handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - DRV_NAME, encoder); + err = devm_request_threaded_irq(dev, encoder->irq_a, NULL, handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + DRV_NAME, encoder); if (err) { dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a); return err; } - err = devm_request_irq(dev, encoder->irq_b, handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - DRV_NAME, encoder); + err = devm_request_threaded_irq(dev, encoder->irq_b, NULL, handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + DRV_NAME, encoder); if (err) { dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b); return err; -- cgit v1.3 From 6a6f70b3864a5f8f862b7153c1b4d1217f50e4d4 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 16 Jan 2016 20:50:06 -0800 Subject: Input: rotary_encoder - mark PM methods as __maybe_unused Instead of guarding PM methods with #ifdef let's mark them as __maybe_unused as it allows for better compile coverage. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/rotary_encoder.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index aeeaaea69610..713247146167 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -383,8 +383,7 @@ static int rotary_encoder_probe(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int rotary_encoder_suspend(struct device *dev) +static int __maybe_unused rotary_encoder_suspend(struct device *dev) { struct rotary_encoder *encoder = dev_get_drvdata(dev); @@ -396,7 +395,7 @@ static int rotary_encoder_suspend(struct device *dev) return 0; } -static int rotary_encoder_resume(struct device *dev) +static int __maybe_unused rotary_encoder_resume(struct device *dev) { struct rotary_encoder *encoder = dev_get_drvdata(dev); @@ -407,10 +406,9 @@ static int rotary_encoder_resume(struct device *dev) return 0; } -#endif static SIMPLE_DEV_PM_OPS(rotary_encoder_pm_ops, - rotary_encoder_suspend, rotary_encoder_resume); + rotary_encoder_suspend, rotary_encoder_resume); static struct platform_driver rotary_encoder_driver = { .probe = rotary_encoder_probe, -- cgit v1.3 From 77a8f0ad38844b5d4163424c4feb8abbbbb55af0 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 17 Jan 2016 10:18:12 -0800 Subject: Input: rotary_encoder - convert to use gpiod API Instead of using old GPIO API, let's switch to GPIOD API, which automatically handles polarity. Signed-off-by: Dmitry Torokhov --- arch/arm/mach-pxa/raumfeld.c | 21 +++++++++-- drivers/input/misc/rotary_encoder.c | 74 +++++++++++++++++-------------------- include/linux/rotary_encoder.h | 4 -- 3 files changed, 50 insertions(+), 49 deletions(-) (limited to 'drivers/input') diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index 36571a9a44fe..bac88e0be58a 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -366,14 +367,21 @@ static struct pxaohci_platform_data raumfeld_ohci_info = { * Rotary encoder input device */ +static struct gpiod_lookup_table raumfeld_rotary_gpios_table = { + .dev_id = "rotary-encoder.0", + .table = { + GPIO_LOOKUP_IDX("gpio-0", + GPIO_VOLENC_A, NULL, 0, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-0", + GPIO_VOLENC_B, NULL, 1, GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct rotary_encoder_platform_data raumfeld_rotary_encoder_info = { .steps = 24, .axis = REL_X, .relative_axis = 1, - .gpio_a = GPIO_VOLENC_A, - .gpio_b = GPIO_VOLENC_B, - .inverted_a = 1, - .inverted_b = 0, }; static struct platform_device rotary_encoder_device = { @@ -1051,7 +1059,10 @@ static void __init raumfeld_controller_init(void) int ret; pxa3xx_mfp_config(ARRAY_AND_SIZE(raumfeld_controller_pin_config)); + + gpiod_add_lookup_table(&raumfeld_rotary_gpios_table); platform_device_register(&rotary_encoder_device); + spi_register_board_info(ARRAY_AND_SIZE(controller_spi_devices)); i2c_register_board_info(0, &raumfeld_controller_i2c_board_info, 1); @@ -1086,6 +1097,8 @@ static void __init raumfeld_speaker_init(void) i2c_register_board_info(0, &raumfeld_connector_i2c_board_info, 1); platform_device_register(&smc91x_device); + + gpiod_add_lookup_table(&raumfeld_rotary_gpios_table); platform_device_register(&rotary_encoder_device); raumfeld_audio_init(); diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 713247146167..471175e5306b 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -20,12 +20,11 @@ #include #include #include -#include +#include #include #include #include #include -#include #include #define DRV_NAME "rotary-encoder" @@ -38,6 +37,9 @@ struct rotary_encoder { unsigned int axis; unsigned int pos; + struct gpio_desc *gpio_a; + struct gpio_desc *gpio_b; + unsigned int irq_a; unsigned int irq_b; @@ -47,13 +49,10 @@ struct rotary_encoder { char last_stable; }; -static int rotary_encoder_get_state(const struct rotary_encoder_platform_data *pdata) +static int rotary_encoder_get_state(struct rotary_encoder *encoder) { - int a = !!gpio_get_value_cansleep(pdata->gpio_a); - int b = !!gpio_get_value_cansleep(pdata->gpio_b); - - a ^= pdata->inverted_a; - b ^= pdata->inverted_b; + int a = !!gpiod_get_value_cansleep(encoder->gpio_a); + int b = !!gpiod_get_value_cansleep(encoder->gpio_b); return ((a << 1) | b); } @@ -97,7 +96,7 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) mutex_lock(&encoder->access_mutex); - state = rotary_encoder_get_state(encoder->pdata); + state = rotary_encoder_get_state(encoder); switch (state) { case 0x0: @@ -130,7 +129,7 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) mutex_lock(&encoder->access_mutex); - state = rotary_encoder_get_state(encoder->pdata); + state = rotary_encoder_get_state(encoder); switch (state) { case 0x00: @@ -160,7 +159,7 @@ static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id) mutex_lock(&encoder->access_mutex); - state = rotary_encoder_get_state(encoder->pdata); + state = rotary_encoder_get_state(encoder); /* * We encode the previous and the current state using a byte. @@ -218,7 +217,6 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic of_match_device(rotary_encoder_of_match, dev); struct device_node *np = dev->of_node; struct rotary_encoder_platform_data *pdata; - enum of_gpio_flags flags; int error; if (!of_id || !np) @@ -232,12 +230,6 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic of_property_read_u32(np, "rotary-encoder,steps", &pdata->steps); of_property_read_u32(np, "linux,axis", &pdata->axis); - pdata->gpio_a = of_get_gpio_flags(np, 0, &flags); - pdata->inverted_a = flags & OF_GPIO_ACTIVE_LOW; - - pdata->gpio_b = of_get_gpio_flags(np, 1, &flags); - pdata->inverted_b = flags & OF_GPIO_ACTIVE_LOW; - pdata->relative_axis = of_property_read_bool(np, "rotary-encoder,relative-axis"); pdata->rollover = of_property_read_bool(np, "rotary-encoder,rollover"); @@ -294,14 +286,32 @@ static int rotary_encoder_probe(struct platform_device *pdev) if (!encoder) return -ENOMEM; + mutex_init(&encoder->access_mutex); + encoder->pdata = pdata; + + encoder->gpio_a = devm_gpiod_get_index(dev, NULL, 0, GPIOD_IN); + if (IS_ERR(encoder->gpio_a)) { + err = PTR_ERR(encoder->gpio_a); + dev_err(dev, "unable to get GPIO at index 0: %d\n", err); + return err; + } + + encoder->irq_a = gpiod_to_irq(encoder->gpio_a); + + encoder->gpio_b = devm_gpiod_get_index(dev, NULL, 1, GPIOD_IN); + if (IS_ERR(encoder->gpio_b)) { + err = PTR_ERR(encoder->gpio_b); + dev_err(dev, "unable to get GPIO at index 1: %d\n", err); + return err; + } + + encoder->irq_b = gpiod_to_irq(encoder->gpio_b); + input = devm_input_allocate_device(dev); if (!input) return -ENOMEM; - mutex_init(&encoder->access_mutex); - encoder->input = input; - encoder->pdata = pdata; input->name = pdev->name; input->id.bustype = BUS_HOST; @@ -316,32 +326,14 @@ static int rotary_encoder_probe(struct platform_device *pdev) pdata->axis, 0, pdata->steps, 0, 1); } - /* request the GPIOs */ - err = devm_gpio_request_one(dev, pdata->gpio_a, GPIOF_IN, - dev_name(dev)); - if (err) { - dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_a); - return err; - } - - err = devm_gpio_request_one(dev, pdata->gpio_b, GPIOF_IN, - dev_name(dev)); - if (err) { - dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_b); - return err; - } - - encoder->irq_a = gpio_to_irq(pdata->gpio_a); - encoder->irq_b = gpio_to_irq(pdata->gpio_b); - switch (pdata->steps_per_period) { case 4: handler = &rotary_encoder_quarter_period_irq; - encoder->last_stable = rotary_encoder_get_state(pdata); + encoder->last_stable = rotary_encoder_get_state(encoder); break; case 2: handler = &rotary_encoder_half_period_irq; - encoder->last_stable = rotary_encoder_get_state(pdata); + encoder->last_stable = rotary_encoder_get_state(encoder); break; case 1: handler = &rotary_encoder_irq; diff --git a/include/linux/rotary_encoder.h b/include/linux/rotary_encoder.h index fe3dc64e5aeb..4536c813a1e9 100644 --- a/include/linux/rotary_encoder.h +++ b/include/linux/rotary_encoder.h @@ -4,10 +4,6 @@ struct rotary_encoder_platform_data { unsigned int steps; unsigned int axis; - unsigned int gpio_a; - unsigned int gpio_b; - unsigned int inverted_a; - unsigned int inverted_b; unsigned int steps_per_period; bool relative_axis; bool rollover; -- cgit v1.3 From 8631580f4fde9584ef39480eb0f2219708e5aeba Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 17 Jan 2016 10:52:54 -0800 Subject: Input: rotary_encoder - use input_set_capability() Instead of manipulating capability bits directly let's use appropriate helpers. Also there is no need to explicitly set EV_ABS when calling input_set_abs_params(). Signed-off-by: Dmitry Torokhov --- drivers/input/misc/rotary_encoder.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 471175e5306b..70fdcce84866 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -317,14 +317,10 @@ static int rotary_encoder_probe(struct platform_device *pdev) input->id.bustype = BUS_HOST; input->dev.parent = dev; - if (pdata->relative_axis) { - input->evbit[0] = BIT_MASK(EV_REL); - input->relbit[0] = BIT_MASK(pdata->axis); - } else { - input->evbit[0] = BIT_MASK(EV_ABS); - input_set_abs_params(encoder->input, - pdata->axis, 0, pdata->steps, 0, 1); - } + if (pdata->relative_axis) + input_set_capability(input, EV_REL, pdata->axis); + else + input_set_abs_params(input, pdata->axis, 0, pdata->steps, 0, 1); switch (pdata->steps_per_period) { case 4: -- cgit v1.3 From a9e340dce3c3bceeb42f6b6d33b7858822d76cb6 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 17 Jan 2016 10:57:09 -0800 Subject: Input: rotary_encoder - move away from platform data structure Drop support for platform data passed via a C-structure and switch to device properties instead, which should make the driver compatible with all platforms: OF, ACPI and static boards. Static boards should use property sets to communicate device parameters to the driver. Signed-off-by: Dmitry Torokhov --- arch/arm/mach-pxa/raumfeld.c | 29 +++++-- drivers/input/misc/rotary_encoder.c | 146 ++++++++++++++---------------------- include/linux/rotary_encoder.h | 13 ---- 3 files changed, 76 insertions(+), 112 deletions(-) delete mode 100644 include/linux/rotary_encoder.h (limited to 'drivers/input') diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index bac88e0be58a..82689ac20ccf 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -18,13 +18,13 @@ #include #include +#include #include #include #include #include #include #include -#include #include #include #include @@ -378,18 +378,27 @@ static struct gpiod_lookup_table raumfeld_rotary_gpios_table = { }, }; -static struct rotary_encoder_platform_data raumfeld_rotary_encoder_info = { - .steps = 24, - .axis = REL_X, - .relative_axis = 1, +static u32 raumfeld_rotary_encoder_steps = 24; +static u32 raumfeld_rotary_encoder_axis = REL_X; +static u32 raumfeld_rotary_encoder_relative_axis = 1; + +static struct property_entry raumfeld_rotary_properties[] = { + { "rotary-encoder,steps-per-period", + DEV_PROP_U32, 1, &raumfeld_rotary_encoder_steps, }, + { "linux,axis", + DEV_PROP_U32, 1, &raumfeld_rotary_encoder_axis, }, + { "rotary-encoder,relative_axis", + DEV_PROP_U32, 1, &raumfeld_rotary_encoder_relative_axis, }, + { NULL } +}; + +static struct property_set raumfeld_rotary_property_set = { + .properties = raumfeld_rotary_properties, }; static struct platform_device rotary_encoder_device = { .name = "rotary-encoder", .id = 0, - .dev = { - .platform_data = &raumfeld_rotary_encoder_info, - } }; /** @@ -1061,6 +1070,8 @@ static void __init raumfeld_controller_init(void) pxa3xx_mfp_config(ARRAY_AND_SIZE(raumfeld_controller_pin_config)); gpiod_add_lookup_table(&raumfeld_rotary_gpios_table); + device_add_property_set(&rotary_encoder_device.dev, + &raumfeld_rotary_property_set); platform_device_register(&rotary_encoder_device); spi_register_board_info(ARRAY_AND_SIZE(controller_spi_devices)); @@ -1099,6 +1110,8 @@ static void __init raumfeld_speaker_init(void) platform_device_register(&smc91x_device); gpiod_add_lookup_table(&raumfeld_rotary_gpios_table); + device_add_property_set(&rotary_encoder_device.dev, + &raumfeld_rotary_property_set); platform_device_register(&rotary_encoder_device); raumfeld_audio_init(); diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 70fdcce84866..5a4e1d69c4af 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -21,20 +21,23 @@ #include #include #include -#include #include #include -#include #include +#include #define DRV_NAME "rotary-encoder" struct rotary_encoder { struct input_dev *input; - const struct rotary_encoder_platform_data *pdata; + struct mutex access_mutex; - unsigned int axis; + u32 steps; + u32 axis; + bool relative_axis; + bool rollover; + unsigned int pos; struct gpio_desc *gpio_a; @@ -59,31 +62,29 @@ static int rotary_encoder_get_state(struct rotary_encoder *encoder) static void rotary_encoder_report_event(struct rotary_encoder *encoder) { - const struct rotary_encoder_platform_data *pdata = encoder->pdata; - - if (pdata->relative_axis) { + if (encoder->relative_axis) { input_report_rel(encoder->input, - pdata->axis, encoder->dir ? -1 : 1); + encoder->axis, encoder->dir ? -1 : 1); } else { unsigned int pos = encoder->pos; if (encoder->dir) { /* turning counter-clockwise */ - if (pdata->rollover) - pos += pdata->steps; + if (encoder->rollover) + pos += encoder->steps; if (pos) pos--; } else { /* turning clockwise */ - if (pdata->rollover || pos < pdata->steps) + if (encoder->rollover || pos < encoder->steps) pos++; } - if (pdata->rollover) - pos %= pdata->steps; + if (encoder->rollover) + pos %= encoder->steps; encoder->pos = pos; - input_report_abs(encoder->input, pdata->axis, encoder->pos); + input_report_abs(encoder->input, encoder->axis, encoder->pos); } input_sync(encoder->input); @@ -204,90 +205,43 @@ out: return IRQ_HANDLED; } -#ifdef CONFIG_OF -static const struct of_device_id rotary_encoder_of_match[] = { - { .compatible = "rotary-encoder", }, - { }, -}; -MODULE_DEVICE_TABLE(of, rotary_encoder_of_match); - -static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct device *dev) -{ - const struct of_device_id *of_id = - of_match_device(rotary_encoder_of_match, dev); - struct device_node *np = dev->of_node; - struct rotary_encoder_platform_data *pdata; - int error; - - if (!of_id || !np) - return NULL; - - pdata = devm_kzalloc(dev, sizeof(struct rotary_encoder_platform_data), - GFP_KERNEL); - if (!pdata) - return ERR_PTR(-ENOMEM); - - of_property_read_u32(np, "rotary-encoder,steps", &pdata->steps); - of_property_read_u32(np, "linux,axis", &pdata->axis); - - pdata->relative_axis = - of_property_read_bool(np, "rotary-encoder,relative-axis"); - pdata->rollover = of_property_read_bool(np, "rotary-encoder,rollover"); - - error = of_property_read_u32(np, "rotary-encoder,steps-per-period", - &pdata->steps_per_period); - if (error) { - /* - * The 'half-period' property has been deprecated, you must use - * 'steps-per-period' and set an appropriate value, but we still - * need to parse it to maintain compatibility. - */ - if (of_property_read_bool(np, "rotary-encoder,half-period")) { - pdata->steps_per_period = 2; - } else { - /* Fallback to one step per period behavior */ - pdata->steps_per_period = 1; - } - } - - pdata->wakeup_source = of_property_read_bool(np, "wakeup-source"); - - return pdata; -} -#else -static inline struct rotary_encoder_platform_data * -rotary_encoder_parse_dt(struct device *dev) -{ - return NULL; -} -#endif - static int rotary_encoder_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - const struct rotary_encoder_platform_data *pdata = dev_get_platdata(dev); struct rotary_encoder *encoder; struct input_dev *input; irq_handler_t handler; + u32 steps_per_period; int err; - if (!pdata) { - pdata = rotary_encoder_parse_dt(dev); - if (IS_ERR(pdata)) - return PTR_ERR(pdata); - - if (!pdata) { - dev_err(dev, "missing platform data\n"); - return -EINVAL; - } - } - encoder = devm_kzalloc(dev, sizeof(struct rotary_encoder), GFP_KERNEL); if (!encoder) return -ENOMEM; mutex_init(&encoder->access_mutex); - encoder->pdata = pdata; + + device_property_read_u32(dev, "rotary-encoder,steps", &encoder->steps); + + err = device_property_read_u32(dev, "rotary-encoder,steps-per-period", + &steps_per_period); + if (err) { + /* + * The 'half-period' property has been deprecated, you must + * use 'steps-per-period' and set an appropriate value, but + * we still need to parse it to maintain compatibility. If + * neither property is present we fall back to the one step + * per period behavior. + */ + steps_per_period = device_property_read_bool(dev, + "rotary-encoder,half-period") ? 2 : 1; + } + + encoder->rollover = + device_property_read_bool(dev, "rotary-encoder,rollover"); + + device_property_read_u32(dev, "linux,axis", &encoder->axis); + encoder->relative_axis = + device_property_read_bool(dev, "rotary-encoder,relative-axis"); encoder->gpio_a = devm_gpiod_get_index(dev, NULL, 0, GPIOD_IN); if (IS_ERR(encoder->gpio_a)) { @@ -317,12 +271,13 @@ static int rotary_encoder_probe(struct platform_device *pdev) input->id.bustype = BUS_HOST; input->dev.parent = dev; - if (pdata->relative_axis) - input_set_capability(input, EV_REL, pdata->axis); + if (encoder->relative_axis) + input_set_capability(input, EV_REL, encoder->axis); else - input_set_abs_params(input, pdata->axis, 0, pdata->steps, 0, 1); + input_set_abs_params(input, + encoder->axis, 0, encoder->steps, 0, 1); - switch (pdata->steps_per_period) { + switch (steps_per_period) { case 4: handler = &rotary_encoder_quarter_period_irq; encoder->last_stable = rotary_encoder_get_state(encoder); @@ -336,7 +291,7 @@ static int rotary_encoder_probe(struct platform_device *pdev) break; default: dev_err(dev, "'%d' is not a valid steps-per-period value\n", - pdata->steps_per_period); + steps_per_period); return -EINVAL; } @@ -364,7 +319,8 @@ static int rotary_encoder_probe(struct platform_device *pdev) return err; } - device_init_wakeup(&pdev->dev, pdata->wakeup_source); + device_init_wakeup(dev, + device_property_read_bool(dev, "wakeup-source")); platform_set_drvdata(pdev, encoder); @@ -398,6 +354,14 @@ static int __maybe_unused rotary_encoder_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(rotary_encoder_pm_ops, rotary_encoder_suspend, rotary_encoder_resume); +#ifdef CONFIG_OF +static const struct of_device_id rotary_encoder_of_match[] = { + { .compatible = "rotary-encoder", }, + { }, +}; +MODULE_DEVICE_TABLE(of, rotary_encoder_of_match); +#endif + static struct platform_driver rotary_encoder_driver = { .probe = rotary_encoder_probe, .driver = { diff --git a/include/linux/rotary_encoder.h b/include/linux/rotary_encoder.h deleted file mode 100644 index 4536c813a1e9..000000000000 --- a/include/linux/rotary_encoder.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __ROTARY_ENCODER_H__ -#define __ROTARY_ENCODER_H__ - -struct rotary_encoder_platform_data { - unsigned int steps; - unsigned int axis; - unsigned int steps_per_period; - bool relative_axis; - bool rollover; - bool wakeup_source; -}; - -#endif /* __ROTARY_ENCODER_H__ */ -- cgit v1.3 From 7dde4e74744772efdc85d7ed13495c7b6a0d881b Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 1 Mar 2016 18:25:26 -0800 Subject: Input: rotary-encoder - support more than 2 gpios as input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changes how the used gpios are stored (i.e. a struct gpio_descs instead of two struct gpio_desc) and as with >2 gpios the states are numbered differently the function rotary_encoder_get_state returns unencoded numbers instead of grey encoded numbers before. The latter has some implications on how the returned value is used and so the change is bigger than one might expect at first. Signed-off-by: Uwe Kleine-König Acked-by: Rob Herring Acked-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/rotary-encoder.txt | 2 +- drivers/input/misc/rotary_encoder.c | 156 +++++++++------------ 2 files changed, 65 insertions(+), 93 deletions(-) (limited to 'drivers/input') diff --git a/Documentation/devicetree/bindings/input/rotary-encoder.txt b/Documentation/devicetree/bindings/input/rotary-encoder.txt index de99cbbbf6da..6c9f0c8a846c 100644 --- a/Documentation/devicetree/bindings/input/rotary-encoder.txt +++ b/Documentation/devicetree/bindings/input/rotary-encoder.txt @@ -1,7 +1,7 @@ Rotary encoder DT bindings Required properties: -- gpios: a spec for two GPIOs to be used +- gpios: a spec for at least two GPIOs to be used, most significant first Optional properties: - linux,axis: the input subsystem axis to map to this rotary encoder. diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 5a4e1d69c4af..96c486de49e0 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -40,35 +40,42 @@ struct rotary_encoder { unsigned int pos; - struct gpio_desc *gpio_a; - struct gpio_desc *gpio_b; + struct gpio_descs *gpios; - unsigned int irq_a; - unsigned int irq_b; + unsigned int *irq; bool armed; - unsigned char dir; /* 0 - clockwise, 1 - CCW */ + signed char dir; /* 1 - clockwise, -1 - CCW */ - char last_stable; + unsigned last_stable; }; -static int rotary_encoder_get_state(struct rotary_encoder *encoder) +static unsigned rotary_encoder_get_state(struct rotary_encoder *encoder) { - int a = !!gpiod_get_value_cansleep(encoder->gpio_a); - int b = !!gpiod_get_value_cansleep(encoder->gpio_b); + int i; + unsigned ret = 0; - return ((a << 1) | b); + for (i = 0; i < encoder->gpios->ndescs; ++i) { + int val = gpiod_get_value_cansleep(encoder->gpios->desc[i]); + /* convert from gray encoding to normal */ + if (ret & 1) + val = !val; + + ret = ret << 1 | val; + } + + return ret & 3; } static void rotary_encoder_report_event(struct rotary_encoder *encoder) { if (encoder->relative_axis) { input_report_rel(encoder->input, - encoder->axis, encoder->dir ? -1 : 1); + encoder->axis, encoder->dir); } else { unsigned int pos = encoder->pos; - if (encoder->dir) { + if (encoder->dir < 0) { /* turning counter-clockwise */ if (encoder->rollover) pos += encoder->steps; @@ -93,7 +100,7 @@ static void rotary_encoder_report_event(struct rotary_encoder *encoder) static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) { struct rotary_encoder *encoder = dev_id; - int state; + unsigned state; mutex_lock(&encoder->access_mutex); @@ -108,12 +115,12 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) break; case 0x1: - case 0x2: + case 0x3: if (encoder->armed) - encoder->dir = state - 1; + encoder->dir = 2 - state; break; - case 0x3: + case 0x2: encoder->armed = true; break; } @@ -126,25 +133,19 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) { struct rotary_encoder *encoder = dev_id; - int state; + unsigned int state; mutex_lock(&encoder->access_mutex); state = rotary_encoder_get_state(encoder); - switch (state) { - case 0x00: - case 0x03: + if (state & 1) { + encoder->dir = ((encoder->last_stable - state + 1) % 4) - 1; + } else { if (state != encoder->last_stable) { rotary_encoder_report_event(encoder); encoder->last_stable = state; } - break; - - case 0x01: - case 0x02: - encoder->dir = (encoder->last_stable + state) & 0x01; - break; } mutex_unlock(&encoder->access_mutex); @@ -155,46 +156,18 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id) { struct rotary_encoder *encoder = dev_id; - unsigned char sum; - int state; + unsigned int state; mutex_lock(&encoder->access_mutex); state = rotary_encoder_get_state(encoder); - /* - * We encode the previous and the current state using a byte. - * The previous state in the MSB nibble, the current state in the LSB - * nibble. Then use a table to decide the direction of the turn. - */ - sum = (encoder->last_stable << 4) + state; - switch (sum) { - case 0x31: - case 0x10: - case 0x02: - case 0x23: - encoder->dir = 0; /* clockwise */ - break; - - case 0x13: - case 0x01: - case 0x20: - case 0x32: - encoder->dir = 1; /* counter-clockwise */ - break; - - default: - /* - * Ignore all other values. This covers the case when the - * state didn't change (a spurious interrupt) and the - * cases where the state changed by two steps, making it - * impossible to tell the direction. - * - * In either case, don't report any event and save the - * state for later. - */ + if ((encoder->last_stable + 1) % 4 == state) + encoder->dir = 1; + else if (encoder->last_stable == (state + 1) % 4) + encoder->dir = -1; + else goto out; - } rotary_encoder_report_event(encoder); @@ -212,6 +185,7 @@ static int rotary_encoder_probe(struct platform_device *pdev) struct input_dev *input; irq_handler_t handler; u32 steps_per_period; + unsigned int i; int err; encoder = devm_kzalloc(dev, sizeof(struct rotary_encoder), GFP_KERNEL); @@ -243,24 +217,16 @@ static int rotary_encoder_probe(struct platform_device *pdev) encoder->relative_axis = device_property_read_bool(dev, "rotary-encoder,relative-axis"); - encoder->gpio_a = devm_gpiod_get_index(dev, NULL, 0, GPIOD_IN); - if (IS_ERR(encoder->gpio_a)) { - err = PTR_ERR(encoder->gpio_a); - dev_err(dev, "unable to get GPIO at index 0: %d\n", err); - return err; + encoder->gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN); + if (IS_ERR(encoder->gpios)) { + dev_err(dev, "unable to get gpios\n"); + return PTR_ERR(encoder->gpios); } - - encoder->irq_a = gpiod_to_irq(encoder->gpio_a); - - encoder->gpio_b = devm_gpiod_get_index(dev, NULL, 1, GPIOD_IN); - if (IS_ERR(encoder->gpio_b)) { - err = PTR_ERR(encoder->gpio_b); - dev_err(dev, "unable to get GPIO at index 1: %d\n", err); - return err; + if (encoder->gpios->ndescs < 2) { + dev_err(dev, "not enough gpios found\n"); + return -EINVAL; } - encoder->irq_b = gpiod_to_irq(encoder->gpio_b); - input = devm_input_allocate_device(dev); if (!input) return -ENOMEM; @@ -277,7 +243,7 @@ static int rotary_encoder_probe(struct platform_device *pdev) input_set_abs_params(input, encoder->axis, 0, encoder->steps, 0, 1); - switch (steps_per_period) { + switch (steps_per_period >> (encoder->gpios->ndescs - 2)) { case 4: handler = &rotary_encoder_quarter_period_irq; encoder->last_stable = rotary_encoder_get_state(encoder); @@ -295,22 +261,26 @@ static int rotary_encoder_probe(struct platform_device *pdev) return -EINVAL; } - err = devm_request_threaded_irq(dev, encoder->irq_a, NULL, handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | - IRQF_ONESHOT, - DRV_NAME, encoder); - if (err) { - dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a); - return err; - } + encoder->irq = + devm_kzalloc(dev, + sizeof(*encoder->irq) * encoder->gpios->ndescs, + GFP_KERNEL); + if (!encoder->irq) + return -ENOMEM; - err = devm_request_threaded_irq(dev, encoder->irq_b, NULL, handler, + for (i = 0; i < encoder->gpios->ndescs; ++i) { + encoder->irq[i] = gpiod_to_irq(encoder->gpios->desc[i]); + + err = devm_request_threaded_irq(dev, encoder->irq[i], + NULL, handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, DRV_NAME, encoder); - if (err) { - dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b); - return err; + if (err) { + dev_err(dev, "unable to request IRQ %d (gpio#%d)\n", + encoder->irq[i], i); + return err; + } } err = input_register_device(input); @@ -330,10 +300,11 @@ static int rotary_encoder_probe(struct platform_device *pdev) static int __maybe_unused rotary_encoder_suspend(struct device *dev) { struct rotary_encoder *encoder = dev_get_drvdata(dev); + unsigned int i; if (device_may_wakeup(dev)) { - enable_irq_wake(encoder->irq_a); - enable_irq_wake(encoder->irq_b); + for (i = 0; i < encoder->gpios->ndescs; ++i) + enable_irq_wake(encoder->irq[i]); } return 0; @@ -342,10 +313,11 @@ static int __maybe_unused rotary_encoder_suspend(struct device *dev) static int __maybe_unused rotary_encoder_resume(struct device *dev) { struct rotary_encoder *encoder = dev_get_drvdata(dev); + unsigned int i; if (device_may_wakeup(dev)) { - disable_irq_wake(encoder->irq_a); - disable_irq_wake(encoder->irq_b); + for (i = 0; i < encoder->gpios->ndescs; ++i) + disable_irq_wake(encoder->irq[i]); } return 0; -- cgit v1.3