diff mbox

Input: add Atmel Atmegaxx captouch driver

Message ID 1462295611-49684-1-git-send-email-grundler@chromium.org (mailing list archive)
State New, archived
Headers show

Commit Message

Grant Grundler May 3, 2016, 5:13 p.m. UTC
Add I2C driver for AtmegaXX capacitive touch device.

Signed-off-by: Hung-yu Wu <hywu@google.com>
Signed-off-by: Grant Grundler <grundler@chromium.org>
---
 .../bindings/input/atmel,atmegaxx_captouch.txt     |  34 +++
 drivers/input/misc/Kconfig                         |  11 +
 drivers/input/misc/Makefile                        |   1 +
 drivers/input/misc/atmegaxx_captouch.c             | 278 +++++++++++++++++++++
 4 files changed, 324 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/atmel,atmegaxx_captouch.txt
 create mode 100644 drivers/input/misc/atmegaxx_captouch.c

For those that like to know how sausage is made, ChromeOS code review history here:
   https://chromium-review.googlesource.com/339950

Driver was tested with prototype HW and it reliably reports events correctly.
Manual testing was just using "evtest /dev/input/event0" and watch for events.

Comments

Rob Herring (Arm) May 4, 2016, 1:51 p.m. UTC | #1
On Tue, May 03, 2016 at 10:13:31AM -0700, Grant Grundler wrote:
> Add I2C driver for AtmegaXX capacitive touch device.
> 
> Signed-off-by: Hung-yu Wu <hywu@google.com>
> Signed-off-by: Grant Grundler <grundler@chromium.org>
> ---
>  .../bindings/input/atmel,atmegaxx_captouch.txt     |  34 +++

It is generally preferred that bindings are a separate patch.

>  drivers/input/misc/Kconfig                         |  11 +
>  drivers/input/misc/Makefile                        |   1 +
>  drivers/input/misc/atmegaxx_captouch.c             | 278 +++++++++++++++++++++
>  4 files changed, 324 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/input/atmel,atmegaxx_captouch.txt
>  create mode 100644 drivers/input/misc/atmegaxx_captouch.c
> 
> For those that like to know how sausage is made, ChromeOS code review history here:
>    https://chromium-review.googlesource.com/339950
> 
> Driver was tested with prototype HW and it reliably reports events correctly.
> Manual testing was just using "evtest /dev/input/event0" and watch for events.
> 
> diff --git a/Documentation/devicetree/bindings/input/atmel,atmegaxx_captouch.txt b/Documentation/devicetree/bindings/input/atmel,atmegaxx_captouch.txt
> new file mode 100644
> index 0000000..07a4b0b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/atmel,atmegaxx_captouch.txt
> @@ -0,0 +1,34 @@
> +Device tree bindings for Atmel AtmegaXX capacitive touch sensor
> +
> +The node for this device must be a child of a I2C controller node, as the
> +device communicates via I2C.
> +
> +Required properties:
> +
> +	compatible:	Must be "atmel,atmegaxx_captouch".

No wildcards in the compatible strings. Use the specific devices.

Also, use hyphen rather than underscore. However, if the device is only 
a touch controller, then '_captouch' is not needed. The part number is 
sufficient to identify the device.

