Re: [PATCH 2/2] Input: Add driver for a generic ADC keypad

2015-03-29 Thread Andrew Bresticker
On Sat, Mar 28, 2015 at 7:02 AM, Jonathan Cameron  wrote:
> On 28/03/15 00:43, Andrew Bresticker wrote:
>> Add a polled input driver for a keypad in which the buttons are connected
>> in resistor ladders to an ADC.  The IIO framework is used to claim and
>> read the ADC channels.
>>
>> Signed-off-by: Andrew Bresticker 

>> +static int adc_keypad_probe(struct platform_device *pdev)
>> +{
>> + struct adc_keypad *keypad;
>> + struct input_polled_dev *poll_dev;
>> + struct input_dev *input;
>> + unsigned int i;
>> + int ret;
>> +
>> + keypad = devm_kzalloc(>dev, sizeof(*keypad), GFP_KERNEL);
>> + if (!keypad)
>> + return -ENOMEM;
>> + keypad->dev = >dev;
>> + platform_set_drvdata(pdev, keypad);
>> +
>> + keypad->iio_chans = iio_channel_get_all(>dev);
>> + if (IS_ERR(keypad->iio_chans)) {
>> + dev_err(>dev, "Failed to get IIO channels: %ld\n",
>> + PTR_ERR(keypad->iio_chans));
>> + return PTR_ERR(keypad->iio_chans);
>> + }
>> +
>> + i = 0;
>> + while (keypad->iio_chans[i].channel != NULL)
>> + i++;
>> + keypad->num_chans = i;
>> + keypad->chan_map = devm_kcalloc(>dev, keypad->num_chans,
>> + sizeof(*keypad->chan_map), GFP_KERNEL);
>> + if (!keypad->chan_map) {
>> + ret = -ENOMEM;
>> + goto put_chans;
>> + }
>> +
>> + ret = adc_keypad_of_parse(keypad);
>> + if (ret < 0)
>> + goto put_chans;
>> +
>> + poll_dev = devm_input_allocate_polled_device(>dev);
>> + if (!poll_dev) {
>> + ret = -ENOMEM;
>> + goto put_chans;
>> + }
>> + keypad->poll_dev = poll_dev;
>> +
>> + poll_dev->private = keypad;
>> + poll_dev->poll = adc_keypad_poll;
>> + poll_dev->poll_interval = keypad->poll_interval;
>> +
>> + 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;

> Why these particular values?

I just chose these because these are the values most other platform
input devices use, including gpio_keys and gpio_keys_polled.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/2] Input: Add driver for a generic ADC keypad

2015-03-29 Thread Andrew Bresticker
On Sat, Mar 28, 2015 at 7:02 AM, Jonathan Cameron ji...@kernel.org wrote:
 On 28/03/15 00:43, Andrew Bresticker wrote:
 Add a polled input driver for a keypad in which the buttons are connected
 in resistor ladders to an ADC.  The IIO framework is used to claim and
 read the ADC channels.

 Signed-off-by: Andrew Bresticker abres...@chromium.org

 +static int adc_keypad_probe(struct platform_device *pdev)
 +{
 + struct adc_keypad *keypad;
 + struct input_polled_dev *poll_dev;
 + struct input_dev *input;
 + unsigned int i;
 + int ret;
 +
 + keypad = devm_kzalloc(pdev-dev, sizeof(*keypad), GFP_KERNEL);
 + if (!keypad)
 + return -ENOMEM;
 + keypad-dev = pdev-dev;
 + platform_set_drvdata(pdev, keypad);
 +
 + keypad-iio_chans = iio_channel_get_all(pdev-dev);
 + if (IS_ERR(keypad-iio_chans)) {
 + dev_err(pdev-dev, Failed to get IIO channels: %ld\n,
 + PTR_ERR(keypad-iio_chans));
 + return PTR_ERR(keypad-iio_chans);
 + }
 +
 + i = 0;
 + while (keypad-iio_chans[i].channel != NULL)
 + i++;
 + keypad-num_chans = i;
 + keypad-chan_map = devm_kcalloc(pdev-dev, keypad-num_chans,
 + sizeof(*keypad-chan_map), GFP_KERNEL);
 + if (!keypad-chan_map) {
 + ret = -ENOMEM;
 + goto put_chans;
 + }
 +
 + ret = adc_keypad_of_parse(keypad);
 + if (ret  0)
 + goto put_chans;
 +
 + poll_dev = devm_input_allocate_polled_device(pdev-dev);
 + if (!poll_dev) {
 + ret = -ENOMEM;
 + goto put_chans;
 + }
 + keypad-poll_dev = poll_dev;
 +
 + poll_dev-private = keypad;
 + poll_dev-poll = adc_keypad_poll;
 + poll_dev-poll_interval = keypad-poll_interval;
 +
 + 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;

 Why these particular values?

I just chose these because these are the values most other platform
input devices use, including gpio_keys and gpio_keys_polled.
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/2] Input: Add driver for a generic ADC keypad

