Thread (4 messages) 4 messages, 1 author, 2017-07-06

[PATCH v3 2/4] Input: icn8318 - Add support for icn8505

flat view
STALE3397d

From: Hans de Goede <hidden>
Date: 2017-07-06 20:49:37
Subsystem: chipone icn8318 i2c touchscreen driver, input (keyboard, mouse, joystick, touchscreen) drivers, open firmware and flattened device tree bindings, the rest · Maintainers: Hans de Goede, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Torvalds

The icn8505 variant found on some x86 tablets has almost the same protocol
as the 8318, protocol wise there are only a few small differences:

1) The 8505 uses 16 bit register addresses and has a different register
address for the location of the touch data.
2) The 8505 coordinates are in little-endian format instead of in be.
3) The 8505 allows reading the resolution back from the controller

Signed-off-by: Hans de Goede <redacted>
---
Changes in v2:
-Read resolution directly from the controller
Changes in v3:
-Make x/y touch_data members u8 arrays instead of __be16 with a force-cast
 to __le16 for the icn8505 case
-Add a coord_to_cpu function pointer to struct icn8318_data, instead
 of doing a data->model check
---
 .../bindings/input/touchscreen/chipone_icn8318.txt |  2 +-
 drivers/input/touchscreen/Kconfig                  |  3 +-
 drivers/input/touchscreen/chipone_icn8318.c        | 91 ++++++++++++++++++----
 3 files changed, 77 insertions(+), 19 deletions(-)
diff --git a/Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt b/Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt
index d11f8d615b5d..9fdd80749386 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt
@@ -1,7 +1,7 @@
 * ChipOne icn8318 I2C touchscreen controller
 
 Required properties:
- - compatible		  : "chipone,icn8318"
+ - compatible		  : "chipone,icn8318" or "chipone,icn8505"
  - reg			  : I2C slave address of the chip (0x40)
  - interrupt-parent	  : a phandle pointing to the interrupt controller
 			    serving the interrupt for this chip
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index cf26ca49ae6d..fff1467506e7 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -157,7 +157,8 @@ config TOUCHSCREEN_CHIPONE_ICN8318
 	depends on I2C
 	depends on OF
 	help
-	  Say Y here if you have a ChipOne icn8318 based I2C touchscreen.
+	  Say Y here if you have a ChipOne icn8318 or icn8505 based
+	  I2C touchscreen.
 
 	  If unsure, say N.
 
diff --git a/drivers/input/touchscreen/chipone_icn8318.c b/drivers/input/touchscreen/chipone_icn8318.c
index 27df6ca3a8a3..eba2f7eb3c3a 100644
--- a/drivers/input/touchscreen/chipone_icn8318.c
+++ b/drivers/input/touchscreen/chipone_icn8318.c
@@ -1,7 +1,7 @@
 /*
  * Driver for ChipOne icn8318 i2c touchscreen controller
  *
- * Copyright (c) 2015 Red Hat Inc.
+ * Copyright (c) 2015-2017 Red Hat Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -12,6 +12,7 @@
  * Hans de Goede <hdegoede@redhat.com>
  */
 
+#include <asm/unaligned.h>
 #include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
@@ -20,6 +21,7 @@
 #include <linux/input/touchscreen.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 
 #define ICN8318_REG_POWER		4
 #define ICN8318_REG_TOUCHDATA		16
@@ -30,10 +32,18 @@
 
 #define ICN8318_MAX_TOUCHES		5
 