> +	reg:		The I2C slave address of the device.
> +	interrupts:	Property describing the interrupt line the device
> +			is connected to. The device only has one interrupt
> +			source.
> +	linux,keycodes:	Specifies an array of numeric keycode values to
> +			be used for reporting button presses. The array can
> +			contain up to 8 entries.
> +
> +Optional properties:
> +
> +	autorepeat:	Enables the Linux input system's autorepeat
> +			feature on the input device.
> +
> +Example:
> +
> +	atmegaxx_captouch@51 {

atmegaxx@51 (with actual part number)

> +		compatible = "atmel,atmegaxx_captouch";
> +		reg = <0x51>;
> +		interrupt-parent = <&tlmm>;
> +		interrupts = <67 IRQ_TYPE_EDGE_FALLING>;
> +		linux,keycodes = <BTN_0>, <BTN_1>,
> +			<BTN_2>, <BTN_3>,
> +			<BTN_4>, <BTN_5>,
> +			<BTN_6>, <BTN_7>;
> +		autorepeat;
> +	};
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Grant Grundler May 4, 2016, 4:43 p.m. UTC | #2
On Wed, May 4, 2016 at 6:51 AM, Rob Herring <robh@kernel.org> wrote:
> On Tue, May 03, 2016 at 10:13:31AM -0700, Grant Grundler wrote:
>> Add I2C driver for AtmegaXX capacitive touch device.
>>
>> Signed-off-by: Hung-yu Wu <hywu@google.com>
>> Signed-off-by: Grant Grundler <grundler@chromium.org>
>> ---
>>  .../bindings/input/atmel,atmegaxx_captouch.txt     |  34 +++
>
> It is generally preferred that bindings are a separate patch.

ACK - I just discovered Documentation/devicetree/bindings/submitting-patches.txt
(which explains this in more detail)

>>  drivers/input/misc/Kconfig                         |  11 +
>>  drivers/input/misc/Makefile                        |   1 +
>>  drivers/input/misc/atmegaxx_captouch.c             | 278 +++++++++++++++++++++
>>  4 files changed, 324 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/input/atmel,atmegaxx_captouch.txt
>>  create mode 100644 drivers/input/misc/atmegaxx_captouch.c
>>
>> For those that like to know how sausage is made, ChromeOS code review history here:
>>    https://chromium-review.googlesource.com/339950
>>
>> Driver was tested with prototype HW and it reliably reports events correctly.
>> Manual testing was just using "evtest /dev/input/event0" and watch for events.
>>
>> diff --git a/Documentation/devicetree/bindings/input/atmel,atmegaxx_captouch.txt b/Documentation/devicetree/bindings/input/atmel,atmegaxx_captouch.txt
>> new file mode 100644
>> index 0000000..07a4b0b
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/input/atmel,atmegaxx_captouch.txt
>> @@ -0,0 +1,34 @@
>> +Device tree bindings for Atmel AtmegaXX capacitive touch sensor
>> +
>> +The node for this device must be a child of a I2C controller node, as the
>> +device communicates via I2C.
>> +
>> +Required properties:
>> +
>> +     compatible:     Must be "atmel,atmegaxx_captouch".
>
> No wildcards in the compatible strings. Use the specific devices.

Sorry, I don't understand - What is a wildcard in this context?

I also just discovered
Documentation/devicetree/bindings/submitting-patches.txt and the "5)
the wildcard" text doesn't seem to match the usage here.

> Also, use hyphen rather than underscore.

ACK - I have no clue why - I've been scrounging around in
Documentation and haven't stumbled across "coding style" for device
tree document.


> However, if the device is only a touch controller, then '_captouch' is not needed.
> The part number is sufficient to identify the device.

atmegaxx is an Atmel microcontroller series and in this particular
case used to drive a capacitive touch input device (just buttons).
Since the microcontroller can be used for "anything", "captouch" is
sort of the "model" of this implementation.


>> +     reg:            The I2C slave address of the device.
>> +     interrupts:     Property describing the interrupt line the device
>> +                     is connected to. The device only has one interrupt
>> +                     source.
>> +     linux,keycodes: Specifies an array of numeric keycode values to
>> +                     be used for reporting button presses. The array can
>> +                     contain up to 8 entries.
>> +
>> +Optional properties:
>> +
>> +     autorepeat:     Enables the Linux input system's autorepeat
>> +                     feature on the input device.
>> +
>> +Example:
>> +
>> +     atmegaxx_captouch@51 {
>
> atmegaxx@51 (with actual part number)

atmegaxx_captouch (or -captouch) is how Atmel has been referring to
this implementation. I'm not aware of any other part number or model
number.

>> +             compatible = "atmel,atmegaxx_captouch";
>> +             reg = <0x51>;
>> +             interrupt-parent = <&tlmm>;
>> +             interrupts = <67 IRQ_TYPE_EDGE_FALLING>;
>> +             linux,keycodes = <BTN_0>, <BTN_1>,
>> +                     <BTN_2>, <BTN_3>,
>> +                     <BTN_4>, <BTN_5>,
>> +                     <BTN_6>, <BTN_7>;
>> +             autorepeat;
>> +     };

