From a8a7bdc598ec0c355491bc1cac75f8f6b8a1740d Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 19 Aug 2016 09:40:58 -0700 Subject: Input: jornada720_kbd - switch to devm_* APIs Switch the jornada720_kbd driver to use the devm_* APIs. This is in preparation to removing the mach/irqs.h include from this driver. Signed-off-by: Russell King Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/jornada720_kbd.c | 43 ++++++--------------------------- 1 file changed, 8 insertions(+), 35 deletions(-) (limited to 'drivers/input/keyboard') diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index 421d9c55b0e8..0a7832e0e05a 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -99,12 +99,10 @@ static int jornada720_kbd_probe(struct platform_device *pdev) struct input_dev *input_dev; int i, err; - jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!jornadakbd || !input_dev) { - err = -ENOMEM; - goto fail1; - } + 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_GPIO0, jornada720_kbd_interrupt, + IRQF_TRIGGER_FALLING, "jornadakbd", pdev); if (err) { printk(KERN_INFO "jornadakbd720_kbd: Unable to grab IRQ\n"); - goto fail1; + 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); -- cgit v1.2.3 From 0f631d87d9a5e3f5f22908b102c8eaad944f390e Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 19 Aug 2016 09:41:47 -0700 Subject: Input: jornada720_kbd - get rid of mach/irqs.h include Switch the jornada720 keyboard driver to obtain its interrupt from the platform device, rather than via a hard-coded interrupt number obtained from the mach/irqs.h header. Signed-off-by: Russell King Signed-off-by: Dmitry Torokhov --- arch/arm/mach-sa1100/jornada720.c | 6 ++++++ drivers/input/keyboard/jornada720_kbd.c | 11 +++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/input/keyboard') diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c index c0b1f5bafae4..2b96f7bc16bd 100644 --- a/arch/arm/mach-sa1100/jornada720.c +++ b/arch/arm/mach-sa1100/jornada720.c @@ -217,9 +217,15 @@ static struct platform_device jornada_ssp_device = { .id = -1, }; +static struct resource jornada_kbd_resources[] = { + DEFINE_RES_IRQ(IRQ_GPIO0), +}; + static struct platform_device jornada_kbd_device = { .name = "jornada720_kbd", .id = -1, + .num_resources = ARRAY_SIZE(jornada_kbd_resources), + .resource = jornada_kbd_resources, }; static struct platform_device jornada_ts_device = { diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index 0a7832e0e05a..648340439d5f 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -26,7 +26,6 @@ #include #include -#include MODULE_AUTHOR("Kristoffer Ericson "); MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver"); @@ -97,7 +96,11 @@ static int jornada720_kbd_probe(struct platform_device *pdev) { struct jornadakbd *jornadakbd; struct input_dev *input_dev; - int i, err; + int i, err, irq; + + 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); @@ -125,10 +128,10 @@ static int jornada720_kbd_probe(struct platform_device *pdev) input_set_capability(input_dev, EV_MSC, MSC_SCAN); - err = devm_request_irq(&pdev->dev, IRQ_GPIO0, jornada720_kbd_interrupt, + 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"); + dev_err(&pdev->dev, "unable to grab IRQ%d: %d\n", irq, err); return err; } -- cgit v1.2.3 From 99ff4d3af80caa91eef5a4b709def6b8b362ce8c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 19 Aug 2016 10:03:59 -0700 Subject: Input: jornada720_kbd - switch to using dev_dbg Switch to using dev_dbg instead of naked printk so that output is uniform with the other driver messages in the kernel. Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/jornada720_kbd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/input/keyboard') diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index 648340439d5f..fd8e15ea9149 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -65,10 +65,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); -- cgit v1.2.3 From 680772647d96ed853d20f837a2726151f24d8b20 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 29 Aug 2016 19:57:06 -0700 Subject: Input: add ADC resistor ladder driver A common way of multiplexing buttons on a single input in cheap devices is to use a resistor ladder on an ADC. This driver supports that configuration by polling an ADC channel provided by IIO. Acked-by: Jonathan Cameron Signed-off-by: Alexandre Belloni Acked-by: Rob Herring Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/adc-keys.txt | 49 +++++ drivers/input/keyboard/Kconfig | 15 ++ drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/adc-keys.c | 210 +++++++++++++++++++++ 4 files changed, 275 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/adc-keys.txt create mode 100644 drivers/input/keyboard/adc-keys.c (limited to 'drivers/input/keyboard') diff --git a/Documentation/devicetree/bindings/input/adc-keys.txt b/Documentation/devicetree/bindings/input/adc-keys.txt new file mode 100644 index 000000000000..e551814629b4 --- /dev/null +++ b/Documentation/devicetree/bindings/input/adc-keys.txt @@ -0,0 +1,49 @@ +ADC attached resistor ladder buttons +------------------------------------ + +Required properties: + - compatible: "adc-keys" + - io-channels: Phandle to an ADC channel + - io-channel-names = "buttons"; + - keyup-threshold-microvolt: Voltage at which all the keys are considered up. + +Optional properties: + - poll-interval: Poll interval time in milliseconds + - autorepeat: Boolean, Enable auto repeat feature of Linux input + subsystem. + +Each button (key) is represented as a sub-node of "adc-keys": + +Required subnode-properties: + - label: Descriptive name of the key. + - linux,code: Keycode to emit. + - press-threshold-microvolt: Voltage ADC input when this key is pressed. + +Example: + +#include + + adc-keys { + compatible = "adc-keys"; + io-channels = <&lradc 0>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <2000000>; + + button-up { + label = "Volume Up"; + linux,code = ; + press-threshold-microvolt = <1500000>; + }; + + button-down { + label = "Volume Down"; + linux,code = ; + press-threshold-microvolt = <1000000>; + }; + + button-enter { + label = "Enter"; + linux,code = ; + press-threshold-microvolt = <500000>; + }; + }; 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 "); +MODULE_DESCRIPTION("Input driver for resistor ladder connected on ADC"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 72f6d0b9eaee7e00ffab57b49d8543cc35a7d894 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 7 Sep 2016 19:21:06 -0700 Subject: Input: jornada720_kbd - remove unneeded mach/hardware.h include The Jornada720 keyboard driver does not make use of anything from the mach/hardware.h header, so this header can be removed. Tested-by: Adam Wysocki Signed-off-by: Russell King Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/jornada720_kbd.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/input/keyboard') diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index fd8e15ea9149..1277c39f9482 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -25,7 +25,6 @@ #include #include -#include MODULE_AUTHOR("Kristoffer Ericson "); MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver"); -- cgit v1.2.3 From d095c500fd79421f915cea26925677cd16ecd623 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 23 Sep 2016 15:01:07 -0700 Subject: Input: snvs_pwrkey - drop input_free_device call if input_register_device fails Current code uses devm_input_allocate_device() so don't explicitly call input_free_device if input_register_device fails. Signed-off-by: Axel Lin Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/snvs_pwrkey.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/input/keyboard') 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; } -- cgit v1.2.3