2015-03-28 Thread Jonathan Cameron
On 28/03/15 00:43, Andrew Bresticker wrote:
> Add a polled input driver for a keypad in which the buttons are connected
> in resistor ladders to an ADC.  The IIO framework is used to claim and
> read the ADC channels.
> 
> Signed-off-by: Andrew Bresticker 
The IIO side of things looks fine.
> ---
>  drivers/input/keyboard/Kconfig|  13 ++
>  drivers/input/keyboard/Makefile   |   1 +
>  drivers/input/keyboard/adc-keys.c | 291 
> ++
>  3 files changed, 305 insertions(+)
>  create mode 100644 drivers/input/keyboard/adc-keys.c
> 
> diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
> index a89ba7c..bbaff9e 100644
> --- a/drivers/input/keyboard/Kconfig
> +++ b/drivers/input/keyboard/Kconfig
> @@ -12,6 +12,19 @@ menuconfig INPUT_KEYBOARD
>  
>  if INPUT_KEYBOARD
>  
> +config KEYBOARD_ADC
> + tristate "ADC Keypad"
> + depends on IIO
> + select INPUT_POLLDEV
> + help
> +   This driver supports generic ADC keypads using IIO.
> +
> +   Say Y here if your device has buttons connected in a resistor ladder
> +   to an ADC.
> +
> +   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 4707678..888fa62 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 000..1b9bcad
> --- /dev/null
> +++ b/drivers/input/keyboard/adc-keys.c
> @@ -0,0 +1,291 @@
> +/*
> + * ADC keypad driver
> + *
> + * Copyright (C) 2015 Google, Inc.
> + *
> + * Based on /drivers/input/keybaord/gpio_keys_polled.c:
> + *  Copyright (C) 2007-2010 Gabor Juhos 
> + *  Copyright (C) 2010 Nuno Goncalves 
> + *
> + * 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 
> +
> +struct adc_key {
> + const char *desc;
> + unsigned int type;
> + unsigned int code;
> + unsigned int min_uV;
> + unsigned int max_uV;
> +};
> +
> +struct adc_chan_map {
> + struct adc_key *keys;
> + unsigned int num_keys;
> + int last_key;
> +};
> +
> +struct adc_keypad {
> + struct device *dev;
> + struct input_polled_dev *poll_dev;
> + unsigned int poll_interval;
> + bool autorepeat;
> + struct iio_channel *iio_chans;
> + unsigned int num_chans;
> + struct adc_chan_map *chan_map;
> +};
> +
> +static void adc_keypad_poll_chan(struct adc_keypad *keypad, unsigned int 
> chan)
> +{
> + struct adc_chan_map *chan_map = >chan_map[chan];
> + struct input_dev *input = keypad->poll_dev->input;
> + struct adc_key *key;
> + unsigned int adc_uV;
> + int ret, val, i;
> +
> + ret = iio_read_channel_processed(>iio_chans[chan], );
> + if (ret < 0) {
> + dev_err(keypad->dev, "Failed to read ADC: %d\n", ret);
> + return;
> + }
> + adc_uV = val * 1000;
> +
> + for (i = 0; i < chan_map->num_keys; i++) {
> + if (adc_uV >= chan_map->keys[i].min_uV &&
> + adc_uV <= chan_map->keys[i].max_uV)
> + break;
> + }
> + if (i >= chan_map->num_keys)
> + i = -1;
> +
> + if (i != chan_map->last_key) {
> + if (chan_map->last_key >= 0) {
> + key = _map->keys[chan_map->last_key];
> + input_event(input, key->type, key->code, 0);
> + }
> + if (i >= 0) {
> + key = _map->keys[i];
> + input_event(input, key->type, key->code, 1);
> + }
> + input_sync(input);
> + chan_map->last_key = i;
> + }
> +}
> +
> +static void adc_keypad_poll(struct input_polled_dev *poll_dev)
> +{
> + struct adc_keypad *keypad = poll_dev->private;
> + unsigned int i;
> +
> + for (i = 0; i < keypad->num_chans; i++)
> + adc_keypad_poll_chan(keypad, i);
> +}
> +
> +static int adc_keypad_of_parse_chan(struct adc_keypad *keypad,
> + unsigned int chan)
> +{
> + struct device_node *child, *np = keypad->dev->of_node;
> + struct adc_key *keys;
> + unsigned int i = 0;
> + int ret;
> +

Re: [PATCH 2/2] Input: Add driver for a generic ADC keypad

2015-03-28 Thread Jonathan Cameron
On 28/03/15 00:43, Andrew Bresticker wrote:
 Add a polled input driver for a keypad in which the buttons are connected
 in resistor ladders to an ADC.  The IIO framework is used to claim and
 read the ADC channels.
 
 Signed-off-by: Andrew Bresticker abres...@chromium.org
The IIO side of things looks fine.
 ---
  drivers/input/keyboard/Kconfig|  13 ++
  drivers/input/keyboard/Makefile   |   1 +
  drivers/input/keyboard/adc-keys.c | 291 
 ++
  3 files changed, 305 insertions(+)
  create mode 100644 drivers/input/keyboard/adc-keys.c
 
 diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
 index a89ba7c..bbaff9e 100644
 --- a/drivers/input/keyboard/Kconfig
 +++ b/drivers/input/keyboard/Kconfig
 @@ -12,6 +12,19 @@ menuconfig INPUT_KEYBOARD
  
  if INPUT_KEYBOARD
  
 +config KEYBOARD_ADC
 + tristate ADC Keypad
 + depends on IIO
 + select INPUT_POLLDEV
 + help
 +   This driver supports generic ADC keypads using IIO.
 +
 +   Say Y here if your device has buttons connected in a resistor ladder
 +   to an ADC.
 +
 +   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 4707678..888fa62 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 000..1b9bcad
 --- /dev/null
 +++ b/drivers/input/keyboard/adc-keys.c
 @@ -0,0 +1,291 @@
 +/*
 + * ADC keypad driver
 + *
 + * Copyright (C) 2015 Google, Inc.
 + *
 + * Based on /drivers/input/keybaord/gpio_keys_polled.c:
 + *  Copyright (C) 2007-2010 Gabor Juhos juh...@openwrt.org
 + *  Copyright (C) 2010 Nuno Goncalves nuno...@gmail.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
 + * published by the Free Software Foundation.
 + */
 +
 +#include linux/iio/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
 +#include linux/slab.h
 +
 +struct adc_key {
 + const char *desc;
 + unsigned int type;
 + unsigned int code;
 + unsigned int min_uV;
 + unsigned int max_uV;
 +};
 +
 +struct adc_chan_map {
 + struct adc_key *keys;
 + unsigned int num_keys;
 + int last_key;
 +};
 +
 +struct adc_keypad {
 + struct device *dev;
 + struct input_polled_dev *poll_dev;
 + unsigned int poll_interval;
 + bool autorepeat;
 + struct iio_channel *iio_chans;
 + unsigned int num_chans;
 + struct adc_chan_map *chan_map;
 +};
 +
 +static void adc_keypad_poll_chan(struct adc_keypad *keypad, unsigned int 
 chan)
 +{
 + struct adc_chan_map *chan_map = keypad-chan_map[chan];
 + struct input_dev *input = keypad-poll_dev-input;
 + struct adc_key *key;
 + unsigned int adc_uV;
 + int ret, val, i;
 +
 + ret = iio_read_channel_processed(keypad-iio_chans[chan], val);
 + if (ret  0) {
 + dev_err(keypad-dev, Failed to read ADC: %d\n, ret);
 + return;
 + }
 + adc_uV = val * 1000;
 +
 + for (i = 0; i  chan_map-num_keys; i++) {
 + if (adc_uV = chan_map-keys[i].min_uV 
 + adc_uV = chan_map-keys[i].max_uV)
 + break;
 + }
 + if (i = chan_map-num_keys)
 + i = -1;
 +
 + if (i != chan_map-last_key) {
 + if (chan_map-last_key = 0) {
 + key = chan_map-keys[chan_map-last_key];
 + input_event(input, key-type, key-code, 0);
 + }
 + if (i = 0) {
 + key = chan_map-keys[i];
 + input_event(input, key-type, key-code, 1);
 + }
 + input_sync(input);
 + chan_map-last_key = i;
 + }
 +}
 +
 +static void adc_keypad_poll(struct input_polled_dev *poll_dev)
 +{
 + struct adc_keypad *keypad = poll_dev-private;
 + unsigned int i;
 +
 + for (i = 0; i  keypad-num_chans; i++)
 + adc_keypad_poll_chan(keypad, i);
 +}
 +
 +static int adc_keypad_of_parse_chan(struct adc_keypad *keypad,
 + unsigned int chan)
 +{
 + struct device_node *child, *np = keypad-dev-of_node;
 + struct adc_key *keys;
 + unsigned int i = 0;
 + 

[PATCH 2/2] Input: Add driver for a generic ADC keypad

2015-03-27 Thread Andrew Bresticker
Add a polled input driver for a keypad in which the buttons are connected
in resistor ladders to an ADC.  The IIO framework is used to claim and
read the ADC channels.

Signed-off-by: Andrew Bresticker 
---
 drivers/input/keyboard/Kconfig|  13 ++
 drivers/input/keyboard/Makefile   |   1 +
 drivers/input/keyboard/adc-keys.c | 291 ++
 3 files changed, 305 insertions(+)
 create mode 100644 drivers/input/keyboard/adc-keys.c

diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index a89ba7c..bbaff9e 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -12,6 +12,19 @@ menuconfig INPUT_KEYBOARD
 
 if INPUT_KEYBOARD
 
+config KEYBOARD_ADC
+   tristate "ADC Keypad"
+   depends on IIO
+   select INPUT_POLLDEV
+   help
+ This driver supports generic ADC keypads using IIO.
+
+ Say Y here if your device has buttons connected in a resistor ladder
+ to an ADC.
+
+ 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 4707678..888fa62 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 000..1b9bcad
--- /dev/null
+++ b/drivers/input/keyboard/adc-keys.c
@@ -0,0 +1,291 @@
+/*
+ * ADC keypad driver
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Based on /drivers/input/keybaord/gpio_keys_polled.c:
+ *  Copyright (C) 2007-2010 Gabor Juhos 
+ *  Copyright (C) 2010 Nuno Goncalves 
+ *
+ * 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 
+
+struct adc_key {
+   const char *desc;
+   unsigned int type;
+   unsigned int code;
+   unsigned int min_uV;
+   unsigned int max_uV;
+};
+
+struct adc_chan_map {
+   struct adc_key *keys;
+   unsigned int num_keys;
+   int last_key;
+};
+
+struct adc_keypad {
+   struct device *dev;
+   struct input_polled_dev *poll_dev;
+   unsigned int poll_interval;
+   bool autorepeat;
+   struct iio_channel *iio_chans;
+   unsigned int num_chans;
+   struct adc_chan_map *chan_map;
+};
+
+static void adc_keypad_poll_chan(struct adc_keypad *keypad, unsigned int chan)
+{
+   struct adc_chan_map *chan_map = >chan_map[chan];
+   struct input_dev *input = keypad->poll_dev->input;
+   struct adc_key *key;
+   unsigned int adc_uV;
+   int ret, val, i;
+
+   ret = iio_read_channel_processed(>iio_chans[chan], );
+   if (ret < 0) {
+   dev_err(keypad->dev, "Failed to read ADC: %d\n", ret);
+   return;
+   }
+   adc_uV = val * 1000;
+
+   for (i = 0; i < chan_map->num_keys; i++) {
+   if (adc_uV >= chan_map->keys[i].min_uV &&
+   adc_uV <= chan_map->keys[i].max_uV)
+   break;
+   }
+   if (i >= chan_map->num_keys)
+   i = -1;
+
+   if (i != chan_map->last_key) {
+   if (chan_map->last_key >= 0) {
+   key = _map->keys[chan_map->last_key];
+   input_event(input, key->type, key->code, 0);
+   }
+   if (i >= 0) {
+   key = _map->keys[i];
+   input_event(input, key->type, key->code, 1);
+   }
+   input_sync(input);
+   chan_map->last_key = i;
+   }
+}
+
+static void adc_keypad_poll(struct input_polled_dev *poll_dev)
+{
+   struct adc_keypad *keypad = poll_dev->private;
+   unsigned int i;
+
+   for (i = 0; i < keypad->num_chans; i++)
+   adc_keypad_poll_chan(keypad, i);
+}
+
+static int adc_keypad_of_parse_chan(struct adc_keypad *keypad,
+   unsigned int chan)
+{
+   struct device_node *child, *np = keypad->dev->of_node;
+   struct adc_key *keys;
+   unsigned int i = 0;
+   int ret;
+
+   for_each_child_of_node(np, child) {
+   unsigned int c;
+
+   ret = of_property_read_u32(child, "channel", );
+   if (ret < 0)
+   continue;
+   if (c != chan)
+   continue;
+

[PATCH 2/2] Input: Add driver for a generic ADC keypad

2015-03-27 Thread Andrew Bresticker
Add a polled input driver for a keypad in which the buttons are connected
in resistor ladders to an ADC.  The IIO framework is used to claim and
read the ADC channels.

Signed-off-by: Andrew Bresticker abres...@chromium.org
---
 drivers/input/keyboard/Kconfig|  13 ++
 drivers/input/keyboard/Makefile   |   1 +
 drivers/input/keyboard/adc-keys.c | 291 ++
 3 files changed, 305 insertions(+)
 create mode 100644 drivers/input/keyboard/adc-keys.c

diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index a89ba7c..bbaff9e 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -12,6 +12,19 @@ menuconfig INPUT_KEYBOARD
 
 if INPUT_KEYBOARD
 
+config KEYBOARD_ADC
+   tristate ADC Keypad
+   depends on IIO
+   select INPUT_POLLDEV
+   help
+ This driver supports generic ADC keypads using IIO.
+
+ Say Y here if your device has buttons connected in a resistor ladder
+ to an ADC.
+
+ 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 4707678..888fa62 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 000..1b9bcad
--- /dev/null
+++ b/drivers/input/keyboard/adc-keys.c
@@ -0,0 +1,291 @@
+/*
+ * ADC keypad driver
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Based on /drivers/input/keybaord/gpio_keys_polled.c:
+ *  Copyright (C) 2007-2010 Gabor Juhos juh...@openwrt.org
+ *  Copyright (C) 2010 Nuno Goncalves nuno...@gmail.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
+ * published by the Free Software Foundation.
+ */
+
+#include linux/iio/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
+#include linux/slab.h
+
+struct adc_key {
+   const char *desc;
+   unsigned int type;
+   unsigned int code;
+   unsigned int min_uV;
+   unsigned int max_uV;
+};
+
+struct adc_chan_map {
+   struct adc_key *keys;
+   unsigned int num_keys;
+   int last_key;
+};
+
+struct adc_keypad {
+   struct device *dev;
+   struct input_polled_dev *poll_dev;
+   unsigned int poll_interval;
+   bool autorepeat;
+   struct iio_channel *iio_chans;
+   unsigned int num_chans;
+   struct adc_chan_map *chan_map;
+};
+
+static void adc_keypad_poll_chan(struct adc_keypad *keypad, unsigned int chan)
+{
+   struct adc_chan_map *chan_map = keypad-chan_map[chan];
+   struct input_dev *input = keypad-poll_dev-input;
+   struct adc_key *key;
+   unsigned int adc_uV;
+   int ret, val, i;
+
+   ret = iio_read_channel_processed(keypad-iio_chans[chan], val);
+   if (ret  0) {
+   dev_err(keypad-dev, Failed to read ADC: %d\n, ret);
+   return;
+   }
+   adc_uV = val * 1000;
+
+   for (i = 0; i  chan_map-num_keys; i++) {
+   if (adc_uV = chan_map-keys[i].min_uV 
+   adc_uV = chan_map-keys[i].max_uV)
+   break;
+   }
+   if (i = chan_map-num_keys)
+   i = -1;
+
+   if (i != chan_map-last_key) {
+   if (chan_map-last_key = 0) {
+   key = chan_map-keys[chan_map-last_key];
+   input_event(input, key-type, key-code, 0);
+   }
+   if (i = 0) {
+   key = chan_map-keys[i];
+   input_event(input, key-type, key-code, 1);
+   }
+   input_sync(input);
+   chan_map-last_key = i;
+   }
+}
+
+static void adc_keypad_poll(struct input_polled_dev *poll_dev)
+{
+   struct adc_keypad *keypad = poll_dev-private;
+   unsigned int i;
+
+   for (i = 0; i  keypad-num_chans; i++)
+   adc_keypad_poll_chan(keypad, i);
+}
+
+static int adc_keypad_of_parse_chan(struct adc_keypad *keypad,
+   unsigned int chan)
+{
+   struct device_node *child, *np = keypad-dev-of_node;
+   struct adc_key *keys;
+   unsigned int i = 0;
+   int ret;
+
+   for_each_child_of_node(np, child) {
+   unsigned int c;
+
+   ret =