Thanks for the feedback!
I'll repost with s/_/-/ fix after naming is clear.

thanks,
grant
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Grant Grundler May 5, 2016, 4:04 p.m. UTC | #3
On Wed, May 4, 2016 at 6:51 AM, Rob Herring <robh@kernel.org> wrote:
...
>> +Required properties:
>> +
>> +     compatible:     Must be "atmel,atmegaxx_captouch".
>
> No wildcards in the compatible strings. Use the specific devices.
>
> Also, use hyphen rather than underscore. However, if the device is only
> a touch controller, then '_captouch' is not needed. The part number is
> sufficient to identify the device.

The primary part used on the board is AtMega88PA. Details of that SoC
are public:
    http://www.atmel.com/devices/ATMEGA88PA.aspx

I don't see why the exact chip is relevant to the driver. The driver
is just talking to an I2C device that reports button events.  The
protocol across the I2C determines what this driver has to do and that
protocol is implemented by the on-board firmware (supplied by Atmel).
Any AVR CPU could implement this same protocol.

Can we call this "atmel,qtouch-buttons-v2" or something like that?

I personally don't have anything invested in any particular name. Feel
free to suggest a different one. I'm perfectly happy with any color
paint on the shed.

...
>> +Example:
>> +
>> +     atmegaxx_captouch@51 {
>
> atmegaxx@51 (with actual part number)

Is "qtouch-buttons@51" ok?

>
>> +             compatible = "atmel,atmegaxx_captouch";
>> +             reg = <0x51>;
>> +             interrupt-parent = <&tlmm>;
>> +             interrupts = <67 IRQ_TYPE_EDGE_FALLING>;
>> +             linux,keycodes = <BTN_0>, <BTN_1>,
>> +                     <BTN_2>, <BTN_3>,
>> +                     <BTN_4>, <BTN_5>,
>> +                     <BTN_6>, <BTN_7>;
>> +             autorepeat;
>> +     };

cheers,
grant
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Nicolas Ferre May 6, 2016, 9:19 a.m. UTC | #4
Le 05/05/2016 18:04, Grant Grundler a écrit :
> On Wed, May 4, 2016 at 6:51 AM, Rob Herring <robh@kernel.org> wrote:
> ...
>>> +Required properties:
>>> +
>>> +     compatible:     Must be "atmel,atmegaxx_captouch".
>>
>> No wildcards in the compatible strings. Use the specific devices.
>>
>> Also, use hyphen rather than underscore. However, if the device is only
>> a touch controller, then '_captouch' is not needed. The part number is
>> sufficient to identify the device.
> 
> The primary part used on the board is AtMega88PA. Details of that SoC
> are public:
>     http://www.atmel.com/devices/ATMEGA88PA.aspx
> 
> I don't see why the exact chip is relevant to the driver. The driver
> is just talking to an I2C device that reports button events.  The
> protocol across the I2C determines what this driver has to do and that
> protocol is implemented by the on-board firmware (supplied by Atmel).
> Any AVR CPU could implement this same protocol.
> 
> Can we call this "atmel,qtouch-buttons-v2" or something like that?

Is it different from the Atmel QT1070 or QT2160 which have drivers
already available in Linux:
drivers/input/keyboard/qt1070.c

Bye,