+#define ICN8505_REG_TOUCHDATA		0x1000
+#define ICN8505_REG_CONFIGDATA		0x8000
+
+enum icn8318_model {
+	ICN8318,
+	ICN8505,
+};
+
 struct icn8318_touch {
 	__u8 slot;
-	__be16 x;
-	__be16 y;
+	__u8 x[2];
+	__u8 y[2];
 	__u8 pressure;	/* Seems more like finger width then pressure really */
 	__u8 event;
 /* The difference between 2 and 3 is unclear */
@@ -54,27 +64,48 @@ struct icn8318_data {
 	struct input_dev *input;
 	struct gpio_desc *wake_gpio;
 	struct touchscreen_properties prop;
+	enum icn8318_model model;
+	int touchdata_reg;
+	u16 (*coord_to_cpu)(const u8 *buf);
 };
 
-static int icn8318_read_touch_data(struct i2c_client *client,
-				   struct icn8318_touch_data *touch_data)
+static int icn8318_read_data(struct icn8318_data *data, int reg,
+			     void *buf, int len)
 {
-	u8 reg = ICN8318_REG_TOUCHDATA;
+	u8 addr[2];
 	struct i2c_msg msg[2] = {
 		{
-			.addr = client->addr,
-			.len = 1,
-			.buf = &reg
+			.addr = data->client->addr,
+			.buf = addr
 		},
 		{
-			.addr = client->addr,
+			.addr = data->client->addr,
 			.flags = I2C_M_RD,
-			.len = sizeof(struct icn8318_touch_data),
-			.buf = (u8 *)touch_data
+			.len = len,
+			.buf = buf
 		}
 	};
 
-	return i2c_transfer(client->adapter, msg, 2);
+	if (data->model == ICN8318) {
+		addr[0] = reg;
+		msg[0].len = 1;
+	} else {
+		addr[0] = reg >> 8;
+		addr[1] = reg & 0xff;
+		msg[0].len = 2;
+	}
+
+	return i2c_transfer(data->client->adapter, msg, 2);
+}
+
+static u16 icn8318_coord_to_cpu(const u8 *buf)
+{
+	return get_unaligned_be16(buf);
+}
+
+static u16 icn8505_coord_to_cpu(const u8 *buf)
+{
+	return get_unaligned_le16(buf);
 }
 
 static inline bool icn8318_touch_active(u8 event)
@@ -90,7 +121,8 @@ static irqreturn_t icn8318_irq(int irq, void *dev_id)
 	struct icn8318_touch_data touch_data;
 	int i, ret;
 
-	ret = icn8318_read_touch_data(data->client, &touch_data);
+	ret = icn8318_read_data(data, data->touchdata_reg,
+				&touch_data, sizeof(touch_data));
 	if (ret < 0) {
 		dev_err(dev, "Error reading touch data: %d\n", ret);
 		return IRQ_HANDLED;
@@ -122,8 +154,9 @@ static irqreturn_t icn8318_irq(int irq, void *dev_id)
 			continue;
 
 		touchscreen_report_pos(data->input, &data->prop,
-				       be16_to_cpu(touch->x),
-				       be16_to_cpu(touch->y), true);
+				       data->coord_to_cpu(touch->x),
+				       data->coord_to_cpu(touch->y),
+				       true);
 	}
 
 	input_mt_sync_frame(data->input);
@@ -188,6 +221,7 @@ static int icn8318_probe(struct i2c_client *client,
 	struct device *dev = &client->dev;
 	struct icn8318_data *data;
 	struct input_dev *input;
+	__le16 resolution[2];
 	int error;
 
 	if (!client->irq) {
@@ -220,6 +254,28 @@ static int icn8318_probe(struct i2c_client *client,
 	input_set_capability(input, EV_ABS, ABS_MT_POSITION_X);
 	input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y);
 
+	data->model = (long)of_device_get_match_data(dev);
+
+	if (data->model == ICN8318) {
+		data->touchdata_reg = ICN8318_REG_TOUCHDATA;
+		data->coord_to_cpu  = icn8318_coord_to_cpu;
+	} else {
+		data->touchdata_reg = ICN8505_REG_TOUCHDATA;
+		data->coord_to_cpu  = icn8505_coord_to_cpu;
+
+		error = icn8318_read_data(data, ICN8505_REG_CONFIGDATA,
+					  resolution, sizeof(resolution));
+		if (error < 0) {
+			dev_err(dev, "Error reading resolution: %d\n", error);
+			return error;
+		}
+
+		input_set_abs_params(input, ABS_MT_POSITION_X, 0,
+				     le16_to_cpu(resolution[0]) - 1, 0, 0);
+		input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
+				     le16_to_cpu(resolution[1]) - 1, 0, 0);
+	}
+
 	touchscreen_parse_properties(input, true, &data->prop);
 	if (!input_abs_get_max(input, ABS_MT_POSITION_X) ||
 	    !input_abs_get_max(input, ABS_MT_POSITION_Y)) {
@@ -256,7 +312,8 @@ static int icn8318_probe(struct i2c_client *client,
 }
 
 static const struct of_device_id icn8318_of_match[] = {
-	{ .compatible = "chipone,icn8318" },
+	{ .compatible = "chipone,icn8318", .data = (void *)ICN8318 },
+	{ .compatible = "chipone,icn8505", .data = (void *)ICN8505 },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, icn8318_of_match);
-- 
2.13.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help