All of lore.kernel.org
 help / color / mirror / Atom feed
* Atmel updates to atmel_mxt_ts touch controller driver
@ 2013-02-22 17:57 Nick Dyer
  2013-02-22 17:57 ` [PATCH 01/40] Input: atmel_mxt_ts - Make wait-after-reset period compatible with all chips Nick Dyer
                   ` (41 more replies)
  0 siblings, 42 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:57 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

The following patches are a large series of updates in functionality to the
atmel_mxt_ts touch driver. They apply cleanly to input/next.

These changes address some of the same issues that appear in the patchsets
submitted by Daniel Kurtz and Peter Meerwald. However, they go much further in
adding support for new objects, improving performance, and increasing
reliability. They have been regularly regression tested against old and new
chips which use the same protocol.

We also provide a set of user-space utilities as open source which are 
available from github and work well with this driver:
  https://github.com/atmel-maxtouch/obp-utils

Most of my focus in working on these changes has been to support Atmel's
customers, who tend not to be using the mainline kernel. Unfortunately this 
has generated somewhat of a backlog in getting these improvements into
mainline. My current focus is to get these improvements upstream and I have
time allocated to make any alterations as necessary. Since the scope of this
patchset is so large any upstream delta tends to cause a big rebasing effort.
I would suggest that I merge any useful improvements from the other patchsets
to make a combined patchset.

regards
--
Nick Dyer Senior Software Engineer
ITDev Hardware and Software Development Consultancy http://www.itdev.co.uk


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH 01/40] Input: atmel_mxt_ts - Make wait-after-reset period compatible with all chips
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
@ 2013-02-22 17:57 ` Nick Dyer
  2013-02-22 23:20   ` Benson Leung
  2013-02-22 17:57 ` [PATCH 02/40] Input: atmel_mxt_ts - add macros for object instances and size Nick Dyer
                   ` (40 subsequent siblings)
  41 siblings, 1 reply; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:57 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Iiro Valkonen, Nick Dyer

From: Iiro Valkonen <iiro.valkonen@atmel.com>

The delay before the chip can be accessed after reset varies between different
chips in maXTouch family. Waiting for 200ms and then monitoring the CHG (chip
is ready when the line is low) is guaranteed to work with all chips.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   91 ++++++++++++++++++++++++------
 include/linux/i2c/atmel_mxt_ts.h         |    1 +
 2 files changed, 76 insertions(+), 16 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index d04f810..b4bf946 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2,6 +2,7 @@
  * Atmel maXTouch Touchscreen driver
  *
  * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Copyright (C) 2011 Atmel Corporation
  * Author: Joonyoung Shim <jy0922.shim@samsung.com>
  *
  * This program is free software; you can redistribute  it and/or modify it
@@ -175,11 +176,14 @@
 
 /* Define for MXT_GEN_COMMAND_T6 */
 #define MXT_BOOT_VALUE		0xa5
+#define MXT_RESET_VALUE		0x01
 #define MXT_BACKUP_VALUE	0x55
-#define MXT_BACKUP_TIME		25	/* msec */
-#define MXT_RESET_TIME		65	/* msec */
 
-#define MXT_FWRESET_TIME	175	/* msec */
+/* Delay times */
+#define MXT_BACKUP_TIME		25	/* msec */
+#define MXT_RESET_TIME		200	/* msec */
+#define MXT_RESET_NOCHGREAD	400	/* msec */
+#define MXT_FWRESET_TIME	1000	/* msec */
 
 /* Command to unlock bootloader */
 #define MXT_UNLOCK_CMD_MSB	0xaa
@@ -249,6 +253,7 @@ struct mxt_data {
 
 	/* Cached parameters from object table */
 	u8 T6_reportid;
+	u16 T6_address;
 	u8 T9_reportid_min;
 	u8 T9_reportid_max;
 };
@@ -599,6 +604,66 @@ end:
 	return IRQ_HANDLED;
 }
 