> I personally don't have anything invested in any particular name. Feel
> free to suggest a different one. I'm perfectly happy with any color
> paint on the shed.
> 
> ...
>>> +Example:
>>> +
>>> +     atmegaxx_captouch@51 {
>>
>> atmegaxx@51 (with actual part number)
> 
> Is "qtouch-buttons@51" ok?
> 
>>
>>> +             compatible = "atmel,atmegaxx_captouch";
>>> +             reg = <0x51>;
>>> +             interrupt-parent = <&tlmm>;
>>> +             interrupts = <67 IRQ_TYPE_EDGE_FALLING>;
>>> +             linux,keycodes = <BTN_0>, <BTN_1>,
>>> +                     <BTN_2>, <BTN_3>,
>>> +                     <BTN_4>, <BTN_5>,
>>> +                     <BTN_6>, <BTN_7>;
>>> +             autorepeat;
>>> +     };
> 
> cheers,
> grant
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
Grant Grundler May 6, 2016, 6:29 p.m. UTC | #5
On Fri, May 6, 2016 at 2:19 AM, Nicolas Ferre <nicolas.ferre@atmel.com> wrote:
...
> Is it different from the Atmel QT1070 or QT2160 which have drivers
> already available in Linux:  drivers/input/keyboard/qt1070.c

Yes.  What Daniel said.  I would describe it as "probe code and
interrupt handling protocol are different" from both qt1070 and
qt2160.

I'll add qt2160 is quite a bit more complex by adding LED driver
support in a separate work handler and can handle a matrix of key
codes. So very different protocol and linux device driver.

cheers,
grant
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Dmitry Torokhov May 9, 2016, 4:29 p.m. UTC | #6
On Fri, May 06, 2016 at 11:14:12PM +0800, Daniel Hung-yu Wu wrote:
> The register set is different, and this chip does not support calibration.
> The I2C protocol is not the same as well; there is an additional byte
> indicating data length.
> 
> Atmega88PA is a general-purpose MCU. In the future, we will add more
> functionalities, such as firmware upgrade through I2C.

Is it Google who will be maintaining and extending the protocol or
Atmel? If it is Google then maybe we should switch compat string to
"google,captouch" or similar.

Thanks.
Grant Grundler May 9, 2016, 4:44 p.m. UTC | #7
On Mon, May 9, 2016 at 9:29 AM, Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
> On Fri, May 06, 2016 at 11:14:12PM +0800, Daniel Hung-yu Wu wrote:
>> The register set is different, and this chip does not support calibration.
>> The I2C protocol is not the same as well; there is an additional byte
>> indicating data length.
>>
>> Atmega88PA is a general-purpose MCU. In the future, we will add more
>> functionalities, such as firmware upgrade through I2C.
>
> Is it Google who will be maintaining and extending the protocol or
> Atmel? If it is Google then maybe we should switch compat string to
> "google,captouch" or similar.

My understanding was Atmel would extend the protocol to support FW update.
No other extensions are planned.

cheers,
grant
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/input/atmel,atmegaxx_captouch.txt b/Documentation/devicetree/bindings/input/atmel,atmegaxx_captouch.txt
new file mode 100644
index 0000000..07a4b0b
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/atmel,atmegaxx_captouch.txt
@@ -0,0 +1,34 @@ 
+Device tree bindings for Atmel AtmegaXX capacitive touch sensor
+
+The node for this device must be a child of a I2C controller node, as the
+device communicates via I2C.
+
+Required properties:
+
+	compatible:	Must be "atmel,atmegaxx_captouch".
+	reg:		The I2C slave address of the device.
+	interrupts:	Property describing the interrupt line the device
+			is connected to. The device only has one interrupt
+			source.
+	linux,keycodes:	Specifies an array of numeric keycode values to
+			be used for reporting button presses. The array can
+			contain up to 8 entries.
+
+Optional properties:
+
+	autorepeat:	Enables the Linux input system's autorepeat
+			feature on the input device.
+
+Example:
+
+	atmegaxx_captouch@51 {
+		compatible = "atmel,atmegaxx_captouch";
+		reg = <0x51>;
+		interrupt-parent = <&tlmm>;
+		interrupts = <67 IRQ_TYPE_EDGE_FALLING>;
+		linux,keycodes = <BTN_0>, <BTN_1>,
+			<BTN_2>, <BTN_3>,
+			<BTN_4>, <BTN_5>,
+			<BTN_6>, <BTN_7>;
+		autorepeat;
+	};
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 838824b..4cee1ac 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -82,6 +82,17 @@  config INPUT_ARIZONA_HAPTICS
 	  To compile this driver as a module, choose M here: the
 	  module will be called arizona-haptics.
 