+static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset, u8 value, bool wait)
+{
+	u16 reg;
+	u8 command_register;
+	int ret;
+	int timeout_counter = 0;
+
+	reg = data->T6_address + cmd_offset;
+
+	ret = mxt_write_reg(data->client, reg, value);
+	if (ret)
+		return ret;
+
+	if (!wait)
+		return 0;
+
+	do {
+		msleep(20);
+		ret = __mxt_read_reg(data->client, reg, 1, &command_register);
+		if (ret)
+			return ret;
+	} while ((command_register != 0) && (timeout_counter++ <= 100));
+
+	if (timeout_counter > 100) {
+		dev_err(&data->client->dev, "Command failed!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int mxt_soft_reset(struct mxt_data *data, u8 value)
+{
+	int ret;
+	int timeout_counter = 0;
+	struct device *dev = &data->client->dev;
+
+	dev_info(dev, "Resetting chip\n");
+
+	ret = mxt_t6_command(data, MXT_COMMAND_RESET, value, false);
+	if (ret)
+		return ret;
+
+	if (data->pdata->read_chg == NULL) {
+		msleep(MXT_RESET_NOCHGREAD);
+	} else {
+		msleep(MXT_RESET_TIME);
+
+		timeout_counter = 0;
+		while ((timeout_counter++ <= 100) && data->pdata->read_chg())
+			msleep(20);
+		if (timeout_counter > 100) {
+			dev_err(dev, "No response after reset!\n");
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
 static int mxt_check_reg_init(struct mxt_data *data)
 {
 	const struct mxt_platform_data *pdata = data->pdata;
@@ -759,6 +824,7 @@ static int mxt_get_object_table(struct mxt_data *data)
 		switch (object->type) {
 		case MXT_GEN_COMMAND_T6:
 			data->T6_reportid = min_id;
+			data->T6_address = object->start_address;
 			break;
 		case MXT_TOUCH_MULTI_T9:
 			data->T9_reportid_min = min_id;
@@ -811,16 +877,9 @@ static int mxt_initialize(struct mxt_data *data)
 
 	mxt_handle_pdata(data);
 
-	/* Backup to memory */
-	mxt_write_object(data, MXT_GEN_COMMAND_T6,
-			MXT_COMMAND_BACKUPNV,
-			MXT_BACKUP_VALUE);
-	msleep(MXT_BACKUP_TIME);
-
-	/* Soft reset */
-	mxt_write_object(data, MXT_GEN_COMMAND_T6,
-			MXT_COMMAND_RESET, 1);
-	msleep(MXT_RESET_TIME);
+	error = mxt_t6_command(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE, false);
+	if (!error)
+		mxt_soft_reset(data, MXT_RESET_VALUE);
 
 	/* Update matrix size at info struct */
 	error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
@@ -960,9 +1019,9 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 	}
 
 	/* Change to the bootloader mode */
-	mxt_write_object(data, MXT_GEN_COMMAND_T6,
-			MXT_COMMAND_RESET, MXT_BOOT_VALUE);
-	msleep(MXT_RESET_TIME);
+	ret = mxt_soft_reset(data, MXT_BOOT_VALUE);
+	if (ret)
+		return ret;
 
 	/* Change to slave address of bootloader */
 	if (client->addr == MXT_APP_LOW)
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index f027f7a..ef59c22 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -39,6 +39,7 @@ struct mxt_platform_data {
 	unsigned int voltage;
 	unsigned char orient;
 	unsigned long irqflags;
+	u8(*read_chg) (void);
 };
 
 #endif /* __LINUX_ATMEL_MXT_TS_H */
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 02/40] Input: atmel_mxt_ts - add macros for object instances and size
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
  2013-02-22 17:57 ` [PATCH 01/40] Input: atmel_mxt_ts - Make wait-after-reset period compatible with all chips Nick Dyer
@ 2013-02-22 17:57 ` Nick Dyer
  2013-02-22 17:57 ` [PATCH 03/40] Input: atmel_mxt_ts - Add memory access interface via sysfs Nick Dyer
                   ` (39 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:57 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

The raw Atmel Object Based Protocol stores the instances and size minus one as
an efficiency measure. This can easily lead to bugs. Rename the variables to
make it clear what they are and implement macros for the conversion.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b4bf946..1de1d24 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -216,6 +216,9 @@
 /* Touchscreen absolute values */
 #define MXT_MAX_AREA		0xff
 
+#define OBP_INSTANCES(o) ((u16)((o)->instances_minus_one) + 1)
+#define OBP_SIZE(o) ((u16)((o)->size_minus_one) + 1)
+
 struct mxt_info {
 	u8 family_id;
 	u8 variant_id;
@@ -229,8 +232,8 @@ struct mxt_info {
 struct mxt_object {
 	u8 type;
 	u16 start_address;
-	u8 size;		/* Size of each instance - 1 */
-	u8 instances;		/* Number of instances - 1 */
+	u8 size_minus_one;
+	u8 instances_minus_one;
 	u8 num_report_ids;
 } __packed;
 
@@ -500,7 +503,7 @@ static int mxt_write_object(struct mxt_data *data,
 	u16 reg;
 
 	object = mxt_get_object(data, type);
-	if (!object || offset >= object->size + 1)
+	if (!object || offset >= OBP_SIZE(object))
 		return -EINVAL;
 
 	reg = object->start_address;
@@ -684,7 +687,7 @@ static int mxt_check_reg_init(struct mxt_data *data)
 		if (!mxt_object_writable(object->type))
 			continue;
 
-		size = (object->size + 1) * (object->instances + 1);
+		size = OBP_SIZE(object) * OBP_INSTANCES(object);
 		if (index + size > pdata->config_length) {
 			dev_err(dev, "Not enough config data!\n");
 			return -EINVAL;
@@ -809,7 +812,7 @@ static int mxt_get_object_table(struct mxt_data *data)
 		if (object->num_report_ids) {
 			min_id = reportid;
 			reportid += object->num_report_ids *
-					(object->instances + 1);
+					OBP_INSTANCES(object);
 			max_id = reportid - 1;
 		} else {
 			min_id = 0;
@@ -818,8 +821,8 @@ static int mxt_get_object_table(struct mxt_data *data)
 
 		dev_dbg(&data->client->dev,
 			"Type %2d Start %3d Size %3d Instances %2d ReportIDs %3u : %3u\n",
-			object->type, object->start_address, object->size + 1,
-			object->instances + 1, min_id, max_id);
+			object->type, object->start_address, OBP_SIZE(object),
+			OBP_INSTANCES(object), min_id, max_id);
 
 		switch (object->type) {
 		case MXT_GEN_COMMAND_T6:
@@ -949,11 +952,11 @@ static ssize_t mxt_show_instance(char *buf, int count,
 {
 	int i;
 
-	if (object->instances > 0)
+	if (OBP_INSTANCES(object) > 1)
 		count += scnprintf(buf + count, PAGE_SIZE - count,
 				   "Instance %u\n", instance);
 
-	for (i = 0; i < object->size + 1; i++)
+	for (i = 0; i < OBP_SIZE(object); i++)
 		count += scnprintf(buf + count, PAGE_SIZE - count,
 				"\t[%2u]: %02x (%d)\n", i, val[i], val[i]);
 	count += scnprintf(buf + count, PAGE_SIZE - count, "\n");
@@ -986,8 +989,8 @@ static ssize_t mxt_object_show(struct device *dev,
 		count += scnprintf(buf + count, PAGE_SIZE - count,
 				"T%u:\n", object->type);
 
-		for (j = 0; j < object->instances + 1; j++) {
-			u16 size = object->size + 1;
+		for (j = 0; j < OBP_INSTANCES(object); j++) {
+			u16 size = OBP_SIZE(object);
 			u16 addr = object->start_address + j * size;
 
 			error = __mxt_read_reg(data->client, addr, size, obuf);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 03/40] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
  2013-02-22 17:57 ` [PATCH 01/40] Input: atmel_mxt_ts - Make wait-after-reset period compatible with all chips Nick Dyer
  2013-02-22 17:57 ` [PATCH 02/40] Input: atmel_mxt_ts - add macros for object instances and size Nick Dyer
@ 2013-02-22 17:57 ` Nick Dyer
  2013-02-22 17:57 ` [PATCH 04/40] Input: atmel_mxt_ts - Implement debug output for messages Nick Dyer
                   ` (38 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:57 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Atmel maXTouch chips can be addressed via an "Object Based Protocol" which
defines how i2c registers are mapped to different functions within the
chips. This interface exposes the register map and allows user-space
utilities to inspect and alter object configuration, and to view diagnostic
data, while the device is running.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   78 ++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 1de1d24..9cfb124 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -49,6 +49,8 @@
 
 #define MXT_OBJECT_SIZE		6
 
+#define MXT_MAX_BLOCK_WRITE	256
+
 /* Object types */
 #define MXT_DEBUG_DIAGNOSTIC_T37	37
 #define MXT_GEN_MESSAGE_T5		5
@@ -249,10 +251,12 @@ struct mxt_data {
 	char phys[64];		/* device physical location */
 	const struct mxt_platform_data *pdata;
 	struct mxt_object *object_table;
+	u16 mem_size;
 	struct mxt_info info;
 	unsigned int irq;
 	unsigned int max_x;
 	unsigned int max_y;
+	struct bin_attribute mem_access_attr;
 
 	/* Cached parameters from object table */
 	u8 T6_reportid;
@@ -794,6 +798,7 @@ static int mxt_get_object_table(struct mxt_data *data)
 	int error;
 	int i;
 	u8 reportid;
+	u16 end_address;
 
 	table_size = data->info.object_num * sizeof(struct mxt_object);
 	error = __mxt_read_reg(client, MXT_OBJECT_START, table_size,
@@ -803,6 +808,7 @@ static int mxt_get_object_table(struct mxt_data *data)
 
 	/* Valid Report IDs start counting from 1 */
 	reportid = 1;
+	data->mem_size = 0;
 	for (i = 0; i < data->info.object_num; i++) {
 		struct mxt_object *object = data->object_table + i;
 		u8 min_id, max_id;
@@ -834,6 +840,12 @@ static int mxt_get_object_table(struct mxt_data *data)
 			data->T9_reportid_max = max_id;
 			break;
 		}
+
+		end_address = object->start_address
+			+ OBP_SIZE(object) * OBP_INSTANCES(object) - 1;
+
+		if (end_address >= data->mem_size)
+			data->mem_size = end_address + 1;
 	}
 
 	return 0;
@@ -1110,6 +1122,56 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 	return count;
 }
 
+static int mxt_check_mem_access_params(struct mxt_data *data, loff_t off,
+				       size_t *count)
+{
+	if (off >= data->mem_size)
+		return -EIO;
+
+	if (off + *count > data->mem_size)
+		*count = data->mem_size - off;
+
+	if (*count > MXT_MAX_BLOCK_WRITE)
+		*count = MXT_MAX_BLOCK_WRITE;
+
+	return 0;
+}
+
+static ssize_t mxt_mem_access_read(struct file *filp, struct kobject *kobj,
+	struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct mxt_data *data = dev_get_drvdata(dev);
+	int ret = 0;
+
+	ret = mxt_check_mem_access_params(data, off, &count);
+	if (ret < 0)
+		return ret;
+
+	if (count > 0)
+		ret = __mxt_read_reg(data->client, off, count, buf);
+
+	return ret == 0 ? count : ret;
+}
+
+static ssize_t mxt_mem_access_write(struct file *filp, struct kobject *kobj,
+	struct bin_attribute *bin_attr, char *buf, loff_t off,
+	size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct mxt_data *data = dev_get_drvdata(dev);
+	int ret = 0;
+
+	ret = mxt_check_mem_access_params(data, off, &count);
+	if (ret < 0)
+		return ret;
+
+	if (count > 0)
+		ret = __mxt_write_reg(data->client, off, count, buf);
+
+	return ret == 0 ? count : 0;
+}
+
 static DEVICE_ATTR(fw_version, S_IRUGO, mxt_fw_version_show, NULL);
 static DEVICE_ATTR(hw_version, S_IRUGO, mxt_hw_version_show, NULL);
 static DEVICE_ATTR(object, S_IRUGO, mxt_object_show, NULL);
@@ -1247,8 +1309,23 @@ static int mxt_probe(struct i2c_client *client,
 	if (error)
 		goto err_unregister_device;
 
+	sysfs_bin_attr_init(&data->mem_access_attr);
+	data->mem_access_attr.attr.name = "mem_access";
+	data->mem_access_attr.attr.mode = S_IRUGO | S_IWUSR;
+	data->mem_access_attr.read = mxt_mem_access_read;
+	data->mem_access_attr.write = mxt_mem_access_write;
+	data->mem_access_attr.size = data->mem_size;
+
+	if (sysfs_create_bin_file(&client->dev.kobj,
+				  &data->mem_access_attr) < 0) {
+		dev_err(&client->dev, "Failed to create %s\n",
+			data->mem_access_attr.attr.name);
+		goto err_remove_sysfs_group;
+	}
 	return 0;
 
+err_remove_sysfs_group:
+	sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
 err_unregister_device:
 	input_unregister_device(input_dev);
 	input_dev = NULL;
@@ -1266,6 +1343,7 @@ static int mxt_remove(struct i2c_client *client)
 {
 	struct mxt_data *data = i2c_get_clientdata(client);
 
+	sysfs_remove_bin_file(&client->dev.kobj, &data->mem_access_attr);
 	sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
 	free_irq(data->irq, data);
 	input_unregister_device(data->input_dev);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 04/40] Input: atmel_mxt_ts - Implement debug output for messages
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (2 preceding siblings ...)
  2013-02-22 17:57 ` [PATCH 03/40] Input: atmel_mxt_ts - Add memory access interface via sysfs Nick Dyer
@ 2013-02-22 17:57 ` Nick Dyer
  2013-02-22 17:57 ` [PATCH 05/40] Input: atmel_mxt_ts - Improve error reporting and debug Nick Dyer
                   ` (37 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:57 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Add a debug switch which causes all messages from the touch controller to be
dumped to the dmesg log with a set prefix "MXT MSG:". This is used by Atmel
user-space utilities to debug touch operation. This does impact touch
performance somewhat.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   57 +++++++++++++++++++++++++-----
 1 file changed, 49 insertions(+), 8 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 9cfb124..dad0be9 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -80,6 +80,9 @@
 #define MXT_SPT_MESSAGECOUNT_T44	44
 #define MXT_SPT_CTECONFIG_T46		46
 
+/* MXT_GEN_MESSAGE_T5 object */
+#define MXT_RPTID_NOMSG		0xff
+
 /* MXT_GEN_COMMAND_T6 field */
 #define MXT_COMMAND_RESET	0
 #define MXT_COMMAND_BACKUPNV	1
@@ -257,6 +260,7 @@ struct mxt_data {
 	unsigned int max_x;
 	unsigned int max_y;
 	struct bin_attribute mem_access_attr;
+	bool debug_enabled;
 
 	/* Cached parameters from object table */
 	u8 T6_reportid;
@@ -329,11 +333,10 @@ static bool mxt_object_writable(unsigned int type)
 	}
 }
 
-static void mxt_dump_message(struct device *dev,
-			     struct mxt_message *message)
+static void mxt_dump_message(struct device *dev, struct mxt_message *message)
 {
-	dev_dbg(dev, "reportid: %u\tmessage: %*ph\n",
-		message->reportid, 7, message->message);
+	dev_dbg(dev, "MXT MSG: %*ph\n",
+		       sizeof(struct mxt_message), message);
 }
 
 static int mxt_check_bootloader(struct i2c_client *client,
@@ -579,6 +582,7 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
 	struct device *dev = &data->client->dev;
 	u8 reportid;
 	bool update_input = false;
+	bool handled;
 
 	do {
 		if (mxt_read_message(data, &message)) {
@@ -587,20 +591,24 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
 		}
 
 		reportid = message.reportid;
+		handled = false;
 
 		if (reportid == data->T6_reportid) {
 			u8 status = payload[0];
 			unsigned csum = mxt_extract_T6_csum(&payload[1]);
 			dev_dbg(dev, "Status: %02x Config Checksum: %06x\n",
 				status, csum);
+			handled = true;
 		} else if (mxt_is_T9_message(data, &message)) {
 			int id = reportid - data->T9_reportid_min;
 			mxt_input_touchevent(data, &message, id);
 			update_input = true;
-		} else {
-			mxt_dump_message(dev, &message);
+			handled = true;
 		}
-	} while (reportid != 0xff);
+
+		if (!handled || data->debug_enabled)
+			mxt_dump_message(dev, &message);
+	} while (reportid != MXT_RPTID_NOMSG);
 
 	if (update_input) {
 		input_mt_report_pointer_emulation(data->input_dev, false);
@@ -719,7 +727,7 @@ static int mxt_make_highchg(struct mxt_data *data)
 		error = mxt_read_message(data, &message);
 		if (error)
 			return error;
-	} while (message.reportid != 0xff && --count);
+	} while (message.reportid != MXT_RPTID_NOMSG && --count);
 
 	if (!count) {
 		dev_err(dev, "CHG pin isn't cleared\n");
@@ -1122,6 +1130,36 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 	return count;
 }
 
+static ssize_t mxt_debug_enable_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct mxt_data *data = dev_get_drvdata(dev);
+	int count;
+	char c;
+
+	c = data->debug_enabled ? '1' : '0';
+	count = sprintf(buf, "%c\n", c);
+
+	return count;
+}
+
+static ssize_t mxt_debug_enable_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct mxt_data *data = dev_get_drvdata(dev);
+	int i;
+
+	if (sscanf(buf, "%u", &i) == 1 && i < 2) {
+		data->debug_enabled = (i == 1);
+
+		dev_dbg(dev, "%s\n", i ? "debug enabled" : "debug disabled");
+		return count;
+	} else {
+		dev_dbg(dev, "debug_enabled write error\n");
+		return -EINVAL;
+	}
+}
+
 static int mxt_check_mem_access_params(struct mxt_data *data, loff_t off,
 				       size_t *count)
 {
@@ -1176,12 +1214,15 @@ static DEVICE_ATTR(fw_version, S_IRUGO, mxt_fw_version_show, NULL);
 static DEVICE_ATTR(hw_version, S_IRUGO, mxt_hw_version_show, NULL);
 static DEVICE_ATTR(object, S_IRUGO, mxt_object_show, NULL);
 static DEVICE_ATTR(update_fw, S_IWUSR, NULL, mxt_update_fw_store);
+static DEVICE_ATTR(debug_enable, S_IWUSR | S_IRUSR, mxt_debug_enable_show,
+		   mxt_debug_enable_store);
 
 static struct attribute *mxt_attrs[] = {
 	&dev_attr_fw_version.attr,
 	&dev_attr_hw_version.attr,
 	&dev_attr_object.attr,
 	&dev_attr_update_fw.attr,
+	&dev_attr_debug_enable.attr,
 	NULL
 };
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 05/40] Input: atmel_mxt_ts - Improve error reporting and debug
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (3 preceding siblings ...)
  2013-02-22 17:57 ` [PATCH 04/40] Input: atmel_mxt_ts - Implement debug output for messages Nick Dyer
@ 2013-02-22 17:57 ` Nick Dyer
  2013-02-22 17:57 ` [PATCH 06/40] Input: atmel_mxt_ts - Remove unnecessary platform data Nick Dyer
                   ` (36 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:57 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Add error messages for probe errors
Report type in invalid object type
Tweak some other debug output messages

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   35 ++++++++++++++++++++----------
 1 file changed, 24 insertions(+), 11 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index dad0be9..9e734dc 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -364,7 +364,7 @@ recheck:
 	}
 
 	if (val != state) {
-		dev_err(&client->dev, "Unvalid bootloader mode state\n");
+		dev_err(&client->dev, "Invalid bootloader mode state\n");
 		return -EINVAL;
 	}
 
@@ -484,7 +484,7 @@ mxt_get_object(struct mxt_data *data, u8 type)
 			return object;
 	}
 
-	dev_err(&data->client->dev, "Invalid object type\n");
+	dev_err(&data->client->dev, "Invalid object type T%u\n", type);
 	return NULL;
 }
 
@@ -834,7 +834,7 @@ static int mxt_get_object_table(struct mxt_data *data)
 		}
 
 		dev_dbg(&data->client->dev,
-			"Type %2d Start %3d Size %3d Instances %2d ReportIDs %3u : %3u\n",
+			"T%u Start:%u Size:%u Instances:%u Report IDs:%u-%u\n",
 			object->type, object->start_address, OBP_SIZE(object),
 			OBP_INSTANCES(object), min_id, max_id);
 
@@ -890,13 +890,18 @@ static int mxt_initialize(struct mxt_data *data)
 
 	/* Get object table information */
 	error = mxt_get_object_table(data);
-	if (error)
-		goto err_free_object_table;
+	if (error) {
+		dev_err(&client->dev, "Error %d reading object table\n", error);
+		return error;
+	}
 
 	/* Check register init values */
 	error = mxt_check_reg_init(data);
-	if (error)
-		goto err_free_object_table;
+	if (error) {
+		dev_err(&client->dev, "Error %d initialising configuration\n",
+			error);
+		return error;
+	}
 
 	mxt_handle_pdata(data);
 
@@ -916,7 +921,7 @@ static int mxt_initialize(struct mxt_data *data)
 	info->matrix_ysize = val;
 
 	dev_info(&client->dev,
-			"Family ID: %u Variant ID: %u Major.Minor.Build: %u.%u.%02X\n",
+			"Family ID: %u Variant ID: %u Firmware V%u.%u.%02X\n",
 			info->family_id, info->variant_id, info->version >> 4,
 			info->version & 0xf, info->build);
 
@@ -1339,16 +1344,24 @@ static int mxt_probe(struct i2c_client *client,
 	}
 
 	error = mxt_make_highchg(data);
-	if (error)
+	if (error) {
+		dev_err(&client->dev, "Error %d clearing messages\n", error);
 		goto err_free_irq;
+	}
 
 	error = input_register_device(input_dev);
-	if (error)
+	if (error) {
+		dev_err(&client->dev, "Error %d registering input device\n",
+			error);
 		goto err_free_irq;
+	}
 
 	error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
-	if (error)
+	if (error) {
+		dev_err(&client->dev, "Failure %d creating sysfs group\n",
+			error);
 		goto err_unregister_device;
+	}
 
 	sysfs_bin_attr_init(&data->mem_access_attr);
 	data->mem_access_attr.attr.name = "mem_access";
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 06/40] Input: atmel_mxt_ts - Remove unnecessary platform data
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (4 preceding siblings ...)
  2013-02-22 17:57 ` [PATCH 05/40] Input: atmel_mxt_ts - Improve error reporting and debug Nick Dyer
@ 2013-02-22 17:57 ` Nick Dyer
  2013-02-22 17:57 ` [PATCH 07/40] Input: atmel_mxt_ts - Implement CRC check for configuration data Nick Dyer
                   ` (35 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:57 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

It is not necessary to download these values to the chip on every probe, since
they are stored in non-volatile memory. They only represent a tiny subset of
the available configuration options, tracking all of these options in platform
data would be a sisyphean task. It makes platform data more complex and makes
device integration more error-prone because it duplicates information set
elsewhere. In addition, different versions of maXTouch chips may have these
values in different places or may not even have them at all.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 arch/arm/mach-exynos/mach-nuri.c           |    5 ---
 arch/arm/mach-exynos/mach-universal_c210.c |    5 ---
 arch/arm/mach-s5pv210/mach-goni.c          |    5 ---
 drivers/input/touchscreen/atmel_mxt_ts.c   |   50 ----------------------------
 include/linux/i2c/atmel_mxt_ts.h           |    6 +---
 5 files changed, 1 insertion(+), 70 deletions(-)

diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
index c05d7aa..770d314 100644
--- a/arch/arm/mach-exynos/mach-nuri.c
+++ b/arch/arm/mach-exynos/mach-nuri.c
@@ -335,13 +335,8 @@ static struct i2c_board_info i2c1_devs[] __initdata = {
 
 /* TSP */
 static struct mxt_platform_data mxt_platform_data = {
-	.x_line			= 18,
-	.y_line			= 11,
 	.x_size			= 1024,
 	.y_size			= 600,
-	.blen			= 0x1,
-	.threshold		= 0x28,
-	.voltage		= 2800000,		/* 2.8V */
 	.orient			= MXT_DIAGONAL_COUNTER,
 	.irqflags		= IRQF_TRIGGER_FALLING,
 };
diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c
index ebc9dd3..8de6e36 100644
--- a/arch/arm/mach-exynos/mach-universal_c210.c
+++ b/arch/arm/mach-exynos/mach-universal_c210.c
@@ -605,13 +605,8 @@ static struct i2c_board_info i2c5_devs[] __initdata = {
 
 /* I2C3 (TSP) */
 static struct mxt_platform_data qt602240_platform_data = {
-	.x_line		= 19,
-	.y_line		= 11,
 	.x_size		= 800,
 	.y_size		= 480,
-	.blen		= 0x11,
-	.threshold	= 0x28,
-	.voltage	= 2800000,		/* 2.8V */
 	.orient		= MXT_DIAGONAL,
 	.irqflags	= IRQF_TRIGGER_FALLING,
 };
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
index 55e1dba..2743751 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -240,13 +240,8 @@ static void __init goni_radio_init(void)
 
 /* TSP */
 static struct mxt_platform_data qt602240_platform_data = {
-	.x_line		= 17,
-	.y_line		= 11,
 	.x_size		= 800,
 	.y_size		= 480,
-	.blen		= 0x21,
-	.threshold	= 0x28,
-	.voltage	= 2800000,              /* 2.8V */
 	.orient		= MXT_DIAGONAL,
 	.irqflags	= IRQF_TRIGGER_FALLING,
 };
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 9e734dc..fa294d1 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -737,54 +737,6 @@ static int mxt_make_highchg(struct mxt_data *data)
 	return 0;
 }
 
-static void mxt_handle_pdata(struct mxt_data *data)
-{
-	const struct mxt_platform_data *pdata = data->pdata;
-	u8 voltage;
-
-	/* Set touchscreen lines */
-	mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_XSIZE,
-			pdata->x_line);
-	mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_YSIZE,
-			pdata->y_line);
-
-	/* Set touchscreen orient */
-	mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_ORIENT,
-			pdata->orient);
-
-	/* Set touchscreen burst length */
-	mxt_write_object(data, MXT_TOUCH_MULTI_T9,
-			MXT_TOUCH_BLEN, pdata->blen);
-
-	/* Set touchscreen threshold */
-	mxt_write_object(data, MXT_TOUCH_MULTI_T9,
-			MXT_TOUCH_TCHTHR, pdata->threshold);
-
-	/* Set touchscreen resolution */
-	mxt_write_object(data, MXT_TOUCH_MULTI_T9,
-			MXT_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff);
-	mxt_write_object(data, MXT_TOUCH_MULTI_T9,
-			MXT_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8);
-	mxt_write_object(data, MXT_TOUCH_MULTI_T9,
-			MXT_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff);
-	mxt_write_object(data, MXT_TOUCH_MULTI_T9,
-			MXT_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8);
-
-	/* Set touchscreen voltage */
-	if (pdata->voltage) {
-		if (pdata->voltage < MXT_VOLTAGE_DEFAULT) {
-			voltage = (MXT_VOLTAGE_DEFAULT - pdata->voltage) /
-				MXT_VOLTAGE_STEP;
-			voltage = 0xff - voltage + 1;
-		} else
-			voltage = (pdata->voltage - MXT_VOLTAGE_DEFAULT) /
-				MXT_VOLTAGE_STEP;
-
-		mxt_write_object(data, MXT_SPT_CTECONFIG_T28,
-				MXT_CTE_VOLTAGE, voltage);
-	}
-}
-
 static int mxt_get_info(struct mxt_data *data)
 {
 	struct i2c_client *client = data->client;
@@ -903,8 +855,6 @@ static int mxt_initialize(struct mxt_data *data)
 		return error;
 	}
 
-	mxt_handle_pdata(data);
-
 	error = mxt_t6_command(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE, false);
 	if (!error)
 		mxt_soft_reset(data, MXT_RESET_VALUE);
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index ef59c22..6a879a6 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -30,14 +30,10 @@ struct mxt_platform_data {
 	const u8 *config;
 	size_t config_length;
 
-	unsigned int x_line;
-	unsigned int y_line;
 	unsigned int x_size;
 	unsigned int y_size;
-	unsigned int blen;
-	unsigned int threshold;
-	unsigned int voltage;
 	unsigned char orient;
+
 	unsigned long irqflags;
 	u8(*read_chg) (void);
 };
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 07/40] Input: atmel_mxt_ts - Implement CRC check for configuration data.
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (5 preceding siblings ...)
  2013-02-22 17:57 ` [PATCH 06/40] Input: atmel_mxt_ts - Remove unnecessary platform data Nick Dyer
@ 2013-02-22 17:57 ` Nick Dyer
  2013-02-22 17:57 ` [PATCH 08/40] Input: atmel_mxt_ts - Download device config using firmware loader Nick Dyer
                   ` (34 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:57 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

The configuration is stored in NVRAM on the maXTouch chip. When the device is
reset it reports a CRC of the stored configuration values. Therefore it isn't
necessary to send the configuration on each probe - we can check the CRC
matches and avoid a timeconsuming backup/reset cycle.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   61 ++++++++++++++++++++++++------
 include/linux/i2c/atmel_mxt_ts.h         |    1 +
 2 files changed, 51 insertions(+), 11 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index fa294d1..6f30713 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -261,6 +261,7 @@ struct mxt_data {
 	unsigned int max_y;
 	struct bin_attribute mem_access_attr;
 	bool debug_enabled;
+	u32 config_crc;
 
 	/* Cached parameters from object table */
 	u8 T6_reportid;
@@ -528,6 +529,10 @@ static void mxt_input_touchevent(struct mxt_data *data,
 	int area;
 	int pressure;
 
+	/* do not report events if input device not yet registered */
+	if (!input_dev)
+		return;
+
 	x = (message->message[1] << 4) | ((message->message[3] >> 4) & 0xf);
 	y = (message->message[2] << 4) | ((message->message[3] & 0xf));
 	if (data->max_x < 1024)
@@ -563,7 +568,7 @@ static void mxt_input_touchevent(struct mxt_data *data,
 	}
 }
 
-static unsigned mxt_extract_T6_csum(const u8 *csum)
+static u16 mxt_extract_T6_csum(const u8 *csum)
 {
 	return csum[0] | (csum[1] << 8) | (csum[2] << 16);
 }
@@ -574,9 +579,8 @@ static bool mxt_is_T9_message(struct mxt_data *data, struct mxt_message *msg)
 	return (id >= data->T9_reportid_min && id <= data->T9_reportid_max);
 }
 
-static irqreturn_t mxt_interrupt(int irq, void *dev_id)
+static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 {
-	struct mxt_data *data = dev_id;
 	struct mxt_message message;
 	const u8 *payload = &message.message[0];
 	struct device *dev = &data->client->dev;
@@ -587,7 +591,7 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
 	do {
 		if (mxt_read_message(data, &message)) {
 			dev_err(dev, "Failed to read message\n");
-			goto end;
+			return IRQ_NONE;
 		}
 
 		reportid = message.reportid;
@@ -595,9 +599,9 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
 
 		if (reportid == data->T6_reportid) {
 			u8 status = payload[0];
-			unsigned csum = mxt_extract_T6_csum(&payload[1]);
+			data->config_crc = mxt_extract_T6_csum(&payload[1]);
 			dev_dbg(dev, "Status: %02x Config Checksum: %06x\n",
-				status, csum);
+				status, data->config_crc);
 			handled = true;
 		} else if (mxt_is_T9_message(data, &message)) {
 			int id = reportid - data->T9_reportid_min;
@@ -615,10 +619,16 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
 		input_sync(data->input_dev);
 	}
 
-end:
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t mxt_interrupt(int irq, void *dev_id)
+{
+	struct mxt_data *data = dev_id;
+
+	return mxt_process_messages_until_invalid(data);
+}
+
 static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset, u8 value, bool wait)
 {
 	u16 reg;
@@ -679,6 +689,19 @@ static int mxt_soft_reset(struct mxt_data *data, u8 value)
 	return 0;
 }
 
+static void mxt_read_current_crc(struct mxt_data *data)
+{
+	/* on failure, CRC is set to 0 and config will always be downloaded */
+	data->config_crc = 0;
+
+	mxt_t6_command(data, MXT_COMMAND_REPORTALL, 1, true);
+
+	/* Read all messages until invalid, this will update the config crc
+	 * stored in mxt_data. On failure, CRC is set to 0 and config will
+	 * always be downloaded */
+	mxt_process_messages_until_invalid(data);
+}
+
 static int mxt_check_reg_init(struct mxt_data *data)
 {
 	const struct mxt_platform_data *pdata = data->pdata;
@@ -693,6 +716,16 @@ static int mxt_check_reg_init(struct mxt_data *data)
 		return 0;
 	}
 
+	mxt_read_current_crc(data);
+
+	if (data->config_crc == pdata->config_crc) {
+		dev_info(dev, "Config CRC 0x%06X: OK\n", data->config_crc);
+		return 0;
+	} else {
+		dev_info(dev, "Config CRC 0x%06X: does not match 0x%06X\n",
+				data->config_crc, pdata->config_crc);
+	}
+
 	for (i = 0; i < data->info.object_num; i++) {
 		object = data->object_table + i;
 
@@ -712,6 +745,16 @@ static int mxt_check_reg_init(struct mxt_data *data)
 		index += size;
 	}
 
+	ret = mxt_t6_command(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE, false);
+	if (ret)
+		return ret;
+
+	ret = mxt_soft_reset(data, MXT_RESET_VALUE);
+	if (ret)
+		return ret;
+
+	dev_info(dev, "Config written\n");
+
 	return 0;
 }
 
@@ -855,10 +898,6 @@ static int mxt_initialize(struct mxt_data *data)
 		return error;
 	}
 
-	error = mxt_t6_command(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE, false);
-	if (!error)
-		mxt_soft_reset(data, MXT_RESET_VALUE);
-
 	/* Update matrix size at info struct */
 	error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
 	if (error)
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index 6a879a6..1d5a664 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -29,6 +29,7 @@
 struct mxt_platform_data {
 	const u8 *config;
 	size_t config_length;
+	u32 config_crc;
 
 	unsigned int x_size;
 	unsigned int y_size;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 08/40] Input: atmel_mxt_ts - Download device config using firmware loader
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (6 preceding siblings ...)
  2013-02-22 17:57 ` [PATCH 07/40] Input: atmel_mxt_ts - Implement CRC check for configuration data Nick Dyer
@ 2013-02-22 17:57 ` Nick Dyer
  2013-02-22 17:57 ` [PATCH 09/40] Input: atmel_mxt_ts - Calculate and check CRC in config file Nick Dyer
                   ` (33 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:57 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

The existing implementation which encodes the configuration as a binary blob
in platform data is unsatisfactory since it requires a kernel recompile for
the configuration to be changed, and it doesn't deal well with firmware
changes that move values around on the chip.

Atmel define an ASCII format for the configuration which can be exported from
their tools. This patch implements a parser for that format which loads the
configuration via the firmware loader and sends it to the MXT chip.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  207 +++++++++++++++++++++---------
 include/linux/i2c/atmel_mxt_ts.h         |    4 -
 2 files changed, 148 insertions(+), 63 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 6f30713..d015168 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -33,8 +33,10 @@
 #define MXT_BOOT_LOW		0x24
 #define MXT_BOOT_HIGH		0x25
 
-/* Firmware */
+/* Firmware files */
 #define MXT_FW_NAME		"maxtouch.fw"
+#define MXT_CFG_NAME		"maxtouch.cfg"
+#define MXT_CFG_MAGIC		"OBP_RAW V1"
 
 /* Registers */
 #define MXT_INFO		0x00
@@ -303,37 +305,6 @@ static bool mxt_object_readable(unsigned int type)
 	}
 }
 
-static bool mxt_object_writable(unsigned int type)
-{
-	switch (type) {
-	case MXT_GEN_COMMAND_T6:
-	case MXT_GEN_POWER_T7:
-	case MXT_GEN_ACQUIRE_T8:
-	case MXT_TOUCH_MULTI_T9:
-	case MXT_TOUCH_KEYARRAY_T15:
-	case MXT_TOUCH_PROXIMITY_T23:
-	case MXT_TOUCH_PROXKEY_T52:
-	case MXT_PROCI_GRIPFACE_T20:
-	case MXT_PROCG_NOISE_T22:
-	case MXT_PROCI_ONETOUCH_T24:
-	case MXT_PROCI_TWOTOUCH_T27:
-	case MXT_PROCI_GRIP_T40:
-	case MXT_PROCI_PALM_T41:
-	case MXT_PROCI_TOUCHSUPPRESSION_T42:
-	case MXT_PROCI_STYLUS_T47:
-	case MXT_PROCG_NOISESUPPRESSION_T48:
-	case MXT_SPT_COMMSCONFIG_T18:
-	case MXT_SPT_GPIOPWM_T19:
-	case MXT_SPT_SELFTEST_T25:
-	case MXT_SPT_CTECONFIG_T28:
-	case MXT_SPT_DIGITIZER_T43:
-	case MXT_SPT_CTECONFIG_T46:
-		return true;
-	default:
-		return false;
-	}
-}
-
 static void mxt_dump_message(struct device *dev, struct mxt_message *message)
 {
 	dev_dbg(dev, "MXT MSG: %*ph\n",
@@ -704,58 +675,176 @@ static void mxt_read_current_crc(struct mxt_data *data)
 
 static int mxt_check_reg_init(struct mxt_data *data)
 {
-	const struct mxt_platform_data *pdata = data->pdata;
-	struct mxt_object *object;
 	struct device *dev = &data->client->dev;
-	int index = 0;
-	int i, size;
+	struct mxt_info cfg_info;
+	struct mxt_object *object;
+	const struct firmware *cfg = NULL;
 	int ret;
+	int offset;
+	int pos;
+	int i;
+	u32 info_crc, config_crc;
+	unsigned int type, instance, size;
+	u8 val;
+	u16 reg;
 
-	if (!pdata->config) {
-		dev_dbg(dev, "No cfg data defined, skipping reg init\n");
+	ret = request_firmware(&cfg, MXT_CFG_NAME, dev);
+	if (ret < 0) {
+		dev_err(dev, "Failure to request config file %s\n",
+			MXT_CFG_NAME);
 		return 0;
 	}
 
 	mxt_read_current_crc(data);
 
-	if (data->config_crc == pdata->config_crc) {
-		dev_info(dev, "Config CRC 0x%06X: OK\n", data->config_crc);
-		return 0;
+	if (strncmp(cfg->data, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) {
+		dev_err(dev, "Unrecognised config file\n");
+		ret = -EINVAL;
+		goto release;
+	}
+
+	pos = strlen(MXT_CFG_MAGIC);
+
+	/* Load information block and check */
+	for (i = 0; i < sizeof(struct mxt_info); i++) {
+		ret = sscanf(cfg->data + pos, "%hhx%n",
+			     (unsigned char *)&cfg_info + i,
+			     &offset);
+		if (ret != 1) {
+			dev_err(dev, "Bad format\n");
+			ret = -EINVAL;
+			goto release;
+		}
+
+		pos += offset;
+	}
+
+	if (cfg_info.family_id != data->info.family_id) {
+		dev_err(dev, "Family ID mismatch!\n");
+		ret = -EINVAL;
+		goto release;
+	}
+
+	if (cfg_info.variant_id != data->info.variant_id) {
+		dev_err(dev, "Variant ID mismatch!\n");
+		ret = -EINVAL;
+		goto release;
+	}
+
+	if (cfg_info.version != data->info.version)
+		dev_err(dev, "Warning: version mismatch!\n");
+
+	if (cfg_info.build != data->info.build)
+		dev_err(dev, "Warning: build num mismatch!\n");
+
+	ret = sscanf(cfg->data + pos, "%x%n", &info_crc, &offset);
+	if (ret != 1) {
+		dev_err(dev, "Bad format: failed to parse Info CRC\n");
+		ret = -EINVAL;
+		goto release;
+	}
+	pos += offset;
+
+	/* Check config CRC */
+	ret = sscanf(cfg->data + pos, "%x%n", &config_crc, &offset);
+	if (ret != 1) {
+		dev_err(dev, "Bad format: failed to parse Config CRC\n");
+		ret = -EINVAL;
+		goto release;
+	}
+	pos += offset;
+
+	if (data->config_crc == config_crc) {
+		dev_info(dev, "Config CRC 0x%06X: OK\n", config_crc);
+		ret = 0;
+		goto release;
 	} else {
-		dev_info(dev, "Config CRC 0x%06X: does not match 0x%06X\n",
-				data->config_crc, pdata->config_crc);
+		dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n",
+			 data->config_crc, config_crc);
 	}
 
-	for (i = 0; i < data->info.object_num; i++) {
-		object = data->object_table + i;
+	while (pos < cfg->size) {
+		/* Read type, instance, length */
+		ret = sscanf(cfg->data + pos, "%x %x %x%n",
+			     &type, &instance, &size, &offset);
+		if (ret == 0) {
+			/* EOF */
+			ret = 1;
+			goto release;
+		} else if (ret != 3) {
+			dev_err(dev, "Bad format: failed to parse object\n");
+			ret = -EINVAL;
+			goto release;
+		}
+		pos += offset;
 
-		if (!mxt_object_writable(object->type))
-			continue;
+		object = mxt_get_object(data, type);
+		if (!object) {
+			ret = -EINVAL;
+			goto release;
+		}
 
-		size = OBP_SIZE(object) * OBP_INSTANCES(object);
-		if (index + size > pdata->config_length) {
-			dev_err(dev, "Not enough config data!\n");
-			return -EINVAL;
+		if (size > OBP_SIZE(object)) {
+			dev_err(dev, "Object length exceeded!\n");
+			ret = -EINVAL;
+			goto release;
 		}
 
-		ret = __mxt_write_reg(data->client, object->start_address,
-				size, &pdata->config[index]);
-		if (ret)
-			return ret;
-		index += size;
+		if (instance >= OBP_INSTANCES(object)) {
+			dev_err(dev, "Object instances exceeded!\n");
+			ret = -EINVAL;
+			goto release;
+		}
+
+		reg = object->start_address + OBP_SIZE(object) * instance;
+
+		for (i = 0; i < size; i++) {
+			ret = sscanf(cfg->data + pos, "%hhx%n",
+				     &val,
+				     &offset);
+			if (ret != 1) {
+				dev_err(dev, "Bad format in T%d\n", type);
+				ret = -EINVAL;
+				goto release;
+			}
+
+			ret = mxt_write_reg(data->client, reg + i, val);
+			if (ret)
+				goto release;
+
+			pos += offset;
+		}
+
+		/* If firmware is upgraded, new bytes may be added to end of
+		 * objects. It is generally forward compatible to zero these
+		 * bytes - previous behaviour will be retained. However
+		 * this does invalidate the CRC and will force a config
+		 * download every time until the configuration is updated */
+		if (size < OBP_SIZE(object)) {
+			dev_info(dev, "Warning: zeroing %d byte(s) in T%d\n",
+				 OBP_SIZE(object) - size, type);
+
+			for (i = size + 1; i < OBP_SIZE(object); i++) {
+				ret = mxt_write_reg(data->client, reg + i, 0);
+				if (ret)
+					goto release;
+			}
+		}
 	}
 
 	ret = mxt_t6_command(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE, false);
 	if (ret)
-		return ret;
+		goto release;
 
 	ret = mxt_soft_reset(data, MXT_RESET_VALUE);
 	if (ret)
-		return ret;
+		goto release;
 
 	dev_info(dev, "Config written\n");
 
-	return 0;
+release:
+	release_firmware(cfg);
+	return ret;
 }
 
 static int mxt_make_highchg(struct mxt_data *data)
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index 1d5a664..1ebb8fd 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -27,10 +27,6 @@
 
 /* The platform data for the Atmel maXTouch touchscreen driver */
 struct mxt_platform_data {
-	const u8 *config;
-	size_t config_length;
-	u32 config_crc;
-
 	unsigned int x_size;
 	unsigned int y_size;
 	unsigned char orient;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 09/40] Input: atmel_mxt_ts - Calculate and check CRC in config file
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (7 preceding siblings ...)
  2013-02-22 17:57 ` [PATCH 08/40] Input: atmel_mxt_ts - Download device config using firmware loader Nick Dyer
@ 2013-02-22 17:57 ` Nick Dyer
  2013-02-22 17:57 ` [PATCH 10/40] Input: atmel_mxt_ts - Improve bootloader support Nick Dyer
                   ` (32 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:57 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

By validating the checksum, we can identify if the configuration is corrupt.
In addition, this patch writes the configuration in a short series of block
writes rather than as many individual values.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  237 +++++++++++++++++++++---------
 1 file changed, 168 insertions(+), 69 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index d015168..302c03e 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -264,10 +264,12 @@ struct mxt_data {
 	struct bin_attribute mem_access_attr;
 	bool debug_enabled;
 	u32 config_crc;
+	u32 info_crc;
 
 	/* Cached parameters from object table */
 	u8 T6_reportid;
 	u16 T6_address;
+	u16 T7_address;
 	u8 T9_reportid_min;
 	u8 T9_reportid_max;
 };
@@ -673,6 +675,45 @@ static void mxt_read_current_crc(struct mxt_data *data)
 	mxt_process_messages_until_invalid(data);
 }
 
+static void mxt_calc_crc24(u32 *crc, u8 firstbyte, u8 secondbyte)
+{
+	static const unsigned int crcpoly = 0x80001B;
+	u32 result;
+	u32 data_word;
+
+	data_word = (secondbyte << 8) | firstbyte;
+	result = ((*crc << 1) ^ data_word);
+
+	if (result & 0x1000000)
+		result ^= crcpoly;
+
+	*crc = result;
+}
+
+static u32 mxt_calculate_crc(u8 *base, off_t start_off, off_t end_off)
+{
+	u32 crc = 0;
+	u8 *ptr = base + start_off;
+	u8 *last_val = base + end_off - 1;
+
+	if (end_off < start_off)
+		return -EINVAL;
+
+	while (ptr < last_val) {
+		mxt_calc_crc24(&crc, *ptr, *(ptr + 1));
+		ptr += 2;
+	}
+
+	/* if len is odd, fill the last byte with 0 */
+	if (ptr == last_val)
+		mxt_calc_crc24(&crc, *ptr, 0);
+
+	/* Mask to 24-bit */
+	crc &= 0x00FFFFFF;
+
+	return crc;
+}
+
 static int mxt_check_reg_init(struct mxt_data *data)
 {
 	struct device *dev = &data->client->dev;
@@ -681,9 +722,13 @@ static int mxt_check_reg_init(struct mxt_data *data)
 	const struct firmware *cfg = NULL;
 	int ret;
 	int offset;
-	int pos;
+	int data_pos;
+	int byte_offset;
 	int i;
-	u32 info_crc, config_crc;
+	int config_start_offset;
+	u32 info_crc, config_crc, calculated_crc;
+	u8 *config_mem;
+	size_t config_mem_size;
 	unsigned int type, instance, size;
 	u8 val;
 	u16 reg;
@@ -703,11 +748,11 @@ static int mxt_check_reg_init(struct mxt_data *data)
 		goto release;
 	}
 
-	pos = strlen(MXT_CFG_MAGIC);
+	data_pos = strlen(MXT_CFG_MAGIC);
 
 	/* Load information block and check */
 	for (i = 0; i < sizeof(struct mxt_info); i++) {
-		ret = sscanf(cfg->data + pos, "%hhx%n",
+		ret = sscanf(cfg->data + data_pos, "%hhx%n",
 			     (unsigned char *)&cfg_info + i,
 			     &offset);
 		if (ret != 1) {
@@ -716,132 +761,183 @@ static int mxt_check_reg_init(struct mxt_data *data)
 			goto release;
 		}
 
-		pos += offset;
+		data_pos += offset;
 	}
 
-	if (cfg_info.family_id != data->info.family_id) {
-		dev_err(dev, "Family ID mismatch!\n");
-		ret = -EINVAL;
-		goto release;
-	}
-
-	if (cfg_info.variant_id != data->info.variant_id) {
-		dev_err(dev, "Variant ID mismatch!\n");
-		ret = -EINVAL;
-		goto release;
-	}
-
-	if (cfg_info.version != data->info.version)
-		dev_err(dev, "Warning: version mismatch!\n");
-
-	if (cfg_info.build != data->info.build)
-		dev_err(dev, "Warning: build num mismatch!\n");
-
-	ret = sscanf(cfg->data + pos, "%x%n", &info_crc, &offset);
+	/* Read CRCs */
+	ret = sscanf(cfg->data + data_pos, "%x%n", &info_crc, &offset);
 	if (ret != 1) {
 		dev_err(dev, "Bad format: failed to parse Info CRC\n");
 		ret = -EINVAL;
 		goto release;
 	}
-	pos += offset;
+	data_pos += offset;
 
-	/* Check config CRC */
-	ret = sscanf(cfg->data + pos, "%x%n", &config_crc, &offset);
+	ret = sscanf(cfg->data + data_pos, "%x%n", &config_crc, &offset);
 	if (ret != 1) {
 		dev_err(dev, "Bad format: failed to parse Config CRC\n");
 		ret = -EINVAL;
 		goto release;
 	}
-	pos += offset;
+	data_pos += offset;
+
+	/* The Info Block CRC is calculated over mxt_info and the object table
+	 * If it does not match then we are trying to load the configuration
+	 * from a different chip or firmware version, so the configuration CRC
+	 * is invalid anyway. */
+	if (info_crc == data->info_crc) {
+		if (config_crc == 0 || data->config_crc == 0) {
+			dev_info(dev, "CRC zero, attempting to apply config\n");
+		} else if (config_crc == data->config_crc) {
+			dev_info(dev, "Config CRC 0x%06X: OK\n", data->config_crc);
+			ret = 0;
+			goto release;
+		} else {
+			dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n",
+				 data->config_crc, config_crc);
+		}
+	} else {
+		dev_warn(dev,
+			 "Warning: Info CRC error - device=0x%06X file=0x%06X\n",
+			data->info_crc, info_crc);
+	}
 
-	if (data->config_crc == config_crc) {
-		dev_info(dev, "Config CRC 0x%06X: OK\n", config_crc);
-		ret = 0;
+	/* Malloc memory to store configuration */
+	config_start_offset = MXT_OBJECT_START
+		+ data->info.object_num * sizeof(struct mxt_object);
+	config_mem_size = data->mem_size - config_start_offset;
+	config_mem = kzalloc(config_mem_size, GFP_KERNEL);
+	if (!config_mem) {
+		dev_err(dev, "Failed to allocate memory\n");
+		ret = -ENOMEM;
 		goto release;
-	} else {
-		dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n",
-			 data->config_crc, config_crc);
 	}
 
-	while (pos < cfg->size) {
+	while (data_pos < cfg->size) {
 		/* Read type, instance, length */
-		ret = sscanf(cfg->data + pos, "%x %x %x%n",
+		ret = sscanf(cfg->data + data_pos, "%x %x %x%n",
 			     &type, &instance, &size, &offset);
 		if (ret == 0) {
 			/* EOF */
-			ret = 1;
-			goto release;
+			break;
 		} else if (ret != 3) {
 			dev_err(dev, "Bad format: failed to parse object\n");
 			ret = -EINVAL;
-			goto release;
+			goto release_mem;
 		}
-		pos += offset;
+		data_pos += offset;
 
 		object = mxt_get_object(data, type);
 		if (!object) {
 			ret = -EINVAL;
-			goto release;
-		}
-
-		if (size > OBP_SIZE(object)) {
-			dev_err(dev, "Object length exceeded!\n");
-			ret = -EINVAL;
-			goto release;
+			goto release_mem;
 		}
 
 		if (instance >= OBP_INSTANCES(object)) {
 			dev_err(dev, "Object instances exceeded!\n");
 			ret = -EINVAL;
-			goto release;
+			goto release_mem;
 		}
 
 		reg = object->start_address + OBP_SIZE(object) * instance;
 
+		if (size > OBP_SIZE(object)) {
+			/* Either we are in fallback mode due to wrong
+			 * config or config from a later fw version,
+			 * or the file is corrupt or hand-edited */
+			dev_warn(dev, "Discarding %u bytes in T%u!\n",
+				 size - OBP_SIZE(object), type);
+
+			size = OBP_SIZE(object);
+		} else if (OBP_SIZE(object) > size) {
+			/* If firmware is upgraded, new bytes may be added to
+			 * end of objects. It is generally forward compatible
+			 * to zero these bytes - previous behaviour will be
+			 * retained. However this does invalidate the CRC and
+			 * will force fallback mode until the configuration is
+			 * updated. We warn here but do nothing else - the
+			 * malloc has zeroed the entire configuration. */
+			dev_warn(dev, "Zeroing %d byte(s) in T%d\n",
+				 OBP_SIZE(object) - size, type);
+		}
+
 		for (i = 0; i < size; i++) {
-			ret = sscanf(cfg->data + pos, "%hhx%n",
+			ret = sscanf(cfg->data + data_pos, "%hhx%n",
 				     &val,
 				     &offset);
 			if (ret != 1) {
 				dev_err(dev, "Bad format in T%d\n", type);
 				ret = -EINVAL;
-				goto release;
+				goto release_mem;
 			}
 
-			ret = mxt_write_reg(data->client, reg + i, val);
-			if (ret)
-				goto release;
+			byte_offset = reg + i - config_start_offset;
+
+			if ((byte_offset >= 0)
+			    && (byte_offset <= config_mem_size)) {
+				*(config_mem + byte_offset) = val;
+			} else {
+				dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n",
+					reg, object->type, byte_offset);
+				ret = -EINVAL;
+				goto release_mem;
+			}
 
-			pos += offset;
+			data_pos += offset;
 		}
 
-		/* If firmware is upgraded, new bytes may be added to end of
-		 * objects. It is generally forward compatible to zero these
-		 * bytes - previous behaviour will be retained. However
-		 * this does invalidate the CRC and will force a config
-		 * download every time until the configuration is updated */
-		if (size < OBP_SIZE(object)) {
-			dev_info(dev, "Warning: zeroing %d byte(s) in T%d\n",
-				 OBP_SIZE(object) - size, type);
+	}
 
-			for (i = size + 1; i < OBP_SIZE(object); i++) {
-				ret = mxt_write_reg(data->client, reg + i, 0);
-				if (ret)
-					goto release;
-			}
+	/* calculate crc of the received configs (not the raw config file) */
+	if (data->T7_address < config_start_offset) {
+		dev_err(dev, "Bad T7 address, T7addr = %x, config offset %x\n",
+				data->T7_address, config_start_offset);
+		ret = 0;
+		goto release_mem;
+	}
+
+	calculated_crc = mxt_calculate_crc(config_mem,
+			data->T7_address - config_start_offset, config_mem_size);
+
+	/* check the crc, calculated should same as what's in file */
+	if (config_crc > 0 && (config_crc != calculated_crc)) {
+		dev_err(dev, "CRC mismatch in config file, calculated=%06X, file=%06X\n",
+				calculated_crc, config_crc);
+		ret = 0;
+		goto release_mem;
+	}
+
+	/* Write configuration as blocks */
+	byte_offset = 0;
+	while (byte_offset < config_mem_size) {
+		size = config_mem_size - byte_offset;
+
+		if (size > MXT_MAX_BLOCK_WRITE)
+			size = MXT_MAX_BLOCK_WRITE;
+
+		ret = __mxt_write_reg(data->client,
+				      config_start_offset + byte_offset,
+				      size, config_mem + byte_offset);
+		if (ret != 0) {
+			dev_err(dev, "Config write error, ret=%d\n", ret);
+			goto release_mem;
 		}
+
+		byte_offset += size;
 	}
 
 	ret = mxt_t6_command(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE, false);
 	if (ret)
-		goto release;
+		goto release_mem;
 
 	ret = mxt_soft_reset(data, MXT_RESET_VALUE);
 	if (ret)
-		goto release;
+		goto release_mem;
 
 	dev_info(dev, "Config written\n");
 
+release_mem:
+	kfree(config_mem);
 release:
 	release_firmware(cfg);
 	return ret;
@@ -927,6 +1023,9 @@ static int mxt_get_object_table(struct mxt_data *data)
 			data->T6_reportid = min_id;
 			data->T6_address = object->start_address;
 			break;
+		case MXT_GEN_POWER_T7:
+			data->T7_address = object->start_address;
+			break;
 		case MXT_TOUCH_MULTI_T9:
 			data->T9_reportid_min = min_id;
 			data->T9_reportid_max = max_id;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 10/40] Input: atmel_mxt_ts - Improve bootloader support
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (8 preceding siblings ...)
  2013-02-22 17:57 ` [PATCH 09/40] Input: atmel_mxt_ts - Calculate and check CRC in config file Nick Dyer
@ 2013-02-22 17:57 ` Nick Dyer
  2013-02-22 17:57 ` [PATCH 11/40] Input: atmel_mxt_ts - Bootloader addresses for mXT1664/mXT1188S Nick Dyer
                   ` (31 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:57 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

    Add additional bootloader addresses
    Read and report bootloader version
    Increase fw reset time for greater reliability
    Further bootloader improvements
    Handle APP_CRC_FAIL on startup
    Handle bootloader frame CRC failure
    Recover gracefully from flash aborted halfway through

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/Kconfig        |    1 +
 drivers/input/touchscreen/atmel_mxt_ts.c |  318 +++++++++++++++++++++++-------
 2 files changed, 244 insertions(+), 75 deletions(-)

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 9a647ee..a4f98c8 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -89,6 +89,7 @@ config TOUCHSCREEN_AD7879_SPI
 config TOUCHSCREEN_ATMEL_MXT
 	tristate "Atmel mXT I2C Touchscreen"
 	depends on I2C
+	select FW_LOADER
 	help
 	  Say Y here if you have Atmel mXT series I2C touchscreen,
 	  such as AT42QT602240/ATMXT224, connected to your system.
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 302c03e..16af68d 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -27,12 +27,6 @@
 #define MXT_VER_21		21
 #define MXT_VER_22		22
 
-/* Slave addresses */
-#define MXT_APP_LOW		0x4a
-#define MXT_APP_HIGH		0x4b
-#define MXT_BOOT_LOW		0x24
-#define MXT_BOOT_HIGH		0x25
-
 /* Firmware files */
 #define MXT_FW_NAME		"maxtouch.fw"
 #define MXT_CFG_NAME		"maxtouch.cfg"
@@ -204,6 +198,8 @@
 #define MXT_FRAME_CRC_PASS	0x04
 #define MXT_APP_CRC_FAIL	0x40	/* valid 7 8 bit only */
 #define MXT_BOOT_STATUS_MASK	0x3f
+#define MXT_BOOT_EXTENDED_ID	(1 << 5)
+#define MXT_BOOT_ID_MASK	0x1f
 
 /* Touch status */
 #define MXT_UNGRIP		(1 << 0)
@@ -249,12 +245,15 @@ struct mxt_message {
 	u8 message[7];
 };
 
+enum mxt_device_state { INIT, APPMODE, BOOTLOADER, FAILED };
+
 /* Each client has this additional data */
 struct mxt_data {
 	struct i2c_client *client;
 	struct input_dev *input_dev;
 	char phys[64];		/* device physical location */
 	const struct mxt_platform_data *pdata;
+	enum mxt_device_state state;
 	struct mxt_object *object_table;
 	u16 mem_size;
 	struct mxt_info info;
@@ -265,6 +264,7 @@ struct mxt_data {
 	bool debug_enabled;
 	u32 config_crc;
 	u32 info_crc;
+	u8 bootloader_addr;
 
 	/* Cached parameters from object table */
 	u8 T6_reportid;
@@ -274,6 +274,21 @@ struct mxt_data {
 	u8 T9_reportid_max;
 };
 
+/* I2C slave address pairs */
+struct mxt_i2c_address_pair {
+	u8 bootloader;
+	u8 application;
+};
+
+static const struct mxt_i2c_address_pair mxt_i2c_addresses[] = {
+	{ 0x24, 0x4a },
+	{ 0x25, 0x4b },
+	{ 0x26, 0x4c },
+	{ 0x27, 0x4d },
+	{ 0x34, 0x5a },
+	{ 0x35, 0x5b },
+};
+
 static bool mxt_object_readable(unsigned int type)
 {
 	switch (type) {
@@ -313,59 +328,165 @@ static void mxt_dump_message(struct device *dev, struct mxt_message *message)
 		       sizeof(struct mxt_message), message);
 }
 
-static int mxt_check_bootloader(struct i2c_client *client,
-				     unsigned int state)
+static int mxt_bootloader_read(struct mxt_data *data, u8 *val, unsigned int count)
+{
+	int ret;
+	struct i2c_msg msg;
+
+	msg.addr = data->bootloader_addr;
+	msg.flags = data->client->flags & I2C_M_TEN;
+	msg.flags |= I2C_M_RD;
+	msg.len = count;
+	msg.buf = val;
+
+	ret = i2c_transfer(data->client->adapter, &msg, 1);
+
+	return (ret == 1) ? 0 : ret;
+}
+
+static int mxt_bootloader_write(struct mxt_data *data, const u8 * const val,
+	unsigned int count)
+{
+	int ret;
+	struct i2c_msg msg;
+
+	msg.addr = data->bootloader_addr;
+	msg.flags = data->client->flags & I2C_M_TEN;
+	msg.len = count;
+	msg.buf = (u8 *)val;
+
+	ret = i2c_transfer(data->client->adapter, &msg, 1);
+
+	return (ret == 1) ? 0 : ret;
+}
+
+static int mxt_get_bootloader_address(struct mxt_data *data)
+{
+	struct i2c_client *client = data->client;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mxt_i2c_addresses); i++) {
+		if (mxt_i2c_addresses[i].application == client->addr) {
+			data->bootloader_addr = mxt_i2c_addresses[i].bootloader;
+
+			dev_info(&client->dev, "Bootloader i2c addr: 0x%02x\n",
+				data->bootloader_addr);
+
+			return 0;
+		}
+	}
+
+	dev_err(&client->dev, "Address 0x%02x not found in address table\n",
+		client->addr);
+	return -EINVAL;
+}
+
+static int mxt_probe_bootloader(struct mxt_data *data)
 {
+	struct device *dev = &data->client->dev;
+	int ret;
 	u8 val;
+	bool crc_failure;
 
-recheck:
-	if (i2c_master_recv(client, &val, 1) != 1) {
-		dev_err(&client->dev, "%s: i2c recv failed\n", __func__);
+	ret = mxt_get_bootloader_address(data);
+	if (ret)
+		return ret;
+
+	ret = mxt_bootloader_read(data, &val, 1);
+	if (ret) {
+		dev_err(dev, "%s: i2c recv failed\n", __func__);
 		return -EIO;
 	}
 
+	/* Check app crc fail mode */
+	crc_failure = (val & ~MXT_BOOT_STATUS_MASK) == MXT_APP_CRC_FAIL;
+
+	dev_err(dev, "Detected bootloader, status:%02X%s\n",
+		val, crc_failure ? ", APP_CRC_FAIL" : "");
+
+	return 0;
+}
+
+static u8 mxt_get_bootloader_version(struct mxt_data *data, u8 val)
+{
+	struct device *dev = &data->client->dev;
+	u8 buf[3];
+
+	if (val & MXT_BOOT_EXTENDED_ID) {
+		if (mxt_bootloader_read(data, &buf[0], 3) != 0) {
+			dev_err(dev, "%s: i2c failure\n", __func__);
+			return -EIO;
+		}
+
+		dev_info(dev, "Bootloader ID:%d Version:%d\n", buf[1], buf[2]);
+
+		return buf[0];
+	} else {
+		dev_info(dev, "Bootloader ID:%d\n", val & MXT_BOOT_ID_MASK);
+
+		return val;
+	}
+}
+
+static int mxt_check_bootloader(struct mxt_data *data,
+				unsigned int state)
+{
+	struct device *dev = &data->client->dev;
+	int ret;
+	u8 val;
+
+recheck:
+	ret = mxt_bootloader_read(data, &val, 1);
+	if (ret) {
+		dev_err(dev, "%s: i2c recv failed, ret=%d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	if (state == MXT_WAITING_BOOTLOAD_CMD)
+		val = mxt_get_bootloader_version(data, val);
+
 	switch (state) {
 	case MXT_WAITING_BOOTLOAD_CMD:
+		val &= ~MXT_BOOT_STATUS_MASK;
+		break;
 	case MXT_WAITING_FRAME_DATA:
+	case MXT_APP_CRC_FAIL:
 		val &= ~MXT_BOOT_STATUS_MASK;
 		break;
 	case MXT_FRAME_CRC_PASS:
 		if (val == MXT_FRAME_CRC_CHECK)
 			goto recheck;
+		if (val == MXT_FRAME_CRC_FAIL) {
+			dev_err(dev, "Bootloader CRC fail\n");
+			return -EINVAL;
+		}
 		break;
 	default:
 		return -EINVAL;
 	}
 
 	if (val != state) {
-		dev_err(&client->dev, "Invalid bootloader mode state\n");
+		dev_err(dev, "Invalid bootloader mode state 0x%02X\n", val);
 		return -EINVAL;
 	}
 
 	return 0;
 }
 
-static int mxt_unlock_bootloader(struct i2c_client *client)
+static int mxt_unlock_bootloader(struct mxt_data *data)
 {
+	int ret;
 	u8 buf[2];
 
 	buf[0] = MXT_UNLOCK_CMD_LSB;
 	buf[1] = MXT_UNLOCK_CMD_MSB;
 
-	if (i2c_master_send(client, buf, 2) != 2) {
-		dev_err(&client->dev, "%s: i2c send failed\n", __func__);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int mxt_fw_write(struct i2c_client *client,
-			     const u8 *data, unsigned int frame_size)
-{
-	if (i2c_master_send(client, data, frame_size) != frame_size) {
-		dev_err(&client->dev, "%s: i2c send failed\n", __func__);
-		return -EIO;
+	ret = mxt_bootloader_write(data, buf, 2);
+	if (ret) {
+		dev_err(&data->client->dev, "%s: i2c send failed, ret=%d\n",
+				__func__, ret);
+		return ret;
 	}
 
 	return 0;
@@ -1060,8 +1181,18 @@ static int mxt_initialize(struct mxt_data *data)
 	u8 val;
 
 	error = mxt_get_info(data);
-	if (error)
-		return error;
+	if (error) {
+		error = mxt_probe_bootloader(data);
+
+		if (error) {
+			return error;
+		} else {
+			data->state = BOOTLOADER;
+			return 0;
+		}
+	}
+
+	data->state = APPMODE;
 
 	data->object_table = kcalloc(info->object_num,
 				     sizeof(struct mxt_object),
@@ -1211,71 +1342,99 @@ done:
 static int mxt_load_fw(struct device *dev, const char *fn)
 {
 	struct mxt_data *data = dev_get_drvdata(dev);
-	struct i2c_client *client = data->client;
 	const struct firmware *fw = NULL;
 	unsigned int frame_size;
 	unsigned int pos = 0;
+	unsigned int retry = 0;
+	unsigned int frame = 0;
 	int ret;
 
 	ret = request_firmware(&fw, fn, dev);
-	if (ret) {
+	if (ret < 0) {
 		dev_err(dev, "Unable to open firmware %s\n", fn);
 		return ret;
 	}
 
-	/* Change to the bootloader mode */
-	ret = mxt_soft_reset(data, MXT_BOOT_VALUE);
-	if (ret)
-		return ret;
+	if (data->state != BOOTLOADER) {
+		/* Change to the bootloader mode */
+		ret = mxt_soft_reset(data, MXT_BOOT_VALUE);
+		if (ret)
+			goto release_firmware;
 
-	/* Change to slave address of bootloader */
-	if (client->addr == MXT_APP_LOW)
-		client->addr = MXT_BOOT_LOW;
-	else
-		client->addr = MXT_BOOT_HIGH;
+		ret = mxt_get_bootloader_address(data);
+		if (ret)
+			goto release_firmware;
 
-	ret = mxt_check_bootloader(client, MXT_WAITING_BOOTLOAD_CMD);
-	if (ret)
-		goto out;
+		data->state = BOOTLOADER;
+	}
+
+	ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD);
+	if (ret) {
+		/* Bootloader may still be unlocked from previous update
+		 * attempt */
+		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);
+		if (ret) {
+			data->state = FAILED;
+			goto release_firmware;
+		}
+	} else {
+		dev_info(dev, "Unlocking bootloader\n");
 
-	/* Unlock bootloader */
-	mxt_unlock_bootloader(client);
+		/* Unlock bootloader */
+		ret = mxt_unlock_bootloader(data);
+		if (ret) {
+			data->state = FAILED;
+			goto release_firmware;
+		}
+	}
 
 	while (pos < fw->size) {
-		ret = mxt_check_bootloader(client,
-						MXT_WAITING_FRAME_DATA);
-		if (ret)
-			goto out;
+		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);
+		if (ret) {
+			data->state = FAILED;
+			goto release_firmware;
+		}
 
 		frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
 
-		/* We should add 2 at frame size as the the firmware data is not
-		 * included the CRC bytes.
-		 */
+		/* Take account of CRC bytes */
 		frame_size += 2;
 
 		/* Write one frame to device */
-		mxt_fw_write(client, fw->data + pos, frame_size);
+		ret = mxt_bootloader_write(data, fw->data + pos, frame_size);
+		if (ret) {
+			data->state = FAILED;
+			goto release_firmware;
+		}
 
-		ret = mxt_check_bootloader(client,
-						MXT_FRAME_CRC_PASS);
-		if (ret)
-			goto out;
+		ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS);
+		if (ret) {
+			retry++;
 
-		pos += frame_size;
+			/* Back off by 20ms per retry */
+			msleep(retry * 20);
 
-		dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size);
+			if (retry > 20) {
+				data->state = FAILED;
+				goto release_firmware;
+			}
+		} else {
+			retry = 0;
+			pos += frame_size;
+			frame++;
+		}
+
+		if (frame % 10 == 0)
+			dev_info(dev, "Updated %d frames, %d/%zd bytes\n",
+				 frame, pos, fw->size);
 	}
 
-out:
-	release_firmware(fw);
+	dev_info(dev, "Finished, sent %d frames, %zd bytes\n", frame, pos);
 
-	/* Change to slave address of application */
-	if (client->addr == MXT_BOOT_LOW)
-		client->addr = MXT_APP_LOW;
-	else
-		client->addr = MXT_APP_HIGH;
+	data->state = INIT;
 
+release_firmware:
+	release_firmware(fw);
 	return ret;
 }
 
@@ -1293,7 +1452,7 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 		dev_err(dev, "The firmware update failed(%d)\n", error);
 		count = error;
 	} else {
-		dev_dbg(dev, "The firmware update succeeded\n");
+		dev_info(dev, "The firmware update succeeded\n");
 
 		/* Wait for reset */
 		msleep(MXT_FWRESET_TIME);
@@ -1303,11 +1462,13 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 		mxt_initialize(data);
 	}
 
-	enable_irq(data->irq);
+	if (data->state == APPMODE) {
+		enable_irq(data->irq);
 
-	error = mxt_make_highchg(data);
-	if (error)
-		return error;
+		error = mxt_make_highchg(data);
+		if (error)
+			return error;
+	}
 
 	return count;
 }
@@ -1345,6 +1506,11 @@ static ssize_t mxt_debug_enable_store(struct device *dev,
 static int mxt_check_mem_access_params(struct mxt_data *data, loff_t off,
 				       size_t *count)
 {
+	if (data->state != APPMODE) {
+		dev_err(&data->client->dev, "Not in APPMODE\n");
+		return -EINVAL;
+	}
+
 	if (off >= data->mem_size)
 		return -EIO;
 
@@ -1462,6 +1628,8 @@ static int mxt_probe(struct i2c_client *client,
 		goto err_free_mem;
 	}
 
+	data->state = INIT;
+
 	input_dev->name = "Atmel maXTouch Touchscreen";
 	snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0",
 		 client->adapter->nr, client->addr);
@@ -1520,10 +1688,10 @@ static int mxt_probe(struct i2c_client *client,
 		goto err_free_object;
 	}
 
-	error = mxt_make_highchg(data);
-	if (error) {
-		dev_err(&client->dev, "Error %d clearing messages\n", error);
-		goto err_free_irq;
+	if (data->state == APPMODE) {
+		error = mxt_make_highchg(data);
+		if (error)
+			goto err_free_irq;
 	}
 
 	error = input_register_device(input_dev);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 11/40] Input: atmel_mxt_ts - Bootloader addresses for mXT1664/mXT1188S
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (9 preceding siblings ...)
  2013-02-22 17:57 ` [PATCH 10/40] Input: atmel_mxt_ts - Improve bootloader support Nick Dyer
@ 2013-02-22 17:57 ` Nick Dyer
  2013-02-22 19:06   ` Benson Leung
  2013-02-22 17:57 ` [PATCH 12/40] Input: atmel_mxt_ts - Read screen config from chip Nick Dyer
                   ` (30 subsequent siblings)
  41 siblings, 1 reply; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:57 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

The mXT1664S family chips use different mappings for bootloader addresses.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 16af68d..903ff54 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -281,12 +281,17 @@ struct mxt_i2c_address_pair {
 };
 
 static const struct mxt_i2c_address_pair mxt_i2c_addresses[] = {
+#ifdef BOOTLOADER_1664_1188
+	{ 0x26, 0x4a },
+	{ 0x27, 0x4b },
+#else
 	{ 0x24, 0x4a },
 	{ 0x25, 0x4b },
 	{ 0x26, 0x4c },
 	{ 0x27, 0x4d },
 	{ 0x34, 0x5a },
 	{ 0x35, 0x5b },
+#endif
 };
 
 static bool mxt_object_readable(unsigned int type)
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 12/40] Input: atmel_mxt_ts - Read screen config from chip
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (10 preceding siblings ...)
  2013-02-22 17:57 ` [PATCH 11/40] Input: atmel_mxt_ts - Bootloader addresses for mXT1664/mXT1188S Nick Dyer
@ 2013-02-22 17:57 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 13/40] Input: atmel_mxt_ts - Use deep sleep mode when stopped Nick Dyer
                   ` (29 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:57 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Rather than having a separate configuration in platform data for screen size
and orientation, read it from the settings that the touchscreen controller is
using.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 arch/arm/mach-exynos/mach-nuri.c           |    3 -
 arch/arm/mach-exynos/mach-universal_c210.c |    3 -
 arch/arm/mach-s5pv210/mach-goni.c          |    3 -
 drivers/input/touchscreen/atmel_mxt_ts.c   |  144 ++++++++++++++--------------
 include/linux/i2c/atmel_mxt_ts.h           |   14 ---
 5 files changed, 70 insertions(+), 97 deletions(-)

diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
index 770d314..0c8dac8 100644
--- a/arch/arm/mach-exynos/mach-nuri.c
+++ b/arch/arm/mach-exynos/mach-nuri.c
@@ -335,9 +335,6 @@ static struct i2c_board_info i2c1_devs[] __initdata = {
 
 /* TSP */
 static struct mxt_platform_data mxt_platform_data = {
-	.x_size			= 1024,
-	.y_size			= 600,
-	.orient			= MXT_DIAGONAL_COUNTER,
 	.irqflags		= IRQF_TRIGGER_FALLING,
 };
 
diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c
index 8de6e36..15aae25 100644
--- a/arch/arm/mach-exynos/mach-universal_c210.c
+++ b/arch/arm/mach-exynos/mach-universal_c210.c
@@ -605,9 +605,6 @@ static struct i2c_board_info i2c5_devs[] __initdata = {
 
 /* I2C3 (TSP) */
 static struct mxt_platform_data qt602240_platform_data = {
-	.x_size		= 800,
-	.y_size		= 480,
-	.orient		= MXT_DIAGONAL,
 	.irqflags	= IRQF_TRIGGER_FALLING,
 };
 
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
index 2743751..7cc1387 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -240,9 +240,6 @@ static void __init goni_radio_init(void)
 
 /* TSP */
 static struct mxt_platform_data qt602240_platform_data = {
-	.x_size		= 800,
-	.y_size		= 480,
-	.orient		= MXT_DIAGONAL,
 	.irqflags	= IRQF_TRIGGER_FALLING,
 };
 
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 903ff54..e1f2bd3 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -102,33 +102,16 @@
 
 /* MXT_TOUCH_MULTI_T9 field */
 #define MXT_TOUCH_CTRL		0
-#define MXT_TOUCH_XORIGIN	1
-#define MXT_TOUCH_YORIGIN	2
-#define MXT_TOUCH_XSIZE		3
-#define MXT_TOUCH_YSIZE		4
-#define MXT_TOUCH_BLEN		6
-#define MXT_TOUCH_TCHTHR	7
-#define MXT_TOUCH_TCHDI		8
-#define MXT_TOUCH_ORIENT	9
-#define MXT_TOUCH_MOVHYSTI	11
-#define MXT_TOUCH_MOVHYSTN	12
-#define MXT_TOUCH_NUMTOUCH	14
-#define MXT_TOUCH_MRGHYST	15
-#define MXT_TOUCH_MRGTHR	16
-#define MXT_TOUCH_AMPHYST	17
-#define MXT_TOUCH_XRANGE_LSB	18
-#define MXT_TOUCH_XRANGE_MSB	19
-#define MXT_TOUCH_YRANGE_LSB	20
-#define MXT_TOUCH_YRANGE_MSB	21
-#define MXT_TOUCH_XLOCLIP	22
-#define MXT_TOUCH_XHICLIP	23
-#define MXT_TOUCH_YLOCLIP	24
-#define MXT_TOUCH_YHICLIP	25
-#define MXT_TOUCH_XEDGECTRL	26
-#define MXT_TOUCH_XEDGEDIST	27
-#define MXT_TOUCH_YEDGECTRL	28
-#define MXT_TOUCH_YEDGEDIST	29
-#define MXT_TOUCH_JUMPLIMIT	30
+#define MXT_T9_ORIENT		9
+#define MXT_T9_RANGE		18
+
+struct t9_range {
+	u16 x;
+	u16 y;
+} __packed;
+
+/* Touch orient bits */
+#define MXT_XY_SWITCH		(1 << 0)
 
 /* MXT_PROCI_GRIPFACE_T20 field */
 #define MXT_GRIPFACE_CTRL	0
@@ -211,11 +194,6 @@
 #define MXT_PRESS		(1 << 6)
 #define MXT_DETECT		(1 << 7)
 
-/* Touch orient bits */
-#define MXT_XY_SWITCH		(1 << 0)
-#define MXT_X_INVERT		(1 << 1)
-#define MXT_Y_INVERT		(1 << 2)
-
 /* Touchscreen absolute values */
 #define MXT_MAX_AREA		0xff
 
@@ -532,11 +510,6 @@ static int __mxt_read_reg(struct i2c_client *client,
 	return ret;
 }
 
-static int mxt_read_reg(struct i2c_client *client, u16 reg, u8 *val)
-{
-	return __mxt_read_reg(client, reg, 1, val);
-}
-
 static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len,
 			   const void *val)
 {
@@ -1178,12 +1151,66 @@ static void mxt_free_object_table(struct mxt_data *data)
 
 }
 
+static int mxt_read_t9_resolution(struct mxt_data *data)
+{
+	struct i2c_client *client = data->client;
+	int error;
+	struct t9_range range;
+	unsigned char orient;
+	struct mxt_object *object;
+
+	object = mxt_get_object(data, MXT_TOUCH_MULTI_T9);
+	if (!object)
+		return -EINVAL;
+
+	/* Update matrix size in info struct (may change after reset) */
+	error = mxt_get_info(data);
+	if (error)
+		return error;
+
+	error = __mxt_read_reg(client,
+			       object->start_address + MXT_T9_RANGE,
+			       sizeof(range), &range);
+	if (error)
+		return error;
+
+	le16_to_cpus(range.x);
+	le16_to_cpus(range.y);
+
+	error =  __mxt_read_reg(client,
+				object->start_address + MXT_T9_ORIENT,
+				1, &orient);
+	if (error)
+		return error;
+
+	/* Handle default values */
+	if (range.x == 0)
+		range.x = 1023;
+
+	if (range.y == 0)
+		range.y = 1023;
+
+	if (orient & MXT_XY_SWITCH) {
+		data->max_x = range.y;
+		data->max_y = range.x;
+	} else {
+		data->max_x = range.x;
+		data->max_y = range.y;
+	}
+
+	dev_info(&client->dev,
+			"Matrix Size X%uY%u Touchscreen size X%uY%u\n",
+			data->info.matrix_xsize, data->info.matrix_ysize,
+			data->max_x, data->max_y);
+
+	return 0;
+}
+
 static int mxt_initialize(struct mxt_data *data)
 {
 	struct i2c_client *client = data->client;
 	struct mxt_info *info = &data->info;
 	int error;
-	u8 val;
 
 	error = mxt_get_info(data);
 	if (error) {
@@ -1222,46 +1249,17 @@ static int mxt_initialize(struct mxt_data *data)
 		return error;
 	}
 
-	/* Update matrix size at info struct */
-	error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
+	error = mxt_read_t9_resolution(data);
 	if (error)
-		goto err_free_object_table;
-	info->matrix_xsize = val;
-
-	error = mxt_read_reg(client, MXT_MATRIX_Y_SIZE, &val);
-	if (error)
-		goto err_free_object_table;
-	info->matrix_ysize = val;
+		dev_warn(&client->dev, "Failed to initialize T9 resolution\n");
 
 	dev_info(&client->dev,
-			"Family ID: %u Variant ID: %u Firmware V%u.%u.%02X\n",
+			"Family ID: %u Variant ID: %u Firmware V%u.%u.%02X "
+			" Object Num:%d\n",
 			info->family_id, info->variant_id, info->version >> 4,
-			info->version & 0xf, info->build);
-
-	dev_info(&client->dev,
-			"Matrix X Size: %u Matrix Y Size: %u Object Num: %u\n",
-			info->matrix_xsize, info->matrix_ysize,
-			info->object_num);
+			info->version & 0xf, info->build, info->object_num);
 
 	return 0;
-
-err_free_object_table:
-	mxt_free_object_table(data);
-	return error;
-}
-
-static void mxt_calc_resolution(struct mxt_data *data)
-{
-	unsigned int max_x = data->pdata->x_size - 1;
-	unsigned int max_y = data->pdata->y_size - 1;
-
-	if (data->pdata->orient & MXT_XY_SWITCH) {
-		data->max_x = max_y;
-		data->max_y = max_x;
-	} else {
-		data->max_x = max_x;
-		data->max_y = max_y;
-	}
 }
 
 /* Firmware Version is returned as Major.Minor.Build */
@@ -1650,8 +1648,6 @@ static int mxt_probe(struct i2c_client *client,
 	data->pdata = pdata;
 	data->irq = client->irq;
 
-	mxt_calc_resolution(data);
-
 	error = mxt_initialize(data);
 	if (error)
 		goto err_free_mem;
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index 1ebb8fd..e7bceee 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -15,22 +15,8 @@
 
 #include <linux/types.h>
 
-/* Orient */
-#define MXT_NORMAL		0x0
-#define MXT_DIAGONAL		0x1
-#define MXT_HORIZONTAL_FLIP	0x2
-#define MXT_ROTATED_90_COUNTER	0x3
-#define MXT_VERTICAL_FLIP	0x4
-#define MXT_ROTATED_90		0x5
-#define MXT_ROTATED_180		0x6
-#define MXT_DIAGONAL_COUNTER	0x7
-
 /* The platform data for the Atmel maXTouch touchscreen driver */
 struct mxt_platform_data {
-	unsigned int x_size;
-	unsigned int y_size;
-	unsigned char orient;
-
 	unsigned long irqflags;
 	u8(*read_chg) (void);
 };
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 13/40] Input: atmel_mxt_ts - Use deep sleep mode when stopped
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (11 preceding siblings ...)
  2013-02-22 17:57 ` [PATCH 12/40] Input: atmel_mxt_ts - Read screen config from chip Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 14/40] Input: atmel_mxt_ts - add shutdown function Nick Dyer
                   ` (28 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

By writing zero to both the active and idle cycle times the maXTouch device is
put into a deep sleep mode when it consumes no power.

It is counterproductive to reset the chip on resume, it will result in a long
delay. The power consumption in deep sleep mode is minimal.  However it is
necessary to issue a calibrate command after the chip has spent any time in
deep sleep.

This patch also deals with the situation where the power configuration is zero
on probe, which would mean that the device never wakes up to execute commands.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  107 +++++++++++++++++++++---------
 1 file changed, 77 insertions(+), 30 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index e1f2bd3..bbe9aff 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -87,9 +87,13 @@
 #define MXT_COMMAND_DIAGNOSTIC	5
 
 /* MXT_GEN_POWER_T7 field */
-#define MXT_POWER_IDLEACQINT	0
-#define MXT_POWER_ACTVACQINT	1
-#define MXT_POWER_ACTV2IDLETO	2
+struct t7_config {
+	u8 idle;
+	u8 active;
+} __packed;
+
+#define MXT_POWER_CFG_RUN		0
+#define MXT_POWER_CFG_DEEPSLEEP		1
 
 /* MXT_GEN_ACQUIRE_T8 field */
 #define MXT_ACQUIRE_CHRGTIME	0
@@ -101,7 +105,6 @@
 #define MXT_ACQUIRE_ATCHCALSTHR	7
 
 /* MXT_TOUCH_MULTI_T9 field */
-#define MXT_TOUCH_CTRL		0
 #define MXT_T9_ORIENT		9
 #define MXT_T9_RANGE		18
 
@@ -243,6 +246,7 @@ struct mxt_data {
 	u32 config_crc;
 	u32 info_crc;
 	u8 bootloader_addr;
+	struct t7_config t7_cfg;
 
 	/* Cached parameters from object table */
 	u8 T6_reportid;
@@ -576,20 +580,6 @@ static int mxt_read_message(struct mxt_data *data,
 			sizeof(struct mxt_message), message);
 }
 
-static int mxt_write_object(struct mxt_data *data,
-				 u8 type, u8 offset, u8 val)
-{
-	struct mxt_object *object;
-	u16 reg;
-
-	object = mxt_get_object(data, type);
-	if (!object || offset >= OBP_SIZE(object))
-		return -EINVAL;
-
-	reg = object->start_address;
-	return mxt_write_reg(data->client, reg + offset, val);
-}
-
 static void mxt_input_touchevent(struct mxt_data *data,
 				      struct mxt_message *message, int id)
 {
@@ -1042,6 +1032,64 @@ release:
 	return ret;
 }
 
+static int mxt_set_t7_power_cfg(struct mxt_data *data, u8 sleep)
+{
+	struct device *dev = &data->client->dev;
+	int error;
+	struct t7_config *new_config;
+	struct t7_config deepsleep = { .active = 0, .idle = 0 };
+
+	if (sleep == MXT_POWER_CFG_DEEPSLEEP)
+		new_config = &deepsleep;
+	else
+		new_config = &data->t7_cfg;
+
+	error = __mxt_write_reg(data->client, data->T7_address,
+			sizeof(data->t7_cfg),
+			new_config);
+	if (error)
+		return error;
+
+	dev_dbg(dev, "Set T7 ACTV:%d IDLE:%d\n",
+		new_config->active, new_config->idle);
+
+	return 0;
+}
+
+static int mxt_init_t7_power_cfg(struct mxt_data *data)
+{
+	struct device *dev = &data->client->dev;
+	int error;
+	bool retry = false;
+
+recheck:
+	error = __mxt_read_reg(data->client, data->T7_address,
+				sizeof(data->t7_cfg), &data->t7_cfg);
+	if (error)
+		return error;
+
+	if (data->t7_cfg.active == 0 || data->t7_cfg.idle == 0) {
+		if (!retry) {
+			dev_info(dev, "T7 cfg zero, resetting\n");
+			error = mxt_soft_reset(data, MXT_RESET_VALUE);
+			if (error)
+				return error;
+
+			retry = true;
+			goto recheck;
+		} else {
+		    dev_dbg(dev, "T7 cfg zero after reset, overriding\n");
+		    data->t7_cfg.active = 20;
+		    data->t7_cfg.idle = 100;
+		    return mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
+		}
+	} else {
+		dev_info(dev, "Initialised power cfg: ACTV %d, IDLE %d\n",
+				data->t7_cfg.active, data->t7_cfg.idle);
+		return 0;
+	}
+}
+
 static int mxt_make_highchg(struct mxt_data *data)
 {
 	struct device *dev = &data->client->dev;
@@ -1249,6 +1297,12 @@ static int mxt_initialize(struct mxt_data *data)
 		return error;
 	}
 
+	error = mxt_init_t7_power_cfg(data);
+	if (error) {
+		dev_err(&client->dev, "Failed to initialize power cfg\n");
+		return error;
+	}
+
 	error = mxt_read_t9_resolution(data);
 	if (error)
 		dev_warn(&client->dev, "Failed to initialize T9 resolution\n");
@@ -1583,16 +1637,15 @@ static const struct attribute_group mxt_attr_group = {
 
 static void mxt_start(struct mxt_data *data)
 {
-	/* Touch enable */
-	mxt_write_object(data,
-			MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0x83);
+	mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
+
+	/* Recalibrate since chip has been in deep sleep */
+	mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false);
 }
 
 static void mxt_stop(struct mxt_data *data)
 {
-	/* Touch disable */
-	mxt_write_object(data,
-			MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0);
+	mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
 }
 
 static int mxt_input_open(struct input_dev *dev)
@@ -1776,12 +1829,6 @@ static int mxt_resume(struct device *dev)
 	struct mxt_data *data = i2c_get_clientdata(client);
 	struct input_dev *input_dev = data->input_dev;
 
-	/* Soft reset */
-	mxt_write_object(data, MXT_GEN_COMMAND_T6,
-			MXT_COMMAND_RESET, 1);
-
-	msleep(MXT_RESET_TIME);
-
 	mutex_lock(&input_dev->mutex);
 
 	if (input_dev->users)
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 14/40] Input: atmel_mxt_ts - add shutdown function
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (12 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 13/40] Input: atmel_mxt_ts - Use deep sleep mode when stopped Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 15/40] Input: atmel_mxt_ts - Improve touch reporting for T9 Nick Dyer
                   ` (27 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index bbe9aff..3994564 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -226,7 +226,7 @@ struct mxt_message {
 	u8 message[7];
 };
 
-enum mxt_device_state { INIT, APPMODE, BOOTLOADER, FAILED };
+enum mxt_device_state { INIT, APPMODE, BOOTLOADER, FAILED, SHUTDOWN };
 
 /* Each client has this additional data */
 struct mxt_data {
@@ -1842,6 +1842,14 @@ static int mxt_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume);
 
+static void mxt_shutdown(struct i2c_client *client)
+{
+	struct mxt_data *data = i2c_get_clientdata(client);
+
+	disable_irq(data->irq);
+	data->state = SHUTDOWN;
+}
+
 static const struct i2c_device_id mxt_id[] = {
 	{ "qt602240_ts", 0 },
 	{ "atmel_mxt_ts", 0 },
@@ -1858,6 +1866,7 @@ static struct i2c_driver mxt_driver = {
 	},
 	.probe		= mxt_probe,
 	.remove		= mxt_remove,
+	.shutdown	= mxt_shutdown,
 	.id_table	= mxt_id,
 };
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 15/40] Input: atmel_mxt_ts - Improve touch reporting for T9
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (13 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 14/40] Input: atmel_mxt_ts - add shutdown function Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 16/40] Input: atmel_mxt_ts - Move input device configuration into separate function Nick Dyer
                   ` (26 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Handle multiple touch statuses in one report
Rename defines to add T9
Rename pressure to amplitude to match device spec

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   85 ++++++++++++++++++------------
 1 file changed, 51 insertions(+), 34 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 3994564..335fa1b 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -108,13 +108,23 @@ struct t7_config {
 #define MXT_T9_ORIENT		9
 #define MXT_T9_RANGE		18
 
+/* MXT_TOUCH_MULTI_T9 status */
+#define MXT_T9_UNGRIP		(1 << 0)
+#define MXT_T9_SUPPRESS		(1 << 1)
+#define MXT_T9_AMP		(1 << 2)
+#define MXT_T9_VECTOR		(1 << 3)
+#define MXT_T9_MOVE		(1 << 4)
+#define MXT_T9_RELEASE		(1 << 5)
+#define MXT_T9_PRESS		(1 << 6)
+#define MXT_T9_DETECT		(1 << 7)
+
 struct t9_range {
 	u16 x;
 	u16 y;
 } __packed;
 
-/* Touch orient bits */
-#define MXT_XY_SWITCH		(1 << 0)
+/* MXT_TOUCH_MULTI_T9 orient */
+#define MXT_T9_ORIENT_SWITCH	(1 << 0)
 
 /* MXT_PROCI_GRIPFACE_T20 field */
 #define MXT_GRIPFACE_CTRL	0
@@ -187,16 +197,6 @@ struct t9_range {
 #define MXT_BOOT_EXTENDED_ID	(1 << 5)
 #define MXT_BOOT_ID_MASK	0x1f
 
-/* Touch status */
-#define MXT_UNGRIP		(1 << 0)
-#define MXT_SUPPRESS		(1 << 1)
-#define MXT_AMP			(1 << 2)
-#define MXT_VECTOR		(1 << 3)
-#define MXT_MOVE		(1 << 4)
-#define MXT_RELEASE		(1 << 5)
-#define MXT_PRESS		(1 << 6)
-#define MXT_DETECT		(1 << 7)
-
 /* Touchscreen absolute values */
 #define MXT_MAX_AREA		0xff
 
@@ -580,6 +580,12 @@ static int mxt_read_message(struct mxt_data *data,
 			sizeof(struct mxt_message), message);
 }
 
+static void mxt_input_sync(struct input_dev *input_dev)
+{
+	input_mt_report_pointer_emulation(input_dev, false);
+	input_sync(input_dev);
+}
+
 static void mxt_input_touchevent(struct mxt_data *data,
 				      struct mxt_message *message, int id)
 {
@@ -589,7 +595,7 @@ static void mxt_input_touchevent(struct mxt_data *data,
 	int x;
 	int y;
 	int area;
-	int pressure;
+	int amplitude;
 
 	/* do not report events if input device not yet registered */
 	if (!input_dev)
@@ -597,36 +603,49 @@ static void mxt_input_touchevent(struct mxt_data *data,
 
 	x = (message->message[1] << 4) | ((message->message[3] >> 4) & 0xf);
 	y = (message->message[2] << 4) | ((message->message[3] & 0xf));
+
 	if (data->max_x < 1024)
-		x = x >> 2;
+		x >>= 2;
 	if (data->max_y < 1024)
-		y = y >> 2;
+		y >>= 2;
 
 	area = message->message[4];
-	pressure = message->message[5];
+	amplitude = message->message[5];
 
 	dev_dbg(dev,
 		"[%u] %c%c%c%c%c%c%c%c x: %5u y: %5u area: %3u amp: %3u\n",
 		id,
-		(status & MXT_DETECT) ? 'D' : '.',
-		(status & MXT_PRESS) ? 'P' : '.',
-		(status & MXT_RELEASE) ? 'R' : '.',
-		(status & MXT_MOVE) ? 'M' : '.',
-		(status & MXT_VECTOR) ? 'V' : '.',
-		(status & MXT_AMP) ? 'A' : '.',
-		(status & MXT_SUPPRESS) ? 'S' : '.',
-		(status & MXT_UNGRIP) ? 'U' : '.',
-		x, y, area, pressure);
+		(status & MXT_T9_DETECT) ? 'D' : '.',
+		(status & MXT_T9_PRESS) ? 'P' : '.',
+		(status & MXT_T9_RELEASE) ? 'R' : '.',
+		(status & MXT_T9_MOVE) ? 'M' : '.',
+		(status & MXT_T9_VECTOR) ? 'V' : '.',
+		(status & MXT_T9_AMP) ? 'A' : '.',
+		(status & MXT_T9_SUPPRESS) ? 'S' : '.',
+		(status & MXT_T9_UNGRIP) ? 'U' : '.',
+		x, y, area, amplitude);
 
 	input_mt_slot(input_dev, id);
-	input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
-				   status & MXT_DETECT);
 
-	if (status & MXT_DETECT) {
+	if (status & MXT_T9_DETECT) {
+		/* Multiple bits may be set if the host is slow to read the
+		 * status messages, indicating all the events that have
+		 * happened */
+		if (status & MXT_T9_RELEASE) {
+			input_mt_report_slot_state(input_dev,
+						   MT_TOOL_FINGER, 0);
+			mxt_input_sync(input_dev);
+		}
+
+		/* Touch active */
+		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);
 		input_report_abs(input_dev, ABS_MT_POSITION_X, x);
 		input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
-		input_report_abs(input_dev, ABS_MT_PRESSURE, pressure);
+		input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude);
 		input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area);
+	} else {
+		/* Touch no longer active, close out slot */
+		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
 	}
 }
 
@@ -676,10 +695,8 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 			mxt_dump_message(dev, &message);
 	} while (reportid != MXT_RPTID_NOMSG);
 
-	if (update_input) {
-		input_mt_report_pointer_emulation(data->input_dev, false);
-		input_sync(data->input_dev);
-	}
+	if (update_input)
+		mxt_input_sync(data->input_dev);
 
 	return IRQ_HANDLED;
 }
@@ -1238,7 +1255,7 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
 	if (range.y == 0)
 		range.y = 1023;
 
-	if (orient & MXT_XY_SWITCH) {
+	if (orient & MXT_T9_ORIENT_SWITCH) {
 		data->max_x = range.y;
 		data->max_y = range.x;
 	} else {
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 16/40] Input: atmel_mxt_ts - Move input device configuration into separate function
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (14 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 15/40] Input: atmel_mxt_ts - Improve touch reporting for T9 Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 17/40] Input: atmel_mxt_ts - Allow input device name to be configured from platform data Nick Dyer
                   ` (25 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   83 +++++++++++++++++++-----------
 1 file changed, 53 insertions(+), 30 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 335fa1b..b7e5646 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1681,28 +1681,19 @@ static void mxt_input_close(struct input_dev *dev)
 	mxt_stop(data);
 }
 
-static int mxt_probe(struct i2c_client *client,
-		const struct i2c_device_id *id)
+static int mxt_initialize_t9_input_device(struct mxt_data *data)
 {
-	const struct mxt_platform_data *pdata = client->dev.platform_data;
-	struct mxt_data *data;
+	struct i2c_client *client = data->client;
 	struct input_dev *input_dev;
 	int error;
 	unsigned int num_mt_slots;
 
-	if (!pdata)
-		return -EINVAL;
-
-	data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL);
 	input_dev = input_allocate_device();
-	if (!data || !input_dev) {
+	if (!input_dev) {
 		dev_err(&client->dev, "Failed to allocate memory\n");
-		error = -ENOMEM;
-		goto err_free_mem;
+		return -ENOMEM;
 	}
 
-	data->state = INIT;
-
 	input_dev->name = "Atmel maXTouch Touchscreen";
 	snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0",
 		 client->adapter->nr, client->addr);
@@ -1713,18 +1704,8 @@ static int mxt_probe(struct i2c_client *client,
 	input_dev->open = mxt_input_open;
 	input_dev->close = mxt_input_close;
 
-	data->client = client;
-	data->input_dev = input_dev;
-	data->pdata = pdata;
-	data->irq = client->irq;
-
-	error = mxt_initialize(data);
-	if (error)
-		goto err_free_mem;
-
-	__set_bit(EV_ABS, input_dev->evbit);
-	__set_bit(EV_KEY, input_dev->evbit);
-	__set_bit(BTN_TOUCH, input_dev->keybit);
+	set_bit(EV_ABS, input_dev->evbit);
+	input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
 
 	/* For single touch */
 	input_set_abs_params(input_dev, ABS_X,
@@ -1738,7 +1719,8 @@ static int mxt_probe(struct i2c_client *client,
 	num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1;
 	error = input_mt_init_slots(input_dev, num_mt_slots, 0);
 	if (error)
-		goto err_free_object;
+		goto err_free_mem;
+
 	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
 			     0, MXT_MAX_AREA, 0, 0);
 	input_set_abs_params(input_dev, ABS_MT_POSITION_X,
@@ -1749,8 +1731,50 @@ static int mxt_probe(struct i2c_client *client,
 			     0, 255, 0, 0);
 
 	input_set_drvdata(input_dev, data);
+
+	error = input_register_device(input_dev);
+	if (error) {
+		dev_err(&client->dev, "Error %d registering input device\n",
+			error);
+		goto err_free_mem;
+	}
+
+	data->input_dev = input_dev;
+
+	return 0;
+
+err_free_mem:
+	input_free_device(input_dev);
+	return error;
+}
+
+static int mxt_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	const struct mxt_platform_data *pdata = client->dev.platform_data;
+	struct mxt_data *data;
+	int error;
+
+	if (!pdata)
+		return -EINVAL;
+
+	data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL);
+	if (!data) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	data->state = INIT;
+
+	data->client = client;
+	data->pdata = pdata;
+	data->irq = client->irq;
 	i2c_set_clientdata(client, data);
 
+	error = mxt_initialize(data);
+	if (error)
+		goto err_free_mem;
+
 	error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
 				     pdata->irqflags | IRQF_ONESHOT,
 				     client->name, data);
@@ -1765,7 +1789,7 @@ static int mxt_probe(struct i2c_client *client,
 			goto err_free_irq;
 	}
 
-	error = input_register_device(input_dev);
+	error = mxt_initialize_t9_input_device(data);
 	if (error) {
 		dev_err(&client->dev, "Error %d registering input device\n",
 			error);
@@ -1797,14 +1821,13 @@ static int mxt_probe(struct i2c_client *client,
 err_remove_sysfs_group:
 	sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
 err_unregister_device:
-	input_unregister_device(input_dev);
-	input_dev = NULL;
+	input_unregister_device(data->input_dev);
+	data->input_dev = NULL;
 err_free_irq:
 	free_irq(client->irq, data);
 err_free_object:
 	kfree(data->object_table);
 err_free_mem:
-	input_free_device(input_dev);
 	kfree(data);
 	return error;
 }
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 17/40] Input: atmel_mxt_ts - Allow input device name to be configured from platform data
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (15 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 16/40] Input: atmel_mxt_ts - Move input device configuration into separate function Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 18/40] Input: atmel_mxt_ts - Add support for dynamic message size Nick Dyer
                   ` (24 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Some systems (for example Android IDC files) rely on this name being
a specific string.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |    6 +++++-
 include/linux/i2c/atmel_mxt_ts.h         |    1 +
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b7e5646..60231bf 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1694,7 +1694,11 @@ static int mxt_initialize_t9_input_device(struct mxt_data *data)
 		return -ENOMEM;
 	}
 
-	input_dev->name = "Atmel maXTouch Touchscreen";
+	if (data->pdata->input_name)
+		input_dev->name = data->pdata->input_name;
+	else
+		input_dev->name = "Atmel maXTouch Touchscreen";
+
 	snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0",
 		 client->adapter->nr, client->addr);
 	input_dev->phys = data->phys;
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index e7bceee..b96b265 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -19,6 +19,7 @@
 struct mxt_platform_data {
 	unsigned long irqflags;
 	u8(*read_chg) (void);
+	const char *input_name;
 };
 
 #endif /* __LINUX_ATMEL_MXT_TS_H */
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 18/40] Input: atmel_mxt_ts - Add support for dynamic message size
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (16 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 17/40] Input: atmel_mxt_ts - Allow input device name to be configured from platform data Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 19/40] Input: atmel_mxt_ts - Decode T6 status messages Nick Dyer
                   ` (23 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

maXTouch chips and firmware versions have different sizes of message buffer
depending on the objects used, therefore it can't be hardcoded in the driver.
Allocate a buffer on probe instead.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   97 +++++++++++++++++-------------
 1 file changed, 55 insertions(+), 42 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 60231bf..c879778 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -221,11 +221,6 @@ struct mxt_object {
 	u8 num_report_ids;
 } __packed;
 
-struct mxt_message {
-	u8 reportid;
-	u8 message[7];
-};
-
 enum mxt_device_state { INIT, APPMODE, BOOTLOADER, FAILED, SHUTDOWN };
 
 /* Each client has this additional data */
@@ -247,8 +242,10 @@ struct mxt_data {
 	u32 info_crc;
 	u8 bootloader_addr;
 	struct t7_config t7_cfg;
+	u8 *msg_buf;
 
 	/* Cached parameters from object table */
+	u8 T5_msg_size;
 	u8 T6_reportid;
 	u16 T6_address;
 	u16 T7_address;
@@ -309,10 +306,10 @@ static bool mxt_object_readable(unsigned int type)
 	}
 }
 
-static void mxt_dump_message(struct device *dev, struct mxt_message *message)
+static void mxt_dump_message(struct mxt_data *data, u8 *message)
 {
-	dev_dbg(dev, "MXT MSG: %*ph\n",
-		       sizeof(struct mxt_message), message);
+	dev_dbg(&data->client->dev, "MXT MSG: %*ph\n",
+		       data->T5_msg_size, message);
 }
 
 static int mxt_bootloader_read(struct mxt_data *data, u8 *val, unsigned int count)
@@ -565,8 +562,7 @@ mxt_get_object(struct mxt_data *data, u8 type)
 	return NULL;
 }
 
-static int mxt_read_message(struct mxt_data *data,
-				 struct mxt_message *message)
+static int mxt_read_message(struct mxt_data *data, u8 *message)
 {
 	struct mxt_object *object;
 	u16 reg;
@@ -577,7 +573,7 @@ static int mxt_read_message(struct mxt_data *data,
 
 	reg = object->start_address;
 	return __mxt_read_reg(data->client, reg,
-			sizeof(struct mxt_message), message);
+			data->T5_msg_size, message);
 }
 
 static void mxt_input_sync(struct input_dev *input_dev)
@@ -586,12 +582,12 @@ static void mxt_input_sync(struct input_dev *input_dev)
 	input_sync(input_dev);
 }
 
-static void mxt_input_touchevent(struct mxt_data *data,
-				      struct mxt_message *message, int id)
+static void mxt_input_touchevent(struct mxt_data *data, u8 *message)
 {
 	struct device *dev = &data->client->dev;
-	u8 status = message->message[0];
 	struct input_dev *input_dev = data->input_dev;
+	int id;
+	u8 status;
 	int x;
 	int y;
 	int area;
@@ -601,16 +597,18 @@ static void mxt_input_touchevent(struct mxt_data *data,
 	if (!input_dev)
 		return;
 
-	x = (message->message[1] << 4) | ((message->message[3] >> 4) & 0xf);
-	y = (message->message[2] << 4) | ((message->message[3] & 0xf));
+	id = message[0] - data->T9_reportid_min;
+	status = message[1];
+	x = (message[2] << 4) | ((message[4] >> 4) & 0xf);
+	y = (message[3] << 4) | ((message[4] & 0xf));
 
 	if (data->max_x < 1024)
 		x >>= 2;
 	if (data->max_y < 1024)
 		y >>= 2;
 
-	area = message->message[4];
-	amplitude = message->message[5];
+	area = message[5];
+	amplitude = message[6];
 
 	dev_dbg(dev,
 		"[%u] %c%c%c%c%c%c%c%c x: %5u y: %5u area: %3u amp: %3u\n",
@@ -654,28 +652,28 @@ static u16 mxt_extract_T6_csum(const u8 *csum)
 	return csum[0] | (csum[1] << 8) | (csum[2] << 16);
 }
 
-static bool mxt_is_T9_message(struct mxt_data *data, struct mxt_message *msg)
+static bool mxt_is_T9_message(struct mxt_data *data, u8 *msg)
 {
-	u8 id = msg->reportid;
+	u8 id = msg[0];
 	return (id >= data->T9_reportid_min && id <= data->T9_reportid_max);
 }
 
 static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 {
-	struct mxt_message message;
-	const u8 *payload = &message.message[0];
+	u8 *message = &data->msg_buf[0];
+	const u8 *payload = &data->msg_buf[1];
 	struct device *dev = &data->client->dev;
 	u8 reportid;
 	bool update_input = false;
 	bool handled;
 
 	do {
-		if (mxt_read_message(data, &message)) {
+		if (mxt_read_message(data, message)) {
 			dev_err(dev, "Failed to read message\n");
 			return IRQ_NONE;
 		}
 
-		reportid = message.reportid;
+		reportid = message[0];
 		handled = false;
 
 		if (reportid == data->T6_reportid) {
@@ -684,15 +682,14 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 			dev_dbg(dev, "Status: %02x Config Checksum: %06x\n",
 				status, data->config_crc);
 			handled = true;
-		} else if (mxt_is_T9_message(data, &message)) {
-			int id = reportid - data->T9_reportid_min;
-			mxt_input_touchevent(data, &message, id);
+		} else if (mxt_is_T9_message(data, message)) {
+			mxt_input_touchevent(data, message);
 			update_input = true;
 			handled = true;
 		}
 
 		if (!handled || data->debug_enabled)
-			mxt_dump_message(dev, &message);
+			mxt_dump_message(data, message);
 	} while (reportid != MXT_RPTID_NOMSG);
 
 	if (update_input)
@@ -1110,16 +1107,15 @@ recheck:
 static int mxt_make_highchg(struct mxt_data *data)
 {
 	struct device *dev = &data->client->dev;
-	struct mxt_message message;
 	int count = 10;
 	int error;
 
 	/* Read dummy message to make high CHG pin */
 	do {
-		error = mxt_read_message(data, &message);
+		error = mxt_read_message(data, data->msg_buf);
 		if (error)
 			return error;
-	} while (message.reportid != MXT_RPTID_NOMSG && --count);
+	} while (data->msg_buf[0] != MXT_RPTID_NOMSG && --count);
 
 	if (!count) {
 		dev_err(dev, "CHG pin isn't cleared\n");
@@ -1143,6 +1139,19 @@ static int mxt_get_info(struct mxt_data *data)
 	return 0;
 }
 
+static void mxt_free_object_table(struct mxt_data *data)
+{
+	kfree(data->object_table);
+	data->object_table = NULL;
+	kfree(data->msg_buf);
+	data->msg_buf = NULL;
+	data->T5_msg_size = 0;
+	data->T6_reportid = 0;
+	data->T7_address = 0;
+	data->T9_reportid_min = 0;
+	data->T9_reportid_max = 0;
+}
+
 static int mxt_get_object_table(struct mxt_data *data)
 {
 	struct i2c_client *client = data->client;
@@ -1183,6 +1192,9 @@ static int mxt_get_object_table(struct mxt_data *data)
 			OBP_INSTANCES(object), min_id, max_id);
 
 		switch (object->type) {
+		case MXT_GEN_MESSAGE_T5:
+			/* CRC not enabled, therefore don't read last byte */
+			data->T5_msg_size = OBP_SIZE(object) - 1;
 		case MXT_GEN_COMMAND_T6:
 			data->T6_reportid = min_id;
 			data->T6_address = object->start_address;
@@ -1203,17 +1215,18 @@ static int mxt_get_object_table(struct mxt_data *data)
 			data->mem_size = end_address + 1;
 	}
 
-	return 0;
-}
+	data->msg_buf = kzalloc(data->T5_msg_size, GFP_KERNEL);
+	if (!data->msg_buf) {
+		dev_err(&client->dev, "Failed to allocate message buffer\n");
+		error = -ENOMEM;
+		goto free_object_table;
+	}
 
-static void mxt_free_object_table(struct mxt_data *data)
-{
-	kfree(data->object_table);
-	data->object_table = NULL;
-	data->T6_reportid = 0;
-	data->T9_reportid_min = 0;
-	data->T9_reportid_max = 0;
+	return 0;
 
+free_object_table:
+	mxt_free_object_table(data);
+	return error;
 }
 
 static int mxt_read_t9_resolution(struct mxt_data *data)
@@ -1830,7 +1843,7 @@ err_unregister_device:
 err_free_irq:
 	free_irq(client->irq, data);
 err_free_object:
-	kfree(data->object_table);
+	mxt_free_object_table(data);
 err_free_mem:
 	kfree(data);
 	return error;
@@ -1844,7 +1857,7 @@ static int mxt_remove(struct i2c_client *client)
 	sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
 	free_irq(data->irq, data);
 	input_unregister_device(data->input_dev);
-	kfree(data->object_table);
+	mxt_free_object_table(data);
 	kfree(data);
 
 	return 0;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 19/40] Input: atmel_mxt_ts - Decode T6 status messages
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (17 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 18/40] Input: atmel_mxt_ts - Add support for dynamic message size Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 20/40] Input: atmel_mxt_ts - Split interrupt handler into separate functions Nick Dyer
                   ` (22 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   41 ++++++++++++++++++++++--------
 1 file changed, 31 insertions(+), 10 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index c879778..bdf7555 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -86,6 +86,14 @@
 #define MXT_COMMAND_REPORTALL	3
 #define MXT_COMMAND_DIAGNOSTIC	5
 
+/* Define for T6 status byte */
+#define MXT_T6_STATUS_RESET	(1 << 7)
+#define MXT_T6_STATUS_OFL	(1 << 6)
+#define MXT_T6_STATUS_SIGERR	(1 << 5)
+#define MXT_T6_STATUS_CAL	(1 << 4)
+#define MXT_T6_STATUS_CFGERR	(1 << 3)
+#define MXT_T6_STATUS_COMSERR	(1 << 2)
+
 /* MXT_GEN_POWER_T7 field */
 struct t7_config {
 	u8 idle;
@@ -562,6 +570,28 @@ mxt_get_object(struct mxt_data *data, u8 type)
 	return NULL;
 }
 
+static void mxt_proc_t6_messages(struct mxt_data *data, u8 *msg)
+{
+	struct device *dev = &data->client->dev;
+	u8 status = msg[1];
+	u32 crc = msg[2] | (msg[3] << 8) | (msg[4] << 16);
+
+	if (crc != data->config_crc) {
+		data->config_crc = crc;
+		dev_dbg(dev, "T6 Config Checksum: 0x%06X\n", crc);
+	}
+
+	if (status)
+		dev_dbg(dev, "T6 Status 0x%02X%s%s%s%s%s%s\n",
+				status,
+				(status & MXT_T6_STATUS_RESET) ? " RESET" : "",
+				(status & MXT_T6_STATUS_OFL) ? " OFL" : "",
+				(status & MXT_T6_STATUS_SIGERR) ? " SIGERR" : "",
+				(status & MXT_T6_STATUS_CAL) ? " CAL" : "",
+				(status & MXT_T6_STATUS_CFGERR) ? " CFGERR" : "",
+				(status & MXT_T6_STATUS_COMSERR) ? " COMSERR" : "");
+}
+
 static int mxt_read_message(struct mxt_data *data, u8 *message)
 {
 	struct mxt_object *object;
@@ -647,11 +677,6 @@ static void mxt_input_touchevent(struct mxt_data *data, u8 *message)
 	}
 }
 
-static u16 mxt_extract_T6_csum(const u8 *csum)
-{
-	return csum[0] | (csum[1] << 8) | (csum[2] << 16);
-}
-
 static bool mxt_is_T9_message(struct mxt_data *data, u8 *msg)
 {
 	u8 id = msg[0];
@@ -661,7 +686,6 @@ static bool mxt_is_T9_message(struct mxt_data *data, u8 *msg)
 static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 {
 	u8 *message = &data->msg_buf[0];
-	const u8 *payload = &data->msg_buf[1];
 	struct device *dev = &data->client->dev;
 	u8 reportid;
 	bool update_input = false;
@@ -677,10 +701,7 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 		handled = false;
 
 		if (reportid == data->T6_reportid) {
-			u8 status = payload[0];
-			data->config_crc = mxt_extract_T6_csum(&payload[1]);
-			dev_dbg(dev, "Status: %02x Config Checksum: %06x\n",
-				status, data->config_crc);
+			mxt_proc_t6_messages(data, message);
 			handled = true;
 		} else if (mxt_is_T9_message(data, message)) {
 			mxt_input_touchevent(data, message);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 20/40] Input: atmel_mxt_ts - Split interrupt handler into separate functions
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (18 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 19/40] Input: atmel_mxt_ts - Decode T6 status messages Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 21/40] Input: atmel_mxt_ts - Implement T44 message handling Nick Dyer
                   ` (21 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

This is in preparation for support of the T44 message count object.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  112 ++++++++++++++++--------------
 1 file changed, 58 insertions(+), 54 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index bdf7555..51901b7 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -251,8 +251,10 @@ struct mxt_data {
 	u8 bootloader_addr;
 	struct t7_config t7_cfg;
 	u8 *msg_buf;
+	bool update_input;
 
 	/* Cached parameters from object table */
+	u16 T5_address;
 	u8 T5_msg_size;
 	u8 T6_reportid;
 	u16 T6_address;
@@ -592,27 +594,13 @@ static void mxt_proc_t6_messages(struct mxt_data *data, u8 *msg)
 				(status & MXT_T6_STATUS_COMSERR) ? " COMSERR" : "");
 }
 
-static int mxt_read_message(struct mxt_data *data, u8 *message)
-{
-	struct mxt_object *object;
-	u16 reg;
-
-	object = mxt_get_object(data, MXT_GEN_MESSAGE_T5);
-	if (!object)
-		return -EINVAL;
-
-	reg = object->start_address;
-	return __mxt_read_reg(data->client, reg,
-			data->T5_msg_size, message);
-}
-
 static void mxt_input_sync(struct input_dev *input_dev)
 {
 	input_mt_report_pointer_emulation(input_dev, false);
 	input_sync(input_dev);
 }
 
-static void mxt_input_touchevent(struct mxt_data *data, u8 *message)
+static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
 {
 	struct device *dev = &data->client->dev;
 	struct input_dev *input_dev = data->input_dev;
@@ -675,46 +663,62 @@ static void mxt_input_touchevent(struct mxt_data *data, u8 *message)
 		/* Touch no longer active, close out slot */
 		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
 	}
+
+	data->update_input = true;
 }
 
-static bool mxt_is_T9_message(struct mxt_data *data, u8 *msg)
+static int mxt_proc_message(struct mxt_data *data, u8 *message)
 {
-	u8 id = msg[0];
-	return (id >= data->T9_reportid_min && id <= data->T9_reportid_max);
+	u8 report_id = message[0];
+	bool handled = false;
+
+	if (report_id == MXT_RPTID_NOMSG)
+		return 0;
+
+	if (report_id == data->T6_reportid) {
+		mxt_proc_t6_messages(data, message);
+		handled = true;
+	} else if (report_id >= data->T9_reportid_min
+	    && report_id <= data->T9_reportid_max) {
+		mxt_proc_t9_message(data, message);
+		handled = true;
+	}
+
+	if (!handled || data->debug_enabled)
+		mxt_dump_message(data, message);
+
+	return 1;
 }
 
-static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
+static int mxt_read_and_process_message(struct mxt_data *data)
 {
-	u8 *message = &data->msg_buf[0];
 	struct device *dev = &data->client->dev;
-	u8 reportid;
-	bool update_input = false;
-	bool handled;
+	int ret;
 
-	do {
-		if (mxt_read_message(data, message)) {
-			dev_err(dev, "Failed to read message\n");
-			return IRQ_NONE;
-		}
+	ret = __mxt_read_reg(data->client, data->T5_address,
+				data->T5_msg_size, data->msg_buf);
+	if (ret) {
+		dev_err(dev, "Error %d reading message\n", ret);
+		return ret;
+	}
 
-		reportid = message[0];
-		handled = false;
+	return mxt_proc_message(data, data->msg_buf);
+}
 
-		if (reportid == data->T6_reportid) {
-			mxt_proc_t6_messages(data, message);
-			handled = true;
-		} else if (mxt_is_T9_message(data, message)) {
-			mxt_input_touchevent(data, message);
-			update_input = true;
-			handled = true;
-		}
+static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
+{
+	int ret;
 
-		if (!handled || data->debug_enabled)
-			mxt_dump_message(data, message);
-	} while (reportid != MXT_RPTID_NOMSG);
+	do {
+		ret = mxt_read_and_process_message(data);
+		if (ret < 0)
+			return IRQ_NONE;
+	} while (ret > 0);
 
-	if (update_input)
+	if (data->update_input) {
 		mxt_input_sync(data->input_dev);
+		data->update_input = false;
+	}
 
 	return IRQ_HANDLED;
 }
@@ -1129,21 +1133,19 @@ static int mxt_make_highchg(struct mxt_data *data)
 {
 	struct device *dev = &data->client->dev;
 	int count = 10;
-	int error;
+	int ret;
 
-	/* Read dummy message to make high CHG pin */
+	/* Read messages until we force an invalid */
 	do {
-		error = mxt_read_message(data, data->msg_buf);
-		if (error)
-			return error;
-	} while (data->msg_buf[0] != MXT_RPTID_NOMSG && --count);
-
-	if (!count) {
-		dev_err(dev, "CHG pin isn't cleared\n");
-		return -EBUSY;
-	}
+		ret = mxt_read_and_process_message(data);
+		if (ret == 0)
+			return 0;
+		else if (ret < 0)
+			return ret;
+	} while (--count);
 
-	return 0;
+	dev_err(dev, "CHG pin isn't cleared\n");
+	return -EBUSY;
 }
 
 static int mxt_get_info(struct mxt_data *data)
@@ -1166,6 +1168,7 @@ static void mxt_free_object_table(struct mxt_data *data)
 	data->object_table = NULL;
 	kfree(data->msg_buf);
 	data->msg_buf = NULL;
+	data->T5_address = 0;
 	data->T5_msg_size = 0;
 	data->T6_reportid = 0;
 	data->T7_address = 0;
@@ -1216,6 +1219,7 @@ static int mxt_get_object_table(struct mxt_data *data)
 		case MXT_GEN_MESSAGE_T5:
 			/* CRC not enabled, therefore don't read last byte */
 			data->T5_msg_size = OBP_SIZE(object) - 1;
+			data->T5_address = object->start_address;
 		case MXT_GEN_COMMAND_T6:
 			data->T6_reportid = min_id;
 			data->T6_address = object->start_address;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 21/40] Input: atmel_mxt_ts - Implement T44 message handling
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (19 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 20/40] Input: atmel_mxt_ts - Split interrupt handler into separate functions Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 22/40] Input: atmel_mxt_ts - Output status from T48 Noise Supression Nick Dyer
                   ` (20 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

maXTouch chips allow the reading of multiple messages in a single I2C
transaction. The number of messages available to be read is given by the value
in the T44 object which is located directly before the T5 object.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  188 ++++++++++++++++++++++++------
 1 file changed, 155 insertions(+), 33 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 51901b7..238c11c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -246,12 +246,15 @@ struct mxt_data {
 	unsigned int max_y;
 	struct bin_attribute mem_access_attr;
 	bool debug_enabled;
+	u8 max_reportid;
 	u32 config_crc;
 	u32 info_crc;
 	u8 bootloader_addr;
 	struct t7_config t7_cfg;
 	u8 *msg_buf;
 	bool update_input;
+	u8 last_message_count;
+	u8 num_touchids;
 
 	/* Cached parameters from object table */
 	u16 T5_address;
@@ -261,6 +264,7 @@ struct mxt_data {
 	u16 T7_address;
 	u8 T9_reportid_min;
 	u8 T9_reportid_max;
+	u16 T44_address;
 };
 
 /* I2C slave address pairs */
@@ -690,30 +694,143 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
 	return 1;
 }
 
-static int mxt_read_and_process_message(struct mxt_data *data)
+static int mxt_read_and_process_messages(struct mxt_data *data, u8 count)
 {
 	struct device *dev = &data->client->dev;
 	int ret;
+	int i;
+	u8 num_valid = 0;
+
+	/* Safety check for msg_buf */
+	if (count > data->max_reportid)
+		return -EINVAL;
 
+	/* Process remaining messages if necessary */
 	ret = __mxt_read_reg(data->client, data->T5_address,
-				data->T5_msg_size, data->msg_buf);
+				data->T5_msg_size * count, data->msg_buf);
 	if (ret) {
-		dev_err(dev, "Error %d reading message\n", ret);
+		dev_err(dev, "Failed to read %u messages (%d)\n", count, ret);
 		return ret;
 	}
 
-	return mxt_proc_message(data, data->msg_buf);
+	for (i = 0;  i < count; i++) {
+		ret = mxt_proc_message(data,
+			data->msg_buf + data->T5_msg_size * i);
+
+		if (ret == 1)
+			num_valid++;
+	}
+
+	/* return number of messages read */
+	return num_valid;
 }
 
-static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
+static irqreturn_t mxt_process_messages_t44(struct mxt_data *data)
 {
+	struct device *dev = &data->client->dev;
 	int ret;
+	u8 count, num_left;
 
-	do {
-		ret = mxt_read_and_process_message(data);
+	/* Read T44 and T5 together */
+	ret = __mxt_read_reg(data->client, data->T44_address,
+		data->T5_msg_size + 1, data->msg_buf);
+	if (ret) {
+		dev_err(dev, "Failed to read T44 and T5 (%d)\n", ret);
+		return IRQ_NONE;
+	}
+
+	count = data->msg_buf[0];
+
+	if (count == 0) {
+		dev_warn(dev, "Interrupt triggered but zero messages\n");
+		return IRQ_NONE;
+	} else if (count > data->max_reportid) {
+		dev_err(dev, "T44 count exceeded max report id\n");
+		count = data->max_reportid;
+	}
+
+	/* Process first message */
+	ret = mxt_proc_message(data, data->msg_buf + 1);
+	if (ret < 0) {
+		dev_warn(dev, "Unexpected invalid message\n");
+		return IRQ_NONE;
+	}
+
+	num_left = count - 1;
+
+	/* Process remaining messages if necessary */
+	if (num_left) {
+		ret = mxt_read_and_process_messages(data, num_left);
 		if (ret < 0)
+			goto end;
+		else if (ret != num_left)
+			dev_warn(dev, "Unexpected invalid message\n");
+	}
+
+end:
+	if (data->update_input) {
+		mxt_input_sync(data->input_dev);
+		data->update_input = false;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int mxt_process_messages_until_invalid(struct mxt_data *data)
+{
+	struct device *dev = &data->client->dev;
+	int count, read;
+	u8 tries = 2;
+
+	count = data->max_reportid;
+
+	/* Read messages until we force an invalid */
+	do {
+		read = mxt_read_and_process_messages(data, count);
+		if (read < count)
+			return 0;
+	} while (--tries);
+
+	if (data->update_input) {
+		mxt_input_sync(data->input_dev);
+		data->update_input = false;
+	}
+
+	dev_err(dev, "CHG pin isn't cleared\n");
+	return -EBUSY;
+}
+
+static irqreturn_t mxt_process_messages(struct mxt_data *data)
+{
+	int total_handled, num_handled;
+	u8 count = data->last_message_count;
+
+	if (count < 1 || count > data->max_reportid)
+		count = 1;
+
+	/* include final invalid message */
+	total_handled = mxt_read_and_process_messages(data, count + 1);
+	if (total_handled < 0)
+		return IRQ_NONE;
+	/* if there were invalid messages, then we are done */
+	else if (total_handled <= count)
+		goto update_count;
+
+	/* read two at a time until an invalid message or else we reach
+	 * reportid limit */
+	do {
+		num_handled = mxt_read_and_process_messages(data, 2);
+		if (num_handled < 0)
 			return IRQ_NONE;
-	} while (ret > 0);
+
+		total_handled += num_handled;
+
+		if (num_handled < 2)
+			break;
+	} while (total_handled < data->num_touchids);
+
+update_count:
+	data->last_message_count = total_handled;
 
 	if (data->update_input) {
 		mxt_input_sync(data->input_dev);
@@ -727,7 +844,10 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
 {
 	struct mxt_data *data = dev_id;
 
-	return mxt_process_messages_until_invalid(data);
+	if (data->T44_address)
+		return mxt_process_messages_t44(data);
+	else
+		return mxt_process_messages(data);
 }
 
 static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset, u8 value, bool wait)
@@ -1129,25 +1249,6 @@ recheck:
 	}
 }
 
-static int mxt_make_highchg(struct mxt_data *data)
-{
-	struct device *dev = &data->client->dev;
-	int count = 10;
-	int ret;
-
-	/* Read messages until we force an invalid */
-	do {
-		ret = mxt_read_and_process_message(data);
-		if (ret == 0)
-			return 0;
-		else if (ret < 0)
-			return ret;
-	} while (--count);
-
-	dev_err(dev, "CHG pin isn't cleared\n");
-	return -EBUSY;
-}
-
 static int mxt_get_info(struct mxt_data *data)
 {
 	struct i2c_client *client = data->client;
@@ -1217,8 +1318,14 @@ static int mxt_get_object_table(struct mxt_data *data)
 
 		switch (object->type) {
 		case MXT_GEN_MESSAGE_T5:
-			/* CRC not enabled, therefore don't read last byte */
-			data->T5_msg_size = OBP_SIZE(object) - 1;
+			if (data->info.family_id == 0x80) {
+				/* On mXT224 read and discard unused CRC byte
+				 * otherwise DMA reads are misaligned */
+				data->T5_msg_size = OBP_SIZE(object);
+			} else {
+				/* CRC not enabled, therefore don't read last byte */
+				data->T5_msg_size = OBP_SIZE(object) - 1;
+			}
 			data->T5_address = object->start_address;
 		case MXT_GEN_COMMAND_T6:
 			data->T6_reportid = min_id;
@@ -1230,6 +1337,11 @@ static int mxt_get_object_table(struct mxt_data *data)
 		case MXT_TOUCH_MULTI_T9:
 			data->T9_reportid_min = min_id;
 			data->T9_reportid_max = max_id;
+			data->num_touchids =
+				object->num_report_ids * OBP_INSTANCES(object);
+			break;
+		case MXT_SPT_MESSAGECOUNT_T44:
+			data->T44_address = object->start_address;
 			break;
 		}
 
@@ -1240,7 +1352,17 @@ static int mxt_get_object_table(struct mxt_data *data)
 			data->mem_size = end_address + 1;
 	}
 
-	data->msg_buf = kzalloc(data->T5_msg_size, GFP_KERNEL);
+	/* Store maximum reportid */
+	data->max_reportid = reportid;
+
+	/* If T44 exists, T5 position has to be directly after */
+	if (data->T44_address && (data->T5_address != data->T44_address + 1)) {
+		dev_err(&client->dev, "Invalid T44 position\n");
+		error = -EINVAL;
+		goto free_object_table;
+	}
+
+	data->msg_buf = kcalloc(data->max_reportid, data->T5_msg_size, GFP_KERNEL);
 	if (!data->msg_buf) {
 		dev_err(&client->dev, "Failed to allocate message buffer\n");
 		error = -ENOMEM;
@@ -1577,7 +1699,7 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 	if (data->state == APPMODE) {
 		enable_irq(data->irq);
 
-		error = mxt_make_highchg(data);
+		error = mxt_process_messages_until_invalid(data);
 		if (error)
 			return error;
 	}
@@ -1826,7 +1948,7 @@ static int mxt_probe(struct i2c_client *client,
 	}
 
 	if (data->state == APPMODE) {
-		error = mxt_make_highchg(data);
+		error = mxt_process_messages_until_invalid(data);
 		if (error)
 			goto err_free_irq;
 	}
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 22/40] Input: atmel_mxt_ts - Output status from T48 Noise Supression
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (20 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 21/40] Input: atmel_mxt_ts - Implement T44 message handling Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 23/40] Input: atmel_mxt_ts - Output status from T42 Touch Suppression Nick Dyer
                   ` (19 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 238c11c..94e54bd 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -75,6 +75,7 @@
 #define MXT_SPT_DIGITIZER_T43		43
 #define MXT_SPT_MESSAGECOUNT_T44	44
 #define MXT_SPT_CTECONFIG_T46		46
+#define MXT_SPT_NOISESUPPRESSION_T48	48
 
 /* MXT_GEN_MESSAGE_T5 object */
 #define MXT_RPTID_NOMSG		0xff
@@ -265,6 +266,7 @@ struct mxt_data {
 	u8 T9_reportid_min;
 	u8 T9_reportid_max;
 	u16 T44_address;
+	u8 T48_reportid;
 };
 
 /* I2C slave address pairs */
@@ -671,6 +673,26 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
 	data->update_input = true;
 }
 
+static int mxt_proc_t48_messages(struct mxt_data *data, u8 *msg)
+{
+	struct device *dev = &data->client->dev;
+	u8 status, state;
+
+	status = msg[1];
+	state  = msg[4];
+
+	dev_dbg(dev, "T48 state %d status %02X %s%s%s%s%s\n",
+			state,
+			status,
+			(status & 0x01) ? "FREQCHG " : "",
+			(status & 0x02) ? "APXCHG " : "",
+			(status & 0x04) ? "ALGOERR " : "",
+			(status & 0x10) ? "STATCHG " : "",
+			(status & 0x20) ? "NLVLCHG " : "");
+
+	return 0;
+}
+
 static int mxt_proc_message(struct mxt_data *data, u8 *message)
 {
 	u8 report_id = message[0];
@@ -686,6 +708,9 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
 	    && report_id <= data->T9_reportid_max) {
 		mxt_proc_t9_message(data, message);
 		handled = true;
+	} else if (report_id == data->T48_reportid) {
+		mxt_proc_t48_messages(data, message);
+		handled = true;
 	}
 
 	if (!handled || data->debug_enabled)
@@ -1343,6 +1368,9 @@ static int mxt_get_object_table(struct mxt_data *data)
 		case MXT_SPT_MESSAGECOUNT_T44:
 			data->T44_address = object->start_address;
 			break;
+		case MXT_SPT_NOISESUPPRESSION_T48:
+			data->T48_reportid = min_id;
+			break;
 		}
 
 		end_address = object->start_address
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 23/40] Input: atmel_mxt_ts - Output status from T42 Touch Suppression
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (21 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 22/40] Input: atmel_mxt_ts - Output status from T48 Noise Supression Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 24/40] Input: atmel_mxt_ts - Implement vector/orientation support Nick Dyer
                   ` (18 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 94e54bd..b1fdc36 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -185,6 +185,9 @@ struct t9_range {
 #define MXT_RESET_VALUE		0x01
 #define MXT_BACKUP_VALUE	0x55
 
+/* Define for MXT_PROCI_TOUCHSUPPRESSION_T42 */
+#define MXT_T42_MSG_TCHSUP	(1 << 0)
+
 /* Delay times */
 #define MXT_BACKUP_TIME		25	/* msec */
 #define MXT_RESET_TIME		200	/* msec */
@@ -265,6 +268,8 @@ struct mxt_data {
 	u16 T7_address;
 	u8 T9_reportid_min;
 	u8 T9_reportid_max;
+	u8 T42_reportid_min;
+	u8 T42_reportid_max;
 	u16 T44_address;
 	u8 T48_reportid;
 };
@@ -673,6 +678,17 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
 	data->update_input = true;
 }
 
+static void mxt_proc_t42_messages(struct mxt_data *data, u8 *msg)
+{
+	struct device *dev = &data->client->dev;
+	u8 status = msg[1];
+
+	if (status & MXT_T42_MSG_TCHSUP)
+		dev_info(dev, "T42 suppress\n");
+	else
+		dev_info(dev, "T42 normal\n");
+}
+
 static int mxt_proc_t48_messages(struct mxt_data *data, u8 *msg)
 {
 	struct device *dev = &data->client->dev;
@@ -708,6 +724,10 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
 	    && report_id <= data->T9_reportid_max) {
 		mxt_proc_t9_message(data, message);
 		handled = true;
+	} else if (report_id >= data->T42_reportid_min
+		   && report_id <= data->T42_reportid_max) {
+		mxt_proc_t42_messages(data, message);
+		handled = true;
 	} else if (report_id == data->T48_reportid) {
 		mxt_proc_t48_messages(data, message);
 		handled = true;
@@ -1365,6 +1385,10 @@ static int mxt_get_object_table(struct mxt_data *data)
 			data->num_touchids =
 				object->num_report_ids * OBP_INSTANCES(object);
 			break;
+		case MXT_PROCI_TOUCHSUPPRESSION_T42:
+			data->T42_reportid_min = min_id;
+			data->T42_reportid_max = max_id;
+			break;
 		case MXT_SPT_MESSAGECOUNT_T44:
 			data->T44_address = object->start_address;
 			break;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 24/40] Input: atmel_mxt_ts - Implement vector/orientation support
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (22 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 23/40] Input: atmel_mxt_ts - Output status from T42 Touch Suppression Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 25/40] Input: atmel_mxt_ts - implement I2C retries Nick Dyer
                   ` (17 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

The atmel touch messages contain orientation information as a byte in a packed
format which can be passed straight on to Android if the input device
configuration is correct, see
http://source.android.com/tech/input/touch-devices.html#touchorientationcalibration

This requires vector reports to be enabled in maXTouch config (zero DISVECT
bit in T9 CTRL field)

Android converts the format in frameworks/base/services/input/Input.cpp,
search for ORIENTATION_CALIBRATION_VECTOR.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |    9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b1fdc36..6ab7ef6 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -621,6 +621,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
 	int y;
 	int area;
 	int amplitude;
+	u8 vector;
 
 	/* do not report events if input device not yet registered */
 	if (!input_dev)
@@ -638,9 +639,10 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
 
 	area = message[5];
 	amplitude = message[6];
+	vector = message[7];
 
 	dev_dbg(dev,
-		"[%u] %c%c%c%c%c%c%c%c x: %5u y: %5u area: %3u amp: %3u\n",
+		"[%u] %c%c%c%c%c%c%c%c x: %5u y: %5u area: %3u amp: %3u vector: %02X\n",
 		id,
 		(status & MXT_T9_DETECT) ? 'D' : '.',
 		(status & MXT_T9_PRESS) ? 'P' : '.',
@@ -650,7 +652,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
 		(status & MXT_T9_AMP) ? 'A' : '.',
 		(status & MXT_T9_SUPPRESS) ? 'S' : '.',
 		(status & MXT_T9_UNGRIP) ? 'U' : '.',
-		x, y, area, amplitude);
+		x, y, area, amplitude, vector);
 
 	input_mt_slot(input_dev, id);
 
@@ -670,6 +672,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
 		input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
 		input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude);
 		input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area);
+		input_report_abs(input_dev, ABS_MT_ORIENTATION, vector);
 	} else {
 		/* Touch no longer active, close out slot */
 		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
@@ -1945,6 +1948,8 @@ static int mxt_initialize_t9_input_device(struct mxt_data *data)
 			     0, data->max_y, 0, 0);
 	input_set_abs_params(input_dev, ABS_MT_PRESSURE,
 			     0, 255, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_ORIENTATION,
+			     0, 255, 0, 0);
 
 	input_set_drvdata(input_dev, data);
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 25/40] Input: atmel_mxt_ts - implement I2C retries
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (23 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 24/40] Input: atmel_mxt_ts - Implement vector/orientation support Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 26/40] Input: atmel_mxt_ts - Implement T63 Active Stylus support Nick Dyer
                   ` (16 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Some maXTouch chips will not respond on the first I2C request when they are in
a sleep state. It must be retried after a delay for the chip to wake up.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   39 +++++++++++++++++++++---------
 1 file changed, 27 insertions(+), 12 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 6ab7ef6..b0dcae4 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -193,6 +193,7 @@ struct t9_range {
 #define MXT_RESET_TIME		200	/* msec */
 #define MXT_RESET_NOCHGREAD	400	/* msec */
 #define MXT_FWRESET_TIME	1000	/* msec */
+#define MXT_WAKEUP_TIME		25	/* msec */
 
 /* Command to unlock bootloader */
 #define MXT_UNLOCK_CMD_MSB	0xaa
@@ -503,6 +504,7 @@ static int __mxt_read_reg(struct i2c_client *client,
 	struct i2c_msg xfer[2];
 	u8 buf[2];
 	int ret;
+	bool retry = false;
 
 	buf[0] = reg & 0xff;
 	buf[1] = (reg >> 8) & 0xff;
@@ -519,17 +521,22 @@ static int __mxt_read_reg(struct i2c_client *client,
 	xfer[1].len = len;
 	xfer[1].buf = val;
 
-	ret = i2c_transfer(client->adapter, xfer, 2);
-	if (ret == 2) {
-		ret = 0;
-	} else {
-		if (ret >= 0)
-			ret = -EIO;
-		dev_err(&client->dev, "%s: i2c transfer failed (%d)\n",
-			__func__, ret);
+retry_read:
+	ret = i2c_transfer(client->adapter, xfer, ARRAY_SIZE(xfer));
+	if (ret != ARRAY_SIZE(xfer)) {
+		if (!retry) {
+			dev_dbg(&client->dev, "%s: i2c retry\n", __func__);
+			msleep(MXT_WAKEUP_TIME);
+			retry = true;
+			goto retry_read;
+		} else {
+			dev_err(&client->dev, "%s: i2c transfer failed (%d)\n",
+				__func__, ret);
+			return -EIO;
+		}
 	}
 
-	return ret;
+	return 0;
 }
 
 static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len,
@@ -538,6 +545,7 @@ static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len,
 	u8 *buf;
 	size_t count;
 	int ret;
+	bool retry = false;
 
 	count = len + 2;
 	buf = kmalloc(count, GFP_KERNEL);
@@ -548,14 +556,21 @@ static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len,
 	buf[1] = (reg >> 8) & 0xff;
 	memcpy(&buf[2], val, len);
 
+retry_write:
 	ret = i2c_master_send(client, buf, count);
 	if (ret == count) {
 		ret = 0;
 	} else {
-		if (ret >= 0)
+		if (!retry) {
+			dev_dbg(&client->dev, "%s: i2c retry\n", __func__);
+			msleep(MXT_WAKEUP_TIME);
+			retry = true;
+			goto retry_write;
+		} else {
+			dev_err(&client->dev, "%s: i2c send failed (%d)\n",
+				__func__, ret);
 			ret = -EIO;
-		dev_err(&client->dev, "%s: i2c send failed (%d)\n",
-			__func__, ret);
+		}
 	}
 
 	kfree(buf);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 26/40] Input: atmel_mxt_ts - Implement T63 Active Stylus support
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (24 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 25/40] Input: atmel_mxt_ts - implement I2C retries Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 27/40] Input: atmel_mxt_ts - Add check for incorrect firmware file format Nick Dyer
                   ` (15 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   91 +++++++++++++++++++++++++++++-
 1 file changed, 90 insertions(+), 1 deletion(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b0dcae4..3aac912 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -76,6 +76,7 @@
 #define MXT_SPT_MESSAGECOUNT_T44	44
 #define MXT_SPT_CTECONFIG_T46		46
 #define MXT_SPT_NOISESUPPRESSION_T48	48
+#define MXT_PROCI_ACTIVE_STYLUS_T63	63
 
 /* MXT_GEN_MESSAGE_T5 object */
 #define MXT_RPTID_NOMSG		0xff
@@ -188,6 +189,19 @@ struct t9_range {
 /* Define for MXT_PROCI_TOUCHSUPPRESSION_T42 */
 #define MXT_T42_MSG_TCHSUP	(1 << 0)
 
+/* T63 Stylus */
+#define MXT_STYLUS_PRESS	(1 << 0)
+#define MXT_STYLUS_RELEASE	(1 << 1)
+#define MXT_STYLUS_MOVE		(1 << 2)
+#define MXT_STYLUS_SUPPRESS	(1 << 3)
+
+#define MXT_STYLUS_DETECT	(1 << 4)
+#define MXT_STYLUS_TIP		(1 << 5)
+#define MXT_STYLUS_ERASER	(1 << 6)
+#define MXT_STYLUS_BARREL	(1 << 7)
+
+#define MXT_STYLUS_PRESSURE_MASK	0x3F
+
 /* Delay times */
 #define MXT_BACKUP_TIME		25	/* msec */
 #define MXT_RESET_TIME		200	/* msec */
@@ -260,6 +274,7 @@ struct mxt_data {
 	bool update_input;
 	u8 last_message_count;
 	u8 num_touchids;
+	u8 num_stylusids;
 
 	/* Cached parameters from object table */
 	u16 T5_address;
@@ -273,6 +288,8 @@ struct mxt_data {
 	u8 T42_reportid_max;
 	u16 T44_address;
 	u8 T48_reportid;
+	u8 T63_reportid_min;
+	u8 T63_reportid_max;
 };
 
 /* I2C slave address pairs */
@@ -727,6 +744,60 @@ static int mxt_proc_t48_messages(struct mxt_data *data, u8 *msg)
 	return 0;
 }
 
+static void mxt_proc_t63_messages(struct mxt_data *data, u8 *msg)
+{
+	struct device *dev = &data->client->dev;
+	struct input_dev *input_dev = data->input_dev;
+	u8 id;
+	u16 x, y;
+	u8 pressure;
+
+	if (!input_dev)
+		return;
+
+	/* stylus slots come after touch slots */
+	id = data->num_touchids + (msg[0] - data->T63_reportid_min);
+
+	if (id < 0 || id > (data->num_touchids + data->num_stylusids)) {
+		dev_err(dev, "invalid stylus id %d, max slot is %d\n",
+			id, data->num_stylusids);
+		return;
+	}
+
+	x = msg[3] | (msg[4] << 8);
+	y = msg[5] | (msg[6] << 8);
+	pressure = msg[7] & MXT_STYLUS_PRESSURE_MASK;
+
+	dev_dbg(dev,
+		"[%d] %c%c%c%c x: %d y: %d pressure: %d stylus:%c%c%c%c\n",
+		id,
+		(msg[1] & MXT_STYLUS_SUPPRESS) ? 'S' : '.',
+		(msg[1] & MXT_STYLUS_MOVE)     ? 'M' : '.',
+		(msg[1] & MXT_STYLUS_RELEASE)  ? 'R' : '.',
+		(msg[1] & MXT_STYLUS_PRESS)    ? 'P' : '.',
+		x, y, pressure,
+		(msg[2] & MXT_STYLUS_BARREL) ? 'B' : '.',
+		(msg[2] & MXT_STYLUS_ERASER) ? 'E' : '.',
+		(msg[2] & MXT_STYLUS_TIP)    ? 'T' : '.',
+		(msg[2] & MXT_STYLUS_DETECT) ? 'D' : '.');
+
+	input_mt_slot(input_dev, id);
+
+	if (msg[2] & MXT_STYLUS_DETECT) {
+		input_mt_report_slot_state(input_dev, MT_TOOL_PEN, 1);
+		input_report_abs(input_dev, ABS_MT_POSITION_X, x);
+		input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+		input_report_abs(input_dev, ABS_MT_PRESSURE, pressure);
+	} else {
+		input_mt_report_slot_state(input_dev, MT_TOOL_PEN, 0);
+	}
+
+	input_report_key(input_dev, BTN_STYLUS, (msg[2] & MXT_STYLUS_ERASER));
+	input_report_key(input_dev, BTN_STYLUS2, (msg[2] & MXT_STYLUS_BARREL));
+
+	mxt_input_sync(input_dev);
+}
+
 static int mxt_proc_message(struct mxt_data *data, u8 *message)
 {
 	u8 report_id = message[0];
@@ -742,6 +813,10 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
 	    && report_id <= data->T9_reportid_max) {
 		mxt_proc_t9_message(data, message);
 		handled = true;
+	} else if (report_id >= data->T63_reportid_min
+		   && report_id <= data->T63_reportid_max) {
+		mxt_proc_t63_messages(data, message);
+		handled = true;
 	} else if (report_id >= data->T42_reportid_min
 		   && report_id <= data->T42_reportid_max) {
 		mxt_proc_t42_messages(data, message);
@@ -1413,6 +1488,12 @@ static int mxt_get_object_table(struct mxt_data *data)
 		case MXT_SPT_NOISESUPPRESSION_T48:
 			data->T48_reportid = min_id;
 			break;
+		case MXT_PROCI_ACTIVE_STYLUS_T63:
+			data->T63_reportid_min = min_id;
+			data->T63_reportid_max = max_id;
+			data->num_stylusids =
+				object->num_report_ids * OBP_INSTANCES(object);
+			break;
 		}
 
 		end_address = object->start_address
@@ -1950,7 +2031,7 @@ static int mxt_initialize_t9_input_device(struct mxt_data *data)
 			     0, 255, 0, 0);
 
 	/* For multi touch */
-	num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1;
+	num_mt_slots = data->num_touchids + data->num_stylusids;
 	error = input_mt_init_slots(input_dev, num_mt_slots, 0);
 	if (error)
 		goto err_free_mem;
@@ -1966,6 +2047,14 @@ static int mxt_initialize_t9_input_device(struct mxt_data *data)
 	input_set_abs_params(input_dev, ABS_MT_ORIENTATION,
 			     0, 255, 0, 0);
 
+	/* For T63 active stylus */
+	if (data->T63_reportid_min) {
+		input_set_capability(input_dev, EV_KEY, BTN_STYLUS);
+		input_set_capability(input_dev, EV_KEY, BTN_STYLUS2);
+		input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
+			0, MT_TOOL_MAX, 0, 0);
+	}
+
 	input_set_drvdata(input_dev, data);
 
 	error = input_register_device(input_dev);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 27/40] Input: atmel_mxt_ts - Add check for incorrect firmware file format
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (25 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 26/40] Input: atmel_mxt_ts - Implement T63 Active Stylus support Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 28/40] Input: atmel_mxt_ts - Add CHG line handling in bootloader code Nick Dyer
                   ` (14 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Atmel supplies firmware files in ASCII HEX format (.enc) which must be
converted before they can be loaded by kernel driver. Try to detect the error
and print a friendly error message rather than feeding junk to the bootloader.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 3aac912..a1f196b 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1724,6 +1724,27 @@ done:
 	return error ?: count;
 }
 
+static int mxt_check_firmware_format(struct device *dev, const struct firmware *fw)
+{
+	unsigned int pos = 0;
+	char c;
+
+	while (pos < fw->size) {
+		c = *(fw->data + pos);
+
+		if (c < '0' || (c > '9' && c < 'A') || c > 'F')
+			return 0;
+
+		pos++;
+	}
+
+	/* To convert file try
+	 * xxd -r -p mXTXXX__APP_VX-X-XX.enc > maxtouch.fw */
+	dev_err(dev, "Aborting: firmware file must be in binary format\n");
+
+	return -1;
+}
+
 static int mxt_load_fw(struct device *dev, const char *fn)
 {
 	struct mxt_data *data = dev_get_drvdata(dev);
@@ -1740,6 +1761,11 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 		return ret;
 	}
 
+	/* Check for incorrect enc file */
+	ret = mxt_check_firmware_format(dev, fw);
+	if (ret)
+		goto release_firmware;
+
 	if (data->state != BOOTLOADER) {
 		/* Change to the bootloader mode */
 		ret = mxt_soft_reset(data, MXT_BOOT_VALUE);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 28/40] Input: atmel_mxt_ts - Add CHG line handling in bootloader code
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (26 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 27/40] Input: atmel_mxt_ts - Add check for incorrect firmware file format Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 22:35   ` Benson Leung
  2013-02-23  1:45   ` Benson Leung
  2013-02-22 17:58 ` [PATCH 29/40] Input: atmel_mxt_ts - Use wait_for_chg in soft_reset Nick Dyer
                   ` (13 subsequent siblings)
  41 siblings, 2 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

The bootloader state machine toggles the CHG/Interrupt line to indicate when
it has transitioned between states. Waiting for this event improves bootloader
reliability.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index a1f196b..f182228 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -430,6 +430,27 @@ static int mxt_probe_bootloader(struct mxt_data *data)
 	return 0;
 }
 
+static int mxt_wait_for_chg(struct mxt_data *data)
+{
+	int timeout_counter = 0;
+	int count = 1E6;
+
+	if (data->pdata->read_chg == NULL) {
+		msleep(20);
+		return 0;
+	}
+
+	while ((timeout_counter++ <= count) && data->pdata->read_chg())
+		udelay(20);
+
+	if (timeout_counter > count) {
+		dev_err(&data->client->dev, "mxt_wait_for_chg() timeout!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
 static u8 mxt_get_bootloader_version(struct mxt_data *data, u8 val)
 {
 	struct device *dev = &data->client->dev;
@@ -478,9 +499,10 @@ recheck:
 		val &= ~MXT_BOOT_STATUS_MASK;
 		break;
 	case MXT_FRAME_CRC_PASS:
-		if (val == MXT_FRAME_CRC_CHECK)
+		if (val == MXT_FRAME_CRC_CHECK) {
+			mxt_wait_for_chg(data);
 			goto recheck;
-		if (val == MXT_FRAME_CRC_FAIL) {
+		} else if (val == MXT_FRAME_CRC_FAIL) {
 			dev_err(dev, "Bootloader CRC fail\n");
 			return -EINVAL;
 		}
@@ -1781,6 +1803,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 
 	ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD);
 	if (ret) {
+		mxt_wait_for_chg(data);
 		/* Bootloader may still be unlocked from previous update
 		 * attempt */
 		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);
@@ -1800,6 +1823,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 	}
 
 	while (pos < fw->size) {
+		mxt_wait_for_chg(data);
 		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);
 		if (ret) {
 			data->state = FAILED;
@@ -1818,6 +1842,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 			goto release_firmware;
 		}
 
+		mxt_wait_for_chg(data);
 		ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS);
 		if (ret) {
 			retry++;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 29/40] Input: atmel_mxt_ts - Use wait_for_chg in soft_reset
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (27 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 28/40] Input: atmel_mxt_ts - Add CHG line handling in bootloader code Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 30/40] Input: atmel_mxt_ts - recover from bootloader on probe Nick Dyer
                   ` (12 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index f182228..96c961e 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1044,7 +1044,6 @@ static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset, u8 value, bool
 static int mxt_soft_reset(struct mxt_data *data, u8 value)
 {
 	int ret;
-	int timeout_counter = 0;
 	struct device *dev = &data->client->dev;
 
 	dev_info(dev, "Resetting chip\n");
@@ -1057,14 +1056,7 @@ static int mxt_soft_reset(struct mxt_data *data, u8 value)
 		msleep(MXT_RESET_NOCHGREAD);
 	} else {
 		msleep(MXT_RESET_TIME);
-
-		timeout_counter = 0;
-		while ((timeout_counter++ <= 100) && data->pdata->read_chg())
-			msleep(20);
-		if (timeout_counter > 100) {
-			dev_err(dev, "No response after reset!\n");
-			return -EIO;
-		}
+		mxt_wait_for_chg(data);
 	}
 
 	return 0;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 30/40] Input: atmel_mxt_ts - recover from bootloader on probe
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (28 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 29/40] Input: atmel_mxt_ts - Use wait_for_chg in soft_reset Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 31/40] Input: atmel_mxt_ts - Implement T15 Key Array support Nick Dyer
                   ` (11 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

The MXT device may be in bootloader mode on probe, due to:
1) APP CRC failure, either:
  a) flash corruption
  b) bad power or other intermittent problem in checking CRC
2) If the device has been reset 10 or more times without accessing comms
3) Warm probe, device was in bootloader mode already

This code attempts to recover from 1(b) and 3.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   33 +++++++++++++++++++++++-------
 1 file changed, 26 insertions(+), 7 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 96c961e..02fce62 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -519,13 +519,18 @@ recheck:
 	return 0;
 }
 
-static int mxt_unlock_bootloader(struct mxt_data *data)
+static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock)
 {
 	int ret;
 	u8 buf[2];
 
-	buf[0] = MXT_UNLOCK_CMD_LSB;
-	buf[1] = MXT_UNLOCK_CMD_MSB;
+	if (unlock) {
+		buf[0] = MXT_UNLOCK_CMD_LSB;
+		buf[1] = MXT_UNLOCK_CMD_MSB;
+	} else {
+		buf[0] = 0x01;
+		buf[1] = 0x01;
+	}
 
 	ret = mxt_bootloader_write(data, buf, 2);
 	if (ret) {
@@ -1601,16 +1606,30 @@ static int mxt_initialize(struct mxt_data *data)
 	struct i2c_client *client = data->client;
 	struct mxt_info *info = &data->info;
 	int error;
+	u8 retry_count = 0;
 
+retry_probe:
 	error = mxt_get_info(data);
 	if (error) {
 		error = mxt_probe_bootloader(data);
-
 		if (error) {
+			/* Chip is not in appmode or bootloader mode */
 			return error;
 		} else {
-			data->state = BOOTLOADER;
-			return 0;
+			if (++retry_count > 10) {
+				dev_err(&client->dev,
+					"Could not recover device from "
+					"bootloader mode\n");
+				data->state = BOOTLOADER;
+				/* this is not an error state, we can reflash
+				 * from here */
+				return 0;
+			}
+
+			/* Attempt to exit bootloader into app mode */
+			mxt_send_bootloader_cmd(data, false);
+			msleep(MXT_FWRESET_TIME);
+			goto retry_probe;
 		}
 	}
 
@@ -1807,7 +1826,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 		dev_info(dev, "Unlocking bootloader\n");
 
 		/* Unlock bootloader */
-		ret = mxt_unlock_bootloader(data);
+		ret = mxt_send_bootloader_cmd(data, true);
 		if (ret) {
 			data->state = FAILED;
 			goto release_firmware;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 31/40] Input: atmel_mxt_ts - Implement T15 Key Array support
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (29 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 30/40] Input: atmel_mxt_ts - recover from bootloader on probe Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 32/40] Input: atmel_mxt_ts - remove unused defines Nick Dyer
                   ` (10 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   52 ++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 02fce62..8794353 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -166,6 +166,11 @@ struct t9_range {
 #define MXT_NOISE_FREQ4		15
 #define MXT_NOISE_IDLEGCAFVALID	16
 
+/* T15 Key array */
+int mxt_t15_keys[] = { };
+
+static unsigned long mxt_t15_keystatus;
+
 /* MXT_SPT_COMMSCONFIG_T18 */
 #define MXT_COMMS_CTRL		0
 #define MXT_COMMS_CMD		1
@@ -284,6 +289,8 @@ struct mxt_data {
 	u16 T7_address;
 	u8 T9_reportid_min;
 	u8 T9_reportid_max;
+	u8 T15_reportid_min;
+	u8 T15_reportid_max;
 	u8 T42_reportid_min;
 	u8 T42_reportid_max;
 	u16 T44_address;
@@ -740,6 +747,36 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
 	data->update_input = true;
 }
 
+static void mxt_proc_t15_messages(struct mxt_data *data, u8 *msg)
+{
+	struct input_dev *input_dev = data->input_dev;
+	struct device *dev = &data->client->dev;
+	u8 key;
+	bool curr_state, new_state;
+	bool sync = false;
+	unsigned long keystates = le32_to_cpu(msg[2]);
+
+	for (key = 0; key < ARRAY_SIZE(mxt_t15_keys); key++) {
+		curr_state = test_bit(key, &mxt_t15_keystatus);
+		new_state = test_bit(key, &keystates);
+
+		if (!curr_state && new_state) {
+			dev_dbg(dev, "T15 key press: %u\n", key);
+			__set_bit(key, &mxt_t15_keystatus);
+			input_event(input_dev, EV_KEY, mxt_t15_keys[key], 1);
+			sync = true;
+		} else if (curr_state && !new_state) {
+			dev_dbg(dev, "T15 key release: %u\n", key);
+			__clear_bit(key, &mxt_t15_keystatus);
+			input_event(input_dev, EV_KEY, mxt_t15_keys[key], 0);
+			sync = true;
+		}
+	}
+
+	if (sync)
+		input_sync(input_dev);
+}
+
 static void mxt_proc_t42_messages(struct mxt_data *data, u8 *msg)
 {
 	struct device *dev = &data->client->dev;
@@ -851,6 +888,9 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
 	} else if (report_id == data->T48_reportid) {
 		mxt_proc_t48_messages(data, message);
 		handled = true;
+	} else if (report_id >= data->T15_reportid_min
+		   && report_id <= data->T15_reportid_max) {
+		mxt_proc_t15_messages(data, message);
 	}
 
 	if (!handled || data->debug_enabled)
@@ -1497,6 +1537,10 @@ static int mxt_get_object_table(struct mxt_data *data)
 			data->num_touchids =
 				object->num_report_ids * OBP_INSTANCES(object);
 			break;
+		case MXT_TOUCH_KEYARRAY_T15:
+			data->T15_reportid_min = min_id;
+			data->T15_reportid_max = max_id;
+			break;
 		case MXT_PROCI_TOUCHSUPPRESSION_T42:
 			data->T42_reportid_min = min_id;
 			data->T42_reportid_max = max_id;
@@ -2060,6 +2104,7 @@ static int mxt_initialize_t9_input_device(struct mxt_data *data)
 	struct input_dev *input_dev;
 	int error;
 	unsigned int num_mt_slots;
+	int key;
 
 	input_dev = input_allocate_device();
 	if (!input_dev) {
@@ -2117,6 +2162,13 @@ static int mxt_initialize_t9_input_device(struct mxt_data *data)
 			0, MT_TOOL_MAX, 0, 0);
 	}
 
+	/* For T15 key array */
+	if (data->T15_reportid_min) {
+		mxt_t15_keystatus = 0;
+		for (key = 0; key < ARRAY_SIZE(mxt_t15_keys); key++)
+			input_set_capability(input_dev, EV_KEY, mxt_t15_keys[key]);
+	}
+
 	input_set_drvdata(input_dev, data);
 
 	error = input_register_device(input_dev);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 32/40] Input: atmel_mxt_ts - remove unused defines
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (30 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 31/40] Input: atmel_mxt_ts - Implement T15 Key Array support Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 33/40] Input: atmel_mxt_ts - Verify Information Block checksum on probe Nick Dyer
                   ` (9 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   67 +-----------------------------
 1 file changed, 1 insertion(+), 66 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 8794353..2f3793a 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -22,29 +22,14 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 
-/* Version */
-#define MXT_VER_20		20
-#define MXT_VER_21		21
-#define MXT_VER_22		22
-
 /* Firmware files */
 #define MXT_FW_NAME		"maxtouch.fw"
 #define MXT_CFG_NAME		"maxtouch.cfg"
 #define MXT_CFG_MAGIC		"OBP_RAW V1"
 
 /* Registers */
-#define MXT_INFO		0x00
-#define MXT_FAMILY_ID		0x00
-#define MXT_VARIANT_ID		0x01
-#define MXT_VERSION		0x02
-#define MXT_BUILD		0x03
-#define MXT_MATRIX_X_SIZE	0x04
-#define MXT_MATRIX_Y_SIZE	0x05
-#define MXT_OBJECT_NUM		0x06
 #define MXT_OBJECT_START	0x07
-
 #define MXT_OBJECT_SIZE		6
-
 #define MXT_MAX_BLOCK_WRITE	256
 
 /* Object types */
@@ -105,15 +90,6 @@ struct t7_config {
 #define MXT_POWER_CFG_RUN		0
 #define MXT_POWER_CFG_DEEPSLEEP		1
 
-/* MXT_GEN_ACQUIRE_T8 field */
-#define MXT_ACQUIRE_CHRGTIME	0
-#define MXT_ACQUIRE_TCHDRIFT	2
-#define MXT_ACQUIRE_DRIFTST	3
-#define MXT_ACQUIRE_TCHAUTOCAL	4
-#define MXT_ACQUIRE_SYNC	5
-#define MXT_ACQUIRE_ATCHCALST	6
-#define MXT_ACQUIRE_ATCHCALSTHR	7
-
 /* MXT_TOUCH_MULTI_T9 field */
 #define MXT_T9_ORIENT		9
 #define MXT_T9_RANGE		18
@@ -136,36 +112,6 @@ struct t9_range {
 /* MXT_TOUCH_MULTI_T9 orient */
 #define MXT_T9_ORIENT_SWITCH	(1 << 0)
 
-/* MXT_PROCI_GRIPFACE_T20 field */
-#define MXT_GRIPFACE_CTRL	0
-#define MXT_GRIPFACE_XLOGRIP	1
-#define MXT_GRIPFACE_XHIGRIP	2
-#define MXT_GRIPFACE_YLOGRIP	3
-#define MXT_GRIPFACE_YHIGRIP	4
-#define MXT_GRIPFACE_MAXTCHS	5
-#define MXT_GRIPFACE_SZTHR1	7
-#define MXT_GRIPFACE_SZTHR2	8
-#define MXT_GRIPFACE_SHPTHR1	9
-#define MXT_GRIPFACE_SHPTHR2	10
-#define MXT_GRIPFACE_SUPEXTTO	11
-
-/* MXT_PROCI_NOISE field */
-#define MXT_NOISE_CTRL		0
-#define MXT_NOISE_OUTFLEN	1
-#define MXT_NOISE_GCAFUL_LSB	3
-#define MXT_NOISE_GCAFUL_MSB	4
-#define MXT_NOISE_GCAFLL_LSB	5
-#define MXT_NOISE_GCAFLL_MSB	6
-#define MXT_NOISE_ACTVGCAFVALID	7
-#define MXT_NOISE_NOISETHR	8
-#define MXT_NOISE_FREQHOPSCALE	10
-#define MXT_NOISE_FREQ0		11
-#define MXT_NOISE_FREQ1		12
-#define MXT_NOISE_FREQ2		13
-#define MXT_NOISE_FREQ3		14
-#define MXT_NOISE_FREQ4		15
-#define MXT_NOISE_IDLEGCAFVALID	16
-
 /* T15 Key array */
 int mxt_t15_keys[] = { };
 
@@ -175,17 +121,6 @@ static unsigned long mxt_t15_keystatus;
 #define MXT_COMMS_CTRL		0
 #define MXT_COMMS_CMD		1
 
-/* MXT_SPT_CTECONFIG_T28 field */
-#define MXT_CTE_CTRL		0
-#define MXT_CTE_CMD		1
-#define MXT_CTE_MODE		2
-#define MXT_CTE_IDLEGCAFDEPTH	3
-#define MXT_CTE_ACTVGCAFDEPTH	4
-#define MXT_CTE_VOLTAGE		5
-
-#define MXT_VOLTAGE_DEFAULT	2700000
-#define MXT_VOLTAGE_STEP	10000
-
 /* Define for MXT_GEN_COMMAND_T6 */
 #define MXT_BOOT_VALUE		0xa5
 #define MXT_RESET_VALUE		0x01
@@ -1453,7 +1388,7 @@ static int mxt_get_info(struct mxt_data *data)
 	int error;
 
 	/* Read 7-byte info block starting at address 0 */
-	error = __mxt_read_reg(client, MXT_INFO, sizeof(*info), info);
+	error = __mxt_read_reg(client, 0, sizeof(*info), info);
 	if (error)
 		return error;
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 33/40] Input: atmel_mxt_ts - Verify Information Block checksum on probe
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (31 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 32/40] Input: atmel_mxt_ts - remove unused defines Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 34/40] Input: atmel_mxt_ts - Remove mxt_make_highchg Nick Dyer
                   ` (8 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

By reading the information block and the object table into a contiguous region
of memory, we can verify the checksum at probe time. This means we verify that
we are indeed talking to a chip that supports object protocol correctly. We
also detect I2C comms problems much earlier, resulting in easier diagnosis.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  217 ++++++++++++++++++------------
 1 file changed, 129 insertions(+), 88 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 2f3793a..6dbd3d6 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -30,6 +30,7 @@
 /* Registers */
 #define MXT_OBJECT_START	0x07
 #define MXT_OBJECT_SIZE		6
+#define MXT_INFO_CHECKSUM_SIZE	3
 #define MXT_MAX_BLOCK_WRITE	256
 
 /* Object types */
@@ -199,7 +200,8 @@ struct mxt_data {
 	enum mxt_device_state state;
 	struct mxt_object *object_table;
 	u16 mem_size;
-	struct mxt_info info;
+	struct mxt_info *info;
+	void *raw_info_block;
 	unsigned int irq;
 	unsigned int max_x;
 	unsigned int max_y;
@@ -574,7 +576,7 @@ mxt_get_object(struct mxt_data *data, u8 type)
 	struct mxt_object *object;
 	int i;
 
-	for (i = 0; i < data->info.object_num; i++) {
+	for (i = 0; i < data->info->object_num; i++) {
 		object = data->object_table + i;
 		if (object->type == type)
 			return object;
@@ -1184,7 +1186,7 @@ static int mxt_check_reg_init(struct mxt_data *data)
 
 	/* Malloc memory to store configuration */
 	config_start_offset = MXT_OBJECT_START
-		+ data->info.object_num * sizeof(struct mxt_object);
+		+ data->info->object_num * sizeof(struct mxt_object);
 	config_mem_size = data->mem_size - config_start_offset;
 	config_mem = kzalloc(config_mem_size, GFP_KERNEL);
 	if (!config_mem) {
@@ -1381,53 +1383,17 @@ recheck:
 	}
 }
 
-static int mxt_get_info(struct mxt_data *data)
+static int mxt_parse_object_table(struct mxt_data *data)
 {
 	struct i2c_client *client = data->client;
-	struct mxt_info *info = &data->info;
-	int error;
-
-	/* Read 7-byte info block starting at address 0 */
-	error = __mxt_read_reg(client, 0, sizeof(*info), info);
-	if (error)
-		return error;
-
-	return 0;
-}
-
-static void mxt_free_object_table(struct mxt_data *data)
-{
-	kfree(data->object_table);
-	data->object_table = NULL;
-	kfree(data->msg_buf);
-	data->msg_buf = NULL;
-	data->T5_address = 0;
-	data->T5_msg_size = 0;
-	data->T6_reportid = 0;
-	data->T7_address = 0;
-	data->T9_reportid_min = 0;
-	data->T9_reportid_max = 0;
-}
-
-static int mxt_get_object_table(struct mxt_data *data)
-{
-	struct i2c_client *client = data->client;
-	size_t table_size;
-	int error;
 	int i;
 	u8 reportid;
 	u16 end_address;
 
-	table_size = data->info.object_num * sizeof(struct mxt_object);
-	error = __mxt_read_reg(client, MXT_OBJECT_START, table_size,
-			data->object_table);
-	if (error)
-		return error;
-
 	/* Valid Report IDs start counting from 1 */
 	reportid = 1;
 	data->mem_size = 0;
-	for (i = 0; i < data->info.object_num; i++) {
+	for (i = 0; i < data->info->object_num; i++) {
 		struct mxt_object *object = data->object_table + i;
 		u8 min_id, max_id;
 
@@ -1450,7 +1416,7 @@ static int mxt_get_object_table(struct mxt_data *data)
 
 		switch (object->type) {
 		case MXT_GEN_MESSAGE_T5:
-			if (data->info.family_id == 0x80) {
+			if (data->info->family_id == 0x80) {
 				/* On mXT224 read and discard unused CRC byte
 				 * otherwise DMA reads are misaligned */
 				data->T5_msg_size = OBP_SIZE(object);
@@ -1507,21 +1473,119 @@ static int mxt_get_object_table(struct mxt_data *data)
 	/* If T44 exists, T5 position has to be directly after */
 	if (data->T44_address && (data->T5_address != data->T44_address + 1)) {
 		dev_err(&client->dev, "Invalid T44 position\n");
-		error = -EINVAL;
-		goto free_object_table;
+		return -EINVAL;
 	}
 
 	data->msg_buf = kcalloc(data->max_reportid, data->T5_msg_size, GFP_KERNEL);
 	if (!data->msg_buf) {
 		dev_err(&client->dev, "Failed to allocate message buffer\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void mxt_free_object_table(struct mxt_data *data)
+{
+	kfree(data->raw_info_block);
+	data->raw_info_block = NULL;
+	data->info = NULL;
+	data->object_table = NULL;
+	kfree(data->msg_buf);
+	data->msg_buf = NULL;
+	data->T5_address = 0;
+	data->T5_msg_size = 0;
+	data->T6_address = 0;
+	data->T6_reportid = 0;
+	data->T7_address = 0;
+	data->T9_reportid_min = 0;
+	data->T9_reportid_max = 0;
+}
+
+static int mxt_read_info_block(struct mxt_data *data)
+{
+	struct i2c_client *client = data->client;
+	int error;
+	size_t size;
+	void *buf;
+	struct mxt_info *info;
+	u32 calculated_crc;
+	u8 *crc_ptr;
+
+	/* If info block already allocated, free it */
+	if (data->raw_info_block != NULL)
+		mxt_free_object_table(data);
+
+	/* Read 7-byte ID information block starting at address 0 */
+	size = sizeof(struct mxt_info);
+	buf = kzalloc(size, GFP_KERNEL);
+	if (!buf) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	error = __mxt_read_reg(client, 0, size, buf);
+	if (error)
+		goto err_free_mem;
+
+	/* Resize buffer to give space for rest of info block */
+	info = (struct mxt_info *)buf;
+	size += (info->object_num * sizeof(struct mxt_object))
+		+ MXT_INFO_CHECKSUM_SIZE;
+
+	buf = krealloc(buf, size, GFP_KERNEL);
+	if (!buf) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
 		error = -ENOMEM;
-		goto free_object_table;
+		goto err_free_mem;
+	}
+
+	/* Read rest of info block */
+	error = __mxt_read_reg(client, MXT_OBJECT_START,
+			       size - MXT_OBJECT_START,
+			       buf + MXT_OBJECT_START);
+	if (error)
+		goto err_free_mem;
+
+	/* Extract & calculate checksum */
+	crc_ptr = buf + size - MXT_INFO_CHECKSUM_SIZE;
+	data->info_crc = crc_ptr[0] | (crc_ptr[1] << 8) | (crc_ptr[2] << 16);
+
+	calculated_crc = mxt_calculate_crc(buf, 0, size - MXT_INFO_CHECKSUM_SIZE);
+
+	/* CRC mismatch can be caused by data corruption due to I2C comms
+	 * issue or else device is not using Object Based Protocol */
+	if (data->info_crc != calculated_crc) {
+		dev_err(&client->dev,
+			"Info Block CRC error calculated=0x%06X read=0x%06X\n",
+			data->info_crc, calculated_crc);
+		return -EIO;
+	}
+
+	/* Save pointers in device data structure */
+	data->raw_info_block = buf;
+	data->info = (struct mxt_info *)buf;
+	data->object_table = (struct mxt_object *)(buf + MXT_OBJECT_START);
+
+	/* Parse object table information */
+	error = mxt_parse_object_table(data);
+	if (error) {
+		dev_err(&client->dev, "Error %d reading object table\n", error);
+		mxt_free_object_table(data);
+		return error;
 	}
 
+	dev_info(&client->dev,
+			"Family ID: %u Variant ID: %u Firmware V%u.%u.%02X "
+			" Object Num:%d\n",
+			data->info->family_id, data->info->variant_id,
+			data->info->version >> 4, data->info->version & 0xf,
+			data->info->build, data->info->object_num);
+
 	return 0;
 
-free_object_table:
-	mxt_free_object_table(data);
+err_free_mem:
+	kfree(buf);
 	return error;
 }
 
@@ -1538,7 +1602,7 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
 		return -EINVAL;
 
 	/* Update matrix size in info struct (may change after reset) */
-	error = mxt_get_info(data);
+	error = mxt_read_info_block(data);
 	if (error)
 		return error;
 
@@ -1574,7 +1638,7 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
 
 	dev_info(&client->dev,
 			"Matrix Size X%uY%u Touchscreen size X%uY%u\n",
-			data->info.matrix_xsize, data->info.matrix_ysize,
+			data->info->matrix_xsize, data->info->matrix_ysize,
 			data->max_x, data->max_y);
 
 	return 0;
@@ -1583,12 +1647,11 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
 static int mxt_initialize(struct mxt_data *data)
 {
 	struct i2c_client *client = data->client;
-	struct mxt_info *info = &data->info;
 	int error;
 	u8 retry_count = 0;
 
 retry_probe:
-	error = mxt_get_info(data);
+	error = mxt_read_info_block(data);
 	if (error) {
 		error = mxt_probe_bootloader(data);
 		if (error) {
@@ -1614,21 +1677,6 @@ retry_probe:
 
 	data->state = APPMODE;
 
-	data->object_table = kcalloc(info->object_num,
-				     sizeof(struct mxt_object),
-				     GFP_KERNEL);
-	if (!data->object_table) {
-		dev_err(&client->dev, "Failed to allocate memory\n");
-		return -ENOMEM;
-	}
-
-	/* Get object table information */
-	error = mxt_get_object_table(data);
-	if (error) {
-		dev_err(&client->dev, "Error %d reading object table\n", error);
-		return error;
-	}
-
 	/* Check register init values */
 	error = mxt_check_reg_init(data);
 	if (error) {
@@ -1643,16 +1691,6 @@ retry_probe:
 		return error;
 	}
 
-	error = mxt_read_t9_resolution(data);
-	if (error)
-		dev_warn(&client->dev, "Failed to initialize T9 resolution\n");
-
-	dev_info(&client->dev,
-			"Family ID: %u Variant ID: %u Firmware V%u.%u.%02X "
-			" Object Num:%d\n",
-			info->family_id, info->variant_id, info->version >> 4,
-			info->version & 0xf, info->build, info->object_num);
-
 	return 0;
 }
 
@@ -1661,9 +1699,9 @@ static ssize_t mxt_fw_version_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
 	struct mxt_data *data = dev_get_drvdata(dev);
-	struct mxt_info *info = &data->info;
 	return scnprintf(buf, PAGE_SIZE, "%u.%u.%02X\n",
-			 info->version >> 4, info->version & 0xf, info->build);
+			 data->info->version >> 4, data->info->version & 0xf,
+			 data->info->build);
 }
 
 /* Hardware Version is returned as FamilyID.VariantID */
@@ -1671,9 +1709,8 @@ static ssize_t mxt_hw_version_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
 	struct mxt_data *data = dev_get_drvdata(dev);
-	struct mxt_info *info = &data->info;
 	return scnprintf(buf, PAGE_SIZE, "%u.%u\n",
-			 info->family_id, info->variant_id);
+			data->info->family_id, data->info->variant_id);
 }
 
 static ssize_t mxt_show_instance(char *buf, int count,
@@ -1710,7 +1747,7 @@ static ssize_t mxt_object_show(struct device *dev,
 		return -ENOMEM;
 
 	error = 0;
-	for (i = 0; i < data->info.object_num; i++) {
+	for (i = 0; i < data->info->object_num; i++) {
 		object = data->object_table + i;
 
 		if (!mxt_object_readable(object->type))
@@ -2041,6 +2078,10 @@ static int mxt_initialize_t9_input_device(struct mxt_data *data)
 	unsigned int num_mt_slots;
 	int key;
 
+	error = mxt_read_t9_resolution(data);
+	if (error)
+		dev_warn(&client->dev, "Failed to initialize T9 resolution\n");
+
 	input_dev = input_allocate_device();
 	if (!input_dev) {
 		dev_err(&client->dev, "Failed to allocate memory\n");
@@ -2149,6 +2190,13 @@ static int mxt_probe(struct i2c_client *client,
 	if (error)
 		goto err_free_mem;
 
+	error = mxt_initialize_t9_input_device(data);
+	if (error) {
+		dev_err(&client->dev, "Error %d registering input device\n",
+			error);
+		goto err_free_irq;
+	}
+
 	error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
 				     pdata->irqflags | IRQF_ONESHOT,
 				     client->name, data);
@@ -2163,13 +2211,6 @@ static int mxt_probe(struct i2c_client *client,
 			goto err_free_irq;
 	}
 
-	error = mxt_initialize_t9_input_device(data);
-	if (error) {
-		dev_err(&client->dev, "Error %d registering input device\n",
-			error);
-		goto err_free_irq;
-	}
-
 	error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
 	if (error) {
 		dev_err(&client->dev, "Failure %d creating sysfs group\n",
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 34/40] Input: atmel_mxt_ts - Remove mxt_make_highchg
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (32 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 33/40] Input: atmel_mxt_ts - Verify Information Block checksum on probe Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 35/40] Input: atmel_mxt_ts - Improve messages relating to info block read Nick Dyer
                   ` (7 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Reading all messages until an invalid is received is a way of forcing the CHG
line high, which means that when using edge-triggered interrupts the interrupt
can be acquired.

This only papers over the problem because the interrupt may still be lost
during message reading (although this is very rare), so it is better to either

1) Use level-triggered interrupts
or
2) Use edge-triggered interrupts and enable the RETRIGEN feature in T18
   COMMSCONFIG

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 6dbd3d6..83a0837 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1925,14 +1925,9 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 		mxt_initialize(data);
 	}
 
-	if (data->state == APPMODE) {
+	if (data->state == APPMODE)
 		enable_irq(data->irq);
 
-		error = mxt_process_messages_until_invalid(data);
-		if (error)
-			return error;
-	}
-
 	return count;
 }
 
@@ -2205,12 +2200,6 @@ static int mxt_probe(struct i2c_client *client,
 		goto err_free_object;
 	}
 
-	if (data->state == APPMODE) {
-		error = mxt_process_messages_until_invalid(data);
-		if (error)
-			goto err_free_irq;
-	}
-
 	error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
 	if (error) {
 		dev_err(&client->dev, "Failure %d creating sysfs group\n",
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 35/40] Input: atmel_mxt_ts - Improve messages relating to info block read
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (33 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 34/40] Input: atmel_mxt_ts - Remove mxt_make_highchg Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 36/40] Input: atmel_mxt_ts - Handle reports from T47 Stylus object Nick Dyer
                   ` (6 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

The matrix size is only used to print out a debug message, and results in some
rather confusing code to re-read it if the device configuration is updated. So
don't print it out.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   26 ++++++++++----------------
 1 file changed, 10 insertions(+), 16 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 83a0837..267b5d8 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1390,6 +1390,8 @@ static int mxt_parse_object_table(struct mxt_data *data)
 	u8 reportid;
 	u16 end_address;
 
+	dev_dbg(&client->dev, "Object num: %d\n", data->info->object_num);
+
 	/* Valid Report IDs start counting from 1 */
 	reportid = 1;
 	data->mem_size = 0;
@@ -1567,6 +1569,12 @@ static int mxt_read_info_block(struct mxt_data *data)
 	data->info = (struct mxt_info *)buf;
 	data->object_table = (struct mxt_object *)(buf + MXT_OBJECT_START);
 
+	dev_info(&client->dev,
+			"Family ID: %u Variant ID: %u Firmware: V%u.%u.%02X",
+			data->info->family_id, data->info->variant_id,
+			data->info->version >> 4, data->info->version & 0xf,
+			data->info->build);
+
 	/* Parse object table information */
 	error = mxt_parse_object_table(data);
 	if (error) {
@@ -1575,13 +1583,6 @@ static int mxt_read_info_block(struct mxt_data *data)
 		return error;
 	}
 
-	dev_info(&client->dev,
-			"Family ID: %u Variant ID: %u Firmware V%u.%u.%02X "
-			" Object Num:%d\n",
-			data->info->family_id, data->info->variant_id,
-			data->info->version >> 4, data->info->version & 0xf,
-			data->info->build, data->info->object_num);
-
 	return 0;
 
 err_free_mem:
@@ -1601,11 +1602,6 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
 	if (!object)
 		return -EINVAL;
 
-	/* Update matrix size in info struct (may change after reset) */
-	error = mxt_read_info_block(data);
-	if (error)
-		return error;
-
 	error = __mxt_read_reg(client,
 			       object->start_address + MXT_T9_RANGE,
 			       sizeof(range), &range);
@@ -1636,10 +1632,8 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
 		data->max_y = range.y;
 	}
 
-	dev_info(&client->dev,
-			"Matrix Size X%uY%u Touchscreen size X%uY%u\n",
-			data->info->matrix_xsize, data->info->matrix_ysize,
-			data->max_x, data->max_y);
+	dev_info(&client->dev, "Touchscreen size X%uY%u\n",
+		 data->max_x, data->max_y);
 
 	return 0;
 }
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 36/40] Input: atmel_mxt_ts - Handle reports from T47 Stylus object
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (34 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 35/40] Input: atmel_mxt_ts - Improve messages relating to info block read Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 37/40] Input: atmel_mxt_ts - Release touch state during suspend Nick Dyer
                   ` (5 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 267b5d8..79fe3ba 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -130,6 +130,9 @@ static unsigned long mxt_t15_keystatus;
 /* Define for MXT_PROCI_TOUCHSUPPRESSION_T42 */
 #define MXT_T42_MSG_TCHSUP	(1 << 0)
 
+/* T47 Stylus */
+#define MXT_TOUCH_MAJOR_T47_STYLUS	1
+
 /* T63 Stylus */
 #define MXT_STYLUS_PRESS	(1 << 0)
 #define MXT_STYLUS_RELEASE	(1 << 1)
@@ -625,6 +628,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
 	int area;
 	int amplitude;
 	u8 vector;
+	int tool;
 
 	/* do not report events if input device not yet registered */
 	if (!input_dev)
@@ -641,6 +645,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
 		y >>= 2;
 
 	area = message[5];
+
 	amplitude = message[6];
 	vector = message[7];
 
@@ -664,13 +669,21 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
 		 * status messages, indicating all the events that have
 		 * happened */
 		if (status & MXT_T9_RELEASE) {
-			input_mt_report_slot_state(input_dev,
-						   MT_TOOL_FINGER, 0);
+			input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
 			mxt_input_sync(input_dev);
 		}
 
+		/* A reported size of zero indicates that the reported touch
+		 * is a stylus from a linked Stylus T47 object. */
+		if (area == 0) {
+			area = MXT_TOUCH_MAJOR_T47_STYLUS;
+			tool = MT_TOOL_PEN;
+		} else {
+			tool = MT_TOOL_FINGER;
+		}
+
 		/* Touch active */
-		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);
+		input_mt_report_slot_state(input_dev, tool, 1);
 		input_report_abs(input_dev, ABS_MT_POSITION_X, x);
 		input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
 		input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 37/40] Input: atmel_mxt_ts - Release touch state during suspend
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (35 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 36/40] Input: atmel_mxt_ts - Handle reports from T47 Stylus object Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 38/40] Input: atmel_mxt_ts - Initialize power config before and after downloading cfg Nick Dyer
                   ` (4 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

If fingers are down as the MXT chip goes into suspend it does not send a lift
message. In addition, it may not complete its final measurement cycle
immediately, which means touch messages may be received by the interrupt
handler after mxt_stop() has completed.

So:
- disable irq during suspend
- flush any messages created after suspend
- tell app layer that slots were released at suspend

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   36 +++++++++++++++++++++++++++++-
 1 file changed, 35 insertions(+), 1 deletion(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 79fe3ba..870ad65 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -192,7 +192,7 @@ struct mxt_object {
 	u8 num_report_ids;
 } __packed;
 
-enum mxt_device_state { INIT, APPMODE, BOOTLOADER, FAILED, SHUTDOWN };
+enum mxt_device_state { INIT, APPMODE, BOOTLOADER, FAILED, SHUTDOWN, SUSPEND };
 
 /* Each client has this additional data */
 struct mxt_data {
@@ -817,6 +817,9 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
 	u8 report_id = message[0];
 	bool handled = false;
 
+	if (data->state != APPMODE)
+		return 0;
+
 	if (report_id == MXT_RPTID_NOMSG)
 		return 0;
 
@@ -2043,10 +2046,35 @@ static const struct attribute_group mxt_attr_group = {
 	.attrs = mxt_attrs,
 };
 
+static void mxt_reset_slots(struct mxt_data *data)
+{
+	struct input_dev *input_dev = data->input_dev;
+	unsigned int num_mt_slots;
+	int id;
+
+	num_mt_slots = data->num_touchids + data->num_stylusids;
+
+	for (id = 0; id < num_mt_slots; id++) {
+		input_mt_slot(input_dev, id);
+		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
+	}
+
+	mxt_input_sync(input_dev);
+}
+
 static void mxt_start(struct mxt_data *data)
 {
+	/* Discard any messages still in message buffer from before chip went
+	 * to sleep */
+	mxt_process_messages_until_invalid(data);
+
 	mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
 
+	if (data->state != APPMODE) {
+		enable_irq(data->irq);
+		data->state = APPMODE;
+	}
+
 	/* Recalibrate since chip has been in deep sleep */
 	mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false);
 }
@@ -2054,6 +2082,12 @@ static void mxt_start(struct mxt_data *data)
 static void mxt_stop(struct mxt_data *data)
 {
 	mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
+
+	disable_irq(data->irq);
+
+	data->state = SUSPEND;
+
+	mxt_reset_slots(data);
 }
 
 static int mxt_input_open(struct input_dev *dev)
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 38/40] Input: atmel_mxt_ts - Initialize power config before and after downloading cfg
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (36 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 37/40] Input: atmel_mxt_ts - Release touch state during suspend Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 39/40] Input: atmel_mxt_ts - Add regulator control support Nick Dyer
                   ` (3 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

If the power configuration is zero then the configuration download may fail to
work properly, so initialize T7 before config download. The downloaded
configuration may reset the T7 power configuration so it must be
re-initialized afterwards.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   46 ++++++++++++++++--------------
 1 file changed, 25 insertions(+), 21 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 870ad65..1c878fb 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -149,7 +149,7 @@ static unsigned long mxt_t15_keystatus;
 /* Delay times */
 #define MXT_BACKUP_TIME		25	/* msec */
 #define MXT_RESET_TIME		200	/* msec */
-#define MXT_RESET_NOCHGREAD	400	/* msec */
+#define MXT_RESET_NOCHGREAD	200	/* msec */
 #define MXT_FWRESET_TIME	1000	/* msec */
 #define MXT_WAKEUP_TIME		25	/* msec */
 
@@ -220,6 +220,7 @@ struct mxt_data {
 	u8 last_message_count;
 	u8 num_touchids;
 	u8 num_stylusids;
+	u8(*read_chg) (void);
 
 	/* Cached parameters from object table */
 	u16 T5_address;
@@ -377,17 +378,17 @@ static int mxt_probe_bootloader(struct mxt_data *data)
 	return 0;
 }
 
-static int mxt_wait_for_chg(struct mxt_data *data)
+static int mxt_wait_for_chg(struct mxt_data *data, int fallback_ms)
 {
 	int timeout_counter = 0;
 	int count = 1E6;
 
-	if (data->pdata->read_chg == NULL) {
-		msleep(20);
+	if (data->read_chg == NULL) {
+		msleep(fallback_ms);
 		return 0;
 	}
 
-	while ((timeout_counter++ <= count) && data->pdata->read_chg())
+	while ((timeout_counter++ <= count) && data->read_chg())
 		udelay(20);
 
 	if (timeout_counter > count) {
@@ -447,7 +448,7 @@ recheck:
 		break;
 	case MXT_FRAME_CRC_PASS:
 		if (val == MXT_FRAME_CRC_CHECK) {
-			mxt_wait_for_chg(data);
+			mxt_wait_for_chg(data, 20);
 			goto recheck;
 		} else if (val == MXT_FRAME_CRC_FAIL) {
 			dev_err(dev, "Bootloader CRC fail\n");
@@ -1050,12 +1051,9 @@ static int mxt_soft_reset(struct mxt_data *data, u8 value)
 	if (ret)
 		return ret;
 
-	if (data->pdata->read_chg == NULL) {
-		msleep(MXT_RESET_NOCHGREAD);
-	} else {
-		msleep(MXT_RESET_TIME);
-		mxt_wait_for_chg(data);
-	}
+	msleep(MXT_RESET_TIME);
+
+	mxt_wait_for_chg(data, MXT_RESET_NOCHGREAD);
 
 	return 0;
 }
@@ -1112,6 +1110,8 @@ static u32 mxt_calculate_crc(u8 *base, off_t start_off, off_t end_off)
 	return crc;
 }
 
+static int mxt_init_t7_power_cfg(struct mxt_data *data);
+
 static int mxt_check_reg_init(struct mxt_data *data)
 {
 	struct device *dev = &data->client->dev;
@@ -1334,6 +1334,9 @@ static int mxt_check_reg_init(struct mxt_data *data)
 
 	dev_info(dev, "Config written\n");
 
+	/* T7 config may have changed */
+	mxt_init_t7_power_cfg(data);
+
 release_mem:
 	kfree(config_mem);
 release:
@@ -1687,17 +1690,17 @@ retry_probe:
 
 	data->state = APPMODE;
 
-	/* Check register init values */
-	error = mxt_check_reg_init(data);
+	error = mxt_init_t7_power_cfg(data);
 	if (error) {
-		dev_err(&client->dev, "Error %d initialising configuration\n",
-			error);
+		dev_err(&client->dev, "Failed to initialize power cfg\n");
 		return error;
 	}
 
-	error = mxt_init_t7_power_cfg(data);
+	/* Check register init values */
+	error = mxt_check_reg_init(data);
 	if (error) {
-		dev_err(&client->dev, "Failed to initialize power cfg\n");
+		dev_err(&client->dev, "Error %d initialising configuration\n",
+			error);
 		return error;
 	}
 
@@ -1840,7 +1843,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 
 	ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD);
 	if (ret) {
-		mxt_wait_for_chg(data);
+		mxt_wait_for_chg(data, 20);
 		/* Bootloader may still be unlocked from previous update
 		 * attempt */
 		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);
@@ -1860,7 +1863,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 	}
 
 	while (pos < fw->size) {
-		mxt_wait_for_chg(data);
+		mxt_wait_for_chg(data, 20);
 		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);
 		if (ret) {
 			data->state = FAILED;
@@ -1879,7 +1882,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 			goto release_firmware;
 		}
 
-		mxt_wait_for_chg(data);
+		mxt_wait_for_chg(data, 20);
 		ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS);
 		if (ret) {
 			retry++;
@@ -2219,6 +2222,7 @@ static int mxt_probe(struct i2c_client *client,
 
 	data->client = client;
 	data->pdata = pdata;
+	data->read_chg = pdata->read_chg;
 	data->irq = client->irq;
 	i2c_set_clientdata(client, data);
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 39/40] Input: atmel_mxt_ts - Add regulator control support
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (37 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 38/40] Input: atmel_mxt_ts - Initialize power config before and after downloading cfg Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 17:58 ` [PATCH 40/40] Input: atmel_mxt_ts - Implement support for T100 touch object Nick Dyer
                   ` (2 subsequent siblings)
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Allow the driver to optionally manage enabling/disable power to the touch
controller itself. If the regulators are not present then use the deep sleep
power mode instead.

For a correct power on sequence, it is required that we have control over the
RESET line.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   95 +++++++++++++++++++++++++++---
 include/linux/i2c/atmel_mxt_ts.h         |    1 +
 2 files changed, 87 insertions(+), 9 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 1c878fb..24c262c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -21,6 +21,8 @@
 #include <linux/input/mt.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
 
 /* Firmware files */
 #define MXT_FW_NAME		"maxtouch.fw"
@@ -152,6 +154,8 @@ static unsigned long mxt_t15_keystatus;
 #define MXT_RESET_NOCHGREAD	200	/* msec */
 #define MXT_FWRESET_TIME	1000	/* msec */
 #define MXT_WAKEUP_TIME		25	/* msec */
+#define MXT_REGULATOR_DELAY	150	/* msec */
+#define MXT_POWERON_DELAY	150	/* msec */
 
 /* Command to unlock bootloader */
 #define MXT_UNLOCK_CMD_MSB	0xaa
@@ -221,6 +225,10 @@ struct mxt_data {
 	u8 num_touchids;
 	u8 num_stylusids;
 	u8(*read_chg) (void);
+	bool use_regulator;
+	unsigned long gpio_reset;
+	struct regulator *reg_vdd;
+	struct regulator *reg_avdd;
 
 	/* Cached parameters from object table */
 	u16 T5_address;
@@ -1657,12 +1665,71 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
 	return 0;
 }
 
+static void mxt_regulator_enable(struct mxt_data *data)
+{
+	gpio_set_value(data->gpio_reset, 0);
+	regulator_enable(data->reg_vdd);
+	regulator_enable(data->reg_avdd);
+	msleep(MXT_REGULATOR_DELAY);
+	gpio_set_value(data->gpio_reset, 1);
+	mxt_wait_for_chg(data, MXT_POWERON_DELAY);
+}
+
+static void mxt_regulator_disable(struct mxt_data *data)
+{
+	regulator_disable(data->reg_vdd);
+	regulator_disable(data->reg_avdd);
+}
+
+static void mxt_probe_regulators(struct mxt_data *data)
+{
+	struct device *dev = &data->client->dev;
+	int error;
+
+	/* According to maXTouch power sequencing specification, RESET line
+	 * must be kept low until some time after regulators come up to
+	 * voltage */
+	if (!data->gpio_reset) {
+		dev_warn(dev, "Must have reset GPIO to use regulator support\n");
+		goto fail;
+	}
+
+	data->reg_vdd = regulator_get(dev, "vdd");
+	if (IS_ERR(data->reg_vdd)) {
+		error = PTR_ERR(data->reg_vdd);
+		dev_err(dev, "Error %d getting vdd regulator\n", error);
+		goto fail;
+	}
+
+	data->reg_avdd = regulator_get(dev, "avdd");
+	if (IS_ERR(data->reg_vdd)) {
+		error = PTR_ERR(data->reg_vdd);
+		dev_err(dev, "Error %d getting avdd regulator\n", error);
+		goto fail_release;
+	}
+
+	data->use_regulator = true;
+	mxt_regulator_enable(data);
+
+	dev_dbg(dev, "Initialised regulators\n");
+	return;
+
+fail_release:
+	regulator_put(data->reg_vdd);
+fail:
+	data->reg_vdd = NULL;
+	data->reg_avdd = NULL;
+	data->use_regulator = false;
+}
+
 static int mxt_initialize(struct mxt_data *data)
 {
 	struct i2c_client *client = data->client;
 	int error;
 	u8 retry_count = 0;
 
+	mxt_probe_regulators(data);
+
 retry_probe:
 	error = mxt_read_info_block(data);
 	if (error) {
@@ -2067,27 +2134,34 @@ static void mxt_reset_slots(struct mxt_data *data)
 
 static void mxt_start(struct mxt_data *data)
 {
-	/* Discard any messages still in message buffer from before chip went
-	 * to sleep */
-	mxt_process_messages_until_invalid(data);
+	if (data->use_regulator) {
+		mxt_regulator_enable(data);
+	} else {
+		/* Discard any messages still in message buffer from before chip went
+		 * to sleep */
+		mxt_process_messages_until_invalid(data);
+
+		mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
 
-	mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
+		/* Recalibrate since chip has been in deep sleep */
+		mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false);
+	}
 
 	if (data->state != APPMODE) {
 		enable_irq(data->irq);
 		data->state = APPMODE;
 	}
-
-	/* Recalibrate since chip has been in deep sleep */
-	mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false);
 }
 
 static void mxt_stop(struct mxt_data *data)
 {
-	mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
-
 	disable_irq(data->irq);
 
+	if (data->use_regulator)
+		mxt_regulator_disable(data);
+	else
+		mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
+
 	data->state = SUSPEND;
 
 	mxt_reset_slots(data);
@@ -2223,6 +2297,7 @@ static int mxt_probe(struct i2c_client *client,
 	data->client = client;
 	data->pdata = pdata;
 	data->read_chg = pdata->read_chg;
+	data->gpio_reset = pdata->gpio_reset;
 	data->irq = client->irq;
 	i2c_set_clientdata(client, data);
 
@@ -2289,6 +2364,8 @@ static int mxt_remove(struct i2c_client *client)
 	sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
 	free_irq(data->irq, data);
 	input_unregister_device(data->input_dev);
+	regulator_put(data->reg_avdd);
+	regulator_put(data->reg_vdd);
 	mxt_free_object_table(data);
 	kfree(data);
 
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index b96b265..a952cbe 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -20,6 +20,7 @@ struct mxt_platform_data {
 	unsigned long irqflags;
 	u8(*read_chg) (void);
 	const char *input_name;
+	unsigned long gpio_reset;
 };
 
 #endif /* __LINUX_ATMEL_MXT_TS_H */
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 40/40] Input: atmel_mxt_ts - Implement support for T100 touch object
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (38 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 39/40] Input: atmel_mxt_ts - Add regulator control support Nick Dyer
@ 2013-02-22 17:58 ` Nick Dyer
  2013-02-22 20:19 ` Atmel updates to atmel_mxt_ts touch controller driver Peter Meerwald
  2013-03-29 16:48 ` Henrik Rydberg
  41 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 17:58 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

The T100 object replaces the old T9 multitouch touchscreen object in new
chips.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  307 ++++++++++++++++++++++++++++--
 1 file changed, 296 insertions(+), 11 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 24c262c..13e2028 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -65,6 +65,7 @@
 #define MXT_SPT_CTECONFIG_T46		46
 #define MXT_SPT_NOISESUPPRESSION_T48	48
 #define MXT_PROCI_ACTIVE_STYLUS_T63	63
+#define MXT_TOUCH_MULTITOUCHSCREEN_T100 100
 
 /* MXT_GEN_MESSAGE_T5 object */
 #define MXT_RPTID_NOMSG		0xff
@@ -148,6 +149,23 @@ static unsigned long mxt_t15_keystatus;
 
 #define MXT_STYLUS_PRESSURE_MASK	0x3F
 
+/* T100 Multiple Touch Touchscreen */
+#define MXT_T100_CTRL		0
+#define MXT_T100_CFG1		1
+#define MXT_T100_TCHAUX		3
+#define MXT_T100_XRANGE		13
+#define MXT_T100_YRANGE		24
+
+#define MXT_T100_CFG_SWITCHXY	(1 << 5)
+
+#define MXT_T100_TCHAUX_VECT	(1 << 0)
+#define MXT_T100_TCHAUX_AMPL	(1 << 1)
+#define MXT_T100_TCHAUX_AREA	(1 << 2)
+
+#define MXT_T100_DETECT		(1 << 7)
+#define MXT_T100_TYPE_MASK	0x70
+#define MXT_T100_TYPE_STYLUS	0x20
+
 /* Delay times */
 #define MXT_BACKUP_TIME		25	/* msec */
 #define MXT_RESET_TIME		200	/* msec */
@@ -212,6 +230,9 @@ struct mxt_data {
 	unsigned int irq;
 	unsigned int max_x;
 	unsigned int max_y;
+	u8 aux_ampl;
+	u8 aux_area;
+	u8 aux_vect;
 	struct bin_attribute mem_access_attr;
 	bool debug_enabled;
 	u8 max_reportid;
@@ -246,6 +267,8 @@ struct mxt_data {
 	u8 T48_reportid;
 	u8 T63_reportid_min;
 	u8 T63_reportid_max;
+	u8 T100_reportid_min;
+	u8 T100_reportid_max;
 };
 
 /* I2C slave address pairs */
@@ -706,6 +729,79 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
 	data->update_input = true;
 }
 
+static void mxt_proc_t100_message(struct mxt_data *data, u8 *message)
+{
+	struct device *dev = &data->client->dev;
+	struct input_dev *input_dev = data->input_dev;
+	int id;
+	u8 status;
+	int x;
+	int y;
+	int tool;
+
+	/* do not report events if input device not yet registered */
+	if (!input_dev)
+		return;
+
+	id = message[0] - data->T100_reportid_min - 2;
+
+	/* ignore SCRSTATUS events */
+	if (id < 0)
+		return;
+
+	status = message[1];
+	x = (message[3] << 8) | message[2];
+	y = (message[5] << 8) | message[4];
+
+	dev_dbg(dev,
+		"[%u] status:%02X x:%u y:%u aux:%02X%02X%02X\n",
+		id,
+		status,
+		x, y,
+		message[6],
+		message[7],
+		message[8]);
+
+	input_mt_slot(input_dev, id);
+
+	if (status & MXT_T100_DETECT) {
+		/* A reported size of zero indicates that the reported touch
+		 * is a stylus from a linked Stylus T47 object. */
+		if ((status & MXT_T100_TYPE_MASK) == MXT_T100_TYPE_STYLUS)
+			tool = MT_TOOL_PEN;
+		else
+			tool = MT_TOOL_FINGER;
+
+		/* Touch active */
+		input_mt_report_slot_state(input_dev, tool, 1);
+		input_report_abs(input_dev, ABS_MT_POSITION_X, x);
+		input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+
+		if (data->aux_ampl)
+			input_report_abs(input_dev, ABS_MT_PRESSURE,
+					 message[data->aux_ampl]);
+
+		if (data->aux_area) {
+			if (tool == MT_TOOL_PEN)
+				input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
+						 MXT_TOUCH_MAJOR_T47_STYLUS);
+			else
+				input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
+						 message[data->aux_area]);
+		}
+
+		if (data->aux_vect)
+			input_report_abs(input_dev, ABS_MT_ORIENTATION,
+					 message[data->aux_vect]);
+	} else {
+		/* Touch no longer active, close out slot */
+		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
+	}
+
+	data->update_input = true;
+}
+
+
 static void mxt_proc_t15_messages(struct mxt_data *data, u8 *msg)
 {
 	struct input_dev *input_dev = data->input_dev;
@@ -839,6 +935,10 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
 	    && report_id <= data->T9_reportid_max) {
 		mxt_proc_t9_message(data, message);
 		handled = true;
+	} else if (report_id >= data->T100_reportid_min
+	    && report_id <= data->T100_reportid_max) {
+		mxt_proc_t100_message(data, message);
+		handled = true;
 	} else if (report_id >= data->T63_reportid_min
 		   && report_id <= data->T63_reportid_max) {
 		mxt_proc_t63_messages(data, message);
@@ -1487,6 +1587,12 @@ static int mxt_parse_object_table(struct mxt_data *data)
 			data->num_stylusids =
 				object->num_report_ids * OBP_INSTANCES(object);
 			break;
+		case MXT_TOUCH_MULTITOUCHSCREEN_T100:
+			data->T100_reportid_min = min_id;
+			data->T100_reportid_max = max_id;
+			/* first two report IDs reserved */
+			data->num_touchids = object->num_report_ids - 2;
+			break;
 		}
 
 		end_address = object->start_address
@@ -1529,6 +1635,8 @@ static void mxt_free_object_table(struct mxt_data *data)
 	data->T7_address = 0;
 	data->T9_reportid_min = 0;
 	data->T9_reportid_max = 0;
+	data->T100_reportid_min = 0;
+	data->T100_reportid_max = 0;
 }
 
 static int mxt_read_info_block(struct mxt_data *data)
@@ -1722,6 +1830,172 @@ fail:
 	data->use_regulator = false;
 }
 
+static int mxt_read_t100_config(struct mxt_data *data)
+{
+	struct i2c_client *client = data->client;
+	int error;
+	struct mxt_object *object;
+	u16 range_x, range_y;
+	u8 cfg, tchaux;
+	u8 aux;
+
+	object = mxt_get_object(data, MXT_TOUCH_MULTITOUCHSCREEN_T100);
+	if (!object)
+		return -EINVAL;
+
+	error = __mxt_read_reg(client,
+			       object->start_address + MXT_T100_XRANGE,
+			       sizeof(range_x), &range_x);
+	if (error)
+		return error;
+
+	le16_to_cpus(range_x);
+
+	error = __mxt_read_reg(client,
+			       object->start_address + MXT_T100_YRANGE,
+			       sizeof(range_y), &range_y);
+	if (error)
+		return error;
+
+	le16_to_cpus(range_y);
+
+	error =  __mxt_read_reg(client,
+				object->start_address + MXT_T100_CFG1,
+				1, &cfg);
+	if (error)
+		return error;
+
+	error =  __mxt_read_reg(client,
+				object->start_address + MXT_T100_TCHAUX,
+				1, &tchaux);
+	if (error)
+		return error;
+
+	/* Handle default values */
+	if (range_x == 0)
+		range_x = 1023;
+
+	/* Handle default values */
+	if (range_x == 0)
+		range_x = 1023;
+
+	if (range_y == 0)
+		range_y = 1023;
+
+	if (cfg & MXT_T100_CFG_SWITCHXY) {
+		data->max_x = range_y;
+		data->max_y = range_x;
+	} else {
+		data->max_x = range_x;
+		data->max_y = range_y;
+	}
+
+	/* allocate aux bytes */
+	aux = 6;
+
+	if (tchaux & MXT_T100_TCHAUX_VECT)
+		data->aux_vect = aux++;
+
+	if (tchaux & MXT_T100_TCHAUX_AMPL)
+		data->aux_ampl = aux++;
+
+	if (tchaux & MXT_T100_TCHAUX_AREA)
+		data->aux_area = aux++;
+
+	dev_info(&client->dev,
+		 "T100 Touchscreen size X%uY%u\n", data->max_x, data->max_y);
+
+	return 0;
+}
+
+static int mxt_input_open(struct input_dev *dev);
+static void mxt_input_close(struct input_dev *dev);
+
+static int mxt_initialize_t100_input_device(struct mxt_data *data)
+{
+	struct i2c_client *client = data->client;
+	struct input_dev *input_dev;
+	int error;
+
+	error = mxt_read_t100_config(data);
+	if (error)
+		dev_warn(&client->dev, "Failed to initialize T9 resolution\n");
+
+	input_dev = input_allocate_device();
+	if (!data || !input_dev) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	if (data->pdata->input_name)
+		input_dev->name = data->pdata->input_name;
+	else
+		input_dev->name = "Atmel maXTouch Touchscreen";
+
+	snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0",
+		 client->adapter->nr, client->addr);
+	input_dev->phys = data->phys;
+
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+	input_dev->open = mxt_input_open;
+	input_dev->close = mxt_input_close;
+
+	set_bit(EV_ABS, input_dev->evbit);
+	input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
+
+	/* For single touch */
+	input_set_abs_params(input_dev, ABS_X,
+			     0, data->max_x, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y,
+			     0, data->max_y, 0, 0);
+
+	if (data->aux_ampl)
+		input_set_abs_params(input_dev, ABS_PRESSURE,
+				     0, 255, 0, 0);
+
+	/* For multi touch */
+	error = input_mt_init_slots(input_dev, data->num_touchids, 0);
+	if (error)
+		goto err_free_mem;
+
+	input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+			     0, data->max_x, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+			     0, data->max_y, 0, 0);
+
+	if (data->aux_area)
+		input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+				     0, MXT_MAX_AREA, 0, 0);
+
+	if (data->aux_ampl)
+		input_set_abs_params(input_dev, ABS_MT_PRESSURE,
+				     0, 255, 0, 0);
+
+	if (data->aux_vect)
+		input_set_abs_params(input_dev, ABS_MT_ORIENTATION,
+				     0, 255, 0, 0);
+
+	input_set_drvdata(input_dev, data);
+
+	error = input_register_device(input_dev);
+	if (error) {
+		dev_err(&client->dev, "Error %d registering input device\n",
+			error);
+		goto err_free_mem;
+	}
+
+	data->input_dev = input_dev;
+
+	return 0;
+
+err_free_mem:
+	input_free_device(input_dev);
+	return error;
+}
+
+static int mxt_initialize_t9_input_device(struct mxt_data *data);
+
 static int mxt_initialize(struct mxt_data *data)
 {
 	struct i2c_client *client = data->client;
@@ -1771,6 +2045,26 @@ retry_probe:
 		return error;
 	}
 
+	if (data->T9_reportid_min) {
+		error = mxt_initialize_t9_input_device(data);
+		if (error) {
+			dev_err(&client->dev,
+				"error %d registering T9 input device\n",
+				error);
+			return error;
+		}
+	} else if (data->T100_reportid_min) {
+		error = mxt_initialize_t100_input_device(data);
+		if (error) {
+			dev_err(&client->dev,
+				"error %d registering T100 input device\n",
+				error);
+			return error;
+		}
+	} else {
+		dev_warn(&client->dev, "No touch object detected\n");
+	}
+
 	return 0;
 }
 
@@ -2305,13 +2599,6 @@ static int mxt_probe(struct i2c_client *client,
 	if (error)
 		goto err_free_mem;
 
-	error = mxt_initialize_t9_input_device(data);
-	if (error) {
-		dev_err(&client->dev, "Error %d registering input device\n",
-			error);
-		goto err_free_irq;
-	}
-
 	error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
 				     pdata->irqflags | IRQF_ONESHOT,
 				     client->name, data);
@@ -2324,7 +2611,7 @@ static int mxt_probe(struct i2c_client *client,
 	if (error) {
 		dev_err(&client->dev, "Failure %d creating sysfs group\n",
 			error);
-		goto err_unregister_device;
+		goto err_free_irq;
 	}
 
 	sysfs_bin_attr_init(&data->mem_access_attr);
@@ -2344,9 +2631,6 @@ static int mxt_probe(struct i2c_client *client,
 
 err_remove_sysfs_group:
 	sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
-err_unregister_device:
-	input_unregister_device(data->input_dev);
-	data->input_dev = NULL;
 err_free_irq:
 	free_irq(client->irq, data);
 err_free_object:
@@ -2364,6 +2648,7 @@ static int mxt_remove(struct i2c_client *client)
 	sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
 	free_irq(data->irq, data);
 	input_unregister_device(data->input_dev);
+	data->input_dev = NULL;
 	regulator_put(data->reg_avdd);
 	regulator_put(data->reg_vdd);
 	mxt_free_object_table(data);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Re: [PATCH 11/40] Input: atmel_mxt_ts - Bootloader addresses for mXT1664/mXT1188S
  2013-02-22 17:57 ` [PATCH 11/40] Input: atmel_mxt_ts - Bootloader addresses for mXT1664/mXT1188S Nick Dyer
@ 2013-02-22 19:06   ` Benson Leung
  2013-02-22 19:51     ` Nick Dyer
  0 siblings, 1 reply; 51+ messages in thread
From: Benson Leung @ 2013-02-22 19:06 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Bowens, Alan, linux-input, linux-kernel, Peter Meerwald,
	Olof Johansson, Yufeng Shen

This is disappointing that Atmel decided to change the bootloader
address scheme for the 1664S family. Unfortunately, this ifdef won't
work for situations where there are more than one Atmel device of a
different kind on a system using this same driver.

For the Chromebook Pixel, we use the same atmel_mxt_ts driver for a
1664S device and a 224SL.

The 1664S has the pair 0x26 and 0x4a, while the 224SL has 0x25 and 0x4b.

Benson

On Fri, Feb 22, 2013 at 9:57 AM, Nick Dyer <nick.dyer@itdev.co.uk> wrote:
> The mXT1664S family chips use different mappings for bootloader addresses.
>
> Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
> ---
>  drivers/input/touchscreen/atmel_mxt_ts.c |    5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
> index 16af68d..903ff54 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -281,12 +281,17 @@ struct mxt_i2c_address_pair {
>  };
>
>  static const struct mxt_i2c_address_pair mxt_i2c_addresses[] = {
> +#ifdef BOOTLOADER_1664_1188
> +       { 0x26, 0x4a },
> +       { 0x27, 0x4b },
> +#else
>         { 0x24, 0x4a },
>         { 0x25, 0x4b },
>         { 0x26, 0x4c },
>         { 0x27, 0x4d },
>         { 0x34, 0x5a },
>         { 0x35, 0x5b },
> +#endif
>  };
>
>  static bool mxt_object_readable(unsigned int type)
> --
> 1.7.10.4
>



--
Benson Leung
Software Engineer, Chrom* OS
bleung@chromium.org

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 11/40] Input: atmel_mxt_ts - Bootloader addresses for mXT1664/mXT1188S
  2013-02-22 19:06   ` Benson Leung
@ 2013-02-22 19:51     ` Nick Dyer
  2013-02-22 23:09       ` Benson Leung
  0 siblings, 1 reply; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 19:51 UTC (permalink / raw)
  To: Benson Leung
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Bowens, Alan, linux-input, linux-kernel, Peter Meerwald,
	Olof Johansson, Yufeng Shen

Benson Leung wrote:
> This is disappointing that Atmel decided to change the bootloader 
> address scheme for the 1664S family. Unfortunately, this ifdef won't 
> work for situations where there are more than one Atmel device of a 
> different kind on a system using this same driver.
> 
> For the Chromebook Pixel, we use the same atmel_mxt_ts driver for a 
> 1664S device and a 224SL.
> 
> The 1664S has the pair 0x26 and 0x4a, while the 224SL has 0x25 and
> 0x4b.

If I put a bootloader address override in the platform data will that meet
your requirements?

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: Atmel updates to atmel_mxt_ts touch controller driver
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (39 preceding siblings ...)
  2013-02-22 17:58 ` [PATCH 40/40] Input: atmel_mxt_ts - Implement support for T100 touch object Nick Dyer
@ 2013-02-22 20:19 ` Peter Meerwald
  2013-02-22 20:53   ` Nick Dyer
  2013-03-29 16:48 ` Henrik Rydberg
  41 siblings, 1 reply; 51+ messages in thread
From: Peter Meerwald @ 2013-02-22 20:19 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, bleung, olofj

Hello Nick,

> These changes address some of the same issues that appear in the patchsets
> submitted by Daniel Kurtz and Peter Meerwald. However, they go much further in
> adding support for new objects, improving performance, and increasing
> reliability. They have been regularly regression tested against old and new
> chips which use the same protocol.

the series gets rid of the fragile binary config data and 
handle_pdata() - I like it, but haven't tested yet

is there a reference to the specification of the new config format?
the format of the old pdata->config was immediately obvious from reading 
the source, the new way not so much...

regards, p.

-- 

Peter Meerwald
+43-664-2444418 (mobile)

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: Atmel updates to atmel_mxt_ts touch controller driver
  2013-02-22 20:19 ` Atmel updates to atmel_mxt_ts touch controller driver Peter Meerwald
@ 2013-02-22 20:53   ` Nick Dyer
  0 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-02-22 20:53 UTC (permalink / raw)
  To: Peter Meerwald
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, bleung, olofj

Peter Meerwald wrote:
> the series gets rid of the fragile binary config data and handle_pdata()
> - I like it, but haven't tested yet
> 
> is there a reference to the specification of the new config format? the
> format of the old pdata->config was immediately obvious from reading the
> source, the new way not so much...

It's basically:

OBP_RAW V1
family_id variant_id version build x_size y_size num_objects
info_block_crc
config_crc
<type> <instance> <num_bytes> <object_bytes...>
(repeat last line for each object/instance)

Everything is ASCII hex. It's designed to be simple to parse/generate. We
also have an INI like format called xcfg which is much friendlier to
humans, but parsing that in a kernel driver would be a bit horrid.

I can point you to a bit of code that writes it:

https://github.com/atmel-maxtouch/obp-utils/blob/master/src/libmaxtouch/config.c#L39

It will not read the config CRC, but you can get that from dmesg output
(it's in T6 messages).

You can try the mxt-app tool without the driver changes via i2c-dev, just
run it like "mxt-app -d2 -a4b" (for /dev/i2c-2, addr 4b).

cheers

-- 
Nick Dyer
Senior Software Engineer, ITDev
Hardware and Software Development Consultancy

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 28/40] Input: atmel_mxt_ts - Add CHG line handling in bootloader code
  2013-02-22 17:58 ` [PATCH 28/40] Input: atmel_mxt_ts - Add CHG line handling in bootloader code Nick Dyer
@ 2013-02-22 22:35   ` Benson Leung
  2013-02-23  1:45   ` Benson Leung
  1 sibling, 0 replies; 51+ messages in thread
From: Benson Leung @ 2013-02-22 22:35 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Bowens, Alan, linux-input, linux-kernel, Peter Meerwald,
	Olof Johansson, Yufeng Shen

This is very similar to a patch that Daniel and I sent earlier this month.

http://www.spinics.net/lists/linux-input/msg24666.html

The major difference is that your wait_for_chg does a polling read of
chg, while the one we worked on leaves the irq enabled and waits on
completion.

On Fri, Feb 22, 2013 at 9:58 AM, Nick Dyer <nick.dyer@itdev.co.uk> wrote:
> The bootloader state machine toggles the CHG/Interrupt line to indicate when
> it has transitioned between states. Waiting for this event improves bootloader
> reliability.
>
> Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
> ---
>  drivers/input/touchscreen/atmel_mxt_ts.c |   29 +++++++++++++++++++++++++++--
>  1 file changed, 27 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
> index a1f196b..f182228 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -430,6 +430,27 @@ static int mxt_probe_bootloader(struct mxt_data *data)
>         return 0;
>  }
>
> +static int mxt_wait_for_chg(struct mxt_data *data)
> +{
> +       int timeout_counter = 0;
> +       int count = 1E6;
> +
> +       if (data->pdata->read_chg == NULL) {
> +               msleep(20);
> +               return 0;
> +       }
> +
> +       while ((timeout_counter++ <= count) && data->pdata->read_chg())
> +               udelay(20);
> +
> +       if (timeout_counter > count) {
> +               dev_err(&data->client->dev, "mxt_wait_for_chg() timeout!\n");
> +               return -EIO;
> +       }
> +
> +       return 0;
> +}
> +
>  static u8 mxt_get_bootloader_version(struct mxt_data *data, u8 val)
>  {
>         struct device *dev = &data->client->dev;
> @@ -478,9 +499,10 @@ recheck:
>                 val &= ~MXT_BOOT_STATUS_MASK;
>                 break;
>         case MXT_FRAME_CRC_PASS:
> -               if (val == MXT_FRAME_CRC_CHECK)
> +               if (val == MXT_FRAME_CRC_CHECK) {
> +                       mxt_wait_for_chg(data);
>                         goto recheck;
> -               if (val == MXT_FRAME_CRC_FAIL) {
> +               } else if (val == MXT_FRAME_CRC_FAIL) {
>                         dev_err(dev, "Bootloader CRC fail\n");
>                         return -EINVAL;
>                 }
> @@ -1781,6 +1803,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
>
>         ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD);
>         if (ret) {
> +               mxt_wait_for_chg(data);
>                 /* Bootloader may still be unlocked from previous update
>                  * attempt */
>                 ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);
> @@ -1800,6 +1823,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
>         }
>
>         while (pos < fw->size) {
> +               mxt_wait_for_chg(data);
>                 ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);
>                 if (ret) {
>                         data->state = FAILED;
> @@ -1818,6 +1842,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
>                         goto release_firmware;
>                 }
>
> +               mxt_wait_for_chg(data);
>                 ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS);
>                 if (ret) {
>                         retry++;
> --
> 1.7.10.4
>



--
Benson Leung
Software Engineer, Chrom* OS
bleung@chromium.org

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 11/40] Input: atmel_mxt_ts - Bootloader addresses for mXT1664/mXT1188S
  2013-02-22 19:51     ` Nick Dyer
@ 2013-02-22 23:09       ` Benson Leung
  0 siblings, 0 replies; 51+ messages in thread
From: Benson Leung @ 2013-02-22 23:09 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Bowens, Alan, linux-input, linux-kernel, Peter Meerwald,
	Olof Johansson, Yufeng Shen

We've moved away from using platform data in our project because it's
clunky, and because we implemented the config loading that's similar
to what you submitted elsewhere in this series.

Furthermore, for our ARM projects specifically, we are using flattened
device trees to describe our board and instantiate devices. The upside
is that it means that we no longer have to modify the kernel to bring
up a new board with some varied hardware.

The downside is that it's impossible to setup platform data for i2c
devices from the device tree. drivers/of/of_i2c.c instantiates i2c
devices including the atmel touch device, and it doesn't and shouldn't
know about how atmel_mxt_ts's platform data is structured. All it does
is i2c_new_device on the right adapter, at the right address, and
optionally pass in an irq #.



On Fri, Feb 22, 2013 at 11:51 AM, Nick Dyer <nick.dyer@itdev.co.uk> wrote:
> Benson Leung wrote:
>> This is disappointing that Atmel decided to change the bootloader
>> address scheme for the 1664S family. Unfortunately, this ifdef won't
>> work for situations where there are more than one Atmel device of a
>> different kind on a system using this same driver.
>>
>> For the Chromebook Pixel, we use the same atmel_mxt_ts driver for a
>> 1664S device and a 224SL.
>>
>> The 1664S has the pair 0x26 and 0x4a, while the 224SL has 0x25 and
>> 0x4b.
>
> If I put a bootloader address override in the platform data will that meet
> your requirements?



--
Benson Leung
Software Engineer, Chrom* OS
bleung@chromium.org

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 01/40] Input: atmel_mxt_ts - Make wait-after-reset period compatible with all chips
  2013-02-22 17:57 ` [PATCH 01/40] Input: atmel_mxt_ts - Make wait-after-reset period compatible with all chips Nick Dyer
@ 2013-02-22 23:20   ` Benson Leung
  0 siblings, 0 replies; 51+ messages in thread
From: Benson Leung @ 2013-02-22 23:20 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Bowens, Alan, linux-input, linux-kernel, Peter Meerwald,
	Olof Johansson, Iiro Valkonen, Yufeng Shen

Hi Nick,

Thanks for this patch. Comments inline.

On Fri, Feb 22, 2013 at 9:57 AM, Nick Dyer <nick.dyer@itdev.co.uk> wrote:
> From: Iiro Valkonen <iiro.valkonen@atmel.com>
>
> The delay before the chip can be accessed after reset varies between different
> chips in maXTouch family. Waiting for 200ms and then monitoring the CHG (chip
> is ready when the line is low) is guaranteed to work with all chips.
>
> Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
> ---
>  drivers/input/touchscreen/atmel_mxt_ts.c |   91 ++++++++++++++++++++++++------
>  include/linux/i2c/atmel_mxt_ts.h         |    1 +
>  2 files changed, 76 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
> index d04f810..b4bf946 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -2,6 +2,7 @@
>   * Atmel maXTouch Touchscreen driver
>   *
>   * Copyright (C) 2010 Samsung Electronics Co.Ltd
> + * Copyright (C) 2011 Atmel Corporation
>   * Author: Joonyoung Shim <jy0922.shim@samsung.com>
>   *
>   * This program is free software; you can redistribute  it and/or modify it
> @@ -175,11 +176,14 @@
>
>  /* Define for MXT_GEN_COMMAND_T6 */
>  #define MXT_BOOT_VALUE         0xa5
> +#define MXT_RESET_VALUE                0x01
>  #define MXT_BACKUP_VALUE       0x55
> -#define MXT_BACKUP_TIME                25      /* msec */
> -#define MXT_RESET_TIME         65      /* msec */
>
> -#define MXT_FWRESET_TIME       175     /* msec */
> +/* Delay times */
> +#define MXT_BACKUP_TIME                25      /* msec */
> +#define MXT_RESET_TIME         200     /* msec */
> +#define MXT_RESET_NOCHGREAD    400     /* msec */
> +#define MXT_FWRESET_TIME       1000    /* msec */
>
>  /* Command to unlock bootloader */
>  #define MXT_UNLOCK_CMD_MSB     0xaa
> @@ -249,6 +253,7 @@ struct mxt_data {
>
>         /* Cached parameters from object table */
>         u8 T6_reportid;
> +       u16 T6_address;
>         u8 T9_reportid_min;
>         u8 T9_reportid_max;
>  };
> @@ -599,6 +604,66 @@ end:
>         return IRQ_HANDLED;
>  }
>
> +static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset, u8 value, bool wait)
> +{
> +       u16 reg;
> +       u8 command_register;
> +       int ret;
> +       int timeout_counter = 0;
> +
> +       reg = data->T6_address + cmd_offset;
> +
> +       ret = mxt_write_reg(data->client, reg, value);
> +       if (ret)
> +               return ret;
> +
> +       if (!wait)
> +               return 0;
> +
> +       do {
> +               msleep(20);
> +               ret = __mxt_read_reg(data->client, reg, 1, &command_register);
> +               if (ret)
> +                       return ret;
> +       } while ((command_register != 0) && (timeout_counter++ <= 100));
> +
> +       if (timeout_counter > 100) {
> +               dev_err(&data->client->dev, "Command failed!\n");
> +               return -EIO;
> +       }
> +
> +       return 0;
> +}
> +
> +static int mxt_soft_reset(struct mxt_data *data, u8 value)
> +{
> +       int ret;
> +       int timeout_counter = 0;
> +       struct device *dev = &data->client->dev;
> +
> +       dev_info(dev, "Resetting chip\n");
> +
> +       ret = mxt_t6_command(data, MXT_COMMAND_RESET, value, false);
> +       if (ret)
> +               return ret;
> +
> +       if (data->pdata->read_chg == NULL) {

Is it possible for data->pdata to be NULL here?
For our chromiumos projects, we operate with a NULL pdata. There may
be a bunch of other places where this is a problem, actually.

> +               msleep(MXT_RESET_NOCHGREAD);
> +       } else {
> +               msleep(MXT_RESET_TIME);
> +
> +               timeout_counter = 0;
> +               while ((timeout_counter++ <= 100) && data->pdata->read_chg())
> +                       msleep(20);
> +               if (timeout_counter > 100) {
> +                       dev_err(dev, "No response after reset!\n");
> +                       return -EIO;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
>  static int mxt_check_reg_init(struct mxt_data *data)
>  {
>         const struct mxt_platform_data *pdata = data->pdata;
> @@ -759,6 +824,7 @@ static int mxt_get_object_table(struct mxt_data *data)
>                 switch (object->type) {
>                 case MXT_GEN_COMMAND_T6:
>                         data->T6_reportid = min_id;
> +                       data->T6_address = object->start_address;
>                         break;
>                 case MXT_TOUCH_MULTI_T9:
>                         data->T9_reportid_min = min_id;
> @@ -811,16 +877,9 @@ static int mxt_initialize(struct mxt_data *data)
>
>         mxt_handle_pdata(data);
>
> -       /* Backup to memory */
> -       mxt_write_object(data, MXT_GEN_COMMAND_T6,
> -                       MXT_COMMAND_BACKUPNV,
> -                       MXT_BACKUP_VALUE);
> -       msleep(MXT_BACKUP_TIME);
> -
> -       /* Soft reset */
> -       mxt_write_object(data, MXT_GEN_COMMAND_T6,
> -                       MXT_COMMAND_RESET, 1);
> -       msleep(MXT_RESET_TIME);
> +       error = mxt_t6_command(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE, false);
> +       if (!error)
> +               mxt_soft_reset(data, MXT_RESET_VALUE);
>
>         /* Update matrix size at info struct */
>         error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
> @@ -960,9 +1019,9 @@ static int mxt_load_fw(struct device *dev, const char *fn)
>         }
>
>         /* Change to the bootloader mode */
> -       mxt_write_object(data, MXT_GEN_COMMAND_T6,
> -                       MXT_COMMAND_RESET, MXT_BOOT_VALUE);
> -       msleep(MXT_RESET_TIME);
> +       ret = mxt_soft_reset(data, MXT_BOOT_VALUE);
> +       if (ret)
> +               return ret;
>
>         /* Change to slave address of bootloader */
>         if (client->addr == MXT_APP_LOW)
> diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
> index f027f7a..ef59c22 100644
> --- a/include/linux/i2c/atmel_mxt_ts.h
> +++ b/include/linux/i2c/atmel_mxt_ts.h
> @@ -39,6 +39,7 @@ struct mxt_platform_data {
>         unsigned int voltage;
>         unsigned char orient;
>         unsigned long irqflags;
> +       u8(*read_chg) (void);
>  };
>
>  #endif /* __LINUX_ATMEL_MXT_TS_H */
> --
> 1.7.10.4
>



-- 
Benson Leung
Software Engineer, Chrom* OS
bleung@chromium.org

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 28/40] Input: atmel_mxt_ts - Add CHG line handling in bootloader code
  2013-02-22 17:58 ` [PATCH 28/40] Input: atmel_mxt_ts - Add CHG line handling in bootloader code Nick Dyer
  2013-02-22 22:35   ` Benson Leung
@ 2013-02-23  1:45   ` Benson Leung
  1 sibling, 0 replies; 51+ messages in thread
From: Benson Leung @ 2013-02-23  1:45 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Bowens, Alan, linux-input, linux-kernel, Peter Meerwald,
	Olof Johansson

On Fri, Feb 22, 2013 at 9:58 AM, Nick Dyer <nick.dyer@itdev.co.uk> wrote:
> The bootloader state machine toggles the CHG/Interrupt line to indicate when
> it has transitioned between states. Waiting for this event improves bootloader
> reliability.
>
> Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
> ---
>  drivers/input/touchscreen/atmel_mxt_ts.c |   29 +++++++++++++++++++++++++++--
>  1 file changed, 27 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
> index a1f196b..f182228 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -430,6 +430,27 @@ static int mxt_probe_bootloader(struct mxt_data *data)
>         return 0;
>  }
>
> +static int mxt_wait_for_chg(struct mxt_data *data)
> +{
> +       int timeout_counter = 0;
> +       int count = 1E6;
> +
> +       if (data->pdata->read_chg == NULL) {

This also assumes the existence of data->pdata. If data->pdata ==
NULL, you're going to have a bad time.

> +               msleep(20);
> +               return 0;
> +       }
> +
> +       while ((timeout_counter++ <= count) && data->pdata->read_chg())
> +               udelay(20);
> +
> +       if (timeout_counter > count) {
> +               dev_err(&data->client->dev, "mxt_wait_for_chg() timeout!\n");
> +               return -EIO;
> +       }
> +
> +       return 0;
> +}
> +

> --
> 1.7.10.4
>



-- 
Benson Leung
Software Engineer, Chrom* OS
bleung@chromium.org

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: Atmel updates to atmel_mxt_ts touch controller driver
  2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
                   ` (40 preceding siblings ...)
  2013-02-22 20:19 ` Atmel updates to atmel_mxt_ts touch controller driver Peter Meerwald
@ 2013-03-29 16:48 ` Henrik Rydberg
  2013-04-08 14:36   ` Nick Dyer
  41 siblings, 1 reply; 51+ messages in thread
From: Henrik Rydberg @ 2013-03-29 16:48 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Joonyoung Shim, Alan.Bowens,
	linux-input, linux-kernel, pmeerw, bleung, olofj

Hi Nick,

> The following patches are a large series of updates in functionality to the
> atmel_mxt_ts touch driver. They apply cleanly to input/next.

I guess this is no longer true.

> These changes address some of the same issues that appear in the patchsets
> submitted by Daniel Kurtz and Peter Meerwald. However, they go much further in
> adding support for new objects, improving performance, and increasing
> reliability. They have been regularly regression tested against old and new
> chips which use the same protocol.
> 
> We also provide a set of user-space utilities as open source which are 
> available from github and work well with this driver:
>   https://github.com/atmel-maxtouch/obp-utils
> 
> Most of my focus in working on these changes has been to support Atmel's
> customers, who tend not to be using the mainline kernel. Unfortunately this 
> has generated somewhat of a backlog in getting these improvements into
> mainline. My current focus is to get these improvements upstream and I have
> time allocated to make any alterations as necessary. Since the scope of this
> patchset is so large any upstream delta tends to cause a big rebasing effort.
> I would suggest that I merge any useful improvements from the other patchsets
> to make a combined patchset.

Are you planning to submit a version for 3.9? If you do, please
consider sending a smaller set.

Thanks,
Henrik

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: Atmel updates to atmel_mxt_ts touch controller driver
  2013-03-29 16:48 ` Henrik Rydberg
@ 2013-04-08 14:36   ` Nick Dyer
  0 siblings, 0 replies; 51+ messages in thread
From: Nick Dyer @ 2013-04-08 14:36 UTC (permalink / raw)
  To: Henrik Rydberg
  Cc: Dmitry Torokhov, Daniel Kurtz, Joonyoung Shim, Alan.Bowens,
	linux-input, linux-kernel, pmeerw, bleung, olofj

Henrik Rydberg wrote:
>> Most of my focus in working on these changes has been to support Atmel's
>> customers, who tend not to be using the mainline kernel. Unfortunately this 
>> has generated somewhat of a backlog in getting these improvements into
>> mainline. My current focus is to get these improvements upstream and I have
>> time allocated to make any alterations as necessary. Since the scope of this
>> patchset is so large any upstream delta tends to cause a big rebasing effort.
>> I would suggest that I merge any useful improvements from the other patchsets
>> to make a combined patchset.
> 
> Are you planning to submit a version for 3.9? If you do, please
> consider sending a smaller set.

My goal is to try and get our changes into 3.10, we still have a couple of
bugs to shake out (unfortunately in the bootloading code, which is at the
front of the series), I will post an updated series once I have resolved that.

You can see the WIP here:
https://github.com/ndyer/linux/commits/for-next

^ permalink raw reply	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2013-04-08 14:44 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-22 17:57 Atmel updates to atmel_mxt_ts touch controller driver Nick Dyer
2013-02-22 17:57 ` [PATCH 01/40] Input: atmel_mxt_ts - Make wait-after-reset period compatible with all chips Nick Dyer
2013-02-22 23:20   ` Benson Leung
2013-02-22 17:57 ` [PATCH 02/40] Input: atmel_mxt_ts - add macros for object instances and size Nick Dyer
2013-02-22 17:57 ` [PATCH 03/40] Input: atmel_mxt_ts - Add memory access interface via sysfs Nick Dyer
2013-02-22 17:57 ` [PATCH 04/40] Input: atmel_mxt_ts - Implement debug output for messages Nick Dyer
2013-02-22 17:57 ` [PATCH 05/40] Input: atmel_mxt_ts - Improve error reporting and debug Nick Dyer
2013-02-22 17:57 ` [PATCH 06/40] Input: atmel_mxt_ts - Remove unnecessary platform data Nick Dyer
2013-02-22 17:57 ` [PATCH 07/40] Input: atmel_mxt_ts - Implement CRC check for configuration data Nick Dyer
2013-02-22 17:57 ` [PATCH 08/40] Input: atmel_mxt_ts - Download device config using firmware loader Nick Dyer
2013-02-22 17:57 ` [PATCH 09/40] Input: atmel_mxt_ts - Calculate and check CRC in config file Nick Dyer
2013-02-22 17:57 ` [PATCH 10/40] Input: atmel_mxt_ts - Improve bootloader support Nick Dyer
2013-02-22 17:57 ` [PATCH 11/40] Input: atmel_mxt_ts - Bootloader addresses for mXT1664/mXT1188S Nick Dyer
2013-02-22 19:06   ` Benson Leung
2013-02-22 19:51     ` Nick Dyer
2013-02-22 23:09       ` Benson Leung
2013-02-22 17:57 ` [PATCH 12/40] Input: atmel_mxt_ts - Read screen config from chip Nick Dyer
2013-02-22 17:58 ` [PATCH 13/40] Input: atmel_mxt_ts - Use deep sleep mode when stopped Nick Dyer
2013-02-22 17:58 ` [PATCH 14/40] Input: atmel_mxt_ts - add shutdown function Nick Dyer
2013-02-22 17:58 ` [PATCH 15/40] Input: atmel_mxt_ts - Improve touch reporting for T9 Nick Dyer
2013-02-22 17:58 ` [PATCH 16/40] Input: atmel_mxt_ts - Move input device configuration into separate function Nick Dyer
2013-02-22 17:58 ` [PATCH 17/40] Input: atmel_mxt_ts - Allow input device name to be configured from platform data Nick Dyer
2013-02-22 17:58 ` [PATCH 18/40] Input: atmel_mxt_ts - Add support for dynamic message size Nick Dyer
2013-02-22 17:58 ` [PATCH 19/40] Input: atmel_mxt_ts - Decode T6 status messages Nick Dyer
2013-02-22 17:58 ` [PATCH 20/40] Input: atmel_mxt_ts - Split interrupt handler into separate functions Nick Dyer
2013-02-22 17:58 ` [PATCH 21/40] Input: atmel_mxt_ts - Implement T44 message handling Nick Dyer
2013-02-22 17:58 ` [PATCH 22/40] Input: atmel_mxt_ts - Output status from T48 Noise Supression Nick Dyer
2013-02-22 17:58 ` [PATCH 23/40] Input: atmel_mxt_ts - Output status from T42 Touch Suppression Nick Dyer
2013-02-22 17:58 ` [PATCH 24/40] Input: atmel_mxt_ts - Implement vector/orientation support Nick Dyer
2013-02-22 17:58 ` [PATCH 25/40] Input: atmel_mxt_ts - implement I2C retries Nick Dyer
2013-02-22 17:58 ` [PATCH 26/40] Input: atmel_mxt_ts - Implement T63 Active Stylus support Nick Dyer
2013-02-22 17:58 ` [PATCH 27/40] Input: atmel_mxt_ts - Add check for incorrect firmware file format Nick Dyer
2013-02-22 17:58 ` [PATCH 28/40] Input: atmel_mxt_ts - Add CHG line handling in bootloader code Nick Dyer
2013-02-22 22:35   ` Benson Leung
2013-02-23  1:45   ` Benson Leung
2013-02-22 17:58 ` [PATCH 29/40] Input: atmel_mxt_ts - Use wait_for_chg in soft_reset Nick Dyer
2013-02-22 17:58 ` [PATCH 30/40] Input: atmel_mxt_ts - recover from bootloader on probe Nick Dyer
2013-02-22 17:58 ` [PATCH 31/40] Input: atmel_mxt_ts - Implement T15 Key Array support Nick Dyer
2013-02-22 17:58 ` [PATCH 32/40] Input: atmel_mxt_ts - remove unused defines Nick Dyer
2013-02-22 17:58 ` [PATCH 33/40] Input: atmel_mxt_ts - Verify Information Block checksum on probe Nick Dyer
2013-02-22 17:58 ` [PATCH 34/40] Input: atmel_mxt_ts - Remove mxt_make_highchg Nick Dyer
2013-02-22 17:58 ` [PATCH 35/40] Input: atmel_mxt_ts - Improve messages relating to info block read Nick Dyer
2013-02-22 17:58 ` [PATCH 36/40] Input: atmel_mxt_ts - Handle reports from T47 Stylus object Nick Dyer
2013-02-22 17:58 ` [PATCH 37/40] Input: atmel_mxt_ts - Release touch state during suspend Nick Dyer
2013-02-22 17:58 ` [PATCH 38/40] Input: atmel_mxt_ts - Initialize power config before and after downloading cfg Nick Dyer
2013-02-22 17:58 ` [PATCH 39/40] Input: atmel_mxt_ts - Add regulator control support Nick Dyer
2013-02-22 17:58 ` [PATCH 40/40] Input: atmel_mxt_ts - Implement support for T100 touch object Nick Dyer
2013-02-22 20:19 ` Atmel updates to atmel_mxt_ts touch controller driver Peter Meerwald
2013-02-22 20:53   ` Nick Dyer
2013-03-29 16:48 ` Henrik Rydberg
2013-04-08 14:36   ` Nick Dyer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.