+config INPUT_ATMEGAXX_CAPTOUCH
+	tristate "Atmel AtmegaXX Capacitive Touch"
+	depends on OF || COMPILE_TEST
+	help
+	  Say Y here if an Atmel Capacitive Touch device is connected to
+	  an I2C bus. One should find "atmel,atmegaxx_captouch" node in
+	  the board specific DTS.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called atmegaxx_captouch.
+
 config INPUT_BMA150
 	tristate "BMA150/SMB380 acceleration sensor support"
 	depends on I2C
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index f77268e..7254bd6c 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -17,6 +17,7 @@  obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
 obj-$(CONFIG_INPUT_ARIZONA_HAPTICS)	+= arizona-haptics.o
 obj-$(CONFIG_INPUT_ATI_REMOTE2)		+= ati_remote2.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS)		+= atlas_btns.o
+obj-$(CONFIG_INPUT_ATMEGAXX_CAPTOUCH)	+= atmegaxx_captouch.o
 obj-$(CONFIG_INPUT_BFIN_ROTARY)		+= bfin_rotary.o
 obj-$(CONFIG_INPUT_BMA150)		+= bma150.o
 obj-$(CONFIG_INPUT_CM109)		+= cm109.o
diff --git a/drivers/input/misc/atmegaxx_captouch.c b/drivers/input/misc/atmegaxx_captouch.c
new file mode 100644
index 0000000..bd886c1
--- /dev/null
+++ b/drivers/input/misc/atmegaxx_captouch.c
@@ -0,0 +1,278 @@ 
+/*
+ * Atmel Atmegaxx Capacitive Touch Driver
+ *
+ * Copyright (C) 2016 Google, inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * For raw i2c access from userspace, use i2cset/i2cget
+ * to poke at /dev/i2c-N devices.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+/* Maximum number of buttons supported */
+#define MAX_NUM_OF_BUTTONS		8
+
+/* Registers */
+#define REG_KEY1_THRESHOLD		0x02
+#define REG_KEY2_THRESHOLD		0x03
+#define REG_KEY3_THRESHOLD		0x04
+#define REG_KEY4_THRESHOLD		0x05
+
+#define REG_KEY1_REF_H			0x20
+#define REG_KEY1_REF_L			0x21
+#define REG_KEY2_REF_H			0x22
+#define REG_KEY2_REF_L			0x23
+#define REG_KEY3_REF_H			0x24
+#define REG_KEY3_REF_L			0x25
+#define REG_KEY4_REF_H			0x26
+#define REG_KEY4_REF_L			0x27
+
+#define REG_KEY1_DLT_H			0x30
+#define REG_KEY1_DLT_L			0x31
+#define REG_KEY2_DLT_H			0x32
+#define REG_KEY2_DLT_L			0x33
+#define REG_KEY3_DLT_H			0x34
+#define REG_KEY3_DLT_L			0x35
+#define REG_KEY4_DLT_H			0x36
+#define REG_KEY4_DLT_L			0x37
+
+#define REG_KEY_STATE			0x3C
+
+/*
+ * @i2c_client: I2C slave device client pointer
+ * @input: Input device pointer
+ * @num_btn: Number of buttons
+ * @keycodes: map of button# to KeyCode
+ * @prev_btn: Previous key state to detect button "press" or "release"
+ * @xfer_buf: I2C transfer buffer
+ */
+struct atmegaxx_captouch_device {
+	struct i2c_client *client;
+	struct input_dev *input;
+	u32 num_btn;
+	u32 keycodes[MAX_NUM_OF_BUTTONS];
+	u8 prev_btn;
+	u8 xfer_buf[8] ____cacheline_aligned;
+};
+
+/*
+ * Read from I2C slave device
+ * The protocol is that the client has to provide both the register address
+ * and the length, and while reading back the device would prepend the data
+ * with address and length for verification.
+ */
+static int atmegaxx_read(struct atmegaxx_captouch_device *atmegaxx,
+			 u8 reg, u8 *data, size_t len)
+{
+	struct i2c_client *client = atmegaxx->client;
+	struct device *dev = &client->dev;
+	struct i2c_msg msg[2];
+	int err;
+
+	if (len > sizeof(atmegaxx->xfer_buf) - 2)
+		return -EINVAL;
+
+	atmegaxx->xfer_buf[0] = reg;
+	atmegaxx->xfer_buf[1] = len;
+
+	msg[0].addr = client->addr;
+	msg[0].flags = 0;
+	msg[0].buf = atmegaxx->xfer_buf;
+	msg[0].len = 2;
+
+	msg[1].addr = client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].buf = atmegaxx->xfer_buf;
+	msg[1].len = len + 2;
+
+	err = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+	if (err != ARRAY_SIZE(msg))
+		return err < 0 ? err : -EIO;
+
+	if (atmegaxx->xfer_buf[0] != reg) {
+		dev_err(dev, "I2C read error: register address does not match\n");
+		return -ECOMM;
+	}
+
+	memcpy(data, &atmegaxx->xfer_buf[2], len);
+
+	return 0;
+}
+
+/*
+ * Handle interrupt and report the key changes to the input system.
+ * Multi-touch can be supported; however, it really depends on whether
+ * the device can multi-touch.
+ */
+static irqreturn_t atmegaxx_captouch_isr(int irq, void *data)
+{
+	struct atmegaxx_captouch_device *atmegaxx = data;
+	struct device *dev = &atmegaxx->client->dev;
+	int error;
+	int i;
+	u8 new_btn;
+	u8 changed_btn;
+
+	error = atmegaxx_read(atmegaxx, REG_KEY_STATE, &new_btn, 1);
+	if (error) {
+		dev_err(dev, "failed to read button state: %d\n", error);
+		goto out;
+	}
+
+	dev_dbg(dev, "%s: button state %#02x\n", __func__, new_btn);
+
+	changed_btn = new_btn ^ atmegaxx->prev_btn;
+	atmegaxx->prev_btn = new_btn;
+
+	for (i = 0; i < atmegaxx->num_btn; i++) {
+		if (changed_btn & BIT(i))
+			input_report_key(atmegaxx->input,
+					 atmegaxx->keycodes[i],
+					 new_btn & BIT(i));
+	}
+
+	input_sync(atmegaxx->input);
+
+out:
+	return IRQ_HANDLED;
+}
+
+/*
+ * Probe function to setup the device, input system and interrupt
+ */
+static int atmegaxx_captouch_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct atmegaxx_captouch_device *atmegaxx;
+	struct device *dev = &client->dev;
+	struct device_node *node;
+	int i;
+	int err;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_BYTE_DATA |
+					I2C_FUNC_SMBUS_WORD_DATA |
+					I2C_FUNC_SMBUS_I2C_BLOCK)) {
+		dev_err(dev, "needed i2c functionality is not supported\n");
+		return -EINVAL;
+	}
+
+	atmegaxx = devm_kzalloc(dev, sizeof(*atmegaxx), GFP_KERNEL);
+	if (!atmegaxx)
+		return -ENOMEM;
+
+	atmegaxx->client = client;
+	i2c_set_clientdata(client, atmegaxx);
+
+	err = atmegaxx_read(atmegaxx, REG_KEY_STATE,
+			    &atmegaxx->prev_btn, sizeof(atmegaxx->prev_btn));
+	if (err) {
+		dev_err(dev, "failed to read initial button state: %d\n", err);
+		return err;
+	}
+
+	atmegaxx->input = devm_input_allocate_device(dev);
+	if (!atmegaxx->input) {
+		dev_err(dev, "failed to allocate input device\n");
+		return -ENOMEM;
+	}
+
+	atmegaxx->input->id.bustype = BUS_I2C;
+	atmegaxx->input->id.product = 0x880A;
+	atmegaxx->input->id.version = 0;
+	atmegaxx->input->name = "ATMegaXX Capacitive Button Controller";
+	__set_bit(EV_KEY, atmegaxx->input->evbit);
+
+	node = dev->of_node;
+	if (!node) {
+		dev_err(dev, "failed to find matching node in device tree\n");
+		return -EINVAL;
+	}
+
+	if (of_property_read_bool(node, "autorepeat"))
+		__set_bit(EV_REP, atmegaxx->input->evbit);
+
+	atmegaxx->num_btn = of_property_count_u32_elems(node, "linux,keymap");
+	if (atmegaxx->num_btn > MAX_NUM_OF_BUTTONS)
+		atmegaxx->num_btn = MAX_NUM_OF_BUTTONS;
+
+	err = of_property_read_u32_array(node, "linux,keycodes",
+					 atmegaxx->keycodes,
+					 atmegaxx->num_btn);
+	if (err) {
+		dev_err(dev,
+			"failed to read linux,keycode property: %d\n", err);
+		return err;
+	}
+
+	for (i = 0; i < atmegaxx->num_btn; i++)
+		__set_bit(atmegaxx->keycodes[i], atmegaxx->input->keybit);
+
+	atmegaxx->input->keycode = atmegaxx->keycodes;
+	atmegaxx->input->keycodesize = sizeof(atmegaxx->keycodes[0]);
+	atmegaxx->input->keycodemax = atmegaxx->num_btn;
+
+	err = input_register_device(atmegaxx->input);
+	if (err)
+		return err;
+
+	err = devm_request_threaded_irq(dev, client->irq, NULL,
+				atmegaxx_captouch_isr, IRQF_ONESHOT,
+				"atmegaxx_captouch", atmegaxx);
+	if (err) {
+		dev_err(dev, "failed to request irq %d: %d\n",
+			client->irq, err);
+		return err;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id atmegaxx_captouch_of_id[] = {
+	{
+		.compatible = "atmel,atmegaxx_captouch",
+	},
+	{ /* sentinel */ }
+}
+MODULE_DEVICE_TABLE(of, atmegaxx_captouch_of_id);
+#endif
+
+static const struct i2c_device_id atmegaxx_captouch_id[] = {
+	{ "atmegaxx_captouch", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, atmegaxx_captouch_id);
+
+static struct i2c_driver atmegaxx_captouch_driver = {
+	.probe		= atmegaxx_captouch_probe,
+	.id_table	= atmegaxx_captouch_id,
+	.driver		= {
+		.name	= "atmegaxx_captouch",
+		.of_match_table = of_match_ptr(atmegaxx_captouch_of_id),
+	},
+};
+module_i2c_driver(atmegaxx_captouch_driver);
+
+/* Module information */
+MODULE_AUTHOR("Hung-yu Wu <hywu@google.com>");
+MODULE_DESCRIPTION("Atmel ATmegaXX Capacitance Touch Sensor I2C Driver");
+MODULE_LICENSE("GPL v2");