All of lore.kernel.org
 help / color / mirror / Atom feed
* Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org
@ 2013-06-05 17:36 Nick Dyer
  2013-06-05 17:36 ` [PATCH 01/53] Input: atmel_mxt_ts - Remove unnecessary platform data Nick Dyer
                   ` (53 more replies)
  0 siblings, 54 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:36 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 an updated series of patches to the atmel_mxt_ts
touch driver. They should apply cleanly to input/next.

This is a combined patchset, I've been working to merge my changes with the
changes from the Chromium team. It's undergone a lot of testing and review
over the last few months and I believe it is now ready to go upstream.

Most of these changes have been maintained and tested out-of-tree in some form
for a long time. I apologise for the backlog.

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

You can see the in-between versions at
  https://github.com/ndyer/linux/

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



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

* [PATCH 01/53] Input: atmel_mxt_ts - Remove unnecessary platform data
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
@ 2013-06-05 17:36 ` Nick Dyer
  2013-06-05 17:36 ` [PATCH 02/53] Input: atmel_mxt_ts - Improve T19 GPIO keys handling Nick Dyer
                   ` (52 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:36 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 maXTouch chip on every
probe, since they are stored in NVRAM. It makes life difficult when tuning the
device to keep them in sync with the config array/file, and requires a new
kernel build for minor tweaks.

These parameters only represent a tiny subset of the available configuration
options, tracking all of these options in platform data would be a endless
task. In addition, different versions of maXTouch chips may have these values
in different places or may not even have them at all.

Having these values also makes life more complex for device tree and other
platforms where having to define a static configuration isn't helpful.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
---
 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 ----------------------------
 drivers/platform/x86/chromeos_laptop.c     |   10 ------
 include/linux/i2c/atmel_mxt_ts.h           |    6 +---
 6 files changed, 1 insertion(+), 80 deletions(-)

diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
index 1ea7973..4516d26 100644
--- a/arch/arm/mach-exynos/mach-nuri.c
+++ b/arch/arm/mach-exynos/mach-nuri.c
@@ -333,13 +333,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 497fcb7..2461e60 100644
--- a/arch/arm/mach-exynos/mach-universal_c210.c
+++ b/arch/arm/mach-exynos/mach-universal_c210.c
@@ -604,13 +604,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 3a38f7b..eca73af 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -239,13 +239,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 59aa240..e01a9ed 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -686,54 +686,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;
@@ -841,8 +793,6 @@ static int mxt_initialize(struct mxt_data *data)
 	if (error)
 		goto err_free_object_table;
 
-	mxt_handle_pdata(data);
-
 	/* Backup to memory */
 	mxt_write_object(data, MXT_GEN_COMMAND_T6,
 			MXT_COMMAND_BACKUPNV,
diff --git a/drivers/platform/x86/chromeos_laptop.c b/drivers/platform/x86/chromeos_laptop.c
index 3e5b4497..78ed277 100644
--- a/drivers/platform/x86/chromeos_laptop.c
+++ b/drivers/platform/x86/chromeos_laptop.c
@@ -71,13 +71,8 @@ static struct i2c_board_info __initdata tsl2563_als_device = {
 };
 
 static struct mxt_platform_data atmel_224s_tp_platform_data = {
-	.x_line			= 18,
-	.y_line			= 12,
 	.x_size			= 102*20,
 	.y_size			= 68*20,
-	.blen			= 0x80,	/* Gain setting is in upper 4 bits */
-	.threshold		= 0x32,
-	.voltage		= 0,	/* 3.3V */
 	.orient			= MXT_VERTICAL_FLIP,
 	.irqflags		= IRQF_TRIGGER_FALLING,
 	.is_tp			= true,
@@ -96,13 +91,8 @@ static struct i2c_board_info __initdata atmel_224s_tp_device = {
 };
 
 static struct mxt_platform_data atmel_1664s_platform_data = {
-	.x_line			= 32,
-	.y_line			= 50,
 	.x_size			= 1700,
 	.y_size			= 2560,
-	.blen			= 0x89,	/* Gain setting is in upper 4 bits */
-	.threshold		= 0x28,
-	.voltage		= 0,	/* 3.3V */
 	.orient			= MXT_ROTATED_90_COUNTER,
 	.irqflags		= IRQF_TRIGGER_FALLING,
 	.is_tp			= false,
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index 99e379b..eff0cdc 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -33,14 +33,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;
 	bool is_tp;
 	const unsigned int key_map[MXT_NUM_GPIO];
-- 
1.7.10.4


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

* [PATCH 02/53] Input: atmel_mxt_ts - Improve T19 GPIO keys handling
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
  2013-06-05 17:36 ` [PATCH 01/53] Input: atmel_mxt_ts - Remove unnecessary platform data Nick Dyer
@ 2013-06-05 17:36 ` Nick Dyer
  2013-06-05 17:36 ` [PATCH 03/53] Input: atmel_mxt_ts - Return IRQ_NONE when interrupt handler fails Nick Dyer
                   ` (51 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:36 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 mapping of the GPIO numbers into the T19 status byte varies between
   different maXTouch chips. Some have up to 7 GPIOs. Allowing a keycode array
   of up to 8 items is simpler and more generic. So replace #define with
   configurable number of keys which also allows the removal of is_tp.
 * Rename platform data parameters to include "t19" to prevent confusion with
   T15 key array.
 * Probe aborts early on when pdata is NULL, so no need to check.
 * Move "int i" to beginning of function (mixed declarations and code)
 * Use API calls rather than __set_bit()
 * Remove unused dev variable.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   44 ++++++++++++------------------
 drivers/platform/x86/chromeos_laptop.c   |   17 ++++++++----
 include/linux/i2c/atmel_mxt_ts.h         |    7 ++---
 3 files changed, 30 insertions(+), 38 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index e01a9ed..6702175 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -181,12 +181,6 @@
 
 #define MXT_FWRESET_TIME	175	/* msec */
 
-/* MXT_SPT_GPIOPWM_T19 field */
-#define MXT_GPIO0_MASK		0x04
-#define MXT_GPIO1_MASK		0x08
-#define MXT_GPIO2_MASK		0x10
-#define MXT_GPIO3_MASK		0x20
-
 /* Command to unlock bootloader */
 #define MXT_UNLOCK_CMD_MSB	0xaa
 #define MXT_UNLOCK_CMD_LSB	0xdc
@@ -251,7 +245,6 @@ struct mxt_data {
 	const struct mxt_platform_data *pdata;
 	struct mxt_object *object_table;
 	struct mxt_info info;
-	bool is_tp;
 
 	unsigned int irq;
 	unsigned int max_x;
@@ -516,15 +509,16 @@ static int mxt_write_object(struct mxt_data *data,
 static void mxt_input_button(struct mxt_data *data, struct mxt_message *message)
 {
 	struct input_dev *input = data->input_dev;
+	const struct mxt_platform_data *pdata = data->pdata;
 	bool button;
 	int i;
 
 	/* Active-low switch */
-	for (i = 0; i < MXT_NUM_GPIO; i++) {
-		if (data->pdata->key_map[i] == KEY_RESERVED)
+	for (i = 0; i < pdata->t19_num_keys; i++) {
+		if (pdata->t19_keymap[i] == KEY_RESERVED)
 			continue;
-		button = !(message->message[0] & MXT_GPIO0_MASK << i);
-		input_report_key(input, data->pdata->key_map[i], button);
+		button = !(message->message[0] & (1 << i));
+		input_report_key(input, pdata->t19_keymap[i], button);
 	}
 }
 
@@ -1085,6 +1079,8 @@ static int mxt_probe(struct i2c_client *client,
 	struct input_dev *input_dev;
 	int error;
 	unsigned int num_mt_slots;
+	unsigned int mt_flags = 0;
+	int i;
 
 	if (!pdata)
 		return -EINVAL;
@@ -1097,10 +1093,7 @@ static int mxt_probe(struct i2c_client *client,
 		goto err_free_mem;
 	}
 
-	data->is_tp = pdata && pdata->is_tp;
-
-	input_dev->name = (data->is_tp) ? "Atmel maXTouch Touchpad" :
-					  "Atmel maXTouch Touchscreen";
+	input_dev->name = "Atmel maXTouch Touchscreen";
 	snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0",
 		 client->adapter->nr, client->addr);
 
@@ -1126,20 +1119,15 @@ static int mxt_probe(struct i2c_client *client,
 	__set_bit(EV_KEY, input_dev->evbit);
 	__set_bit(BTN_TOUCH, input_dev->keybit);
 
-	if (data->is_tp) {
-		int i;
-		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+	if (pdata->t19_num_keys) {
 		__set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
 
-		for (i = 0; i < MXT_NUM_GPIO; i++)
-			if (pdata->key_map[i] != KEY_RESERVED)
-				__set_bit(pdata->key_map[i], input_dev->keybit);
+		for (i = 0; i < pdata->t19_num_keys; i++)
+			if (pdata->t19_keymap[i] != KEY_RESERVED)
+				input_set_capability(input_dev, EV_KEY,
+						     pdata->t19_keymap[i]);
 
-		__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
-		__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
-		__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
-		__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
-		__set_bit(BTN_TOOL_QUINTTAP, input_dev->keybit);
+		mt_flags |= INPUT_MT_POINTER;
 
 		input_abs_set_res(input_dev, ABS_X, MXT_PIXELS_PER_MM);
 		input_abs_set_res(input_dev, ABS_Y, MXT_PIXELS_PER_MM);
@@ -1147,6 +1135,8 @@ static int mxt_probe(struct i2c_client *client,
 				  MXT_PIXELS_PER_MM);
 		input_abs_set_res(input_dev, ABS_MT_POSITION_Y,
 				  MXT_PIXELS_PER_MM);
+
+		input_dev->name = "Atmel maXTouch Touchpad";
 	}
 
 	/* For single touch */
@@ -1159,7 +1149,7 @@ static int mxt_probe(struct i2c_client *client,
 
 	/* For multi touch */
 	num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1;
-	error = input_mt_init_slots(input_dev, num_mt_slots, 0);
+	error = input_mt_init_slots(input_dev, num_mt_slots, mt_flags);
 	if (error)
 		goto err_free_object;
 	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
diff --git a/drivers/platform/x86/chromeos_laptop.c b/drivers/platform/x86/chromeos_laptop.c
index 78ed277..8026554 100644
--- a/drivers/platform/x86/chromeos_laptop.c
+++ b/drivers/platform/x86/chromeos_laptop.c
@@ -70,16 +70,22 @@ static struct i2c_board_info __initdata tsl2563_als_device = {
 	I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
 };
 
+static int mxt_t19_keys[] = {
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	BTN_LEFT
+};
+
 static struct mxt_platform_data atmel_224s_tp_platform_data = {
 	.x_size			= 102*20,
 	.y_size			= 68*20,
 	.orient			= MXT_VERTICAL_FLIP,
 	.irqflags		= IRQF_TRIGGER_FALLING,
-	.is_tp			= true,
-	.key_map		= { KEY_RESERVED,
-				    KEY_RESERVED,
-				    KEY_RESERVED,
-				    BTN_LEFT },
+	.t19_num_keys		= ARRAY_SIZE(mxt_t19_keys),
+	.t19_keymap		= mxt_t19_keys,
 	.config			= NULL,
 	.config_length		= 0,
 };
@@ -95,7 +101,6 @@ static struct mxt_platform_data atmel_1664s_platform_data = {
 	.y_size			= 2560,
 	.orient			= MXT_ROTATED_90_COUNTER,
 	.irqflags		= IRQF_TRIGGER_FALLING,
-	.is_tp			= false,
 	.config			= NULL,
 	.config_length		= 0,
 };
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index eff0cdc..d26080d 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -15,9 +15,6 @@
 
 #include <linux/types.h>
 
-/* For key_map array */
-#define MXT_NUM_GPIO		4
-
 /* Orient */
 #define MXT_NORMAL		0x0
 #define MXT_DIAGONAL		0x1
@@ -38,8 +35,8 @@ struct mxt_platform_data {
 	unsigned char orient;
 
 	unsigned long irqflags;
-	bool is_tp;
-	const unsigned int key_map[MXT_NUM_GPIO];
+	u8 t19_num_keys;
+	const unsigned int *t19_keymap;
 };
 
 #endif /* __LINUX_ATMEL_MXT_TS_H */
-- 
1.7.10.4


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

* [PATCH 03/53] Input: atmel_mxt_ts - Return IRQ_NONE when interrupt handler fails
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
  2013-06-05 17:36 ` [PATCH 01/53] Input: atmel_mxt_ts - Remove unnecessary platform data Nick Dyer
  2013-06-05 17:36 ` [PATCH 02/53] Input: atmel_mxt_ts - Improve T19 GPIO keys handling Nick Dyer
@ 2013-06-05 17:36 ` Nick Dyer
  2013-06-05 17:36 ` [PATCH 04/53] Input: atmel_mxt_ts - define helper functions for size and instances Nick Dyer
                   ` (50 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:36 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 6702175..2a06657 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -591,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;
@@ -618,7 +618,6 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
 		input_sync(data->input_dev);
 	}
 
-end:
 	return IRQ_HANDLED;
 }
 
-- 
1.7.10.4


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

* [PATCH 04/53] Input: atmel_mxt_ts - define helper functions for size and instances
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (2 preceding siblings ...)
  2013-06-05 17:36 ` [PATCH 03/53] Input: atmel_mxt_ts - Return IRQ_NONE when interrupt handler fails Nick Dyer
@ 2013-06-05 17:36 ` Nick Dyer
  2013-06-05 17:36 ` [PATCH 05/53] Input: atmel_mxt_ts - Select FW_LOADER for firmware code Nick Dyer
                   ` (49 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:36 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

From: Daniel Kurtz <djkurtz@chromium.org>

These two object table entry fields are reported 1 less than their value.
When used, however, we always want the actual size and instances.

To keep the object size and instances 1-byte fields, and thus preserve
the object-table struct's 6-byte packed alignment, add some convenient
accessor functions that do the +1 every time these fields are accessed.

Signed-off-by: Daniel Kurtz <djkurtz@chromium.org>
Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
---
 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 2a06657..7de3b47 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2,6 +2,8 @@
  * Atmel maXTouch Touchscreen driver
  *
  * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Copyright (C) 2012 Google, Inc.
+ *
  * Author: Joonyoung Shim <jy0922.shim@samsung.com>
  *
  * This program is free software; you can redistribute  it and/or modify it
@@ -227,8 +229,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;
 
@@ -257,6 +259,16 @@ struct mxt_data {
 	u8 T19_reportid;
 };
 
+static inline size_t mxt_obj_size(const struct mxt_object *obj)
+{
+	return obj->size_minus_one + 1;
+}
+
+static inline size_t mxt_obj_instances(const struct mxt_object *obj)
+{
+	return obj->instances_minus_one + 1;
+}
+
 static bool mxt_object_readable(unsigned int type)
 {
 	switch (type) {
@@ -499,7 +511,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 >= mxt_obj_size(object))
 		return -EINVAL;
 
 	reg = object->start_address;
@@ -641,7 +653,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 = mxt_obj_size(object) * mxt_obj_instances(object);
 		if (index + size > pdata->config_length) {
 			dev_err(dev, "Not enough config data!\n");
 			return -EINVAL;
@@ -718,7 +730,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);
+					mxt_obj_instances(object);
 			max_id = reportid - 1;
 		} else {
 			min_id = 0;
@@ -727,8 +739,9 @@ 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,
+			mxt_obj_size(object), mxt_obj_instances(object),
+			min_id, max_id);
 
 		switch (object->type) {
 		case MXT_GEN_COMMAND_T6:
@@ -865,11 +878,11 @@ static ssize_t mxt_show_instance(char *buf, int count,
 {
 	int i;
 
-	if (object->instances > 0)
+	if (mxt_obj_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 < mxt_obj_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");
@@ -902,8 +915,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 < mxt_obj_instances(object); j++) {
+			u16 size = mxt_obj_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] 93+ messages in thread

* [PATCH 05/53] Input: atmel_mxt_ts - Select FW_LOADER for firmware code
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (3 preceding siblings ...)
  2013-06-05 17:36 ` [PATCH 04/53] Input: atmel_mxt_ts - define helper functions for size and instances Nick Dyer
@ 2013-06-05 17:36 ` Nick Dyer
  2013-06-05 17:36 ` [PATCH 06/53] Input: atmel_mxt_ts - wait for CHG assert in mxt_check_bootloader Nick Dyer
                   ` (48 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:36 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/Kconfig |    1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index f9a5fd8..beb5ad1 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.
-- 
1.7.10.4


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

* [PATCH 06/53] Input: atmel_mxt_ts - wait for CHG assert in mxt_check_bootloader
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (4 preceding siblings ...)
  2013-06-05 17:36 ` [PATCH 05/53] Input: atmel_mxt_ts - Select FW_LOADER for firmware code Nick Dyer
@ 2013-06-05 17:36 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 07/53] Input: atmel_mxt_ts - wait for CHG after bootloader resets Nick Dyer
                   ` (47 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:36 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

From: Benson Leung <bleung@chromium.org>

The driver should not immediately read bootloader status when
in Application Update Mode. The CHG line will assert when the device
has made a state transition and is ready to report a new status
via i2c.

This change adds a wait for completion in mxt_check_bootloader,
and changes the mxt_interrupt handler to signal the completion.

Signed-off-by: Benson Leung <bleung@chromium.org>
Signed-off-by: Daniel Kurtz <djkurtz@chromium.org>
Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  102 ++++++++++++++++++++++++------
 1 file changed, 81 insertions(+), 21 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 7de3b47..3f75e8c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -15,6 +15,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/firmware.h>
 #include <linux/i2c.h>
@@ -247,16 +248,19 @@ struct mxt_data {
 	const struct mxt_platform_data *pdata;
 	struct mxt_object *object_table;
 	struct mxt_info info;
-
 	unsigned int irq;
 	unsigned int max_x;
 	unsigned int max_y;
+	bool in_bootloader;
 
 	/* Cached parameters from object table */
 	u8 T6_reportid;
 	u8 T9_reportid_min;
 	u8 T9_reportid_max;
 	u8 T19_reportid;
+
+	/* for fw update in bootloader */
+	struct completion bl_completion;
 };
 
 static inline size_t mxt_obj_size(const struct mxt_object *obj)
@@ -340,12 +344,51 @@ static void mxt_dump_message(struct device *dev,
 		message->reportid, 7, message->message);
 }
 
-static int mxt_check_bootloader(struct i2c_client *client,
-				     unsigned int state)
+static int mxt_wait_for_chg(struct mxt_data *data, unsigned int timeout_ms)
+{
+	struct device *dev = &data->client->dev;
+	struct completion *comp = &data->bl_completion;
+	unsigned long timeout = msecs_to_jiffies(timeout_ms);
+	long ret;
+
+	ret = wait_for_completion_interruptible_timeout(comp, timeout);
+	if (ret < 0) {
+		dev_err(dev, "Wait for completion interrupted.\n");
+		return -EINTR;
+	} else if (ret == 0) {
+		dev_err(dev, "Wait for completion timed out.\n");
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+static int mxt_check_bootloader(struct mxt_data *data, unsigned int state)
 {
+	struct i2c_client *client = data->client;
 	u8 val;
+	int ret;
 
 recheck:
+	if (state != MXT_WAITING_BOOTLOAD_CMD) {
+		/*
+		 * In application update mode, the interrupt
+		 * line signals state transitions. We must wait for the
+		 * CHG assertion before reading the status byte.
+		 * Once the status byte has been read, the line is deasserted.
+		 */
+		ret = mxt_wait_for_chg(data, 300);
+		if (ret) {
+			/*
+			 * TODO: handle -EINTR better by terminating fw update
+			 * process before returning to userspace by writing
+			 * length 0x000 to device (iff we are in
+			 * WAITING_FRAME_DATA state).
+			 */
+			dev_err(&client->dev, "Update wait error %d\n", ret);
+			return ret;
+		}
+	}
+
 	if (i2c_master_recv(client, &val, 1) != 1) {
 		dev_err(&client->dev, "%s: i2c recv failed\n", __func__);
 		return -EIO;
@@ -591,9 +634,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;
@@ -633,6 +675,19 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t mxt_interrupt(int irq, void *dev_id)
+{
+	struct mxt_data *data = dev_id;
+
+	if (data->in_bootloader) {
+		/* bootloader state transition completion */
+		complete(&data->bl_completion);
+		return IRQ_HANDLED;
+	}
+
+	return mxt_process_messages_until_invalid(data);
+}
+
 static int mxt_check_reg_init(struct mxt_data *data)
 {
 	const struct mxt_platform_data *pdata = data->pdata;
@@ -948,6 +1003,8 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 	}
 
 	/* Change to the bootloader mode */
+	data->in_bootloader = true;
+
 	mxt_write_object(data, MXT_GEN_COMMAND_T6,
 			MXT_COMMAND_RESET, MXT_BOOT_VALUE);
 	msleep(MXT_RESET_TIME);
@@ -958,18 +1015,19 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 	else
 		client->addr = MXT_BOOT_HIGH;
 
-	ret = mxt_check_bootloader(client, MXT_WAITING_BOOTLOAD_CMD);
+	INIT_COMPLETION(data->bl_completion);
+
+	ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD);
 	if (ret)
-		goto out;
+		goto disable_irq;
 
 	/* Unlock bootloader */
 	mxt_unlock_bootloader(client);
 
 	while (pos < fw->size) {
-		ret = mxt_check_bootloader(client,
-						MXT_WAITING_FRAME_DATA);
+		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);
 		if (ret)
-			goto out;
+			goto disable_irq;
 
 		frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
 
@@ -981,17 +1039,19 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 		/* Write one frame to device */
 		mxt_fw_write(client, fw->data + pos, frame_size);
 
-		ret = mxt_check_bootloader(client,
-						MXT_FRAME_CRC_PASS);
+		ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS);
 		if (ret)
-			goto out;
+			goto disable_irq;
 
 		pos += frame_size;
 
 		dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size);
 	}
 
-out:
+	data->in_bootloader = false;
+
+disable_irq:
+	disable_irq(data->irq);
 	release_firmware(fw);
 
 	/* Change to slave address of application */
@@ -1010,8 +1070,6 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 	struct mxt_data *data = dev_get_drvdata(dev);
 	int error;
 
-	disable_irq(data->irq);
-
 	error = mxt_load_fw(dev, MXT_FW_NAME);
 	if (error) {
 		dev_err(dev, "The firmware update failed(%d)\n", error);
@@ -1025,13 +1083,13 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 		mxt_free_object_table(data);
 
 		mxt_initialize(data);
-	}
 
-	enable_irq(data->irq);
+		enable_irq(data->irq);
 
-	error = mxt_make_highchg(data);
-	if (error)
-		return error;
+		error = mxt_make_highchg(data);
+		if (error)
+			return error;
+	}
 
 	return count;
 }
@@ -1121,6 +1179,8 @@ static int mxt_probe(struct i2c_client *client,
 	data->pdata = pdata;
 	data->irq = client->irq;
 
+	init_completion(&data->bl_completion);
+
 	mxt_calc_resolution(data);
 
 	error = mxt_initialize(data);
-- 
1.7.10.4


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

* [PATCH 07/53] Input: atmel_mxt_ts - wait for CHG after bootloader resets
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (5 preceding siblings ...)
  2013-06-05 17:36 ` [PATCH 06/53] Input: atmel_mxt_ts - wait for CHG assert in mxt_check_bootloader Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 08/53] Input: atmel_mxt_ts - Initialise IRQ before probing Nick Dyer
                   ` (46 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

From: Benson Leung <bleung@chromium.org>

Rather than msleep for MXT_RESET_TIME and MXT_FWRESET_TIME during the
transition to bootloader mode and the transition back from app, wait for the
CHG assert to indicate that the transition is done.

This change replaces the msleep with a wait for completion that the
mxt_interrupt handler signals.

Also add CHG poll after last firmware frame - some bootloader versions will
assert the interrupt line after the final frame, in testing this meant that
the driver attempts to read the info block too early whilst the chip is still
resetting.

This improves firmware update time as we no longer wait longer than necessary
for each reset.

Signed-off-by: Benson Leung <bleung@chromium.org>
Signed-off-by: Daniel Kurtz <djkurtz@chromium.org>
Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 3f75e8c..55d7667 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -181,8 +181,8 @@
 #define MXT_BACKUP_VALUE	0x55
 #define MXT_BACKUP_TIME		50	/* msec */
 #define MXT_RESET_TIME		200	/* msec */
-
-#define MXT_FWRESET_TIME	175	/* msec */
+#define MXT_FW_RESET_TIME	3000	/* msec */
+#define MXT_FW_CHG_TIMEOUT	300	/* msec */
 
 /* Command to unlock bootloader */
 #define MXT_UNLOCK_CMD_MSB	0xaa
@@ -376,7 +376,7 @@ recheck:
 		 * CHG assertion before reading the status byte.
 		 * Once the status byte has been read, the line is deasserted.
 		 */
-		ret = mxt_wait_for_chg(data, 300);
+		ret = mxt_wait_for_chg(data, MXT_FW_CHG_TIMEOUT);
 		if (ret) {
 			/*
 			 * TODO: handle -EINTR better by terminating fw update
@@ -1048,6 +1048,15 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 		dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size);
 	}
 
+	/* Wait for flash. */
+	ret = mxt_wait_for_chg(data, MXT_FW_RESET_TIME);
+	if (ret)
+		goto disable_irq;
+
+	/* Wait for device to reset. Some bootloader versions do not assert
+	 * the CHG line after bootloading has finished, so ignore error */
+	mxt_wait_for_chg(data, MXT_FW_RESET_TIME);
+
 	data->in_bootloader = false;
 
 disable_irq:
@@ -1076,10 +1085,6 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 		count = error;
 	} else {
 		dev_dbg(dev, "The firmware update succeeded\n");
-
-		/* Wait for reset */
-		msleep(MXT_FWRESET_TIME);
-
 		mxt_free_object_table(data);
 
 		mxt_initialize(data);
-- 
1.7.10.4


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

* [PATCH 08/53] Input: atmel_mxt_ts - Initialise IRQ before probing
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (6 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 07/53] Input: atmel_mxt_ts - wait for CHG after bootloader resets Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 09/53] Input: atmel_mxt_ts - Make wait-after-reset period compatible with all chips Nick Dyer
                   ` (45 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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 allows the interrupt handler to be used to detect CHG line during config
download. We need to make sure we do not report events if input device not yet
registered.

data->enable_reporting is checked in each of the possible message handling
function paths rather than higher up (such as at mxt_proc_message) because
some objects may be used for completions (T6).

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   73 +++++++++++++++++++++---------
 1 file changed, 51 insertions(+), 22 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 55d7667..1e24e54 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-2012 Atmel Corporation
  * Copyright (C) 2012 Google, Inc.
  *
  * Author: Joonyoung Shim <jy0922.shim@samsung.com>
@@ -261,6 +262,9 @@ struct mxt_data {
 
 	/* for fw update in bootloader */
 	struct completion bl_completion;
+
+	/* Enable reporting of input events */
+	bool enable_reporting;
 };
 
 static inline size_t mxt_obj_size(const struct mxt_object *obj)
@@ -568,6 +572,10 @@ static void mxt_input_button(struct mxt_data *data, struct mxt_message *message)
 	bool button;
 	int i;
 
+	/* do not report events if input device not yet registered */
+	if (!data->enable_reporting)
+		return;
+
 	/* Active-low switch */
 	for (i = 0; i < pdata->t19_num_keys; i++) {
 		if (pdata->t19_keymap[i] == KEY_RESERVED)
@@ -588,6 +596,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 (!data->enable_reporting)
+		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)
@@ -667,7 +679,7 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 		}
 	} while (reportid != 0xff);
 
-	if (update_input) {
+	if (data->enable_reporting && update_input) {
 		input_mt_report_pointer_emulation(data->input_dev, false);
 		input_sync(data->input_dev);
 	}
@@ -685,6 +697,9 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
 		return IRQ_HANDLED;
 	}
 
+	if (!data->object_table)
+		return IRQ_NONE;
+
 	return mxt_process_messages_until_invalid(data);
 }
 
@@ -746,6 +761,19 @@ static int mxt_make_highchg(struct mxt_data *data)
 	return 0;
 }
 
+static int mxt_acquire_irq(struct mxt_data *data)
+{
+	int error;
+
+	enable_irq(data->irq);
+
+	error = mxt_make_highchg(data);
+	if (error)
+		return error;
+
+	return 0;
+}
+
 static int mxt_get_info(struct mxt_data *data)
 {
 	struct i2c_client *client = data->client;
@@ -819,6 +847,7 @@ static void mxt_free_object_table(struct mxt_data *data)
 {
 	kfree(data->object_table);
 	data->object_table = NULL;
+	data->enable_reporting = false;
 	data->T6_reportid = 0;
 	data->T9_reportid_min = 0;
 	data->T9_reportid_max = 0;
@@ -849,6 +878,10 @@ static int mxt_initialize(struct mxt_data *data)
 	if (error)
 		goto err_free_object_table;
 
+	error = mxt_acquire_irq(data);
+	if (error)
+		goto err_free_object_table;
+
 	/* Check register init values */
 	error = mxt_check_reg_init(data);
 	if (error)
@@ -886,6 +919,8 @@ static int mxt_initialize(struct mxt_data *data)
 			info->matrix_xsize, info->matrix_ysize,
 			info->object_num);
 
+	data->enable_reporting = true;
+
 	return 0;
 
 err_free_object_table:
@@ -1087,11 +1122,7 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 		dev_dbg(dev, "The firmware update succeeded\n");
 		mxt_free_object_table(data);
 
-		mxt_initialize(data);
-
-		enable_irq(data->irq);
-
-		error = mxt_make_highchg(data);
+		error = mxt_initialize(data);
 		if (error)
 			return error;
 	}
@@ -1188,9 +1219,19 @@ static int mxt_probe(struct i2c_client *client,
 
 	mxt_calc_resolution(data);
 
+	error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
+				     pdata->irqflags | IRQF_ONESHOT,
+				     client->name, data);
+	if (error) {
+		dev_err(&client->dev, "Failed to register interrupt\n");
+		goto err_free_mem;
+	}
+
+	disable_irq(client->irq);
+
 	error = mxt_initialize(data);
 	if (error)
-		goto err_free_mem;
+		goto err_free_irq;
 
 	__set_bit(EV_ABS, input_dev->evbit);
 	__set_bit(EV_KEY, input_dev->evbit);
@@ -1241,21 +1282,9 @@ static int mxt_probe(struct i2c_client *client,
 	input_set_drvdata(input_dev, data);
 	i2c_set_clientdata(client, data);
 
-	error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
-				     pdata->irqflags | IRQF_ONESHOT,
-				     client->name, data);
-	if (error) {
-		dev_err(&client->dev, "Failed to register interrupt\n");
-		goto err_free_object;
-	}
-
-	error = mxt_make_highchg(data);
-	if (error)
-		goto err_free_irq;
-
 	error = input_register_device(input_dev);
 	if (error)
-		goto err_free_irq;
+		goto err_free_object;
 
 	error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
 	if (error)
@@ -1266,10 +1295,10 @@ static int mxt_probe(struct i2c_client *client,
 err_unregister_device:
 	input_unregister_device(input_dev);
 	input_dev = NULL;
-err_free_irq:
-	free_irq(client->irq, data);
 err_free_object:
 	kfree(data->object_table);
+err_free_irq:
+	free_irq(client->irq, data);
 err_free_mem:
 	input_free_device(input_dev);
 	kfree(data);
-- 
1.7.10.4


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

* [PATCH 09/53] Input: atmel_mxt_ts - Make wait-after-reset period compatible with all chips
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (7 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 08/53] Input: atmel_mxt_ts - Initialise IRQ before probing Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs Nick Dyer
                   ` (44 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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 an interrupt and a T6 status message
with the RESET bit set is a better behaviour.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  109 ++++++++++++++++++++++++------
 1 file changed, 87 insertions(+), 22 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 1e24e54..11ee78a 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -88,6 +88,9 @@
 #define MXT_COMMAND_REPORTALL	3
 #define MXT_COMMAND_DIAGNOSTIC	5
 
+/* Define for T6 status byte */
+#define MXT_T6_STATUS_RESET	(1 << 7)
+
 /* MXT_GEN_POWER_T7 field */
 #define MXT_POWER_IDLEACQINT	0
 #define MXT_POWER_ACTVACQINT	1
@@ -179,9 +182,13 @@
 
 /* Define for MXT_GEN_COMMAND_T6 */
 #define MXT_BOOT_VALUE		0xa5
+#define MXT_RESET_VALUE		0x01
 #define MXT_BACKUP_VALUE	0x55
+
+/* Delay times */
 #define MXT_BACKUP_TIME		50	/* msec */
 #define MXT_RESET_TIME		200	/* msec */
+#define MXT_RESET_TIMEOUT	3000	/* msec */
 #define MXT_FW_RESET_TIME	3000	/* msec */
 #define MXT_FW_CHG_TIMEOUT	300	/* msec */
 
@@ -256,6 +263,7 @@ struct mxt_data {
 
 	/* Cached parameters from object table */
 	u8 T6_reportid;
+	u16 T6_address;
 	u8 T9_reportid_min;
 	u8 T9_reportid_max;
 	u8 T19_reportid;
@@ -263,6 +271,9 @@ struct mxt_data {
 	/* for fw update in bootloader */
 	struct completion bl_completion;
 
+	/* for reset handling */
+	struct completion reset_completion;
+
 	/* Enable reporting of input events */
 	bool enable_reporting;
 };
@@ -348,10 +359,10 @@ static void mxt_dump_message(struct device *dev,
 		message->reportid, 7, message->message);
 }
 
-static int mxt_wait_for_chg(struct mxt_data *data, unsigned int timeout_ms)
+static int mxt_wait_for_completion(struct mxt_data *data,
+			struct completion *comp, unsigned int timeout_ms)
 {
 	struct device *dev = &data->client->dev;
-	struct completion *comp = &data->bl_completion;
 	unsigned long timeout = msecs_to_jiffies(timeout_ms);
 	long ret;
 
@@ -380,7 +391,8 @@ recheck:
 		 * CHG assertion before reading the status byte.
 		 * Once the status byte has been read, the line is deasserted.
 		 */
-		ret = mxt_wait_for_chg(data, MXT_FW_CHG_TIMEOUT);
+		ret = mxt_wait_for_completion(data, &data->bl_completion,
+					      MXT_FW_CHG_TIMEOUT);
 		if (ret) {
 			/*
 			 * TODO: handle -EINTR better by terminating fw update
@@ -667,6 +679,9 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 			unsigned csum = mxt_extract_T6_csum(&payload[1]);
 			dev_dbg(dev, "Status: %02x Config Checksum: %06x\n",
 				status, csum);
+
+			if (status & MXT_T6_STATUS_RESET)
+				complete(&data->reset_completion);
 		} else if (mxt_is_T9_message(data, &message)) {
 			int id = reportid - data->T9_reportid_min;
 			mxt_input_touchevent(data, &message, id);
@@ -703,6 +718,59 @@ static irqreturn_t mxt_interrupt(int irq, void *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;
+	u8 command_register;
+	int timeout_counter = 0;
+	int ret;
+
+	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)
+{
+	struct device *dev = &data->client->dev;
+	int ret = 0;
+
+	dev_info(dev, "Resetting chip\n");
+
+	INIT_COMPLETION(data->reset_completion);
+
+	ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_RESET_VALUE, false);
+	if (ret)
+		return ret;
+
+	ret = mxt_wait_for_completion(data, &data->reset_completion,
+				      MXT_RESET_TIMEOUT);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 static int mxt_check_reg_init(struct mxt_data *data)
 {
 	const struct mxt_platform_data *pdata = data->pdata;
@@ -829,6 +897,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;
@@ -887,16 +956,10 @@ static int mxt_initialize(struct mxt_data *data)
 	if (error)
 		goto err_free_object_table;
 
-	/* 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);
 
 	/* Update matrix size at info struct */
 	error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
@@ -1040,8 +1103,10 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 	/* Change to the bootloader mode */
 	data->in_bootloader = true;
 
-	mxt_write_object(data, MXT_GEN_COMMAND_T6,
-			MXT_COMMAND_RESET, MXT_BOOT_VALUE);
+	ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_BOOT_VALUE, false);
+	if (ret)
+		goto release_firmware;
+
 	msleep(MXT_RESET_TIME);
 
 	/* Change to slave address of bootloader */
@@ -1084,18 +1149,21 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 	}
 
 	/* Wait for flash. */
-	ret = mxt_wait_for_chg(data, MXT_FW_RESET_TIME);
+	ret = mxt_wait_for_completion(data, &data->bl_completion,
+				MXT_FW_RESET_TIME);
 	if (ret)
 		goto disable_irq;
 
 	/* Wait for device to reset. Some bootloader versions do not assert
 	 * the CHG line after bootloading has finished, so ignore error */
-	mxt_wait_for_chg(data, MXT_FW_RESET_TIME);
+	mxt_wait_for_completion(data, &data->bl_completion,
+				MXT_FW_RESET_TIME);
 
 	data->in_bootloader = false;
 
 disable_irq:
 	disable_irq(data->irq);
+release_firmware:
 	release_firmware(fw);
 
 	/* Change to slave address of application */
@@ -1216,6 +1284,7 @@ static int mxt_probe(struct i2c_client *client,
 	data->irq = client->irq;
 
 	init_completion(&data->bl_completion);
+	init_completion(&data->reset_completion);
 
 	mxt_calc_resolution(data);
 
@@ -1341,11 +1410,7 @@ 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);
+	mxt_soft_reset(data);
 
 	mutex_lock(&input_dev->mutex);
 
-- 
1.7.10.4


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

* [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (8 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 09/53] Input: atmel_mxt_ts - Make wait-after-reset period compatible with all chips Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:57   ` Dmitry Torokhov
  2013-06-06 18:01   ` Greg KH
  2013-06-05 17:37 ` [PATCH 11/53] Input: atmel_mxt_ts - Implement debug output for messages Nick Dyer
                   ` (43 subsequent siblings)
  53 siblings, 2 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   82 ++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 11ee78a..b4bc16f 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -52,6 +52,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
@@ -260,6 +262,8 @@ struct mxt_data {
 	unsigned int max_x;
 	unsigned int max_y;
 	bool in_bootloader;
+	u16 mem_size;
+	struct bin_attribute mem_access_attr;
 
 	/* Cached parameters from object table */
 	u8 T6_reportid;
@@ -863,6 +867,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,
@@ -872,6 +877,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;
@@ -907,6 +913,12 @@ static int mxt_get_object_table(struct mxt_data *data)
 			data->T19_reportid = min_id;
 			break;
 		}
+
+		end_address = object->start_address
+			+ mxt_obj_size(object) * mxt_obj_instances(object) - 1;
+
+		if (end_address >= data->mem_size)
+			data->mem_size = end_address + 1;
 	}
 
 	return 0;
@@ -1198,6 +1210,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);
@@ -1359,8 +1421,24 @@ 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;
@@ -1378,6 +1456,10 @@ static int mxt_remove(struct i2c_client *client)
 {
 	struct mxt_data *data = i2c_get_clientdata(client);
 
+	if (data->mem_access_attr.attr.name)
+		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] 93+ messages in thread

* [PATCH 11/53] Input: atmel_mxt_ts - Implement debug output for messages
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (9 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 12/53] Input: atmel_mxt_ts - Improve error reporting and debug Nick Dyer
                   ` (42 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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. Enabling this output does
impact touch performance.

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

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b4bc16f..08cd7ff 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -83,6 +83,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
@@ -264,6 +267,7 @@ struct mxt_data {
 	bool in_bootloader;
 	u16 mem_size;
 	struct bin_attribute mem_access_attr;
+	bool debug_enabled;
 
 	/* Cached parameters from object table */
 	u8 T6_reportid;
@@ -356,11 +360,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_wait_for_completion(struct mxt_data *data,
@@ -669,6 +672,7 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 	struct device *dev = &data->client->dev;
 	u8 reportid;
 	bool update_input = false;
+	bool dump;
 
 	do {
 		if (mxt_read_message(data, &message)) {
@@ -677,6 +681,7 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 		}
 
 		reportid = message.reportid;
+		dump = data->debug_enabled;
 
 		if (reportid == data->T6_reportid) {
 			u8 status = payload[0];
@@ -694,9 +699,12 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 			mxt_input_button(data, &message);
 			update_input = true;
 		} else {
-			mxt_dump_message(dev, &message);
+			dump = true;
 		}
-	} while (reportid != 0xff);
+
+		if (dump)
+			mxt_dump_message(dev, &message);
+	} while (reportid != MXT_RPTID_NOMSG);
 
 	if (data->enable_reporting && update_input) {
 		input_mt_report_pointer_emulation(data->input_dev, false);
@@ -823,7 +831,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");
@@ -1210,6 +1218,33 @@ 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);
+	char c;
+
+	c = data->debug_enabled ? '1' : '0';
+	return scnprintf(buf, PAGE_SIZE, "%c\n", c);
+}
+
+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)
 {
@@ -1264,12 +1299,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] 93+ messages in thread

* [PATCH 12/53] Input: atmel_mxt_ts - Improve error reporting and debug
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (10 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 11/53] Input: atmel_mxt_ts - Implement debug output for messages Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 13/53] Input: atmel_mxt_ts - Implement CRC check for configuration data Nick Dyer
                   ` (41 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   33 +++++++++++++++++++++---------
 1 file changed, 23 insertions(+), 10 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 08cd7ff..82b001d 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -431,7 +431,8 @@ recheck:
 	}
 
 	if (val != state) {
-		dev_err(&client->dev, "Unvalid bootloader mode state\n");
+		dev_err(&client->dev, "Invalid bootloader state %02X != %02X\n",
+			val, state);
 		return -EINVAL;
 	}
 
@@ -551,7 +552,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;
 }
 
@@ -903,7 +904,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,
 			mxt_obj_size(object), mxt_obj_instances(object),
 			min_id, max_id);
@@ -964,8 +965,10 @@ static int mxt_initialize(struct mxt_data *data)
 
 	/* Get object table information */
 	error = mxt_get_object_table(data);
-	if (error)
+	if (error) {
+		dev_err(&client->dev, "Error %d reading object table\n", error);
 		goto err_free_object_table;
+	}
 
 	error = mxt_acquire_irq(data);
 	if (error)
@@ -973,8 +976,11 @@ static int mxt_initialize(struct mxt_data *data)
 
 	/* Check register init values */
 	error = mxt_check_reg_init(data);
-	if (error)
+	if (error) {
+		dev_err(&client->dev, "Error %d initialising configuration\n",
+			error);
 		goto err_free_object_table;
+	}
 
 	error = mxt_t6_command(data, MXT_COMMAND_BACKUPNV,
 			       MXT_BACKUP_VALUE, false);
@@ -993,12 +999,12 @@ 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: %u Variant: %u Firmware V%u.%u.%02X\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",
+			"Matrix X Size: %u Matrix Y Size: %u Objects: %u\n",
 			info->matrix_xsize, info->matrix_ysize,
 			info->object_num);
 
@@ -1207,7 +1213,8 @@ 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");
+
 		mxt_free_object_table(data);
 
 		error = mxt_initialize(data);
@@ -1452,12 +1459,18 @@ static int mxt_probe(struct i2c_client *client,
 	i2c_set_clientdata(client, data);
 
 	error = input_register_device(input_dev);
-	if (error)
+	if (error) {
+		dev_err(&client->dev, "Error %d registering input device\n",
+			error);
 		goto err_free_object;
+	}
 
 	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] 93+ messages in thread

* [PATCH 13/53] Input: atmel_mxt_ts - Implement CRC check for configuration data
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (11 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 12/53] Input: atmel_mxt_ts - Improve error reporting and debug Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 14/53] Input: atmel_mxt_ts - Download device config using firmware loader Nick Dyer
                   ` (40 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   55 +++++++++++++++++++++++++-----
 include/linux/i2c/atmel_mxt_ts.h         |    1 +
 2 files changed, 48 insertions(+), 8 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 82b001d..434e674 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -194,6 +194,7 @@
 #define MXT_BACKUP_TIME		50	/* msec */
 #define MXT_RESET_TIME		200	/* msec */
 #define MXT_RESET_TIMEOUT	3000	/* msec */
+#define MXT_CRC_TIMEOUT		1000	/* msec */
 #define MXT_FW_RESET_TIME	3000	/* msec */
 #define MXT_FW_CHG_TIMEOUT	300	/* msec */
 
@@ -268,6 +269,7 @@ struct mxt_data {
 	u16 mem_size;
 	struct bin_attribute mem_access_attr;
 	bool debug_enabled;
+	u32 config_crc;
 
 	/* Cached parameters from object table */
 	u8 T6_reportid;
@@ -282,6 +284,9 @@ struct mxt_data {
 	/* for reset handling */
 	struct completion reset_completion;
 
+	/* for reset handling */
+	struct completion crc_completion;
+
 	/* Enable reporting of input events */
 	bool enable_reporting;
 };
@@ -655,7 +660,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);
 }
@@ -674,6 +679,7 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 	u8 reportid;
 	bool update_input = false;
 	bool dump;
+	u32 crc;
 
 	do {
 		if (mxt_read_message(data, &message)) {
@@ -686,9 +692,15 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 
 		if (reportid == data->T6_reportid) {
 			u8 status = payload[0];
-			unsigned csum = mxt_extract_T6_csum(&payload[1]);
+
+			crc = mxt_extract_T6_csum(&payload[1]);
+			if (crc != data->config_crc) {
+				data->config_crc = crc;
+				complete(&data->crc_completion);
+			}
+
 			dev_dbg(dev, "Status: %02x Config Checksum: %06x\n",
-				status, csum);
+				status, data->config_crc);
 
 			if (status & MXT_T6_STATUS_RESET)
 				complete(&data->reset_completion);
@@ -784,6 +796,19 @@ static int mxt_soft_reset(struct mxt_data *data)
 	return 0;
 }
 
+static void mxt_update_crc(struct mxt_data *data, u8 cmd, u8 value)
+{
+	/* on failure, CRC is set to 0 and config will always be downloaded */
+	data->config_crc = 0;
+	INIT_COMPLETION(data->crc_completion);
+
+	mxt_t6_command(data, cmd, value, true);
+
+	/* Wait for crc message. On failure, CRC is set to 0 and config will
+	 * always be downloaded */
+	mxt_wait_for_completion(data, &data->crc_completion, MXT_CRC_TIMEOUT);
+}
+
 static int mxt_check_reg_init(struct mxt_data *data)
 {
 	const struct mxt_platform_data *pdata = data->pdata;
@@ -798,6 +823,16 @@ static int mxt_check_reg_init(struct mxt_data *data)
 		return 0;
 	}
 
+	mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1);
+
+	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;
 
@@ -817,6 +852,14 @@ static int mxt_check_reg_init(struct mxt_data *data)
 		index += size;
 	}
 
+	mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE);
+
+	ret = mxt_soft_reset(data);
+	if (ret)
+		return ret;
+
+	dev_info(dev, "Config written\n");
+
 	return 0;
 }
 
@@ -982,11 +1025,6 @@ static int mxt_initialize(struct mxt_data *data)
 		goto err_free_object_table;
 	}
 
-	error = mxt_t6_command(data, MXT_COMMAND_BACKUPNV,
-			       MXT_BACKUP_VALUE, false);
-	if (!error)
-		mxt_soft_reset(data);
-
 	/* Update matrix size at info struct */
 	error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
 	if (error)
@@ -1392,6 +1430,7 @@ static int mxt_probe(struct i2c_client *client,
 
 	init_completion(&data->bl_completion);
 	init_completion(&data->reset_completion);
+	init_completion(&data->crc_completion);
 
 	mxt_calc_resolution(data);
 
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index d26080d..9f92135 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] 93+ messages in thread

* [PATCH 14/53] Input: atmel_mxt_ts - Download device config using firmware loader
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (12 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 13/53] Input: atmel_mxt_ts - Implement CRC check for configuration data Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 15/53] Input: atmel_mxt_ts - Calculate and check CRC in config file Nick Dyer
                   ` (39 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  234 ++++++++++++++++++++++--------
 drivers/platform/x86/chromeos_laptop.c   |    4 -
 include/linux/i2c/atmel_mxt_ts.h         |    4 -
 3 files changed, 175 insertions(+), 67 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 434e674..7ce8ab4 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -36,8 +36,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
@@ -334,37 +336,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",
@@ -557,7 +528,7 @@ mxt_get_object(struct mxt_data *data, u8 type)
 			return object;
 	}
 
-	dev_err(&data->client->dev, "Invalid object type T%u\n", type);
+	dev_warn(&data->client->dev, "Invalid object type T%u\n", type);
 	return NULL;
 }
 
@@ -809,58 +780,203 @@ static void mxt_update_crc(struct mxt_data *data, u8 cmd, u8 value)
 	mxt_wait_for_completion(data, &data->crc_completion, MXT_CRC_TIMEOUT);
 }
 
+/*
+ * mxt_check_reg_init - download configuration to chip
+ *
+ * Atmel Raw Config File Format
+ *
+ * The first four lines of the raw config file contain:
+ *  1) Version
+ *  2) Chip ID Information (first 7 bytes of device memory)
+ *  3) Chip Information Block 24-bit CRC Checksum
+ *  4) Chip Configuration 24-bit CRC Checksum
+ *
+ * The rest of the file consists of one line per object instance:
+ *   <TYPE> <INSTANCE> <SIZE> <CONTENTS>
+ *
+ *   <TYPE> - 2-byte object type as hex
+ *   <INSTANCE> - 2-byte object instance number as hex
+ *   <SIZE> - 2-byte object size as hex
+ *   <CONTENTS> - array of <SIZE> 1-byte hex values
+ */
 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_update_crc(data, MXT_COMMAND_REPORTALL, 1);
 
-	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);
+	if (strncmp(cfg->data, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) {
+		dev_err(dev, "Unrecognised config file\n");
+		ret = -EINVAL;
+		goto release;
 	}
 
-	for (i = 0; i < data->info.object_num; i++) {
-		object = data->object_table + i;
+	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 (!mxt_object_writable(object->type))
+	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 file 0x%06X\n",
+			 data->config_crc, config_crc);
+	}
+
+	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;
+
+		object = mxt_get_object(data, type);
+		if (!object) {
+			/* Skip object */
+			for (i = 0; i < size; i++) {
+				ret = sscanf(cfg->data + pos, "%hhx%n",
+					     &val,
+					     &offset);
+				pos += offset;
+			}
 			continue;
+		}
 
-		size = mxt_obj_size(object) * mxt_obj_instances(object);
-		if (index + size > pdata->config_length) {
-			dev_err(dev, "Not enough config data!\n");
-			return -EINVAL;
+		if (size > mxt_obj_size(object)) {
+			dev_err(dev, "Discarding %u byte(s) in T%u\n",
+				size - mxt_obj_size(object), type);
 		}
 
-		ret = __mxt_write_reg(data->client, object->start_address,
-				size, &pdata->config[index]);
-		if (ret)
-			return ret;
-		index += size;
+		if (instance >= mxt_obj_instances(object)) {
+			dev_err(dev, "Object instances exceeded!\n");
+			ret = -EINVAL;
+			goto release;
+		}
+
+		reg = object->start_address + mxt_obj_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;
+			}
+			pos += offset;
+
+			if (i > mxt_obj_size(object))
+				continue;
+
+			ret = mxt_write_reg(data->client, reg + i, val);
+			if (ret)
+				goto release;
+
+		}
+
+		/* 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 < mxt_obj_size(object)) {
+			dev_info(dev, "Zeroing %u byte(s) in T%d\n",
+				 mxt_obj_size(object) - size, type);
+
+			for (i = size + 1; i < mxt_obj_size(object); i++) {
+				ret = mxt_write_reg(data->client, reg + i, 0);
+				if (ret)
+					goto release;
+			}
+		}
 	}
 
 	mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE);
 
 	ret = mxt_soft_reset(data);
 	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/drivers/platform/x86/chromeos_laptop.c b/drivers/platform/x86/chromeos_laptop.c
index 8026554..4f6f0b8 100644
--- a/drivers/platform/x86/chromeos_laptop.c
+++ b/drivers/platform/x86/chromeos_laptop.c
@@ -86,8 +86,6 @@ static struct mxt_platform_data atmel_224s_tp_platform_data = {
 	.irqflags		= IRQF_TRIGGER_FALLING,
 	.t19_num_keys		= ARRAY_SIZE(mxt_t19_keys),
 	.t19_keymap		= mxt_t19_keys,
-	.config			= NULL,
-	.config_length		= 0,
 };
 
 static struct i2c_board_info __initdata atmel_224s_tp_device = {
@@ -101,8 +99,6 @@ static struct mxt_platform_data atmel_1664s_platform_data = {
 	.y_size			= 2560,
 	.orient			= MXT_ROTATED_90_COUNTER,
 	.irqflags		= IRQF_TRIGGER_FALLING,
-	.config			= NULL,
-	.config_length		= 0,
 };
 
 static struct i2c_board_info __initdata atmel_1664s_device = {
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index 9f92135..b569bb8 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] 93+ messages in thread

* [PATCH 15/53] Input: atmel_mxt_ts - Calculate and check CRC in config file
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (13 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 14/53] Input: atmel_mxt_ts - Download device config using firmware loader Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 16/53] Input: atmel_mxt_ts - Add additional bootloader addresses Nick Dyer
                   ` (38 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  215 ++++++++++++++++++++++--------
 1 file changed, 161 insertions(+), 54 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 7ce8ab4..d620a4a 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -53,7 +53,7 @@
 #define MXT_OBJECT_START	0x07
 
 #define MXT_OBJECT_SIZE		6
-
+#define MXT_INFO_CHECKSUM_SIZE	3
 #define MXT_MAX_BLOCK_WRITE	256
 
 /* Object types */
@@ -272,10 +272,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;
 	u8 T19_reportid;
@@ -780,6 +782,45 @@ static void mxt_update_crc(struct mxt_data *data, u8 cmd, u8 value)
 	mxt_wait_for_completion(data, &data->crc_completion, MXT_CRC_TIMEOUT);
 }
 
+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;
+}
+
 /*
  * mxt_check_reg_init - download configuration to chip
  *
@@ -807,9 +848,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 cfg_start_ofs;
+	u32 info_crc, config_crc, calculated_crc;
+	u8 *config_mem;
+	size_t config_mem_size;
 	unsigned int type, instance, size;
 	u8 val;
 	u16 reg;
@@ -829,11 +874,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) {
@@ -842,7 +887,7 @@ 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) {
@@ -857,123 +902,182 @@ static int mxt_check_reg_init(struct mxt_data *data)
 		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 */
+	cfg_start_ofs = MXT_OBJECT_START
+		+ data->info.object_num * sizeof(struct mxt_object)
+		+ MXT_INFO_CHECKSUM_SIZE;
+	config_mem_size = data->mem_size - cfg_start_ofs;
+	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) {
 			/* Skip object */
 			for (i = 0; i < size; i++) {
-				ret = sscanf(cfg->data + pos, "%hhx%n",
+				ret = sscanf(cfg->data + data_pos, "%hhx%n",
 					     &val,
 					     &offset);
-				pos += offset;
+				data_pos += offset;
 			}
 			continue;
 		}
 
 		if (size > mxt_obj_size(object)) {
-			dev_err(dev, "Discarding %u byte(s) in T%u\n",
-				size - mxt_obj_size(object), type);
+			/* 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 byte(s) in T%u\n",
+				 size - mxt_obj_size(object), type);
+		} else if (mxt_obj_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 %u byte(s) in T%d\n",
+				 mxt_obj_size(object) - size, type);
 		}
 
 		if (instance >= mxt_obj_instances(object)) {
 			dev_err(dev, "Object instances exceeded!\n");
 			ret = -EINVAL;
-			goto release;
+			goto release_mem;
 		}
 
 		reg = object->start_address + mxt_obj_size(object) * instance;
 
 		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;
 			}
-			pos += offset;
+			data_pos += offset;
 
 			if (i > mxt_obj_size(object))
 				continue;
 
-			ret = mxt_write_reg(data->client, reg + i, val);
-			if (ret)
-				goto release;
+			byte_offset = reg + i - cfg_start_ofs;
 
+			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;
+			}
 		}
+	}
 
-		/* 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 < mxt_obj_size(object)) {
-			dev_info(dev, "Zeroing %u byte(s) in T%d\n",
-				 mxt_obj_size(object) - size, type);
+	/* calculate crc of the received configs (not the raw config file) */
+	if (data->T7_address < cfg_start_ofs) {
+		dev_err(dev, "Bad T7 address, T7addr = %x, config offset %x\n",
+			data->T7_address, cfg_start_ofs);
+		ret = 0;
+		goto release_mem;
+	}
 
-			for (i = size + 1; i < mxt_obj_size(object); i++) {
-				ret = mxt_write_reg(data->client, reg + i, 0);
-				if (ret)
-					goto release;
-			}
+	calculated_crc = mxt_calculate_crc(config_mem,
+					   data->T7_address - cfg_start_ofs,
+					   config_mem_size);
+
+	if (config_crc > 0 && (config_crc != calculated_crc))
+		dev_warn(dev, "Config CRC error, calculated=%06X, file=%06X\n",
+			 calculated_crc, config_crc);
+
+	/* 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,
+				      cfg_start_ofs + 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;
 	}
 
 	mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE);
 
 	ret = mxt_soft_reset(data);
 	if (ret)
-		goto release;
+		goto release_mem;
 
 	dev_info(dev, "Config written\n");
 
+release_mem:
+	kfree(config_mem);
 release:
 	release_firmware(cfg);
 	return ret;
@@ -1073,6 +1177,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] 93+ messages in thread

* [PATCH 16/53] Input: atmel_mxt_ts - Add additional bootloader addresses
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (14 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 15/53] Input: atmel_mxt_ts - Calculate and check CRC in config file Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 17/53] Input: atmel_mxt_ts - Read and report bootloader version Nick Dyer
                   ` (37 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Move bootloaders reads/writes into separate functions. Instead of switching
client->addr, define new field bootloader_addr in mxt_data. Implement lookup
calculation for bootloader addresses.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  138 ++++++++++++++++++++----------
 1 file changed, 93 insertions(+), 45 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index d620a4a..842312e 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -30,12 +30,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"
@@ -273,6 +267,7 @@ struct mxt_data {
 	bool debug_enabled;
 	u32 config_crc;
 	u32 info_crc;
+	u8 bootloader_addr;
 
 	/* Cached parameters from object table */
 	u8 T6_reportid;
@@ -362,9 +357,82 @@ static int mxt_wait_for_completion(struct mxt_data *data,
 	return 0;
 }
 
+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);
+
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		ret = (ret < 0) ? ret : -EIO;
+		dev_err(&data->client->dev, "%s: i2c recv failed (%d)\n",
+			__func__, ret);
+	}
+
+	return 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);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		ret = (ret < 0) ? ret : -EIO;
+		dev_err(&data->client->dev, "%s: i2c send failed (%d)\n",
+			__func__, ret);
+	}
+
+	return ret;
+}
+
+static int mxt_lookup_bootloader_address(struct mxt_data *data)
+{
+	u8 appmode = data->client->addr;
+	u8 bootloader;
+
+	switch (appmode) {
+	case 0x4a:
+	case 0x4b:
+	case 0x4c:
+	case 0x4d:
+	case 0x5a:
+	case 0x5b:
+		bootloader = appmode - 0x26;
+		break;
+	default:
+		dev_err(&data->client->dev,
+			"Appmode i2c address 0x%02x not found\n",
+			appmode);
+		return -EINVAL;
+	}
+
+	data->bootloader_addr = bootloader;
+	return 0;
+}
+
 static int mxt_check_bootloader(struct mxt_data *data, unsigned int state)
 {
-	struct i2c_client *client = data->client;
+	struct device *dev = &data->client->dev;
 	u8 val;
 	int ret;
 
@@ -385,15 +453,14 @@ recheck:
 			 * length 0x000 to device (iff we are in
 			 * WAITING_FRAME_DATA state).
 			 */
-			dev_err(&client->dev, "Update wait error %d\n", ret);
+			dev_err(dev, "Update wait error %d\n", ret);
 			return ret;
 		}
 	}
 
-	if (i2c_master_recv(client, &val, 1) != 1) {
-		dev_err(&client->dev, "%s: i2c recv failed\n", __func__);
-		return -EIO;
-	}
+	ret = mxt_bootloader_read(data, &val, 1);
+	if (ret)
+		return ret;
 
 	switch (state) {
 	case MXT_WAITING_BOOTLOAD_CMD:
@@ -409,7 +476,7 @@ recheck:
 	}
 
 	if (val != state) {
-		dev_err(&client->dev, "Invalid bootloader state %02X != %02X\n",
+		dev_err(dev, "Invalid bootloader state %02X != %02X\n",
 			val, state);
 		return -EINVAL;
 	}
@@ -417,28 +484,17 @@ recheck:
 	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)
+		return ret;
 
 	return 0;
 }
@@ -1375,7 +1431,6 @@ 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;
@@ -1387,6 +1442,10 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 		return ret;
 	}
 
+	ret = mxt_lookup_bootloader_address(data);
+	if (ret)
+		goto release_firmware;
+
 	/* Change to the bootloader mode */
 	data->in_bootloader = true;
 
@@ -1396,12 +1455,6 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 
 	msleep(MXT_RESET_TIME);
 
-	/* Change to slave address of bootloader */
-	if (client->addr == MXT_APP_LOW)
-		client->addr = MXT_BOOT_LOW;
-	else
-		client->addr = MXT_BOOT_HIGH;
-
 	INIT_COMPLETION(data->bl_completion);
 
 	ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD);
@@ -1409,7 +1462,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 		goto disable_irq;
 
 	/* Unlock bootloader */
-	mxt_unlock_bootloader(client);
+	mxt_unlock_bootloader(data);
 
 	while (pos < fw->size) {
 		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);
@@ -1424,7 +1477,9 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 		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)
+			goto disable_irq;
 
 		ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS);
 		if (ret)
@@ -1452,13 +1507,6 @@ disable_irq:
 	disable_irq(data->irq);
 release_firmware:
 	release_firmware(fw);
-
-	/* Change to slave address of application */
-	if (client->addr == MXT_BOOT_LOW)
-		client->addr = MXT_APP_LOW;
-	else
-		client->addr = MXT_APP_HIGH;
-
 	return ret;
 }
 
-- 
1.7.10.4


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

* [PATCH 17/53] Input: atmel_mxt_ts - Read and report bootloader version
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (15 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 16/53] Input: atmel_mxt_ts - Add additional bootloader addresses Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 18/53] Input: atmel_mxt_ts - Implement bootloader frame retries Nick Dyer
                   ` (36 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 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 842312e..df8fc1a 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -206,6 +206,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)
@@ -430,6 +432,27 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data)
 	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;
@@ -462,6 +485,9 @@ recheck:
 	if (ret)
 		return ret;
 
+	if (state == MXT_WAITING_BOOTLOAD_CMD)
+		val = mxt_get_bootloader_version(data, val);
+
 	switch (state) {
 	case MXT_WAITING_BOOTLOAD_CMD:
 	case MXT_WAITING_FRAME_DATA:
-- 
1.7.10.4


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

* [PATCH 18/53] Input: atmel_mxt_ts - Implement bootloader frame retries
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (16 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 17/53] Input: atmel_mxt_ts - Read and report bootloader version Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 19/53] Input: atmel_mxt_ts - Improve bootloader progress output Nick Dyer
                   ` (35 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index df8fc1a..2cd8ead 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -494,8 +494,12 @@ recheck:
 		val &= ~MXT_BOOT_STATUS_MASK;
 		break;
 	case MXT_FRAME_CRC_PASS:
-		if (val == MXT_FRAME_CRC_CHECK)
+		if (val == MXT_FRAME_CRC_CHECK) {
 			goto recheck;
+		} else if (val == MXT_FRAME_CRC_FAIL) {
+			dev_err(dev, "Bootloader CRC fail\n");
+			return -EINVAL;
+		}
 		break;
 	default:
 		return -EINVAL;
@@ -1460,6 +1464,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 	const struct firmware *fw = NULL;
 	unsigned int frame_size;
 	unsigned int pos = 0;
+	unsigned int retry = 0;
 	int ret;
 
 	ret = request_firmware(&fw, fn, dev);
@@ -1497,9 +1502,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 
 		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 */
@@ -1508,10 +1511,20 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 			goto disable_irq;
 
 		ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS);
-		if (ret)
-			goto disable_irq;
+		if (ret) {
+			retry++;
 
-		pos += frame_size;
+			/* Back off by 20ms per retry */
+			msleep(retry * 20);
+
+			if (retry > 20) {
+				dev_err(dev, "Retry count exceeded\n");
+				goto disable_irq;
+			}
+		} else {
+			retry = 0;
+			pos += frame_size;
+		}
 
 		dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size);
 	}
-- 
1.7.10.4


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

* [PATCH 19/53] Input: atmel_mxt_ts - Improve bootloader progress output
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (17 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 18/53] Input: atmel_mxt_ts - Implement bootloader frame retries Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 20/53] Input: atmel_mxt_ts - Add check for incorrect firmware file format Nick Dyer
                   ` (34 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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 implementing a frame counter, print out fewer debug messages (the
firmware may contain hundreds of frames).

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 2cd8ead..e8f410c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1465,6 +1465,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 	unsigned int frame_size;
 	unsigned int pos = 0;
 	unsigned int retry = 0;
+	unsigned int frame = 0;
 	int ret;
 
 	ret = request_firmware(&fw, fn, dev);
@@ -1524,9 +1525,12 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 		} else {
 			retry = 0;
 			pos += frame_size;
+			frame++;
 		}
 
-		dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size);
+		if (frame % 50 == 0)
+			dev_info(dev, "Sent %d frames, %d/%zd bytes\n",
+				 frame, pos, fw->size);
 	}
 
 	/* Wait for flash. */
@@ -1535,6 +1539,8 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 	if (ret)
 		goto disable_irq;
 
+	dev_info(dev, "Sent %d frames, %zd bytes\n", frame, pos);
+
 	/* Wait for device to reset. Some bootloader versions do not assert
 	 * the CHG line after bootloading has finished, so ignore error */
 	mxt_wait_for_completion(data, &data->bl_completion,
-- 
1.7.10.4


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

* [PATCH 20/53] Input: atmel_mxt_ts - Add check for incorrect firmware file format
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (18 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 19/53] Input: atmel_mxt_ts - Improve bootloader progress output Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 21/53] Input: atmel_mxt_ts - Read screen config from chip Nick Dyer
                   ` (33 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index e8f410c..7daa413 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1458,6 +1458,28 @@ 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);
@@ -1474,6 +1496,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;
+
 	ret = mxt_lookup_bootloader_address(data);
 	if (ret)
 		goto release_firmware;
-- 
1.7.10.4


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

* [PATCH 21/53] Input: atmel_mxt_ts - Read screen config from chip
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (19 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 20/53] Input: atmel_mxt_ts - Add check for incorrect firmware file format Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 22/53] Input: atmel_mxt_ts - Set default irqflags when there is no pdata Nick Dyer
                   ` (32 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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 touchscreen configuration from the settings that the maXTouch
chip is actually using, we can remove some platform data.

The matrix size is not used for anything, and results in some rather confusing
code to re-read it because it may change when configuration is downloaded, so
don't print it out.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
---
 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   |  136 +++++++++++++---------------
 drivers/platform/x86/chromeos_laptop.c     |    6 --
 include/linux/i2c/atmel_mxt_ts.h           |   14 ---
 6 files changed, 65 insertions(+), 100 deletions(-)

diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
index 4516d26..726e1b7 100644
--- a/arch/arm/mach-exynos/mach-nuri.c
+++ b/arch/arm/mach-exynos/mach-nuri.c
@@ -333,9 +333,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 2461e60..8bc147f 100644
--- a/arch/arm/mach-exynos/mach-universal_c210.c
+++ b/arch/arm/mach-exynos/mach-universal_c210.c
@@ -604,9 +604,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 eca73af..39cacf0 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -239,9 +239,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 7daa413..037f785 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -108,33 +108,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
@@ -219,11 +202,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
 
@@ -564,11 +542,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)
 {
@@ -1296,12 +1269,59 @@ static void mxt_free_object_table(struct mxt_data *data)
 	data->T19_reportid = 0;
 }
 
+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;
+
+	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,
+		 "Touchscreen size X%uY%u\n", 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)
@@ -1334,26 +1354,16 @@ static int mxt_initialize(struct mxt_data *data)
 		goto err_free_object_table;
 	}
 
-	/* Update matrix size at info struct */
-	error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
-	if (error)
-		goto err_free_object_table;
-	info->matrix_xsize = val;
-
-	error = mxt_read_reg(client, MXT_MATRIX_Y_SIZE, &val);
-	if (error)
+	error = mxt_read_t9_resolution(data);
+	if (error) {
+		dev_err(&client->dev, "Failed to initialize T9 resolution\n");
 		goto err_free_object_table;
-	info->matrix_ysize = val;
-
-	dev_info(&client->dev,
-			"Family: %u Variant: %u Firmware V%u.%u.%02X\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 Objects: %u\n",
-			info->matrix_xsize, info->matrix_ysize,
-			info->object_num);
+		 "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
+		 info->family_id, info->variant_id, info->version >> 4,
+		 info->version & 0xf, info->build, info->object_num);
 
 	data->enable_reporting = true;
 
@@ -1364,20 +1374,6 @@ err_free_object_table:
 	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 */
 static ssize_t mxt_fw_version_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
@@ -1775,8 +1771,6 @@ static int mxt_probe(struct i2c_client *client,
 	init_completion(&data->reset_completion);
 	init_completion(&data->crc_completion);
 
-	mxt_calc_resolution(data);
-
 	error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
 				     pdata->irqflags | IRQF_ONESHOT,
 				     client->name, data);
diff --git a/drivers/platform/x86/chromeos_laptop.c b/drivers/platform/x86/chromeos_laptop.c
index 4f6f0b8..545a6d5 100644
--- a/drivers/platform/x86/chromeos_laptop.c
+++ b/drivers/platform/x86/chromeos_laptop.c
@@ -80,9 +80,6 @@ static int mxt_t19_keys[] = {
 };
 
 static struct mxt_platform_data atmel_224s_tp_platform_data = {
-	.x_size			= 102*20,
-	.y_size			= 68*20,
-	.orient			= MXT_VERTICAL_FLIP,
 	.irqflags		= IRQF_TRIGGER_FALLING,
 	.t19_num_keys		= ARRAY_SIZE(mxt_t19_keys),
 	.t19_keymap		= mxt_t19_keys,
@@ -95,9 +92,6 @@ static struct i2c_board_info __initdata atmel_224s_tp_device = {
 };
 
 static struct mxt_platform_data atmel_1664s_platform_data = {
-	.x_size			= 1700,
-	.y_size			= 2560,
-	.orient			= MXT_ROTATED_90_COUNTER,
 	.irqflags		= IRQF_TRIGGER_FALLING,
 };
 
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index b569bb8..02bf6ea 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 t19_num_keys;
 	const unsigned int *t19_keymap;
-- 
1.7.10.4


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

* [PATCH 22/53] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (20 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 21/53] Input: atmel_mxt_ts - Read screen config from chip Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 23/53] Input: atmel_mxt_ts - Use deep sleep mode when stopped Nick Dyer
                   ` (31 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Yufeng Shen, Nick Dyer

From: Yufeng Shen <miletus@chromium.org>

This is the preparation for supporting the code path when there is
platform data provided and still boot the device into a sane state
with backup NVRAM config.

Make the irqflags default to be IRQF_TRIGGER_FALLING if no platform data is
provided.

Signed-off-by: Yufeng Shen <miletus@chromium.org>
Signed-off-by: Daniel Kurtz <djkurtz@chromium.org>
Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   54 +++++++++++++++++++++---------
 1 file changed, 39 insertions(+), 15 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 037f785..41ec122 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -235,7 +235,7 @@ struct mxt_data {
 	struct i2c_client *client;
 	struct input_dev *input_dev;
 	char phys[64];		/* device physical location */
-	const struct mxt_platform_data *pdata;
+	struct mxt_platform_data *pdata;
 	struct mxt_object *object_table;
 	struct mxt_info info;
 	unsigned int irq;
@@ -1729,10 +1729,29 @@ static void mxt_input_close(struct input_dev *dev)
 	mxt_stop(data);
 }
 
+static int mxt_handle_pdata(struct mxt_data *data)
+{
+	data->pdata = dev_get_platdata(&data->client->dev);
+
+	/* Use provided platform data if present */
+	if (data->pdata)
+		return 0;
+
+	data->pdata = kzalloc(sizeof(*data->pdata), GFP_KERNEL);
+	if (!data->pdata) {
+		dev_err(&data->client->dev, "Failed to allocate pdata\n");
+		return -ENOMEM;
+	}
+
+	/* Set default parameters */
+	data->pdata->irqflags = IRQF_TRIGGER_FALLING;
+
+	return 0;
+}
+
 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;
 	struct input_dev *input_dev;
 	int error;
@@ -1740,9 +1759,6 @@ static int mxt_probe(struct i2c_client *client,
 	unsigned int mt_flags = 0;
 	int i;
 
-	if (!pdata)
-		return -EINVAL;
-
 	data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL);
 	input_dev = input_allocate_device();
 	if (!data || !input_dev) {
@@ -1764,19 +1780,23 @@ static int mxt_probe(struct i2c_client *client,
 
 	data->client = client;
 	data->input_dev = input_dev;
-	data->pdata = pdata;
 	data->irq = client->irq;
+	i2c_set_clientdata(client, data);
+
+	error = mxt_handle_pdata(data);
+	if (error)
+		goto err_free_mem;
 
 	init_completion(&data->bl_completion);
 	init_completion(&data->reset_completion);
 	init_completion(&data->crc_completion);
 
-	error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
-				     pdata->irqflags | IRQF_ONESHOT,
+	error = request_threaded_irq(data->irq, NULL, mxt_interrupt,
+				     data->pdata->irqflags | IRQF_ONESHOT,
 				     client->name, data);
 	if (error) {
 		dev_err(&client->dev, "Failed to register interrupt\n");
-		goto err_free_mem;
+		goto err_free_pdata;
 	}
 
 	disable_irq(client->irq);
@@ -1789,13 +1809,13 @@ static int mxt_probe(struct i2c_client *client,
 	__set_bit(EV_KEY, input_dev->evbit);
 	__set_bit(BTN_TOUCH, input_dev->keybit);
 
-	if (pdata->t19_num_keys) {
+	if (data->pdata->t19_num_keys) {
 		__set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
 
-		for (i = 0; i < pdata->t19_num_keys; i++)
-			if (pdata->t19_keymap[i] != KEY_RESERVED)
+		for (i = 0; i < data->pdata->t19_num_keys; i++)
+			if (data->pdata->t19_keymap[i] != KEY_RESERVED)
 				input_set_capability(input_dev, EV_KEY,
-						     pdata->t19_keymap[i]);
+						data->pdata->t19_keymap[i]);
 
 		mt_flags |= INPUT_MT_POINTER;
 
@@ -1832,7 +1852,6 @@ static int mxt_probe(struct i2c_client *client,
 			     0, 255, 0, 0);
 
 	input_set_drvdata(input_dev, data);
-	i2c_set_clientdata(client, data);
 
 	error = input_register_device(input_dev);
 	if (error) {
@@ -1872,7 +1891,10 @@ err_unregister_device:
 err_free_object:
 	kfree(data->object_table);
 err_free_irq:
-	free_irq(client->irq, data);
+	free_irq(data->irq, data);
+err_free_pdata:
+	if (!dev_get_platdata(&data->client->dev))
+		kfree(data->pdata);
 err_free_mem:
 	input_free_device(input_dev);
 	kfree(data);
@@ -1891,6 +1913,8 @@ static int mxt_remove(struct i2c_client *client)
 	free_irq(data->irq, data);
 	input_unregister_device(data->input_dev);
 	kfree(data->object_table);
+	if (!dev_get_platdata(&data->client->dev))
+		kfree(data->pdata);
 	kfree(data);
 
 	return 0;
-- 
1.7.10.4


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

* [PATCH 23/53] Input: atmel_mxt_ts - Use deep sleep mode when stopped
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (21 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 22/53] Input: atmel_mxt_ts - Set default irqflags when there is no pdata Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 24/53] Input: atmel_mxt_ts - Add shutdown function Nick Dyer
                   ` (30 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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 minimal power. It is unnecessary
to change the configuration of any other objects (for example to disable T9
touchscreen).

It is counterproductive to reset the chip on resume, it will result in a long
delay. 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  100 ++++++++++++++++++++++--------
 1 file changed, 74 insertions(+), 26 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 41ec122..b3fe56c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -93,9 +93,13 @@
 #define MXT_T6_STATUS_RESET	(1 << 7)
 
 /* 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
@@ -107,7 +111,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
 
@@ -248,6 +251,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;
@@ -608,20 +612,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 >= mxt_obj_size(object))
-		return -EINVAL;
-
-	reg = object->start_address;
-	return mxt_write_reg(data->client, reg + offset, val);
-}
-
 static void mxt_input_button(struct mxt_data *data, struct mxt_message *message)
 {
 	struct input_dev *input = data->input_dev;
@@ -1142,6 +1132,61 @@ 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");
+			mxt_soft_reset(data);
+			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;
@@ -1354,6 +1399,12 @@ static int mxt_initialize(struct mxt_data *data)
 		goto err_free_object_table;
 	}
 
+	error = mxt_init_t7_power_cfg(data);
+	if (error) {
+		dev_err(&client->dev, "Failed to initialize power cfg\n");
+		goto err_free_object_table;
+	}
+
 	error = mxt_read_t9_resolution(data);
 	if (error) {
 		dev_err(&client->dev, "Failed to initialize T9 resolution\n");
@@ -1701,16 +1752,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)
@@ -1943,8 +1993,6 @@ static int mxt_resume(struct device *dev)
 	struct mxt_data *data = i2c_get_clientdata(client);
 	struct input_dev *input_dev = data->input_dev;
 
-	mxt_soft_reset(data);
-
 	mutex_lock(&input_dev->mutex);
 
 	if (input_dev->users)
-- 
1.7.10.4


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

* [PATCH 24/53] Input: atmel_mxt_ts - Add shutdown function
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (22 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 23/53] Input: atmel_mxt_ts - Use deep sleep mode when stopped Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 25/53] Input: atmel_mxt_ts - Rename pressure to amplitude to match spec Nick Dyer
                   ` (29 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b3fe56c..2e6ddc5 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2006,6 +2006,13 @@ 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);
+}
+
 static const struct i2c_device_id mxt_id[] = {
 	{ "qt602240_ts", 0 },
 	{ "atmel_mxt_ts", 0 },
@@ -2023,6 +2030,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] 93+ messages in thread

* [PATCH 25/53] Input: atmel_mxt_ts - Rename pressure to amplitude to match spec
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (23 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 24/53] Input: atmel_mxt_ts - Add shutdown function Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 26/53] Input: atmel_mxt_ts - Rename touchscreen defines to include T9 Nick Dyer
                   ` (28 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 2e6ddc5..ab6a1f6 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -641,7 +641,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 (!data->enable_reporting)
@@ -655,7 +655,7 @@ static void mxt_input_touchevent(struct mxt_data *data,
 		y = 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",
@@ -668,7 +668,7 @@ static void mxt_input_touchevent(struct mxt_data *data,
 		(status & MXT_AMP) ? 'A' : '.',
 		(status & MXT_SUPPRESS) ? 'S' : '.',
 		(status & MXT_UNGRIP) ? 'U' : '.',
-		x, y, area, pressure);
+		x, y, area, amplitude);
 
 	input_mt_slot(input_dev, id);
 	input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
@@ -677,7 +677,7 @@ static void mxt_input_touchevent(struct mxt_data *data,
 	if (status & MXT_DETECT) {
 		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);
 	}
 }
-- 
1.7.10.4


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

* [PATCH 26/53] Input: atmel_mxt_ts - Rename touchscreen defines to include T9
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (24 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 25/53] Input: atmel_mxt_ts - Rename pressure to amplitude to match spec Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 27/53] Input: atmel_mxt_ts - Handle multiple input reports in one message Nick Dyer
                   ` (27 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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 avoids confusion with the newer T100 touchscreen object.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   46 +++++++++++++++---------------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index ab6a1f6..ad8b803 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -114,13 +114,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
@@ -195,16 +205,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
 
@@ -660,21 +660,21 @@ static void mxt_input_touchevent(struct mxt_data *data,
 	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' : '.',
+		(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);
+				   status & MXT_T9_DETECT);
 
-	if (status & MXT_DETECT) {
+	if (status & MXT_T9_DETECT) {
 		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);
@@ -1348,7 +1348,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] 93+ messages in thread

* [PATCH 27/53] Input: atmel_mxt_ts - Handle multiple input reports in one message
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (25 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 26/53] Input: atmel_mxt_ts - Rename touchscreen defines to include T9 Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 28/53] Input: atmel_mxt_ts - Move input device init into separate function Nick Dyer
                   ` (26 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   34 +++++++++++++++++++++++-------
 1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index ad8b803..c91b22f 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -632,6 +632,12 @@ static void mxt_input_button(struct mxt_data *data, 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)
 {
@@ -649,10 +655,12 @@ 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));
+
+	/* Handle 10/12 bit switching */
 	if (data->max_x < 1024)
-		x = x >> 2;
+		x >>= 2;
 	if (data->max_y < 1024)
-		y = y >> 2;
+		y >>= 2;
 
 	area = message->message[4];
 	amplitude = message->message[5];
@@ -671,14 +679,26 @@ static void mxt_input_touchevent(struct mxt_data *data,
 		x, y, area, amplitude);
 
 	input_mt_slot(input_dev, id);
-	input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
-				   status & MXT_T9_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, 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);
 	}
 }
 
@@ -741,10 +761,8 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 			mxt_dump_message(dev, &message);
 	} while (reportid != MXT_RPTID_NOMSG);
 
-	if (data->enable_reporting && update_input) {
-		input_mt_report_pointer_emulation(data->input_dev, false);
-		input_sync(data->input_dev);
-	}
+	if (data->enable_reporting && update_input)
+		mxt_input_sync(data->input_dev);
 
 	return IRQ_HANDLED;
 }
-- 
1.7.10.4


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

* [PATCH 28/53] Input: atmel_mxt_ts - Move input device init into separate function
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (26 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 27/53] Input: atmel_mxt_ts - Handle multiple input reports in one message Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 29/53] Input: atmel_mxt_ts - Handle APP_CRC_FAIL on startup Nick Dyer
                   ` (25 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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 |  129 +++++++++++++++++-------------
 1 file changed, 75 insertions(+), 54 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index c91b22f..8d63780 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1817,73 +1817,39 @@ static int mxt_handle_pdata(struct mxt_data *data)
 	return 0;
 }
 
-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)
 {
-	struct mxt_data *data;
+	struct device *dev = &data->client->dev;
+	const struct mxt_platform_data *pdata = data->pdata;
 	struct input_dev *input_dev;
 	int error;
 	unsigned int num_mt_slots;
 	unsigned int mt_flags = 0;
 	int i;
 
-	data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL);
 	input_dev = input_allocate_device();
-	if (!data || !input_dev) {
-		dev_err(&client->dev, "Failed to allocate memory\n");
-		error = -ENOMEM;
-		goto err_free_mem;
+	if (!input_dev) {
+		dev_err(dev, "Failed to allocate memory\n");
+		return -ENOMEM;
 	}
 
 	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->dev.parent = dev;
 	input_dev->open = mxt_input_open;
 	input_dev->close = mxt_input_close;
 
-	data->client = client;
-	data->input_dev = input_dev;
-	data->irq = client->irq;
-	i2c_set_clientdata(client, data);
-
-	error = mxt_handle_pdata(data);
-	if (error)
-		goto err_free_mem;
-
-	init_completion(&data->bl_completion);
-	init_completion(&data->reset_completion);
-	init_completion(&data->crc_completion);
-
-	error = request_threaded_irq(data->irq, NULL, mxt_interrupt,
-				     data->pdata->irqflags | IRQF_ONESHOT,
-				     client->name, data);
-	if (error) {
-		dev_err(&client->dev, "Failed to register interrupt\n");
-		goto err_free_pdata;
-	}
-
-	disable_irq(client->irq);
-
-	error = mxt_initialize(data);
-	if (error)
-		goto err_free_irq;
-
 	__set_bit(EV_ABS, input_dev->evbit);
-	__set_bit(EV_KEY, input_dev->evbit);
-	__set_bit(BTN_TOUCH, input_dev->keybit);
+	input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
 
-	if (data->pdata->t19_num_keys) {
+	if (pdata->t19_num_keys) {
 		__set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
 
-		for (i = 0; i < data->pdata->t19_num_keys; i++)
-			if (data->pdata->t19_keymap[i] != KEY_RESERVED)
+		for (i = 0; i < pdata->t19_num_keys; i++)
+			if (pdata->t19_keymap[i] != KEY_RESERVED)
 				input_set_capability(input_dev, EV_KEY,
-						data->pdata->t19_keymap[i]);
+						     pdata->t19_keymap[i]);
 
 		mt_flags |= INPUT_MT_POINTER;
 
@@ -1908,8 +1874,11 @@ static int mxt_probe(struct i2c_client *client,
 	/* For multi touch */
 	num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1;
 	error = input_mt_init_slots(input_dev, num_mt_slots, mt_flags);
-	if (error)
-		goto err_free_object;
+	if (error) {
+		dev_err(dev, "Error %d initialising slots\n", error);
+		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,
@@ -1923,11 +1892,64 @@ static int mxt_probe(struct i2c_client *client,
 
 	error = input_register_device(input_dev);
 	if (error) {
-		dev_err(&client->dev, "Error %d registering input device\n",
-			error);
-		goto err_free_object;
+		dev_err(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)
+{
+	struct mxt_data *data;
+	int error;
+
+	data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL);
+	if (!data) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0",
+		 client->adapter->nr, client->addr);
+
+	data->client = client;
+	data->irq = client->irq;
+	i2c_set_clientdata(client, data);
+
+	error = mxt_handle_pdata(data);
+	if (error)
+		goto err_free_mem;
+
+	init_completion(&data->bl_completion);
+	init_completion(&data->reset_completion);
+	init_completion(&data->crc_completion);
+
+	error = request_threaded_irq(data->irq, NULL, mxt_interrupt,
+				     data->pdata->irqflags | IRQF_ONESHOT,
+				     client->name, data);
+	if (error) {
+		dev_err(&client->dev, "Failed to register interrupt\n");
+		goto err_free_pdata;
+	}
+
+	disable_irq(data->irq);
+
+	error = mxt_initialize(data);
+	if (error)
+		goto err_free_irq;
+
+	error = mxt_initialize_t9_input_device(data);
+	if (error)
+		goto err_free_object;
+
 	error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
 	if (error) {
 		dev_err(&client->dev, "Failure %d creating sysfs group\n",
@@ -1954,8 +1976,8 @@ 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_object:
 	kfree(data->object_table);
 err_free_irq:
@@ -1964,7 +1986,6 @@ err_free_pdata:
 	if (!dev_get_platdata(&data->client->dev))
 		kfree(data->pdata);
 err_free_mem:
-	input_free_device(input_dev);
 	kfree(data);
 	return error;
 }
-- 
1.7.10.4


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

* [PATCH 29/53] Input: atmel_mxt_ts - Handle APP_CRC_FAIL on startup
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (27 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 28/53] Input: atmel_mxt_ts - Move input device init into separate function Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 30/53] Input: atmel_mxt_ts - Handle bootloader previously unlocked Nick Dyer
                   ` (24 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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 bootloader fails to start the appmode image on the touch controller, it
stays in bootloader mode. It is possible to reflash a working firmware image
from this state.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   61 +++++++++++++++++++++++-------
 1 file changed, 48 insertions(+), 13 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 8d63780..c18803a 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -414,6 +414,30 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data)
 	return 0;
 }
 
+static int mxt_probe_bootloader(struct mxt_data *data)
+{
+	struct device *dev = &data->client->dev;
+	int ret;
+	u8 val;
+	bool crc_failure;
+
+	ret = mxt_lookup_bootloader_address(data);
+	if (ret)
+		return ret;
+
+	ret = mxt_bootloader_read(data, &val, 1);
+	if (ret)
+		return ret;
+
+	/* 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;
@@ -473,6 +497,7 @@ recheck:
 	switch (state) {
 	case MXT_WAITING_BOOTLOAD_CMD:
 	case MXT_WAITING_FRAME_DATA:
+	case MXT_APP_CRC_FAIL:
 		val &= ~MXT_BOOT_STATUS_MASK;
 		break;
 	case MXT_FRAME_CRC_PASS:
@@ -1387,8 +1412,14 @@ static int mxt_initialize(struct mxt_data *data)
 	int error;
 
 	error = mxt_get_info(data);
-	if (error)
-		return error;
+	if (error) {
+		error = mxt_probe_bootloader(data);
+		if (error)
+			return error;
+
+		data->in_bootloader = true;
+		return 0;
+	}
 
 	data->object_table = kcalloc(info->object_num,
 				     sizeof(struct mxt_object),
@@ -1570,15 +1601,19 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 	if (ret)
 		goto release_firmware;
 
-	/* Change to the bootloader mode */
-	data->in_bootloader = true;
+	if (!data->in_bootloader) {
+		/* Change to the bootloader mode */
+		data->in_bootloader = true;
 
-	ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_BOOT_VALUE, false);
-	if (ret)
-		goto release_firmware;
+		ret = mxt_t6_command(data, MXT_COMMAND_RESET,
+				     MXT_BOOT_VALUE, false);
+		if (ret)
+			goto release_firmware;
 
-	msleep(MXT_RESET_TIME);
+		msleep(MXT_RESET_TIME);
+	}
 
+	mxt_free_object_table(data);
 	INIT_COMPLETION(data->bl_completion);
 
 	ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD);
@@ -1661,8 +1696,6 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 	} else {
 		dev_info(dev, "The firmware update succeeded\n");
 
-		mxt_free_object_table(data);
-
 		error = mxt_initialize(data);
 		if (error)
 			return error;
@@ -1946,9 +1979,11 @@ static int mxt_probe(struct i2c_client *client,
 	if (error)
 		goto err_free_irq;
 
-	error = mxt_initialize_t9_input_device(data);
-	if (error)
-		goto err_free_object;
+	if (!data->in_bootloader) {
+		error = mxt_initialize_t9_input_device(data);
+		if (error)
+			goto err_free_object;
+	}
 
 	error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
 	if (error) {
-- 
1.7.10.4


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

* [PATCH 30/53] Input: atmel_mxt_ts - Handle bootloader previously unlocked
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (28 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 29/53] Input: atmel_mxt_ts - Handle APP_CRC_FAIL on startup Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 31/53] Input: atmel_mxt_ts - Add bootloader addresses for new chips Nick Dyer
                   ` (23 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index c18803a..125fe2f 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -459,14 +459,15 @@ static u8 mxt_get_bootloader_version(struct mxt_data *data, u8 val)
 	}
 }
 
-static int mxt_check_bootloader(struct mxt_data *data, unsigned int state)
+static int mxt_check_bootloader(struct mxt_data *data, unsigned int state,
+				bool wait)
 {
 	struct device *dev = &data->client->dev;
 	u8 val;
 	int ret;
 
 recheck:
-	if (state != MXT_WAITING_BOOTLOAD_CMD) {
+	if (wait) {
 		/*
 		 * In application update mode, the interrupt
 		 * line signals state transitions. We must wait for the
@@ -1616,15 +1617,24 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 	mxt_free_object_table(data);
 	INIT_COMPLETION(data->bl_completion);
 
-	ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD);
-	if (ret)
-		goto disable_irq;
+	ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD, false);
+	if (ret) {
+		/* Bootloader may still be unlocked from previous update
+		 * attempt */
+		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, false);
+		if (ret)
+			goto disable_irq;
+	} else {
+		dev_info(dev, "Unlocking bootloader\n");
 
-	/* Unlock bootloader */
-	mxt_unlock_bootloader(data);
+		/* Unlock bootloader */
+		ret = mxt_unlock_bootloader(data);
+		if (ret)
+			goto disable_irq;
+	}
 
 	while (pos < fw->size) {
-		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);
+		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, true);
 		if (ret)
 			goto disable_irq;
 
@@ -1638,7 +1648,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 		if (ret)
 			goto disable_irq;
 
-		ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS);
+		ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS, true);
 		if (ret) {
 			retry++;
 
-- 
1.7.10.4


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

* [PATCH 31/53] Input: atmel_mxt_ts - Add bootloader addresses for new chips
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (29 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 30/53] Input: atmel_mxt_ts - Handle bootloader previously unlocked Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 32/53] Input: atmel_mxt_ts - Recover from bootloader on probe Nick Dyer
                   ` (22 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Later chips (for example mXT1664S) different mappings for bootloader addresses.
This means that we must look at the family ID to determine which address to
use. There is an additional complication: when we probe and we don't know the
family ID yet, we need to try both possible addresses to find the bootloader.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 125fe2f..06b631b 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -397,6 +397,12 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data)
 	switch (appmode) {
 	case 0x4a:
 	case 0x4b:
+		/* Chips after 1664S use different scheme */
+		if (data->info.family_id >= 0xa2) {
+			bootloader = appmode - 0x24;
+			break;
+		}
+		/* Fall through for normal case */
 	case 0x4c:
 	case 0x4d:
 	case 0x5a:
-- 
1.7.10.4


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

* [PATCH 32/53] Input: atmel_mxt_ts - Recover from bootloader on probe
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (30 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 31/53] Input: atmel_mxt_ts - Add bootloader addresses for new chips Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 33/53] Input: atmel_mxt_ts - Add support for dynamic message size Nick Dyer
                   ` (21 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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 while 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 |   68 ++++++++++++++++++++++--------
 1 file changed, 51 insertions(+), 17 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 06b631b..ae9ea93 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -389,7 +389,7 @@ static int mxt_bootloader_write(struct mxt_data *data,
 	return ret;
 }
 
-static int mxt_lookup_bootloader_address(struct mxt_data *data)
+static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry)
 {
 	u8 appmode = data->client->addr;
 	u8 bootloader;
@@ -398,7 +398,7 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data)
 	case 0x4a:
 	case 0x4b:
 		/* Chips after 1664S use different scheme */
-		if (data->info.family_id >= 0xa2) {
+		if (retry || data->info.family_id >= 0xa2) {
 			bootloader = appmode - 0x24;
 			break;
 		}
@@ -420,14 +420,14 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data)
 	return 0;
 }
 
-static int mxt_probe_bootloader(struct mxt_data *data)
+static int mxt_probe_bootloader(struct mxt_data *data, bool retry)
 {
 	struct device *dev = &data->client->dev;
 	int ret;
 	u8 val;
 	bool crc_failure;
 
-	ret = mxt_lookup_bootloader_address(data);
+	ret = mxt_lookup_bootloader_address(data, retry);
 	if (ret)
 		return ret;
 
@@ -528,13 +528,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)
@@ -1417,15 +1422,40 @@ static int mxt_initialize(struct mxt_data *data)
 	struct i2c_client *client = data->client;
 	struct mxt_info *info = &data->info;
 	int error;
+	bool alt_bootloader_addr = false;
+	bool retry = false;
 
+retry_info:
 	error = mxt_get_info(data);
 	if (error) {
-		error = mxt_probe_bootloader(data);
-		if (error)
-			return error;
+retry_bootloader:
+		error = mxt_probe_bootloader(data, alt_bootloader_addr);
+		if (error) {
+			if (alt_bootloader_addr) {
+				/* Chip is not in appmode or bootloader mode */
+				return error;
+			}
 
-		data->in_bootloader = true;
-		return 0;
+			dev_info(&client->dev, "Trying alternate bootloader address\n");
+			alt_bootloader_addr = true;
+			goto retry_bootloader;
+		} else {
+			if (retry) {
+				dev_err(&client->dev,
+						"Could not recover device from "
+						"bootloader mode\n");
+				/* this is not an error state, we can reflash
+				 * from here */
+				data->in_bootloader = true;
+				return 0;
+			}
+
+			/* Attempt to exit bootloader into app mode */
+			mxt_send_bootloader_cmd(data, false);
+			msleep(MXT_FW_RESET_TIME);
+			retry = true;
+			goto retry_info;
+		}
 	}
 
 	data->object_table = kcalloc(info->object_num,
@@ -1604,10 +1634,6 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 	if (ret)
 		goto release_firmware;
 
-	ret = mxt_lookup_bootloader_address(data);
-	if (ret)
-		goto release_firmware;
-
 	if (!data->in_bootloader) {
 		/* Change to the bootloader mode */
 		data->in_bootloader = true;
@@ -1618,6 +1644,14 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 			goto release_firmware;
 
 		msleep(MXT_RESET_TIME);
+
+		/* At this stage, do not need to scan since we know
+		 * family ID */
+		ret = mxt_lookup_bootloader_address(data, 0);
+		if (ret)
+			goto release_firmware;
+	} else {
+		enable_irq(data->irq);
 	}
 
 	mxt_free_object_table(data);
@@ -1634,7 +1668,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)
 			goto disable_irq;
 	}
-- 
1.7.10.4


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

* [PATCH 33/53] Input: atmel_mxt_ts - Add support for dynamic message size
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (31 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 32/53] Input: atmel_mxt_ts - Recover from bootloader on probe Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 34/53] Input: atmel_mxt_ts - Decode T6 status messages Nick Dyer
                   ` (20 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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 T5 object may have various sizes depending on the objects used on the
particular maXTouch chip and firmware version, 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  108 +++++++++++++++++-------------
 1 file changed, 61 insertions(+), 47 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index ae9ea93..76ad308 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -228,11 +228,6 @@ struct mxt_object {
 	u8 num_report_ids;
 } __packed;
 
-struct mxt_message {
-	u8 reportid;
-	u8 message[7];
-};
-
 /* Each client has this additional data */
 struct mxt_data {
 	struct i2c_client *client;
@@ -252,8 +247,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;
@@ -317,10 +314,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_wait_for_completion(struct mxt_data *data,
@@ -634,8 +631,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;
@@ -646,10 +642,10 @@ 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_button(struct mxt_data *data, struct mxt_message *message)
+static void mxt_input_button(struct mxt_data *data, u8 *message)
 {
 	struct input_dev *input = data->input_dev;
 	const struct mxt_platform_data *pdata = data->pdata;
@@ -664,7 +660,7 @@ static void mxt_input_button(struct mxt_data *data, struct mxt_message *message)
 	for (i = 0; i < pdata->t19_num_keys; i++) {
 		if (pdata->t19_keymap[i] == KEY_RESERVED)
 			continue;
-		button = !(message->message[0] & (1 << i));
+		button = !(message[1] & (1 << i));
 		input_report_key(input, pdata->t19_keymap[i], button);
 	}
 }
@@ -675,12 +671,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;
@@ -690,8 +686,10 @@ static void mxt_input_touchevent(struct mxt_data *data,
 	if (!data->enable_reporting)
 		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));
 
 	/* Handle 10/12 bit switching */
 	if (data->max_x < 1024)
@@ -699,8 +697,8 @@ static void mxt_input_touchevent(struct mxt_data *data,
 	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",
@@ -744,16 +742,16 @@ 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;
@@ -761,12 +759,12 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 	u32 crc;
 
 	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];
 		dump = data->debug_enabled;
 
 		if (reportid == data->T6_reportid) {
@@ -783,19 +781,18 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 
 			if (status & MXT_T6_STATUS_RESET)
 				complete(&data->reset_completion);
-		} 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;
-		} else if (message.reportid == data->T19_reportid) {
-			mxt_input_button(data, &message);
+		} else if (reportid == data->T19_reportid) {
+			mxt_input_button(data, message);
 			update_input = true;
 		} else {
 			dump = true;
 		}
 
 		if (dump)
-			mxt_dump_message(dev, &message);
+			mxt_dump_message(data, message);
 	} while (reportid != MXT_RPTID_NOMSG);
 
 	if (data->enable_reporting && update_input)
@@ -1245,16 +1242,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");
@@ -1291,6 +1287,21 @@ 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->enable_reporting = false;
+	data->T5_msg_size = 0;
+	data->T6_reportid = 0;
+	data->T7_address = 0;
+	data->T9_reportid_min = 0;
+	data->T9_reportid_max = 0;
+	data->T19_reportid = 0;
+}
+
 static int mxt_get_object_table(struct mxt_data *data)
 {
 	struct i2c_client *client = data->client;
@@ -1332,6 +1343,9 @@ static int mxt_get_object_table(struct mxt_data *data)
 			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 = mxt_obj_size(object) - 1;
 		case MXT_GEN_COMMAND_T6:
 			data->T6_reportid = min_id;
 			data->T6_address = object->start_address;
@@ -1355,18 +1369,18 @@ 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);
+	if (!data->msg_buf) {
+		dev_err(&client->dev, "Failed to allocate message buffer\n");
+		error = -ENOMEM;
+		goto free_object_table;
+	}
+
 	return 0;
-}
 
-static void mxt_free_object_table(struct mxt_data *data)
-{
-	kfree(data->object_table);
-	data->object_table = NULL;
-	data->enable_reporting = false;
-	data->T6_reportid = 0;
-	data->T9_reportid_min = 0;
-	data->T9_reportid_max = 0;
-	data->T19_reportid = 0;
+free_object_table:
+	mxt_free_object_table(data);
+	return error;
 }
 
 static int mxt_read_t9_resolution(struct mxt_data *data)
@@ -2064,7 +2078,7 @@ err_unregister_device:
 	input_unregister_device(data->input_dev);
 	data->input_dev = NULL;
 err_free_object:
-	kfree(data->object_table);
+	mxt_free_object_table(data);
 err_free_irq:
 	free_irq(data->irq, data);
 err_free_pdata:
@@ -2086,7 +2100,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);
 	if (!dev_get_platdata(&data->client->dev))
 		kfree(data->pdata);
 	kfree(data);
-- 
1.7.10.4


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

* [PATCH 34/53] Input: atmel_mxt_ts - Decode T6 status messages
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (32 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 33/53] Input: atmel_mxt_ts - Add support for dynamic message size Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 35/53] Input: atmel_mxt_ts - Split message handler into separate functions Nick Dyer
                   ` (19 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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 storing the previous T6 status byte we can detect reset completion more
correctly, and multiple debug output of the same status can be suppressed (for
example CFGERR).

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   60 ++++++++++++++++++++----------
 1 file changed, 40 insertions(+), 20 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 76ad308..39a20fd 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -91,6 +91,11 @@
 
 /* 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 {
@@ -248,6 +253,7 @@ struct mxt_data {
 	u8 bootloader_addr;
 	struct t7_config t7_cfg;
 	u8 *msg_buf;
+	u8 t6_status;
 
 	/* Cached parameters from object table */
 	u8 T5_msg_size;
@@ -631,6 +637,39 @@ 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);
+		complete(&data->crc_completion);
+	}
+
+	/* Detect transition out of reset */
+	if ((data->t6_status & MXT_T6_STATUS_RESET) &&
+	    !(status & MXT_T6_STATUS_RESET))
+		complete(&data->reset_completion);
+
+	/* Output debug if status has changed */
+	if (status != data->t6_status)
+		dev_dbg(dev, "T6 Status 0x%02X%s%s%s%s%s%s%s\n",
+			status,
+			(status == 0) ? " OK" : "",
+			(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" : "");
+
+	/* Save current status */
+	data->t6_status = status;
+}
+
 static int mxt_read_message(struct mxt_data *data, u8 *message)
 {
 	struct mxt_object *object;
@@ -737,11 +776,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];
@@ -751,12 +785,10 @@ 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;
 	bool dump;
-	u32 crc;
 
 	do {
 		if (mxt_read_message(data, message)) {
@@ -768,19 +800,7 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 		dump = data->debug_enabled;
 
 		if (reportid == data->T6_reportid) {
-			u8 status = payload[0];
-
-			crc = mxt_extract_T6_csum(&payload[1]);
-			if (crc != data->config_crc) {
-				data->config_crc = crc;
-				complete(&data->crc_completion);
-			}
-
-			dev_dbg(dev, "Status: %02x Config Checksum: %06x\n",
-				status, data->config_crc);
-
-			if (status & MXT_T6_STATUS_RESET)
-				complete(&data->reset_completion);
+			mxt_proc_t6_messages(data, message);
 		} else if (mxt_is_T9_message(data, message)) {
 			mxt_input_touchevent(data, message);
 			update_input = true;
-- 
1.7.10.4


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

* [PATCH 35/53] Input: atmel_mxt_ts - Split message handler into separate functions
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (33 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 34/53] Input: atmel_mxt_ts - Decode T6 status messages Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 36/53] Input: atmel_mxt_ts - Implement T44 message handling Nick Dyer
                   ` (18 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  120 +++++++++++++++---------------
 1 file changed, 62 insertions(+), 58 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 39a20fd..1033755 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -254,8 +254,10 @@ struct mxt_data {
 	struct t7_config t7_cfg;
 	u8 *msg_buf;
 	u8 t6_status;
+	bool update_input;
 
 	/* Cached parameters from object table */
+	u16 T5_address;
 	u8 T5_msg_size;
 	u8 T6_reportid;
 	u16 T6_address;
@@ -670,20 +672,6 @@ static void mxt_proc_t6_messages(struct mxt_data *data, u8 *msg)
 	data->t6_status = status;
 }
 
-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_button(struct mxt_data *data, u8 *message)
 {
 	struct input_dev *input = data->input_dev;
@@ -710,7 +698,7 @@ static void mxt_input_sync(struct input_dev *input_dev)
 	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;
@@ -774,49 +762,65 @@ 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 dump = data->debug_enabled;
+
+	if (report_id == MXT_RPTID_NOMSG)
+		return 0;
+
+	if (report_id == data->T6_reportid) {
+		mxt_proc_t6_messages(data, message);
+	} else if (report_id >= data->T9_reportid_min
+	    && report_id <= data->T9_reportid_max) {
+		mxt_proc_t9_message(data, message);
+	} else if (report_id == data->T19_reportid) {
+		mxt_input_button(data, message);
+		data->update_input = true;
+	} else {
+		dump = true;
+	}
+
+	if (dump)
+		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 dump;
+	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];
-		dump = data->debug_enabled;
-
-		if (reportid == data->T6_reportid) {
-			mxt_proc_t6_messages(data, message);
-		} else if (mxt_is_T9_message(data, message)) {
-			mxt_input_touchevent(data, message);
-			update_input = true;
-		} else if (reportid == data->T19_reportid) {
-			mxt_input_button(data, message);
-			update_input = true;
-		} else {
-			dump = true;
-		}
+	return mxt_proc_message(data, data->msg_buf);
+}
 
-		if (dump)
-			mxt_dump_message(data, message);
-	} while (reportid != MXT_RPTID_NOMSG);
+static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
+{
+	int ret;
+
+	do {
+		ret = mxt_read_and_process_message(data);
+		if (ret < 0)
+			return IRQ_NONE;
+	} while (ret > 0);
 
-	if (data->enable_reporting && update_input)
+	if (data->enable_reporting && data->update_input) {
 		mxt_input_sync(data->input_dev);
+		data->update_input = false;
+	}
 
 	return IRQ_HANDLED;
 }
@@ -1263,21 +1267,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_acquire_irq(struct mxt_data *data)
@@ -1314,6 +1316,7 @@ static void mxt_free_object_table(struct mxt_data *data)
 	kfree(data->msg_buf);
 	data->msg_buf = NULL;
 	data->enable_reporting = false;
+	data->T5_address = 0;
 	data->T5_msg_size = 0;
 	data->T6_reportid = 0;
 	data->T7_address = 0;
@@ -1366,6 +1369,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 = mxt_obj_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] 93+ messages in thread

* [PATCH 36/53] Input: atmel_mxt_ts - Implement T44 message handling
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (34 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 35/53] Input: atmel_mxt_ts - Split message handler into separate functions Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 37/53] Input: atmel_mxt_ts - Output status from T48 Noise Supression Nick Dyer
                   ` (17 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  190 +++++++++++++++++++++++++-----
 1 file changed, 158 insertions(+), 32 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 1033755..ca02ee1 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -248,6 +248,7 @@ struct mxt_data {
 	u16 mem_size;
 	struct bin_attribute mem_access_attr;
 	bool debug_enabled;
+	u8 max_reportid;
 	u32 config_crc;
 	u32 info_crc;
 	u8 bootloader_addr;
@@ -255,6 +256,8 @@ struct mxt_data {
 	u8 *msg_buf;
 	u8 t6_status;
 	bool update_input;
+	u8 last_message_count;
+	u8 num_touchids;
 
 	/* Cached parameters from object table */
 	u16 T5_address;
@@ -265,6 +268,7 @@ struct mxt_data {
 	u8 T9_reportid_min;
 	u8 T9_reportid_max;
 	u8 T19_reportid;
+	u16 T44_address;
 
 	/* for fw update in bootloader */
 	struct completion bl_completion;
@@ -792,30 +796,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 %d exceeded max report id\n", count);
+		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->enable_reporting && data->update_input) {
 		mxt_input_sync(data->input_dev);
@@ -838,7 +955,11 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
 	if (!data->object_table)
 		return IRQ_NONE;
 
-	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,
@@ -1263,32 +1384,13 @@ 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_acquire_irq(struct mxt_data *data)
 {
 	int error;
 
 	enable_irq(data->irq);
 
-	error = mxt_make_highchg(data);
+	error = mxt_process_messages_until_invalid(data);
 	if (error)
 		return error;
 
@@ -1323,6 +1425,8 @@ static void mxt_free_object_table(struct mxt_data *data)
 	data->T9_reportid_min = 0;
 	data->T9_reportid_max = 0;
 	data->T19_reportid = 0;
+	data->T44_address = 0;
+	data->max_reportid = 0;
 }
 
 static int mxt_get_object_table(struct mxt_data *data)
@@ -1367,8 +1471,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 = mxt_obj_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 = mxt_obj_size(object);
+			} else {
+				/* CRC not enabled, so skip last byte */
+				data->T5_msg_size = mxt_obj_size(object) - 1;
+			}
 			data->T5_address = object->start_address;
 		case MXT_GEN_COMMAND_T6:
 			data->T6_reportid = min_id;
@@ -1380,6 +1490,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
+						* mxt_obj_instances(object);
+			break;
+		case MXT_SPT_MESSAGECOUNT_T44:
+			data->T44_address = object->start_address;
 			break;
 		case MXT_SPT_GPIOPWM_T19:
 			data->T19_reportid = min_id;
@@ -1393,7 +1508,18 @@ 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;
-- 
1.7.10.4


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

* [PATCH 37/53] Input: atmel_mxt_ts - Output status from T48 Noise Supression
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (35 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 36/53] Input: atmel_mxt_ts - Implement T44 message handling Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 38/53] Input: atmel_mxt_ts - Output status from T42 Touch Suppression Nick Dyer
                   ` (16 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index ca02ee1..5291471 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -269,6 +269,7 @@ struct mxt_data {
 	u8 T9_reportid_max;
 	u8 T19_reportid;
 	u16 T44_address;
+	u8 T48_reportid;
 
 	/* for fw update in bootloader */
 	struct completion bl_completion;
@@ -770,6 +771,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];
@@ -786,6 +807,8 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
 	} else if (report_id == data->T19_reportid) {
 		mxt_input_button(data, message);
 		data->update_input = true;
+	} else if (report_id == data->T48_reportid) {
+		mxt_proc_t48_messages(data, message);
 	} else {
 		dump = true;
 	}
@@ -1426,6 +1449,7 @@ static void mxt_free_object_table(struct mxt_data *data)
 	data->T9_reportid_max = 0;
 	data->T19_reportid = 0;
 	data->T44_address = 0;
+	data->T48_reportid = 0;
 	data->max_reportid = 0;
 }
 
@@ -1499,6 +1523,9 @@ static int mxt_get_object_table(struct mxt_data *data)
 		case MXT_SPT_GPIOPWM_T19:
 			data->T19_reportid = min_id;
 			break;
+		case MXT_PROCG_NOISESUPPRESSION_T48:
+			data->T48_reportid = min_id;
+			break;
 		}
 
 		end_address = object->start_address
-- 
1.7.10.4


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

* [PATCH 38/53] Input: atmel_mxt_ts - Output status from T42 Touch Suppression
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (36 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 37/53] Input: atmel_mxt_ts - Output status from T48 Noise Supression Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 39/53] Input: atmel_mxt_ts - Implement vector/orientation support Nick Dyer
                   ` (15 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 5291471..27a2425 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -187,6 +187,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		50	/* msec */
 #define MXT_RESET_TIME		200	/* msec */
@@ -268,6 +271,8 @@ struct mxt_data {
 	u8 T9_reportid_min;
 	u8 T9_reportid_max;
 	u8 T19_reportid;
+	u8 T42_reportid_min;
+	u8 T42_reportid_max;
 	u16 T44_address;
 	u8 T48_reportid;
 
@@ -771,6 +776,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;
@@ -807,6 +823,9 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
 	} else if (report_id == data->T19_reportid) {
 		mxt_input_button(data, message);
 		data->update_input = true;
+	} else if (report_id >= data->T42_reportid_min
+		   && report_id <= data->T42_reportid_max) {
+		mxt_proc_t42_messages(data, message);
 	} else if (report_id == data->T48_reportid) {
 		mxt_proc_t48_messages(data, message);
 	} else {
@@ -1448,6 +1467,8 @@ static void mxt_free_object_table(struct mxt_data *data)
 	data->T9_reportid_min = 0;
 	data->T9_reportid_max = 0;
 	data->T19_reportid = 0;
+	data->T42_reportid_min = 0;
+	data->T42_reportid_max = 0;
 	data->T44_address = 0;
 	data->T48_reportid = 0;
 	data->max_reportid = 0;
@@ -1517,6 +1538,10 @@ static int mxt_get_object_table(struct mxt_data *data)
 			data->num_touchids = object->num_report_ids
 						* mxt_obj_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] 93+ messages in thread

* [PATCH 39/53] Input: atmel_mxt_ts - Implement vector/orientation support
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (37 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 38/53] Input: atmel_mxt_ts - Output status from T42 Touch Suppression Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 40/53] Input: atmel_mxt_ts - implement I2C retries Nick Dyer
                   ` (14 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 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 27a2425..bd8971e 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -718,6 +718,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 (!data->enable_reporting)
@@ -736,9 +737,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' : '.',
@@ -748,7 +750,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);
 
@@ -768,6 +770,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);
@@ -2186,6 +2189,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] 93+ messages in thread

* [PATCH 40/53] Input: atmel_mxt_ts - implement I2C retries
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (38 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 39/53] Input: atmel_mxt_ts - Implement vector/orientation support Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 41/53] Input: atmel_mxt_ts - Implement T63 Active Stylus support Nick Dyer
                   ` (13 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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 (eg mXT1386) 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 |   45 ++++++++++++++++++++----------
 1 file changed, 30 insertions(+), 15 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index bd8971e..5a195be 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -197,6 +197,7 @@ struct t9_range {
 #define MXT_CRC_TIMEOUT		1000	/* msec */
 #define MXT_FW_RESET_TIME	3000	/* msec */
 #define MXT_FW_CHG_TIMEOUT	300	/* msec */
+#define MXT_WAKEUP_TIME		25	/* msec */
 
 /* Command to unlock bootloader */
 #define MXT_UNLOCK_CMD_MSB	0xaa
@@ -569,6 +570,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;
@@ -585,17 +587,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,
@@ -604,6 +611,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);
@@ -614,14 +622,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 (ret != count) {
+		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);
+		}
+	} else {
+		ret = 0;
 	}
 
 	kfree(buf);
-- 
1.7.10.4


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

* [PATCH 41/53] Input: atmel_mxt_ts - Implement T63 Active Stylus support
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (39 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 40/53] Input: atmel_mxt_ts - implement I2C retries Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 42/53] Input: atmel_mxt_ts - Implement support for T15 Key Array Nick Dyer
                   ` (12 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   93 +++++++++++++++++++++++++++++-
 1 file changed, 92 insertions(+), 1 deletion(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 5a195be..8e63403 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -78,6 +78,7 @@
 #define MXT_SPT_DIGITIZER_T43		43
 #define MXT_SPT_MESSAGECOUNT_T44	44
 #define MXT_SPT_CTECONFIG_T46		46
+#define MXT_PROCI_ACTIVE_STYLUS_T63	63
 
 /* MXT_GEN_MESSAGE_T5 object */
 #define MXT_RPTID_NOMSG		0xff
@@ -190,6 +191,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		50	/* msec */
 #define MXT_RESET_TIME		200	/* msec */
@@ -262,6 +276,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;
@@ -276,6 +291,8 @@ struct mxt_data {
 	u8 T42_reportid_max;
 	u16 T44_address;
 	u8 T48_reportid;
+	u8 T63_reportid_min;
+	u8 T63_reportid_max;
 
 	/* for fw update in bootloader */
 	struct completion bl_completion;
@@ -825,6 +842,61 @@ 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;
+
+	/* do not report events if input device not yet registered */
+	if (!data->enable_reporting)
+		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];
@@ -841,6 +913,9 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
 	} else if (report_id == data->T19_reportid) {
 		mxt_input_button(data, message);
 		data->update_input = true;
+	} else if (report_id >= data->T63_reportid_min
+		   && report_id <= data->T63_reportid_max) {
+		mxt_proc_t63_messages(data, message);
 	} else if (report_id >= data->T42_reportid_min
 		   && report_id <= data->T42_reportid_max) {
 		mxt_proc_t42_messages(data, message);
@@ -1489,6 +1564,8 @@ static void mxt_free_object_table(struct mxt_data *data)
 	data->T42_reportid_max = 0;
 	data->T44_address = 0;
 	data->T48_reportid = 0;
+	data->T63_reportid_min = 0;
+	data->T63_reportid_max = 0;
 	data->max_reportid = 0;
 }
 
@@ -1569,6 +1646,12 @@ static int mxt_get_object_table(struct mxt_data *data)
 		case MXT_PROCG_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
+						* mxt_obj_instances(object);
+			break;
 		}
 
 		end_address = object->start_address
@@ -2189,7 +2272,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, mt_flags);
 	if (error) {
 		dev_err(dev, "Error %d initialising slots\n", error);
@@ -2207,6 +2290,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] 93+ messages in thread

* [PATCH 42/53] Input: atmel_mxt_ts - Implement support for T15 Key Array
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (40 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 41/53] Input: atmel_mxt_ts - Implement T63 Active Stylus support Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 43/53] Input: atmel_mxt_ts - Remove unused defines Nick Dyer
                   ` (11 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

There is a key array object in many maXTouch chips which allows some X/Y lines
to be used as a key array. This patch maps them to a series of keys which may
be configured in a platform data array.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   57 ++++++++++++++++++++++++++++++
 include/linux/i2c/atmel_mxt_ts.h         |    2 ++
 2 files changed, 59 insertions(+)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 8e63403..b482f71 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -277,6 +277,7 @@ struct mxt_data {
 	u8 last_message_count;
 	u8 num_touchids;
 	u8 num_stylusids;
+	unsigned long t15_keystatus;
 
 	/* Cached parameters from object table */
 	u16 T5_address;
@@ -286,6 +287,8 @@ struct mxt_data {
 	u16 T7_address;
 	u8 T9_reportid_min;
 	u8 T9_reportid_max;
+	u8 T15_reportid_min;
+	u8 T15_reportid_max;
 	u8 T19_reportid;
 	u8 T42_reportid_min;
 	u8 T42_reportid_max;
@@ -811,6 +814,42 @@ 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;
+	int key;
+	bool curr_state, new_state;
+	bool sync = false;
+	unsigned long keystates = le32_to_cpu(msg[2]);
+
+	/* do not report events if input device not yet registered */
+	if (!data->enable_reporting)
+		return;
+
+	for (key = 0; key < data->pdata->t15_num_keys; key++) {
+		curr_state = test_bit(key, &data->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, &data->t15_keystatus);
+			input_event(input_dev, EV_KEY,
+				    data->pdata->t15_keymap[key], 1);
+			sync = true;
+		} else if (curr_state && !new_state) {
+			dev_dbg(dev, "T15 key release: %u\n", key);
+			__clear_bit(key, &data->t15_keystatus);
+			input_event(input_dev, EV_KEY,
+				    data->pdata->t15_keymap[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;
@@ -921,6 +960,9 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
 		mxt_proc_t42_messages(data, message);
 	} else if (report_id == data->T48_reportid) {
 		mxt_proc_t48_messages(data, message);
+	} else if (report_id >= data->T15_reportid_min
+		   && report_id <= data->T15_reportid_max) {
+		mxt_proc_t15_messages(data, message);
 	} else {
 		dump = true;
 	}
@@ -1559,6 +1601,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->T15_reportid_min = 0;
+	data->T15_reportid_max = 0;
 	data->T19_reportid = 0;
 	data->T42_reportid_min = 0;
 	data->T42_reportid_max = 0;
@@ -1633,6 +1677,10 @@ static int mxt_get_object_table(struct mxt_data *data)
 			data->num_touchids = object->num_report_ids
 						* mxt_obj_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;
@@ -2298,6 +2346,15 @@ 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) {
+		data->t15_keystatus = 0;
+
+		for (i = 0; i < data->pdata->t15_num_keys; i++)
+			input_set_capability(input_dev, EV_KEY,
+					     data->pdata->t15_keymap[i]);
+	}
+
 	input_set_drvdata(input_dev, data);
 
 	error = input_register_device(input_dev);
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index 02bf6ea..b7d2092 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -20,6 +20,8 @@ struct mxt_platform_data {
 	unsigned long irqflags;
 	u8 t19_num_keys;
 	const unsigned int *t19_keymap;
+	int t15_num_keys;
+	const unsigned int *t15_keymap;
 };
 
 #endif /* __LINUX_ATMEL_MXT_TS_H */
-- 
1.7.10.4


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

* [PATCH 43/53] Input: atmel_mxt_ts - Remove unused defines
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (41 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 42/53] Input: atmel_mxt_ts - Implement support for T15 Key Array Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 44/53] Input: atmel_mxt_ts - Verify Information Block checksum on probe Nick Dyer
                   ` (10 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

Many of these values are out of date and they aren't used in the driver - all
they do is increase the size of the kernel source.

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

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b482f71..bbfea7a 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -25,27 +25,13 @@
 #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_INFO_CHECKSUM_SIZE	3
 #define MXT_MAX_BLOCK_WRITE	256
@@ -107,15 +93,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
@@ -138,51 +115,10 @@ 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
-
 /* MXT_SPT_COMMSCONFIG_T18 */
 #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
@@ -1581,7 +1517,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] 93+ messages in thread

* [PATCH 44/53] Input: atmel_mxt_ts - Verify Information Block checksum on probe
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (42 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 43/53] Input: atmel_mxt_ts - Remove unused defines Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-07 18:37   ` Yufeng Shen
  2013-06-05 17:37 ` [PATCH 45/53] Input: atmel_mxt_ts - Use T18 RETRIGEN to handle IRQF_TRIGGER_LOW Nick Dyer
                   ` (9 subsequent siblings)
  53 siblings, 1 reply; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |  181 ++++++++++++++++++------------
 1 file changed, 111 insertions(+), 70 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index bbfea7a..e0ff017 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -194,7 +194,8 @@ struct mxt_data {
 	char phys[64];		/* device physical location */
 	struct mxt_platform_data *pdata;
 	struct mxt_object *object_table;
-	struct mxt_info info;
+	struct mxt_info *info;
+	void *raw_info_block;
 	unsigned int irq;
 	unsigned int max_x;
 	unsigned int max_y;
@@ -365,12 +366,16 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry)
 {
 	u8 appmode = data->client->addr;
 	u8 bootloader;
+	u8 family_id = 0;
+
+	if (data->info)
+		family_id = data->info->family_id;
 
 	switch (appmode) {
 	case 0x4a:
 	case 0x4b:
 		/* Chips after 1664S use different scheme */
-		if (retry || data->info.family_id >= 0xa2) {
+		if (retry || family_id >= 0xa2) {
 			bootloader = appmode - 0x24;
 			break;
 		}
@@ -610,7 +615,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;
@@ -1249,13 +1254,13 @@ static int mxt_check_reg_init(struct mxt_data *data)
 		data_pos += offset;
 	}
 
-	if (cfg_info.family_id != data->info.family_id) {
+	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) {
+	if (cfg_info.variant_id != data->info->variant_id) {
 		dev_err(dev, "Variant ID mismatch!\n");
 		ret = -EINVAL;
 		goto release;
@@ -1302,7 +1307,7 @@ static int mxt_check_reg_init(struct mxt_data *data)
 
 	/* Malloc memory to store configuration */
 	cfg_start_ofs = MXT_OBJECT_START
-		+ data->info.object_num * sizeof(struct mxt_object)
+		+ data->info->object_num * sizeof(struct mxt_object)
 		+ MXT_INFO_CHECKSUM_SIZE;
 	config_mem_size = data->mem_size - cfg_start_ofs;
 	config_mem = kzalloc(config_mem_size, GFP_KERNEL);
@@ -1510,24 +1515,12 @@ static int mxt_acquire_irq(struct mxt_data *data)
 	return 0;
 }
 
-static int mxt_get_info(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);
+	kfree(data->raw_info_block);
 	data->object_table = NULL;
+	data->info = NULL;
+	data->raw_info_block = NULL;
 	kfree(data->msg_buf);
 	data->msg_buf = NULL;
 	data->enable_reporting = false;
@@ -1549,25 +1542,17 @@ static void mxt_free_object_table(struct mxt_data *data)
 	data->max_reportid = 0;
 }
 
-static int mxt_get_object_table(struct mxt_data *data)
+static int mxt_parse_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;
 
@@ -1591,7 +1576,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 = mxt_obj_size(object);
@@ -1651,22 +1636,102 @@ 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 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 == 0) || (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);
+
+	dev_info(&client->dev,
+		 "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
+		 info->family_id, info->variant_id, info->version >> 4,
+		 info->version & 0xf, info->build, info->object_num);
+
+	/* 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;
 	}
 
 	return 0;
 
-free_object_table:
-	mxt_free_object_table(data);
+err_free_mem:
+	kfree(buf);
 	return error;
 }
 
@@ -1721,13 +1786,12 @@ 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;
 	bool alt_bootloader_addr = false;
 	bool retry = false;
 
 retry_info:
-	error = mxt_get_info(data);
+	error = mxt_read_info_block(data);
 	if (error) {
 retry_bootloader:
 		error = mxt_probe_bootloader(data, alt_bootloader_addr);
@@ -1759,21 +1823,6 @@ retry_bootloader:
 		}
 	}
 
-	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);
-		goto err_free_object_table;
-	}
-
 	error = mxt_acquire_irq(data);
 	if (error)
 		goto err_free_object_table;
@@ -1792,17 +1841,6 @@ retry_bootloader:
 		goto err_free_object_table;
 	}
 
-	error = mxt_read_t9_resolution(data);
-	if (error) {
-		dev_err(&client->dev, "Failed to initialize T9 resolution\n");
-		goto err_free_object_table;
-	}
-
-	dev_info(&client->dev,
-		 "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
-		 info->family_id, info->variant_id, info->version >> 4,
-		 info->version & 0xf, info->build, info->object_num);
-
 	data->enable_reporting = true;
 
 	return 0;
@@ -1817,9 +1855,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 */
@@ -1827,9 +1865,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,
@@ -1866,7 +1903,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))
@@ -2211,6 +2248,10 @@ static int mxt_initialize_t9_input_device(struct mxt_data *data)
 	unsigned int mt_flags = 0;
 	int i;
 
+	error = mxt_read_t9_resolution(data);
+	if (error)
+		dev_warn(dev, "Failed to initialize T9 resolution\n");
+
 	input_dev = input_allocate_device();
 	if (!input_dev) {
 		dev_err(dev, "Failed to allocate memory\n");
-- 
1.7.10.4


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

* [PATCH 45/53] Input: atmel_mxt_ts - Use T18 RETRIGEN to handle IRQF_TRIGGER_LOW
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (43 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 44/53] Input: atmel_mxt_ts - Verify Information Block checksum on probe Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 46/53] Input: atmel_mxt_ts - Handle reports from T47 Stylus object Nick Dyer
                   ` (8 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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 workaround of 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.

With level-triggered interrupts this is unnecessary.

Also, most recent maXTouch chips have a feature called RETRIGEN which, when
enabled, reasserts the interrupt line every cycle if there are messages
waiting. This also makes the workaround unnecessary.

Note: the RETRIGEN feature is only in some firmware versions/chips, it's not
valid simply to enable the bit.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   48 ++++++++++++++++++++++++++++--
 1 file changed, 45 insertions(+), 3 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index e0ff017..6631ef1 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -118,6 +118,7 @@ struct t9_range {
 /* MXT_SPT_COMMSCONFIG_T18 */
 #define MXT_COMMS_CTRL		0
 #define MXT_COMMS_CMD		1
+#define MXT_COMMS_RETRIGEN      (1 << 6)
 
 /* Define for MXT_GEN_COMMAND_T6 */
 #define MXT_BOOT_VALUE		0xa5
@@ -215,6 +216,7 @@ struct mxt_data {
 	u8 num_touchids;
 	u8 num_stylusids;
 	unsigned long t15_keystatus;
+	bool use_retrigen_workaround;
 
 	/* Cached parameters from object table */
 	u16 T5_address;
@@ -226,6 +228,7 @@ struct mxt_data {
 	u8 T9_reportid_max;
 	u8 T15_reportid_min;
 	u8 T15_reportid_max;
+	u16 T18_address;
 	u8 T19_reportid;
 	u8 T42_reportid_min;
 	u8 T42_reportid_max;
@@ -1185,6 +1188,31 @@ static u32 mxt_calculate_crc(u8 *base, off_t start_off, off_t end_off)
 	return crc;
 }
 
+static int mxt_check_retrigen(struct mxt_data *data)
+{
+	struct i2c_client *client = data->client;
+	int error;
+	int val;
+
+	if (data->pdata->irqflags & IRQF_TRIGGER_LOW)
+		return 0;
+
+	if (data->T18_address) {
+		error = __mxt_read_reg(client,
+				       data->T18_address + MXT_COMMS_CTRL,
+				       1, &val);
+		if (error)
+			return error;
+
+		if (val & MXT_COMMS_RETRIGEN)
+			return 0;
+	}
+
+	dev_warn(&client->dev, "Enabling RETRIGEN workaround\n");
+	data->use_retrigen_workaround = true;
+	return 0;
+}
+
 /*
  * mxt_check_reg_init - download configuration to chip
  *
@@ -1434,6 +1462,10 @@ static int mxt_check_reg_init(struct mxt_data *data)
 
 	mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE);
 
+	ret = mxt_check_retrigen(data);
+	if (ret)
+		goto release_mem;
+
 	ret = mxt_soft_reset(data);
 	if (ret)
 		goto release_mem;
@@ -1508,9 +1540,11 @@ static int mxt_acquire_irq(struct mxt_data *data)
 
 	enable_irq(data->irq);
 
-	error = mxt_process_messages_until_invalid(data);
-	if (error)
-		return error;
+	if (data->use_retrigen_workaround) {
+		error = mxt_process_messages_until_invalid(data);
+		if (error)
+			return error;
+	}
 
 	return 0;
 }
@@ -1532,6 +1566,7 @@ static void mxt_free_object_table(struct mxt_data *data)
 	data->T9_reportid_max = 0;
 	data->T15_reportid_min = 0;
 	data->T15_reportid_max = 0;
+	data->T18_address = 0;
 	data->T19_reportid = 0;
 	data->T42_reportid_min = 0;
 	data->T42_reportid_max = 0;
@@ -1602,6 +1637,9 @@ static int mxt_parse_object_table(struct mxt_data *data)
 			data->T15_reportid_min = min_id;
 			data->T15_reportid_max = max_id;
 			break;
+		case MXT_SPT_COMMSCONFIG_T18:
+			data->T18_address = object->start_address;
+			break;
 		case MXT_PROCI_TOUCHSUPPRESSION_T42:
 			data->T42_reportid_min = min_id;
 			data->T42_reportid_max = max_id;
@@ -1823,6 +1861,10 @@ retry_bootloader:
 		}
 	}
 
+	error = mxt_check_retrigen(data);
+	if (error)
+		goto err_free_object_table;
+
 	error = mxt_acquire_irq(data);
 	if (error)
 		goto err_free_object_table;
-- 
1.7.10.4


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

* [PATCH 46/53] Input: atmel_mxt_ts - Handle reports from T47 Stylus object
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (44 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 45/53] Input: atmel_mxt_ts - Use T18 RETRIGEN to handle IRQF_TRIGGER_LOW Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 47/53] Input: atmel_mxt_ts - Release touch state during suspend Nick Dyer
                   ` (7 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 6631ef1..cd8f3e0 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -128,6 +128,9 @@ struct t9_range {
 /* 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)
@@ -698,6 +701,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 (!data->enable_reporting)
@@ -715,6 +719,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
 		y >>= 2;
 
 	area = message[5];
+
 	amplitude = message[6];
 	vector = message[7];
 
@@ -743,8 +748,17 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
 			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] 93+ messages in thread

* [PATCH 47/53] Input: atmel_mxt_ts - Release touch state during suspend
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (45 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 46/53] Input: atmel_mxt_ts - Handle reports from T47 Stylus object Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 48/53] Input: atmel_mxt_ts - Initialize power config before and after downloading cfg Nick Dyer
                   ` (6 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   46 ++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index cd8f3e0..724a95d 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -251,6 +251,9 @@ struct mxt_data {
 
 	/* Enable reporting of input events */
 	bool enable_reporting;
+
+	/* Indicates whether device is in suspend */
+	bool suspended;
 };
 
 static inline size_t mxt_obj_size(const struct mxt_object *obj)
@@ -2028,6 +2031,11 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 	if (ret)
 		goto release_firmware;
 
+	if (data->suspended) {
+		enable_irq(data->irq);
+		data->suspended = false;
+	}
+
 	if (!data->in_bootloader) {
 		/* Change to the bootloader mode */
 		data->in_bootloader = true;
@@ -2140,6 +2148,8 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 	} else {
 		dev_info(dev, "The firmware update succeeded\n");
 
+		data->suspended = false;
+
 		error = mxt_initialize(data);
 		if (error)
 			return error;
@@ -2245,17 +2255,53 @@ 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)
 {
+	if (!data->suspended || data->in_bootloader)
+		return;
+
+	/* Discard any touch 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);
 
 	/* Recalibrate since chip has been in deep sleep */
 	mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false);
+
+	mxt_acquire_irq(data);
+	data->enable_reporting = true;
+	data->suspended = false;
 }
 
 static void mxt_stop(struct mxt_data *data)
 {
+	if (data->suspended || data->in_bootloader)
+		return;
+
+	data->enable_reporting = false;
+	disable_irq(data->irq);
+
 	mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
+
+	mxt_reset_slots(data);
+	data->suspended = true;
 }
 
 static int mxt_input_open(struct input_dev *dev)
-- 
1.7.10.4


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

* [PATCH 48/53] Input: atmel_mxt_ts - Initialize power config before and after downloading cfg
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (46 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 47/53] Input: atmel_mxt_ts - Release touch state during suspend Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 49/53] Input: atmel_mxt_ts - Add regulator control support Nick Dyer
                   ` (5 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 724a95d..8e19ab1 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1230,6 +1230,8 @@ static int mxt_check_retrigen(struct mxt_data *data)
 	return 0;
 }
 
+static int mxt_init_t7_power_cfg(struct mxt_data *data);
+
 /*
  * mxt_check_reg_init - download configuration to chip
  *
@@ -1489,6 +1491,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:
@@ -1886,17 +1891,17 @@ retry_bootloader:
 	if (error)
 		goto err_free_object_table;
 
-	/* 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");
 		goto err_free_object_table;
 	}
 
-	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);
 		goto err_free_object_table;
 	}
 
-- 
1.7.10.4


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

* [PATCH 49/53] Input: atmel_mxt_ts - Add regulator control support
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (47 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 48/53] Input: atmel_mxt_ts - Initialize power config before and after downloading cfg Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 50/53] Input: atmel_mxt_ts - Implement support for T100 touch object Nick Dyer
                   ` (4 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   95 +++++++++++++++++++++++++++---
 include/linux/i2c/atmel_mxt_ts.h         |    1 +
 2 files changed, 89 insertions(+), 7 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 8e19ab1..ce676a1 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -24,6 +24,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 @@ struct t9_range {
 #define MXT_FW_RESET_TIME	3000	/* msec */
 #define MXT_FW_CHG_TIMEOUT	300	/* 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
@@ -220,6 +224,9 @@ struct mxt_data {
 	u8 num_stylusids;
 	unsigned long t15_keystatus;
 	bool use_retrigen_workaround;
+	bool use_regulator;
+	struct regulator *reg_vdd;
+	struct regulator *reg_avdd;
 
 	/* Cached parameters from object table */
 	u16 T5_address;
@@ -1843,6 +1850,66 @@ 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->pdata->gpio_reset, 0);
+
+	regulator_enable(data->reg_vdd);
+	regulator_enable(data->reg_avdd);
+	msleep(MXT_REGULATOR_DELAY);
+
+	INIT_COMPLETION(data->bl_completion);
+	gpio_set_value(data->pdata->gpio_reset, 1);
+	mxt_wait_for_completion(data, &data->bl_completion, 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->pdata->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;
@@ -2037,6 +2104,9 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 		goto release_firmware;
 
 	if (data->suspended) {
+		if (data->use_regulator)
+			mxt_regulator_enable(data);
+
 		enable_irq(data->irq);
 		data->suspended = false;
 	}
@@ -2281,14 +2351,18 @@ static void mxt_start(struct mxt_data *data)
 	if (!data->suspended || data->in_bootloader)
 		return;
 
-	/* Discard any touch 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);
+		/* Recalibrate since chip has been in deep sleep */
+		mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false);
+	}
 
 	mxt_acquire_irq(data);
 	data->enable_reporting = true;
@@ -2303,7 +2377,10 @@ static void mxt_stop(struct mxt_data *data)
 	data->enable_reporting = false;
 	disable_irq(data->irq);
 
-	mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
+	if (data->use_regulator)
+		mxt_regulator_disable(data);
+	else
+		mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
 
 	mxt_reset_slots(data);
 	data->suspended = true;
@@ -2491,6 +2568,8 @@ static int mxt_probe(struct i2c_client *client,
 		goto err_free_pdata;
 	}
 
+	mxt_probe_regulators(data);
+
 	disable_irq(data->irq);
 
 	error = mxt_initialize(data);
@@ -2554,6 +2633,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);
 	if (!dev_get_platdata(&data->client->dev))
 		kfree(data->pdata);
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index b7d2092..a01f2e8 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -22,6 +22,7 @@ struct mxt_platform_data {
 	const unsigned int *t19_keymap;
 	int t15_num_keys;
 	const unsigned int *t15_keymap;
+	unsigned long gpio_reset;
 };
 
 #endif /* __LINUX_ATMEL_MXT_TS_H */
-- 
1.7.10.4


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

* [PATCH 50/53] Input: atmel_mxt_ts - Implement support for T100 touch object
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (48 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 49/53] Input: atmel_mxt_ts - Add regulator control support Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 51/53] Input: atmel_mxt_ts - Allow specification of firmware file name Nick Dyer
                   ` (3 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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 |  299 ++++++++++++++++++++++++++++--
 1 file changed, 288 insertions(+), 11 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index ce676a1..2b5d876 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -67,6 +67,7 @@
 #define MXT_SPT_MESSAGECOUNT_T44	44
 #define MXT_SPT_CTECONFIG_T46		46
 #define MXT_PROCI_ACTIVE_STYLUS_T63	63
+#define MXT_TOUCH_MULTITOUCHSCREEN_T100 100
 
 /* MXT_GEN_MESSAGE_T5 object */
 #define MXT_RPTID_NOMSG		0xff
@@ -146,6 +147,23 @@ struct t9_range {
 
 #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		50	/* msec */
 #define MXT_RESET_TIME		200	/* msec */
@@ -209,6 +227,9 @@ struct mxt_data {
 	unsigned int max_y;
 	bool in_bootloader;
 	u16 mem_size;
+	u8 t100_aux_ampl;
+	u8 t100_aux_area;
+	u8 t100_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;
 
 	/* for fw update in bootloader */
 	struct completion bl_completion;
@@ -782,6 +805,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 (!data->enable_reporting)
+		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 area:%02X amp:%02X vec:%02X\n",
+		id,
+		status,
+		x, y,
+		(data->t100_aux_area) ? message[data->t100_aux_area] : 0,
+		(data->t100_aux_ampl) ? message[data->t100_aux_ampl] : 0,
+		(data->t100_aux_vect) ? message[data->t100_aux_vect] : 0);
+
+	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->t100_aux_ampl)
+			input_report_abs(input_dev, ABS_MT_PRESSURE,
+					 message[data->t100_aux_ampl]);
+
+		if (data->t100_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->t100_aux_area]);
+		}
+
+		if (data->t100_aux_vect)
+			input_report_abs(input_dev, ABS_MT_ORIENTATION,
+					 message[data->t100_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;
@@ -917,6 +1013,9 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
 	} else if (report_id >= data->T9_reportid_min
 	    && report_id <= data->T9_reportid_max) {
 		mxt_proc_t9_message(data, message);
+	} else if (report_id >= data->T100_reportid_min
+	    && report_id <= data->T100_reportid_max) {
+		mxt_proc_t100_message(data, message);
 	} else if (report_id == data->T19_reportid) {
 		mxt_input_button(data, message);
 		data->update_input = true;
@@ -1586,6 +1685,12 @@ static void mxt_free_object_table(struct mxt_data *data)
 	data->raw_info_block = NULL;
 	kfree(data->msg_buf);
 	data->msg_buf = NULL;
+
+	if (data->input_dev) {
+		input_unregister_device(data->input_dev);
+		data->input_dev = NULL;
+	}
+
 	data->enable_reporting = false;
 	data->T5_address = 0;
 	data->T5_msg_size = 0;
@@ -1603,6 +1708,8 @@ static void mxt_free_object_table(struct mxt_data *data)
 	data->T48_reportid = 0;
 	data->T63_reportid_min = 0;
 	data->T63_reportid_max = 0;
+	data->T100_reportid_min = 0;
+	data->T100_reportid_max = 0;
 	data->max_reportid = 0;
 }
 
@@ -1688,6 +1795,12 @@ static int mxt_parse_object_table(struct mxt_data *data)
 			data->num_stylusids = object->num_report_ids
 						* mxt_obj_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
@@ -1910,6 +2023,168 @@ 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->t100_aux_vect = aux++;
+
+	if (tchaux & MXT_T100_TCHAUX_AMPL)
+		data->t100_aux_ampl = aux++;
+
+	if (tchaux & MXT_T100_TCHAUX_AREA)
+		data->t100_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 device *dev = &data->client->dev;
+	struct input_dev *input_dev;
+	int error;
+
+	error = mxt_read_t100_config(data);
+	if (error)
+		dev_warn(dev, "Failed to initialize T9 resolution\n");
+
+	input_dev = input_allocate_device();
+	if (!data || !input_dev) {
+		dev_err(dev, "Failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	input_dev->name = "atmel_mxt_ts T100 touchscreen";
+
+	input_dev->phys = data->phys;
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &data->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->t100_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) {
+		dev_err(dev, "Error %d initialising slots\n", error);
+		goto err_free_mem;
+	}
+
+	input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0);
+	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->t100_aux_area)
+		input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+				     0, MXT_MAX_AREA, 0, 0);
+
+	if (data->t100_aux_ampl)
+		input_set_abs_params(input_dev, ABS_MT_PRESSURE,
+				     0, 255, 0, 0);
+
+	if (data->t100_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(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;
@@ -1972,6 +2247,18 @@ retry_bootloader:
 		goto err_free_object_table;
 	}
 
+	if (data->T9_reportid_min) {
+		error = mxt_initialize_t9_input_device(data);
+		if (error)
+			goto err_free_object_table;
+	} else if (data->T100_reportid_min) {
+		error = mxt_initialize_t100_input_device(data);
+		if (error)
+			goto err_free_object_table;
+	} else {
+		dev_warn(&client->dev, "No touch object detected\n");
+	}
+
 	data->enable_reporting = true;
 
 	return 0;
@@ -2576,17 +2863,11 @@ static int mxt_probe(struct i2c_client *client,
 	if (error)
 		goto err_free_irq;
 
-	if (!data->in_bootloader) {
-		error = mxt_initialize_t9_input_device(data);
-		if (error)
-			goto err_free_object;
-	}
-
 	error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
 	if (error) {
 		dev_err(&client->dev, "Failure %d creating sysfs group\n",
 			error);
-		goto err_unregister_device;
+		goto err_free_object;
 	}
 
 	sysfs_bin_attr_init(&data->mem_access_attr);
@@ -2607,9 +2888,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_object:
 	mxt_free_object_table(data);
 err_free_irq:
@@ -2632,7 +2910,6 @@ 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);
-- 
1.7.10.4


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

* [PATCH 51/53] Input: atmel_mxt_ts - Allow specification of firmware file name
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (49 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 50/53] Input: atmel_mxt_ts - Implement support for T100 touch object Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 52/53] Input: atmel_mxt_ts - Handle cfg filename via pdata/sysfs Nick Dyer
                   ` (2 subsequent siblings)
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

On platforms which have multiple device instances using this driver, the
firmware may be different on each device. This patch makes the user give the
name of the firmware file when flashing.

This also prevents accidental triggering of the firmware load process.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   45 ++++++++++++++++++++++++++----
 1 file changed, 39 insertions(+), 6 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 2b5d876..3a74371 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -27,8 +27,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/gpio.h>
 
-/* Firmware files */
-#define MXT_FW_NAME		"maxtouch.fw"
+/* Configuration file */
 #define MXT_CFG_NAME		"maxtouch.cfg"
 #define MXT_CFG_MAGIC		"OBP_RAW V1"
 
@@ -248,6 +247,7 @@ struct mxt_data {
 	bool use_regulator;
 	struct regulator *reg_vdd;
 	struct regulator *reg_avdd;
+	char *fw_name;
 
 	/* Cached parameters from object table */
 	u16 T5_address;
@@ -2369,7 +2369,7 @@ static int mxt_check_firmware_format(struct device *dev,
 	return -1;
 }
 
-static int mxt_load_fw(struct device *dev, const char *fn)
+static int mxt_load_fw(struct device *dev)
 {
 	struct mxt_data *data = dev_get_drvdata(dev);
 	const struct firmware *fw = NULL;
@@ -2379,9 +2379,9 @@ static int mxt_load_fw(struct device *dev, const char *fn)
 	unsigned int frame = 0;
 	int ret;
 
-	ret = request_firmware(&fw, fn, dev);
+	ret = request_firmware(&fw, data->fw_name, dev);
 	if (ret) {
-		dev_err(dev, "Unable to open firmware %s\n", fn);
+		dev_err(dev, "Unable to open firmware %s\n", data->fw_name);
 		return ret;
 	}
 
@@ -2496,6 +2496,35 @@ release_firmware:
 	return ret;
 }
 
+static int mxt_update_file_name(struct device *dev, char **file_name,
+				const char *buf, size_t count)
+{
+	char *file_name_tmp;
+
+	/* Simple sanity check */
+	if (count > 64) {
+		dev_warn(dev, "File name too long\n");
+		return -EINVAL;
+	}
+
+	file_name_tmp = krealloc(*file_name, count + 1, GFP_KERNEL);
+	if (!file_name_tmp) {
+		dev_warn(dev, "no memory\n");
+		return -ENOMEM;
+	}
+
+	*file_name = file_name_tmp;
+	memcpy(*file_name, buf, count);
+
+	/* Echo into the sysfs entry may append newline at the end of buf */
+	if (buf[count - 1] == '\n')
+		(*file_name)[count - 1] = '\0';
+	else
+		(*file_name)[count] = '\0';
+
+	return 0;
+}
+
 static ssize_t mxt_update_fw_store(struct device *dev,
 					struct device_attribute *attr,
 					const char *buf, size_t count)
@@ -2503,7 +2532,11 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 	struct mxt_data *data = dev_get_drvdata(dev);
 	int error;
 
-	error = mxt_load_fw(dev, MXT_FW_NAME);
+	error = mxt_update_file_name(dev, &data->fw_name, buf, count);
+	if (error)
+		return error;
+
+	error = mxt_load_fw(dev);
 	if (error) {
 		dev_err(dev, "The firmware update failed(%d)\n", error);
 		count = error;
-- 
1.7.10.4


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

* [PATCH 52/53] Input: atmel_mxt_ts - Handle cfg filename via pdata/sysfs
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (50 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 51/53] Input: atmel_mxt_ts - Allow specification of firmware file name Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-05 17:37 ` [PATCH 53/53] Input: atmel_mxt_ts - Only use first T9 instance Nick Dyer
  2013-06-06 19:18 ` Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Dmitry Torokhov
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 UTC (permalink / raw)
  To: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj
  Cc: Nick Dyer

There may be multiple maXTouch chips on a single device which will require
different configuration files. Add a platform data value for the configuration
filename.

Add sysfs entry to write configuration file if the platform data is not set.

Split out the object initialisation code from mxt_initialize() into
mxt_configure_objects() to allow this.

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

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 3a74371..0474cb9 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -28,7 +28,6 @@
 #include <linux/gpio.h>
 
 /* Configuration file */
-#define MXT_CFG_NAME		"maxtouch.cfg"
 #define MXT_CFG_MAGIC		"OBP_RAW V1"
 
 /* Registers */
@@ -248,6 +247,7 @@ struct mxt_data {
 	struct regulator *reg_vdd;
 	struct regulator *reg_avdd;
 	char *fw_name;
+	char *cfg_name;
 
 	/* Cached parameters from object table */
 	u16 T5_address;
@@ -1376,10 +1376,15 @@ static int mxt_check_reg_init(struct mxt_data *data)
 	u8 val;
 	u16 reg;
 
-	ret = request_firmware(&cfg, MXT_CFG_NAME, dev);
+	if (!data->cfg_name) {
+		dev_dbg(dev, "Skipping cfg download\n");
+		return 0;
+	}
+
+	ret = request_firmware(&cfg, data->cfg_name, dev);
 	if (ret < 0) {
 		dev_err(dev, "Failure to request config file %s\n",
-			MXT_CFG_NAME);
+			data->cfg_name);
 		return 0;
 	}
 
@@ -1677,6 +1682,14 @@ static int mxt_acquire_irq(struct mxt_data *data)
 	return 0;
 }
 
+static void mxt_free_input_device(struct mxt_data *data)
+{
+	if (data->input_dev) {
+		input_unregister_device(data->input_dev);
+		data->input_dev = NULL;
+	}
+}
+
 static void mxt_free_object_table(struct mxt_data *data)
 {
 	kfree(data->raw_info_block);
@@ -1686,10 +1699,7 @@ static void mxt_free_object_table(struct mxt_data *data)
 	kfree(data->msg_buf);
 	data->msg_buf = NULL;
 
-	if (data->input_dev) {
-		input_unregister_device(data->input_dev);
-		data->input_dev = NULL;
-	}
+	mxt_free_input_device(data);
 
 	data->enable_reporting = false;
 	data->T5_address = 0;
@@ -2184,6 +2194,7 @@ err_free_mem:
 }
 
 static int mxt_initialize_t9_input_device(struct mxt_data *data);
+static int mxt_configure_objects(struct mxt_data *data);
 
 static int mxt_initialize(struct mxt_data *data)
 {
@@ -2227,16 +2238,28 @@ retry_bootloader:
 
 	error = mxt_check_retrigen(data);
 	if (error)
-		goto err_free_object_table;
+		return error;
 
 	error = mxt_acquire_irq(data);
 	if (error)
-		goto err_free_object_table;
+		return error;
+
+	error = mxt_configure_objects(data);
+	if (error)
+		return error;
+
+	return 0;
+}
+
+static int mxt_configure_objects(struct mxt_data *data)
+{
+	struct i2c_client *client = data->client;
+	int error;
 
 	error = mxt_init_t7_power_cfg(data);
 	if (error) {
 		dev_err(&client->dev, "Failed to initialize power cfg\n");
-		goto err_free_object_table;
+		return error;
 	}
 
 	/* Check register init values */
@@ -2244,28 +2267,23 @@ retry_bootloader:
 	if (error) {
 		dev_err(&client->dev, "Error %d initialising configuration\n",
 			error);
-		goto err_free_object_table;
+		return error;
 	}
 
 	if (data->T9_reportid_min) {
 		error = mxt_initialize_t9_input_device(data);
 		if (error)
-			goto err_free_object_table;
+			return error;
 	} else if (data->T100_reportid_min) {
 		error = mxt_initialize_t100_input_device(data);
 		if (error)
-			goto err_free_object_table;
+			return error;
 	} else {
 		dev_warn(&client->dev, "No touch object detected\n");
 	}
 
 	data->enable_reporting = true;
-
 	return 0;
-
-err_free_object_table:
-	mxt_free_object_table(data);
-	return error;
 }
 
 /* Firmware Version is returned as Major.Minor.Build */
@@ -2553,6 +2571,45 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 	return count;
 }
 
+static ssize_t mxt_update_cfg_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct mxt_data *data = dev_get_drvdata(dev);
+	int ret;
+
+	if (data->in_bootloader) {
+		dev_err(dev, "Not in appmode\n");
+		return -EINVAL;
+	}
+
+	ret = mxt_update_file_name(dev, &data->cfg_name, buf, count);
+	if (ret)
+		return ret;
+
+	data->enable_reporting = false;
+	mxt_free_input_device(data);
+
+	if (data->suspended) {
+		if (data->use_regulator)
+			mxt_regulator_enable(data);
+		else
+			mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
+
+		mxt_acquire_irq(data);
+
+		data->suspended = false;
+	}
+
+	ret = mxt_configure_objects(data);
+	if (ret)
+		goto out;
+
+	ret = count;
+out:
+	return ret;
+}
+
 static ssize_t mxt_debug_enable_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
@@ -2634,6 +2691,7 @@ 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(update_cfg, S_IWUSR, NULL, mxt_update_cfg_store);
 static DEVICE_ATTR(debug_enable, S_IWUSR | S_IRUSR, mxt_debug_enable_show,
 		   mxt_debug_enable_store);
 
@@ -2642,6 +2700,7 @@ static struct attribute *mxt_attrs[] = {
 	&dev_attr_hw_version.attr,
 	&dev_attr_object.attr,
 	&dev_attr_update_fw.attr,
+	&dev_attr_update_cfg.attr,
 	&dev_attr_debug_enable.attr,
 	NULL
 };
@@ -2727,8 +2786,15 @@ static int mxt_handle_pdata(struct mxt_data *data)
 	data->pdata = dev_get_platdata(&data->client->dev);
 
 	/* Use provided platform data if present */
-	if (data->pdata)
+	if (data->pdata) {
+		if (data->pdata->cfg_name)
+			mxt_update_file_name(&data->client->dev,
+					     &data->cfg_name,
+					     data->pdata->cfg_name,
+					     strlen(data->pdata->cfg_name));
+
 		return 0;
+	}
 
 	data->pdata = kzalloc(sizeof(*data->pdata), GFP_KERNEL);
 	if (!data->pdata) {
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index a01f2e8..3422bd0 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -23,6 +23,7 @@ struct mxt_platform_data {
 	int t15_num_keys;
 	const unsigned int *t15_keymap;
 	unsigned long gpio_reset;
+	const char *cfg_name;
 };
 
 #endif /* __LINUX_ATMEL_MXT_TS_H */
-- 
1.7.10.4


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

* [PATCH 53/53] Input: atmel_mxt_ts - Only use first T9 instance
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (51 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 52/53] Input: atmel_mxt_ts - Handle cfg filename via pdata/sysfs Nick Dyer
@ 2013-06-05 17:37 ` Nick Dyer
  2013-06-06 19:18 ` Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Dmitry Torokhov
  53 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 17:37 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 driver only registers one input device, which uses the screen parameters
from the first T9 instance. The first T63 instance also uses those parameters.

It is incorrect to send input reports from the second instances of these
objects if they are enabled: the input scaling will be wrong and the positions
will be mashed together.

This also causes problems on Android if the number of slots exceeds 32.

In the future, this could be handled by looking for enabled touch object
instances and creating an input device for each one.

Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
---
 drivers/input/touchscreen/atmel_mxt_ts.c |   13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 0474cb9..5dfdbbb 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1774,10 +1774,11 @@ static int mxt_parse_object_table(struct mxt_data *data)
 			data->T7_address = object->start_address;
 			break;
 		case MXT_TOUCH_MULTI_T9:
+			/* Only handle messages from first T9 instance */
 			data->T9_reportid_min = min_id;
-			data->T9_reportid_max = max_id;
-			data->num_touchids = object->num_report_ids
-						* mxt_obj_instances(object);
+			data->T9_reportid_max = min_id +
+						object->num_report_ids - 1;
+			data->num_touchids = object->num_report_ids;
 			break;
 		case MXT_TOUCH_KEYARRAY_T15:
 			data->T15_reportid_min = min_id;
@@ -1800,10 +1801,10 @@ static int mxt_parse_object_table(struct mxt_data *data)
 			data->T48_reportid = min_id;
 			break;
 		case MXT_PROCI_ACTIVE_STYLUS_T63:
+			/* Only handle messages from first T63 instance */
 			data->T63_reportid_min = min_id;
-			data->T63_reportid_max = max_id;
-			data->num_stylusids = object->num_report_ids
-						* mxt_obj_instances(object);
+			data->T63_reportid_max = min_id;
+			data->num_stylusids = 1;
 			break;
 		case MXT_TOUCH_MULTITOUCHSCREEN_T100:
 			data->T100_reportid_min = min_id;
-- 
1.7.10.4


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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-05 17:37 ` [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs Nick Dyer
@ 2013-06-05 17:57   ` Dmitry Torokhov
  2013-06-05 18:45     ` Nick Dyer
  2013-06-06 18:01   ` Greg KH
  1 sibling, 1 reply; 93+ messages in thread
From: Dmitry Torokhov @ 2013-06-05 17:57 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Daniel Kurtz, Henrik Rydberg, Joonyoung Shim, Alan.Bowens,
	linux-input, linux-kernel, pmeerw, bleung, olofj

Hi Nick,

On Wednesday, June 05, 2013 06:37:03 PM Nick Dyer wrote:
> 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.

I think if the driver was to use regmap then this fucntionality will already 
be there as regmap exports registers via debugfs.

Thanks.

-- 
Dmitry

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-05 17:57   ` Dmitry Torokhov
@ 2013-06-05 18:45     ` Nick Dyer
  2013-06-05 19:04       ` Dmitry Torokhov
  0 siblings, 1 reply; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 18:45 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Daniel Kurtz, Henrik Rydberg, Joonyoung Shim, Alan.Bowens,
	linux-input, linux-kernel, pmeerw, bleung, olofj

Dmitry Torokhov wrote:
> On Wednesday, June 05, 2013 06:37:03 PM Nick Dyer wrote:
>> 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.
> 
> I think if the driver was to use regmap then this fucntionality will already 
> be there as regmap exports registers via debugfs.

Yes, this was suggested in the past and I spent some time looking into it.

We have made a deliberate choice to implement this via sysfs rather than
debugfs since it needs to work on devices that don't have debugfs enabled.

In addition, there are some quirks about the way in which we have to
read/write registers which means regmap isn't a good fit.

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-05 18:45     ` Nick Dyer
@ 2013-06-05 19:04       ` Dmitry Torokhov
  2013-06-05 20:31         ` Nick Dyer
  0 siblings, 1 reply; 93+ messages in thread
From: Dmitry Torokhov @ 2013-06-05 19:04 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Daniel Kurtz, Henrik Rydberg, Joonyoung Shim, Alan.Bowens,
	linux-input, linux-kernel, pmeerw, bleung, olofj

On Wednesday, June 05, 2013 07:45:04 PM Nick Dyer wrote:
> Dmitry Torokhov wrote:
> > On Wednesday, June 05, 2013 06:37:03 PM Nick Dyer wrote:
> >> 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.
> > 
> > I think if the driver was to use regmap then this fucntionality will
> > already be there as regmap exports registers via debugfs.
> 
> Yes, this was suggested in the past and I spent some time looking into it.
> 
> We have made a deliberate choice to implement this via sysfs rather than
> debugfs since it needs to work on devices that don't have debugfs enabled.

Then they will have to enable it. Re-implementing something because
someone might not enable needed subsystem is not a good idea. Let's
say somebody disabled I2C - will you write your own implementation because
of that? Of course not, you just say that for given functionality it
is a prerequisite.

> 
> In addition, there are some quirks about the way in which we have to
> read/write registers which means regmap isn't a good fit.

Could you please elaborate more on this?

Thanks.

-- 
Dmitry

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-05 19:04       ` Dmitry Torokhov
@ 2013-06-05 20:31         ` Nick Dyer
  2013-06-05 21:07           ` Dmitry Torokhov
  0 siblings, 1 reply; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 20:31 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Daniel Kurtz, Henrik Rydberg, Joonyoung Shim, Alan.Bowens,
	linux-input, linux-kernel, pmeerw, bleung, olofj

Dmitry Torokhov wrote:
>> We have made a deliberate choice to implement this via sysfs rather than
>> debugfs since it needs to work on devices that don't have debugfs enabled.
> 
> Then they will have to enable it. Re-implementing something because
> someone might not enable needed subsystem is not a good idea. Let's
> say somebody disabled I2C - will you write your own implementation because
> of that? Of course not, you just say that for given functionality it
> is a prerequisite.

debugfs is a debug filesystem. This interface is useful for purposes which
are not debug. I have to be pragmatic: I don't see debugfs enabled on most
shipping Android devices, and however much I tell them to enable debugfs
doesn't seem to hold much weight.

It's partly path dependence - it was implemented like this because regmap
wasn't in mainline at the point when I wrote it. Having a dependency on
regmap would now be a API break complicating support of customers using
older kernels than mainline. I would also have to update a bunch of
software and documentation and people to know about the two different APIs.
The existing implementation already appears in shipping devices, so it is
well tested.

>> In addition, there are some quirks about the way in which we have to
>> read/write registers which means regmap isn't a good fit.
> 
> Could you please elaborate more on this?

- the mxt chip caches the I2C read pointer, so you can get a performance
optimisation by not sending the address on every read/write (I haven't
implemented this yet but plan to)
- the address pointer can wrap around when you read the T5 message
processor, which would confuse regmap
- we require I2C retries in some cases due to way the chip handles sleep states
- I can't see how to map the object protocol (used on mxt chips) into the
way regmap treats register ranges

I can look into porting on top of regmap. But it seems a pity to pepper
regmap with atmel_mxt_ts quirks just to save on three small functions in
the driver.

Thanks for your time to look at this.

N

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-05 20:31         ` Nick Dyer
@ 2013-06-05 21:07           ` Dmitry Torokhov
  2013-06-05 21:36             ` Nick Dyer
  2013-06-06  9:48             ` Mark Brown
  0 siblings, 2 replies; 93+ messages in thread
From: Dmitry Torokhov @ 2013-06-05 21:07 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Daniel Kurtz, Henrik Rydberg, Joonyoung Shim, Alan.Bowens,
	linux-input, linux-kernel, pmeerw, bleung, olofj

On Wed, Jun 05, 2013 at 09:31:39PM +0100, Nick Dyer wrote:
> Dmitry Torokhov wrote:
> >> We have made a deliberate choice to implement this via sysfs rather than
> >> debugfs since it needs to work on devices that don't have debugfs enabled.
> > 
> > Then they will have to enable it. Re-implementing something because
> > someone might not enable needed subsystem is not a good idea. Let's
> > say somebody disabled I2C - will you write your own implementation because
> > of that? Of course not, you just say that for given functionality it
> > is a prerequisite.
> 
> debugfs is a debug filesystem. This interface is useful for purposes which
> are not debug.

What other purposes does it serve? I'd expect you need it during new
board bringup.

> I have to be pragmatic: I don't see debugfs enabled on most
> shipping Android devices, and however much I tell them to enable debugfs
> doesn't seem to hold much weight.

You do not need to have debugfs enabled on shipping kernels, just the
ones you use for integration work.

> 
> It's partly path dependence - it was implemented like this because regmap
> wasn't in mainline at the point when I wrote it. Having a dependency on
> regmap would now be a API break complicating support of customers using
> older kernels than mainline. I would also have to update a bunch of
> software and documentation and people to know about the two different APIs.
> The existing implementation already appears in shipping devices, so it is
> well tested.

This was never a good argument for introducing an interface into the
kernel.

> 
> >> In addition, there are some quirks about the way in which we have to
> >> read/write registers which means regmap isn't a good fit.
> > 
> > Could you please elaborate more on this?
> 
> - the mxt chip caches the I2C read pointer, so you can get a performance
> optimisation by not sending the address on every read/write (I haven't
> implemented this yet but plan to)
> - the address pointer can wrap around when you read the T5 message
> processor, which would confuse regmap
> - we require I2C retries in some cases due to way the chip handles sleep states
> - I can't see how to map the object protocol (used on mxt chips) into the
> way regmap treats register ranges
> 
> I can look into porting on top of regmap. But it seems a pity to pepper
> regmap with atmel_mxt_ts quirks just to save on three small functions in
> the driver.

This is not about saving 3 functions but rather the fact that individual
register access is desired by many parties and instead of each driver
implementing it's own solution (via a char device, sysfs, debugfs, etc)
we should try to standardize on common userspace interface.

Thanks.

-- 
Dmitry

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-05 21:07           ` Dmitry Torokhov
@ 2013-06-05 21:36             ` Nick Dyer
  2013-06-06 10:03               ` Mark Brown
  2013-06-06  9:48             ` Mark Brown
  1 sibling, 1 reply; 93+ messages in thread
From: Nick Dyer @ 2013-06-05 21:36 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Daniel Kurtz, Henrik Rydberg, Joonyoung Shim, Alan.Bowens,
	linux-input, linux-kernel, pmeerw, bleung, olofj

Dmitry Torokhov wrote:
>> debugfs is a debug filesystem. This interface is useful for purposes which
>> are not debug.
> 
> What other purposes does it serve? I'd expect you need it during new
> board bringup.

Yes, during board bringup it's extremely useful. We have implemented
numerous open and closed source utilities that can use this interface.

Run-time examples would be adjusting noise suppression or touch suppression
parameters based on something going on in the app layer (eg having
different parameters during unlock screen), or tuning report rates based on
application requirements, ot to inspect debug data if the touch sensor is
faulty. You might say, well we should implement an kernel driver interface
for these requirements, but they will vary hugely between different
products. We are trying to keep the driver as generic as possible and push
product-specific complexity to user space. Hence exposing the register map
and implementing user-space libraries to deal with this kind of customisation.

>> I have to be pragmatic: I don't see debugfs enabled on most
>> shipping Android devices, and however much I tell them to enable debugfs
>> doesn't seem to hold much weight.
> 
> You do not need to have debugfs enabled on shipping kernels, just the
> ones you use for integration work.

I disagree. See above.

>> It's partly path dependence - it was implemented like this because regmap
>> wasn't in mainline at the point when I wrote it. Having a dependency on
>> regmap would now be a API break complicating support of customers using
>> older kernels than mainline. I would also have to update a bunch of
>> software and documentation and people to know about the two different APIs.
>> The existing implementation already appears in shipping devices, so it is
>> well tested.
> 
> This was never a good argument for introducing an interface into the
> kernel.

Yes, I know. Just pointing out that making changes to this does result in a
significant cost.

>> I can look into porting on top of regmap. But it seems a pity to pepper
>> regmap with atmel_mxt_ts quirks just to save on three small functions in
>> the driver.
> 
> This is not about saving 3 functions but rather the fact that individual
> register access is desired by many parties and instead of each driver
> implementing it's own solution (via a char device, sysfs, debugfs, etc)
> we should try to standardize on common userspace interface.

I agree that a common interface is desirable. If regmap met the
requirements I would certainly use it instead.

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-05 21:07           ` Dmitry Torokhov
  2013-06-05 21:36             ` Nick Dyer
@ 2013-06-06  9:48             ` Mark Brown
  2013-06-06 10:40               ` Nick Dyer
  1 sibling, 1 reply; 93+ messages in thread
From: Mark Brown @ 2013-06-06  9:48 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Nick Dyer, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

[-- Attachment #1: Type: text/plain, Size: 695 bytes --]

On Wed, Jun 05, 2013 at 02:07:15PM -0700, Dmitry Torokhov wrote:
> On Wed, Jun 05, 2013 at 09:31:39PM +0100, Nick Dyer wrote:

> > It's partly path dependence - it was implemented like this because regmap
> > wasn't in mainline at the point when I wrote it. Having a dependency on
> > regmap would now be a API break complicating support of customers using
> > older kernels than mainline. I would also have to update a bunch of

> This was never a good argument for introducing an interface into the
> kernel.

Indeed, and regmap is very easy to backport - it demands little from the
rest of the kernel and most of that is bus specific so you can pretty
much just copy it into an older kernel.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-05 21:36             ` Nick Dyer
@ 2013-06-06 10:03               ` Mark Brown
  2013-06-06 10:31                 ` Nick Dyer
  0 siblings, 1 reply; 93+ messages in thread
From: Mark Brown @ 2013-06-06 10:03 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

[-- Attachment #1: Type: text/plain, Size: 1520 bytes --]

On Wed, Jun 05, 2013 at 10:36:45PM +0100, Nick Dyer wrote:
> Dmitry Torokhov wrote:

> > What other purposes does it serve? I'd expect you need it during new
> > board bringup.

> Run-time examples would be adjusting noise suppression or touch suppression
> parameters based on something going on in the app layer (eg having
> different parameters during unlock screen), or tuning report rates based on
> application requirements, ot to inspect debug data if the touch sensor is
> faulty. You might say, well we should implement an kernel driver interface
> for these requirements, but they will vary hugely between different
> products. We are trying to keep the driver as generic as possible and push

If this interface varies dramatically between products then that sounds
like a badly designed interface.  Obviously the way the interface is
being used would be likely to vary between products but what you're
talking about sounds like parameter get/set stuff which sounds pretty
generic to me.  What userspace chooses to do with the parameters is of
course another story.

> product-specific complexity to user space. Hence exposing the register map
> and implementing user-space libraries to deal with this kind of customisation.

This sounds like a bad design decision for Linux, it's just asking for
fragility if userspace can go randomly poking round the entire register
map of the device with nothing coordinating with the driver code.

If you expose the paramters to userspace wouldn't that address the
issue?

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-06 10:03               ` Mark Brown
@ 2013-06-06 10:31                 ` Nick Dyer
  2013-06-06 10:55                   ` Mark Brown
  0 siblings, 1 reply; 93+ messages in thread
From: Nick Dyer @ 2013-06-06 10:31 UTC (permalink / raw)
  To: Mark Brown
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

Mark Brown wrote:
> On Wed, Jun 05, 2013 at 10:36:45PM +0100, Nick Dyer wrote:
>> Run-time examples would be adjusting noise suppression or touch suppression
>> parameters based on something going on in the app layer (eg having
>> different parameters during unlock screen), or tuning report rates based on
>> application requirements, ot to inspect debug data if the touch sensor is
>> faulty. You might say, well we should implement an kernel driver interface
>> for these requirements, but they will vary hugely between different
>> products. We are trying to keep the driver as generic as possible and push
> 
> If this interface varies dramatically between products then that sounds
> like a badly designed interface.  Obviously the way the interface is
> being used would be likely to vary between products but what you're
> talking about sounds like parameter get/set stuff which sounds pretty
> generic to me.  What userspace chooses to do with the parameters is of
> course another story.

The underlying design is called Object Protocol by Atmel, and defines a
method where the the i2c address space starts with a table defining the
types and locations of various objects. Each object contains many
parameters, most of them are simple get/set as you describe, but many
objects have considerably more dynamic behaviours and interactions.

The Object Protocol itself is generic, but the objects themselves are
different on different maXTouch chips and firmware versions. The objects
may change in size, or be added/removed. The protocol is designed to be
flexible and allow rapid firmware development without having to
continuously update tools.

Having to define every parameter in each object (there are thousands) in
the kernel driver would be impractically technically, since it would result
in a huge, and constantly updating API, which would be always out-of-date,
and impossible to support.

Also, I'm afraid it would also be impractical legally, since it would
breach the NDA terms that Atmel require on these parameter definitions.

>> product-specific complexity to user space. Hence exposing the register map
>> and implementing user-space libraries to deal with this kind of customisation.
> 
> This sounds like a bad design decision for Linux, it's just asking for
> fragility if userspace can go randomly poking round the entire register
> map of the device with nothing coordinating with the driver code.

It works very well in practice. This same abstraction is used across
maXTouch products on many platforms to provide tool support. I agree that
its use should be restricted to system programs.

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-06  9:48             ` Mark Brown
@ 2013-06-06 10:40               ` Nick Dyer
  2013-06-06 10:46                 ` Mark Brown
  0 siblings, 1 reply; 93+ messages in thread
From: Nick Dyer @ 2013-06-06 10:40 UTC (permalink / raw)
  To: Mark Brown
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

Mark Brown wrote:
> On Wed, Jun 05, 2013 at 02:07:15PM -0700, Dmitry Torokhov wrote:
>> On Wed, Jun 05, 2013 at 09:31:39PM +0100, Nick Dyer wrote:
> 
>>> It's partly path dependence - it was implemented like this because regmap
>>> wasn't in mainline at the point when I wrote it. Having a dependency on
>>> regmap would now be a API break complicating support of customers using
>>> older kernels than mainline. I would also have to update a bunch of
> 
>> This was never a good argument for introducing an interface into the
>> kernel.
> 
> Indeed, and regmap is very easy to backport - it demands little from the
> rest of the kernel and most of that is bus specific so you can pretty
> much just copy it into an older kernel.

That is good news. It would still be an extra thing to add to the docs, but
not a blocking point.

I am more worried about the address pointer handling and the I2C retries.

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-06 10:40               ` Nick Dyer
@ 2013-06-06 10:46                 ` Mark Brown
  2013-06-06 11:00                   ` Nick Dyer
  0 siblings, 1 reply; 93+ messages in thread
From: Mark Brown @ 2013-06-06 10:46 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

[-- Attachment #1: Type: text/plain, Size: 416 bytes --]

On Thu, Jun 06, 2013 at 11:40:50AM +0100, Nick Dyer wrote:

> I am more worried about the address pointer handling and the I2C retries.

The retries can just be done further up the stack?  All regmap is doing
with I/O errors is punting them straight back up to the caller so the
caller can retry just as well using regmap as it can using the raw I/O
protocol.

Without seeing the address thing it's hard to comment.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-06 10:31                 ` Nick Dyer
@ 2013-06-06 10:55                   ` Mark Brown
  2013-06-06 11:17                     ` Nick Dyer
  0 siblings, 1 reply; 93+ messages in thread
From: Mark Brown @ 2013-06-06 10:55 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

[-- Attachment #1: Type: text/plain, Size: 1610 bytes --]

On Thu, Jun 06, 2013 at 11:31:57AM +0100, Nick Dyer wrote:

> Having to define every parameter in each object (there are thousands) in
> the kernel driver would be impractically technically, since it would result
> in a huge, and constantly updating API, which would be always out-of-date,
> and impossible to support.

> Also, I'm afraid it would also be impractical legally, since it would
> breach the NDA terms that Atmel require on these parameter definitions.

If that's a big problem just put the data table in a section of the
firmware (or a separate file that gets requested as a firmware).  Or
have the firmware be able to enumerate itself when asked.

> >> product-specific complexity to user space. Hence exposing the register map
> >> and implementing user-space libraries to deal with this kind of customisation.

> > This sounds like a bad design decision for Linux, it's just asking for
> > fragility if userspace can go randomly poking round the entire register
> > map of the device with nothing coordinating with the driver code.

> It works very well in practice. This same abstraction is used across
> maXTouch products on many platforms to provide tool support. I agree that
> its use should be restricted to system programs.

It works well so long as people use the supplied binaries in the way
that's been proscribed.  As soon as people start upgrading kernels,
customising things out of your expected flow (because they can or
they're on a tight deadline) things will get more fragile.  This sort of
stuff is really common, the approaches I'm describing are fairly
standard solutions.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-06 10:46                 ` Mark Brown
@ 2013-06-06 11:00                   ` Nick Dyer
  2013-06-06 11:14                     ` Mark Brown
  0 siblings, 1 reply; 93+ messages in thread
From: Nick Dyer @ 2013-06-06 11:00 UTC (permalink / raw)
  To: Mark Brown
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

Mark Brown wrote:
> On Thu, Jun 06, 2013 at 11:40:50AM +0100, Nick Dyer wrote:
> 
>> I am more worried about the address pointer handling and the I2C retries.
> 
> The retries can just be done further up the stack?  All regmap is doing
> with I/O errors is punting them straight back up to the caller so the
> caller can retry just as well using regmap as it can using the raw I/O
> protocol.

It would have to be put into users of the debugfs interface as well.
There's quite tight timing required to make it work properly (see patch
[40/53]).

> Without seeing the address thing it's hard to comment.

Patch [36/53]. If the T5 message processor is from address 100-110, you can
do a read of 50 bytes starting at address 100, and it will return 10
messages, but anything in regmap that tries to do bounds checking would get
confused, I think.

Also, we would like to implement address pointer caching. maXTouch allows
us to skip the address part of the i2c transaction if the address pointer
in the chip hasn't changed. This speeds up interrupt handler slightly. But
it requires extra housekeeping at a low level to remember what the address
pointer was on the previous transaction to know whether to send it or not.

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-06 11:00                   ` Nick Dyer
@ 2013-06-06 11:14                     ` Mark Brown
  2013-06-06 11:34                       ` Nick Dyer
  0 siblings, 1 reply; 93+ messages in thread
From: Mark Brown @ 2013-06-06 11:14 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

[-- Attachment #1: Type: text/plain, Size: 1716 bytes --]

On Thu, Jun 06, 2013 at 12:00:54PM +0100, Nick Dyer wrote:
> Mark Brown wrote:

> > The retries can just be done further up the stack?  All regmap is doing
> > with I/O errors is punting them straight back up to the caller so the
> > caller can retry just as well using regmap as it can using the raw I/O
> > protocol.

> It would have to be put into users of the debugfs interface as well.
> There's quite tight timing required to make it work properly (see patch
> [40/53]).

This is yet another reason for implementing the protocol properly
instead of trying to bodge around the kernel.  It really seems like
the biggest problem here is the decision to try to bodge the entire
thing into userspace with no kernel support.

> > Without seeing the address thing it's hard to comment.

> Patch [36/53]. If the T5 message processor is from address 100-110, you can
> do a read of 50 bytes starting at address 100, and it will return 10
> messages, but anything in regmap that tries to do bounds checking would get
> confused, I think.

That's just not going to be supported, sorry.  You can implement custom
locks and access the device directly where you need to do stuff like
that while still using regmap for actual registers though.

> Also, we would like to implement address pointer caching. maXTouch allows
> us to skip the address part of the i2c transaction if the address pointer
> in the chip hasn't changed. This speeds up interrupt handler slightly. But
> it requires extra housekeeping at a low level to remember what the address
> pointer was on the previous transaction to know whether to send it or not.

That sounded like what you were talking about, it's pretty common and is
sane enough for reads.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-06 10:55                   ` Mark Brown
@ 2013-06-06 11:17                     ` Nick Dyer
  2013-06-06 13:16                       ` Mark Brown
  0 siblings, 1 reply; 93+ messages in thread
From: Nick Dyer @ 2013-06-06 11:17 UTC (permalink / raw)
  To: Mark Brown
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

Mark Brown wrote:
> On Thu, Jun 06, 2013 at 11:31:57AM +0100, Nick Dyer wrote:
>> Having to define every parameter in each object (there are thousands) in
>> the kernel driver would be impractically technically, since it would result
>> in a huge, and constantly updating API, which would be always out-of-date,
>> and impossible to support.
> 
>> Also, I'm afraid it would also be impractical legally, since it would
>> breach the NDA terms that Atmel require on these parameter definitions.
> 
> If that's a big problem just put the data table in a section of the
> firmware (or a separate file that gets requested as a firmware).  Or
> have the firmware be able to enumerate itself when asked.

That still would breach the NDA, I'm afraid. And there's hundreds of
existing versions of maXTouch chips already out there which don't have the
infrastructure in place to do what you describe.

>> It works very well in practice. This same abstraction is used across
>> maXTouch products on many platforms to provide tool support. I agree that
>> its use should be restricted to system programs.
> 
> It works well so long as people use the supplied binaries in the way
> that's been proscribed.  As soon as people start upgrading kernels,
> customising things out of your expected flow (because they can or
> they're on a tight deadline) things will get more fragile.  This sort of
> stuff is really common, the approaches I'm describing are fairly
> standard solutions.

If we expose every single parameter as a get/set as you suggest, we haven't
added anything that stops a binary of the wrong version doing something
stupid. We've just added a complex API to the same underlying thing, which
gains nothing.

In practice, where there is a risk of the user mucking up their
configuration, the open-source user-space tools that we have released
provide an easy way to back up and restore the configuration in use, and
the kernel driver provides a way to load a known good configuration on
probe. The same configuration formats and tools are used across maXTouch
products on many platforms.

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-06 11:14                     ` Mark Brown
@ 2013-06-06 11:34                       ` Nick Dyer
  2013-06-06 13:21                         ` Mark Brown
  0 siblings, 1 reply; 93+ messages in thread
From: Nick Dyer @ 2013-06-06 11:34 UTC (permalink / raw)
  To: Mark Brown
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

Mark Brown wrote:
> On Thu, Jun 06, 2013 at 12:00:54PM +0100, Nick Dyer wrote:
>> Mark Brown wrote:
> 
>>> The retries can just be done further up the stack?  All regmap is doing
>>> with I/O errors is punting them straight back up to the caller so the
>>> caller can retry just as well using regmap as it can using the raw I/O
>>> protocol.
> 
>> It would have to be put into users of the debugfs interface as well.
>> There's quite tight timing required to make it work properly (see patch
>> [40/53]).
> 
> This is yet another reason for implementing the protocol properly
> instead of trying to bodge around the kernel.  It really seems like
> the biggest problem here is the decision to try to bodge the entire
> thing into userspace with no kernel support.

With the interface I am proposing it is handled properly, in the kernel driver.

>From an Atmel perspective, Linux is just another platform and we want to
use our existing investment in tools and documentation to manage & debug
chips embedded in Linux based devices. So providing a bridge using a
relatively simple API between the tools and the kernel driver is the
correct decision. I can't provide a 3D graph of live touch data in the
kernel driver, for instance.

>>> Without seeing the address thing it's hard to comment.
> 
>> Patch [36/53]. If the T5 message processor is from address 100-110, you can
>> do a read of 50 bytes starting at address 100, and it will return 10
>> messages, but anything in regmap that tries to do bounds checking would get
>> confused, I think.
> 
> That's just not going to be supported, sorry.  You can implement custom
> locks and access the device directly where you need to do stuff like
> that while still using regmap for actual registers though.

OK, fair enough.

>> Also, we would like to implement address pointer caching. maXTouch allows
>> us to skip the address part of the i2c transaction if the address pointer
>> in the chip hasn't changed. This speeds up interrupt handler slightly. But
>> it requires extra housekeeping at a low level to remember what the address
>> pointer was on the previous transaction to know whether to send it or not.
> 
> That sounded like what you were talking about, it's pretty common and is
> sane enough for reads.

The address pointer is shared between reads and writes on maXTouch, but I
guess that's not a huge problem.

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-06 11:17                     ` Nick Dyer
@ 2013-06-06 13:16                       ` Mark Brown
  2013-06-06 16:13                         ` Nick Dyer
  0 siblings, 1 reply; 93+ messages in thread
From: Mark Brown @ 2013-06-06 13:16 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

[-- Attachment #1: Type: text/plain, Size: 2279 bytes --]

On Thu, Jun 06, 2013 at 12:17:56PM +0100, Nick Dyer wrote:
> Mark Brown wrote:

> > If that's a big problem just put the data table in a section of the
> > firmware (or a separate file that gets requested as a firmware).  Or
> > have the firmware be able to enumerate itself when asked.

> That still would breach the NDA, I'm afraid. And there's hundreds of
> existing versions of maXTouch chips already out there which don't have the
> infrastructure in place to do what you describe.

I'm sorry, this just doesn't seem plausible.  The data is going to be on
the running system and accessed via the kernel - as soon as people start
using this back door they're going to be revealing what they're
accessing and the information is going to be present in the binary blobs.
You're only revealing that the parameters are present, not what they
mean, and if it's a big concern then do something like strip down the
data file that gets shipped in production to just the controls that are
being accessed.

Again, the fact that you have shipped this stuff doesn't make much
difference here - you really should work with upstream on interfaces
like this sooner rather than later otherwise you're going to have to
cope with pushback.

> If we expose every single parameter as a get/set as you suggest, we haven't
> added anything that stops a binary of the wrong version doing something
> stupid. We've just added a complex API to the same underlying thing, which
> gains nothing.

So this goes back to what I was saying before about the interface being
badly designed - if the API you have to present is really this complex
then you've got a big problem in kernel or out of kernel.

> In practice, where there is a risk of the user mucking up their
> configuration, the open-source user-space tools that we have released
> provide an easy way to back up and restore the configuration in use, and
> the kernel driver provides a way to load a known good configuration on
> probe. The same configuration formats and tools are used across maXTouch
> products on many platforms.

So you're saying that this is all nice and consistent.  If that's the
case then there should be no problem putting at least the core bit that
does the actual physical interaction with the device into the kernel.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-06 11:34                       ` Nick Dyer
@ 2013-06-06 13:21                         ` Mark Brown
  0 siblings, 0 replies; 93+ messages in thread
From: Mark Brown @ 2013-06-06 13:21 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

[-- Attachment #1: Type: text/plain, Size: 1013 bytes --]

On Thu, Jun 06, 2013 at 12:34:57PM +0100, Nick Dyer wrote:
> Mark Brown wrote:

> > This is yet another reason for implementing the protocol properly
> > instead of trying to bodge around the kernel.  It really seems like
> > the biggest problem here is the decision to try to bodge the entire
> > thing into userspace with no kernel support.

> With the interface I am proposing it is handled properly, in the kernel driver.

You're proposing doing this using direct register I/O...

> From an Atmel perspective, Linux is just another platform and we want to
> use our existing investment in tools and documentation to manage & debug
> chips embedded in Linux based devices. So providing a bridge using a

Broadly speaking the kernel upstream just don't care about this.

> > That sounded like what you were talking about, it's pretty common and is
> > sane enough for reads.

> The address pointer is shared between reads and writes on maXTouch, but I
> guess that's not a huge problem.

That's totally normal.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-06 13:16                       ` Mark Brown
@ 2013-06-06 16:13                         ` Nick Dyer
  2013-06-06 16:46                           ` Mark Brown
  0 siblings, 1 reply; 93+ messages in thread
From: Nick Dyer @ 2013-06-06 16:13 UTC (permalink / raw)
  To: Mark Brown
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

Mark Brown wrote:
> I'm sorry, this just doesn't seem plausible.  The data is going to be on
> the running system and accessed via the kernel - as soon as people start
> using this back door they're going to be revealing what they're
> accessing and the information is going to be present in the binary blobs.
> You're only revealing that the parameters are present, not what they
> mean, and if it's a big concern then do something like strip down the
> data file that gets shipped in production to just the controls that are
> being accessed.

I am not a legal expert, but I have described what you suggest to people
who are more expert in the NDA terms and they say I cannot implement a
solution which exposes the names of all the parameters. In any case,
although having a data file which maps all the parameters is a good idea,
they don't exist at present time, so it's really a moot point in terms of
reaching a usable solution.

Without the register names all you really have is the object protocol that
we started with, you would end up accessing

/sys/bus/i2c/drivers/atmel_mxt_ts/1-0020/objectX/registerX

rather than parsing the object table once when your program started, then
performing a read/write to offset X.

And we wouldn't have won anything, because the user could still write to
the register that turns off reporting (for example) by mistake with both
methods.

And I would then have to write a user-space program that stuck it all back
together and simulated the register access interface so our existing tools
would work properly, and it would probably introduce a bunch of new bugs.

> Again, the fact that you have shipped this stuff doesn't make much
> difference here - you really should work with upstream on interfaces
> like this sooner rather than later otherwise you're going to have to
> cope with pushback.

I appreciate your feedback. In the end the only way to find what will be
accepted is to post patches and try to justify the technical decisions made.

You may dislike the way that these chips have been implemented, but in the
end I can't rip it all up and redesign, I'm only the driver guy and I have
to try and improve things in an incremental fashion from where they
currently are.

The other patches in this series are much more important. If the answer is
that I need to remove this particular change from the series and rework the
driver on top of regmap (or design something new) to meet this requirement,
then that is disappointing. But so be it, we want to be working upstream so
we want to solve this problem upstream.

>> If we expose every single parameter as a get/set as you suggest, we haven't
>> added anything that stops a binary of the wrong version doing something
>> stupid. We've just added a complex API to the same underlying thing, which
>> gains nothing.
> 
> So this goes back to what I was saying before about the interface being
> badly designed - if the API you have to present is really this complex
> then you've got a big problem in kernel or out of kernel.

Touch controllers are inherently complex system with a lot of configurable
parameters. The fact that it's complex and changes quickly doesn't make it
badly designed per se.

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-06 16:13                         ` Nick Dyer
@ 2013-06-06 16:46                           ` Mark Brown
  2013-06-07 15:12                             ` Nick Dyer
  0 siblings, 1 reply; 93+ messages in thread
From: Mark Brown @ 2013-06-06 16:46 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

[-- Attachment #1: Type: text/plain, Size: 2011 bytes --]

On Thu, Jun 06, 2013 at 05:13:32PM +0100, Nick Dyer wrote:

> I am not a legal expert, but I have described what you suggest to people
> who are more expert in the NDA terms and they say I cannot implement a
> solution which exposes the names of all the parameters. In any case,

Who said anything about names?  I'd assume the userspace stuff is
eventually talking to the device based on numbers of some kind and I'd
expect that this would be what ends up in the API.

> Without the register names all you really have is the object protocol that
> we started with, you would end up accessing

> /sys/bus/i2c/drivers/atmel_mxt_ts/1-0020/objectX/registerX

> rather than parsing the object table once when your program started, then
> performing a read/write to offset X.

Well, assuming sysfs makes sense for this.  It's not immediately clear
to me that it does.

> And we wouldn't have won anything, because the user could still write to
> the register that turns off reporting (for example) by mistake with both
> methods.

You'd not have access to the entire device register map which seems like
a win and people would be able to integrate sensibly with things like
the overall device power management (which might help with whatever is
causing you to have to cope with failing I/O) more smoothly.

> > So this goes back to what I was saying before about the interface being
> > badly designed - if the API you have to present is really this complex
> > then you've got a big problem in kernel or out of kernel.

> Touch controllers are inherently complex system with a lot of configurable
> parameters. The fact that it's complex and changes quickly doesn't make it
> badly designed per se.

Having lots of configuration and having the parameters change regularly
doesn't immediately mean that it has to be complex - the requirement is
very common, touchscreens aren't too remarkable here.  The usual thing
is for the kernel to understand how to transfer data back and forth but
not the content of the data.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-05 17:37 ` [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs Nick Dyer
  2013-06-05 17:57   ` Dmitry Torokhov
@ 2013-06-06 18:01   ` Greg KH
  2013-06-07 14:47     ` Nick Dyer
  1 sibling, 1 reply; 93+ messages in thread
From: Greg KH @ 2013-06-06 18:01 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

On Wed, Jun 05, 2013 at 06:37:03PM +0100, Nick Dyer wrote:
> 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>
> Acked-by: Benson Leung <bleung@chromium.org>
> ---
>  drivers/input/touchscreen/atmel_mxt_ts.c |   82 ++++++++++++++++++++++++++++++
>  1 file changed, 82 insertions(+)

Whenever you add/remove/modify sysfs files, you also need a
Documentation/ABI/ update as well.  Please include that.

thanks,

greg k-h

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

* Re: Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org
  2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
                   ` (52 preceding siblings ...)
  2013-06-05 17:37 ` [PATCH 53/53] Input: atmel_mxt_ts - Only use first T9 instance Nick Dyer
@ 2013-06-06 19:18 ` Dmitry Torokhov
       [not found]   ` <CAPDwgkPdtj0Th8P+y9e5O7swARfzS40sG1A3Ba=pAmeXfMx0Dw@mail.gmail.com>
  53 siblings, 1 reply; 93+ messages in thread
From: Dmitry Torokhov @ 2013-06-06 19:18 UTC (permalink / raw)
  To: Daniel Kurtz, Henrik Rydberg
  Cc: Joonyoung Shim, Alan.Bowens, linux-input, linux-kernel, pmeerw,
	bleung, olofj, Nick Dyer

On Wed, Jun 05, 2013 at 06:36:53PM +0100, Nick Dyer wrote:
> The following patches are an updated series of patches to the atmel_mxt_ts
> touch driver. They should apply cleanly to input/next.
> 
> This is a combined patchset, I've been working to merge my changes with the
> changes from the Chromium team. It's undergone a lot of testing and review
> over the last few months and I believe it is now ready to go upstream.
> 
> Most of these changes have been maintained and tested out-of-tree in some form
> for a long time. I apologise for the backlog.
> 
> 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
> 
> You can see the in-between versions at
>   https://github.com/ndyer/linux/
> 

Daniel, Henrik,

Any comments befroe I start pulling parts of this in?

Thanks.

-- 
Dmitry

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

* Re: Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org
       [not found]   ` <CAPDwgkPdtj0Th8P+y9e5O7swARfzS40sG1A3Ba=pAmeXfMx0Dw@mail.gmail.com>
@ 2013-06-06 19:46     ` Dmitry Torokhov
  2013-06-07 20:21       ` Yufeng Shen
  0 siblings, 1 reply; 93+ messages in thread
From: Dmitry Torokhov @ 2013-06-06 19:46 UTC (permalink / raw)
  To: Yufeng Shen
  Cc: Daniel Kurtz, Henrik Rydberg, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson, Nick Dyer

On Thu, Jun 06, 2013 at 03:40:47PM -0400, Yufeng Shen wrote:
> On Thu, Jun 6, 2013 at 3:18 PM, Dmitry Torokhov
> <dmitry.torokhov@gmail.com>wrote:
> 
> > On Wed, Jun 05, 2013 at 06:36:53PM +0100, Nick Dyer wrote:
> > > The following patches are an updated series of patches to the
> > atmel_mxt_ts
> > > touch driver. They should apply cleanly to input/next.
> > >
> > > This is a combined patchset, I've been working to merge my changes with
> > the
> > > changes from the Chromium team. It's undergone a lot of testing and
> > review
> > > over the last few months and I believe it is now ready to go upstream.
> > >
> > > Most of these changes have been maintained and tested out-of-tree in
> > some form
> > > for a long time. I apologise for the backlog.
> > >
> > > 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
> > >
> > > You can see the in-between versions at
> > >   https://github.com/ndyer/linux/
> > >
> >
> > Daniel, Henrik,
> >
> > Any comments befroe I start pulling parts of this in?
> >
> 
> 
> Can you hold this on for a few days ?  I would like to verify this patch
> series from chromium side.
> I probably would do it tomorrow and next monday and send back ack asap.

Sure, holding on is what I do best ;)

Thanks.

-- 
Dmitry

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-06 18:01   ` Greg KH
@ 2013-06-07 14:47     ` Nick Dyer
  0 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-07 14:47 UTC (permalink / raw)
  To: Greg KH
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

Greg KH wrote:
> On Wed, Jun 05, 2013 at 06:37:03PM +0100, Nick Dyer wrote:
>> 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>
>> Acked-by: Benson Leung <bleung@chromium.org>
>> ---
>>  drivers/input/touchscreen/atmel_mxt_ts.c |   82 ++++++++++++++++++++++++++++++
>>  1 file changed, 82 insertions(+)
> 
> Whenever you add/remove/modify sysfs files, you also need a
> Documentation/ABI/ update as well.  Please include that.

Will do. I think I should also document the existing sysfs files which are
missing docs.

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-06 16:46                           ` Mark Brown
@ 2013-06-07 15:12                             ` Nick Dyer
  2013-06-07 15:41                               ` Mark Brown
  0 siblings, 1 reply; 93+ messages in thread
From: Nick Dyer @ 2013-06-07 15:12 UTC (permalink / raw)
  To: Mark Brown
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

Mark Brown wrote:
> On Thu, Jun 06, 2013 at 05:13:32PM +0100, Nick Dyer wrote:
> 
>> I am not a legal expert, but I have described what you suggest to people
>> who are more expert in the NDA terms and they say I cannot implement a
>> solution which exposes the names of all the parameters. In any case,
> 
> Who said anything about names?  I'd assume the userspace stuff is
> eventually talking to the device based on numbers of some kind and I'd
> expect that this would be what ends up in the API.

OK. But if user-space is talking to the device based on register numbers, a
binary attribute seems like the correct way to present that - isn't that
what they're designed for?

>> And we wouldn't have won anything, because the user could still write to
>> the register that turns off reporting (for example) by mistake with both
>> methods.
> 
> You'd not have access to the entire device register map which seems like
> a win

Not really.

The chip itself will enforce which registers are read-only (by ignoring
writes) or write-only (by returning zeros if read). Encoding all this
information in the driver would just make it more brittle in the face of
touch controller firmware updates.

It would be possible for the driver to intermediate for some of the
registers that it cares about. For example, if we change the screen width
then the driver could reinitialise the input device. But I can't see that
it makes sense if you are changing several settings in a row for the input
device to be reinitialised several times. It is far less buggy to provide a
single way of tearing down everything and reinitialising (which could be
simply triggered from user space) than to encode all of the dependencies
(which is bound to introduce bugs).

It's not laziness, it's trying to push policy into user space.

>> Touch controllers are inherently complex system with a lot of configurable
>> parameters. The fact that it's complex and changes quickly doesn't make it
>> badly designed per se.
> 
> Having lots of configuration and having the parameters change regularly
> doesn't immediately mean that it has to be complex - the requirement is
> very common, touchscreens aren't too remarkable here.  The usual thing
> is for the kernel to understand how to transfer data back and forth but
> not the content of the data.

Sure, that's what I'm trying to accomplish. It's just that as far as I can
see it makes more sense to use the established protocol that these chips
have implemented rather than trying to bodge something else over the top or
crowbar it into a different model that will cause abstraction problems. We
have thought about this problem at great length, and discussed it on these
lists, and with other kernel engineers at customers, etc.

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-07 15:12                             ` Nick Dyer
@ 2013-06-07 15:41                               ` Mark Brown
  2013-06-07 16:11                                 ` Nick Dyer
  0 siblings, 1 reply; 93+ messages in thread
From: Mark Brown @ 2013-06-07 15:41 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

[-- Attachment #1: Type: text/plain, Size: 3153 bytes --]

On Fri, Jun 07, 2013 at 04:12:25PM +0100, Nick Dyer wrote:
> Mark Brown wrote:

> > Who said anything about names?  I'd assume the userspace stuff is
> > eventually talking to the device based on numbers of some kind and I'd
> > expect that this would be what ends up in the API.

> OK. But if user-space is talking to the device based on register numbers, a
> binary attribute seems like the correct way to present that - isn't that
> what they're designed for?

I thought there was this protocol you're concerned aboout, not raw
registers?  Presenting the actual data in binary form seems sane, how
one gets to the data is the issue.

> >> And we wouldn't have won anything, because the user could still write to
> >> the register that turns off reporting (for example) by mistake with both
> >> methods.

> > You'd not have access to the entire device register map which seems like
> > a win

> Not really.

> The chip itself will enforce which registers are read-only (by ignoring
> writes) or write-only (by returning zeros if read). Encoding all this
> information in the driver would just make it more brittle in the face of
> touch controller firmware updates.

So not only do you interact with the firmware via this protocol but the
actual hardware register map is unstable and there's nothing in the
device that the driver itself actually interacts with, all it does is
ferry these messages from the application layer to the device?  Given
the number of other patches here that doesn't seem to be the case...

> It would be possible for the driver to intermediate for some of the
> registers that it cares about. For example, if we change the screen width
> then the driver could reinitialise the input device. But I can't see that
> it makes sense if you are changing several settings in a row for the input
> device to be reinitialised several times. It is far less buggy to provide a
> single way of tearing down everything and reinitialising (which could be
> simply triggered from user space) than to encode all of the dependencies
> (which is bound to introduce bugs).

I am having an extremely hard time connecting anything you're talking
about here with the discussion at hand I'm afraid...

> > Having lots of configuration and having the parameters change regularly
> > doesn't immediately mean that it has to be complex - the requirement is
> > very common, touchscreens aren't too remarkable here.  The usual thing
> > is for the kernel to understand how to transfer data back and forth but
> > not the content of the data.

> Sure, that's what I'm trying to accomplish. It's just that as far as I can
> see it makes more sense to use the established protocol that these chips
> have implemented rather than trying to bodge something else over the top or
> crowbar it into a different model that will cause abstraction problems. We
> have thought about this problem at great length, and discussed it on these
> lists, and with other kernel engineers at customers, etc.

Nobody is talking about changing the protocol for interacting with the
device.  The discussion here is about the ABI the driver offers to the
application layer.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-07 15:41                               ` Mark Brown
@ 2013-06-07 16:11                                 ` Nick Dyer
  2013-06-07 16:47                                   ` Mark Brown
  0 siblings, 1 reply; 93+ messages in thread
From: Nick Dyer @ 2013-06-07 16:11 UTC (permalink / raw)
  To: Mark Brown
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

Mark Brown wrote:
>> OK. But if user-space is talking to the device based on register numbers, a
>> binary attribute seems like the correct way to present that - isn't that
>> what they're designed for?
> 
> I thought there was this protocol you're concerned aboout, not raw
> registers?  Presenting the actual data in binary form seems sane, how
> one gets to the data is the issue.

OK, so we seem to have gone round in a circle here. Initially I understood
you to say that providing a binary read/write attribute for access to the
configuration data was not acceptable.

>> The chip itself will enforce which registers are read-only (by ignoring
>> writes) or write-only (by returning zeros if read). Encoding all this
>> information in the driver would just make it more brittle in the face of
>> touch controller firmware updates.
> 
> So not only do you interact with the firmware via this protocol but the
> actual hardware register map is unstable

The register map is fixed at firmware compile time. The driver contains
code which parses the object table and figures out the correct register
offsets which are used on the particular chip that it is talking to.

The user space tools that we have written contain an equivalent parser. Is
it the duplication of this code that is your concern?

> and there's nothing in the
> device that the driver itself actually interacts with, all it does is
> ferry these messages from the application layer to the device?  Given
> the number of other patches here that doesn't seem to be the case...

The driver does interact with a subset of the registers. It's main job is
reading a certain "object" (set of registers) when triggered by interrupt,
which contain the touch reports which are passed to user space.

There are other registers that the driver uses, eg screen parameters, power
control, telling the device to reset.

Are you saying that your concern is that user space shouldn't be able to
directly access these registers, for example to trigger a reset? In which
case, how should user space reset the chip if required?

>> It would be possible for the driver to intermediate for some of the
>> registers that it cares about. For example, if we change the screen width
>> then the driver could reinitialise the input device. But I can't see that
>> it makes sense if you are changing several settings in a row for the input
>> device to be reinitialised several times. It is far less buggy to provide a
>> single way of tearing down everything and reinitialising (which could be
>> simply triggered from user space) than to encode all of the dependencies
>> (which is bound to introduce bugs).
> 
> I am having an extremely hard time connecting anything you're talking
> about here with the discussion at hand I'm afraid...

I'm trying to provide the background to this design as you've requested, I
apologise if you find it confusing.

> Nobody is talking about changing the protocol for interacting with the
> device.  The discussion here is about the ABI the driver offers to the
> application layer.

OK. I think that the ABI offered to the application layer should also be
object protocol, implemented over a binary attribute, which is what the
patch under discussion does. Is the problem that I need to provide better
documentation of object protocol?

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-07 16:11                                 ` Nick Dyer
@ 2013-06-07 16:47                                   ` Mark Brown
  2013-06-11 10:39                                     ` Nick Dyer
  0 siblings, 1 reply; 93+ messages in thread
From: Mark Brown @ 2013-06-07 16:47 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

[-- Attachment #1: Type: text/plain, Size: 4017 bytes --]

On Fri, Jun 07, 2013 at 05:11:28PM +0100, Nick Dyer wrote:
> Mark Brown wrote:

> > I thought there was this protocol you're concerned aboout, not raw
> > registers?  Presenting the actual data in binary form seems sane, how
> > one gets to the data is the issue.

> OK, so we seem to have gone round in a circle here. Initially I understood
> you to say that providing a binary read/write attribute for access to the
> configuration data was not acceptable.

What was being proposed was just mapping the register map straight into
userspace and implementing the entire protocol in userspace.  Having the
unparsed attributes visible themselves is relatively normal.

> >> The chip itself will enforce which registers are read-only (by ignoring
> >> writes) or write-only (by returning zeros if read). Encoding all this
> >> information in the driver would just make it more brittle in the face of
> >> touch controller firmware updates.

> > So not only do you interact with the firmware via this protocol but the
> > actual hardware register map is unstable

> The register map is fixed at firmware compile time. The driver contains
> code which parses the object table and figures out the correct register
> offsets which are used on the particular chip that it is talking to.

> The user space tools that we have written contain an equivalent parser. Is
> it the duplication of this code that is your concern?

I don't think you're using the usual definition of "register map" here.
You seem to be switching between talking about this object model the
device has and device registers - perhaps the objects are also registers
sometimes?

> Are you saying that your concern is that user space shouldn't be able to
> directly access these registers, for example to trigger a reset? In which
> case, how should user space reset the chip if required?

If the application layer can reset the device underneath the driver that
doesn't seem awesome; similarly if the application layer is having to
worry about the device getting powered off underneath it this doesn't
seem great either.

> >> It would be possible for the driver to intermediate for some of the
> >> registers that it cares about. For example, if we change the screen width
> >> then the driver could reinitialise the input device. But I can't see that
> >> it makes sense if you are changing several settings in a row for the input
> >> device to be reinitialised several times. It is far less buggy to provide a
> >> single way of tearing down everything and reinitialising (which could be
> >> simply triggered from user space) than to encode all of the dependencies
> >> (which is bound to introduce bugs).

> > I am having an extremely hard time connecting anything you're talking
> > about here with the discussion at hand I'm afraid...

> I'm trying to provide the background to this design as you've requested, I
> apologise if you find it confusing.

You appear to be assuming a great deal of familiarity with the specifics
of this device here.  Where does all thi stuff about reinitialsing the
device come from?  What are these dependencies and what does all this
have to do with setting parameters?

> > Nobody is talking about changing the protocol for interacting with the
> > device.  The discussion here is about the ABI the driver offers to the
> > application layer.

> OK. I think that the ABI offered to the application layer should also be
> object protocol, implemented over a binary attribute, which is what the
> patch under discussion does. Is the problem that I need to provide better
> documentation of object protocol?

As Greg says you do need to document any new sysfs ABIs you're adding
anyway.  However if this is some stateful protocol you're implementing
then does it really map onto sysfs well, sysfs attributes are normally
more just data values?

Won't the driver end up getting into a fight with the magic userspace
stuff if the driver has no idea what the magic userspace is doing?  How
would suspend and resume work?

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH 44/53] Input: atmel_mxt_ts - Verify Information Block checksum on probe
  2013-06-05 17:37 ` [PATCH 44/53] Input: atmel_mxt_ts - Verify Information Block checksum on probe Nick Dyer
@ 2013-06-07 18:37   ` Yufeng Shen
  2013-06-10  9:35     ` Nick Dyer
  0 siblings, 1 reply; 93+ messages in thread
From: Yufeng Shen @ 2013-06-07 18:37 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan Bowens, linux-input, linux-kernel, Peter Meerwald,
	Benson Leung, Olof Johansson

On Wed, Jun 5, 2013 at 1:37 PM, Nick Dyer <nick.dyer@itdev.co.uk> wrote:
> 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>
> Acked-by: Benson Leung <bleung@chromium.org>
> ---
>  drivers/input/touchscreen/atmel_mxt_ts.c |  181 ++++++++++++++++++------------
>  1 file changed, 111 insertions(+), 70 deletions(-)
>
> diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
> index bbfea7a..e0ff017 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -194,7 +194,8 @@ struct mxt_data {
>         char phys[64];          /* device physical location */
>         struct mxt_platform_data *pdata;
>         struct mxt_object *object_table;
> -       struct mxt_info info;
> +       struct mxt_info *info;
> +       void *raw_info_block;
>         unsigned int irq;
>         unsigned int max_x;
>         unsigned int max_y;
> @@ -365,12 +366,16 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry)
>  {
>         u8 appmode = data->client->addr;
>         u8 bootloader;
> +       u8 family_id = 0;
> +
> +       if (data->info)
> +               family_id = data->info->family_id;
>
>         switch (appmode) {
>         case 0x4a:
>         case 0x4b:
>                 /* Chips after 1664S use different scheme */
> -               if (retry || data->info.family_id >= 0xa2) {
> +               if (retry || family_id >= 0xa2) {
>                         bootloader = appmode - 0x24;
>                         break;
>                 }
> @@ -610,7 +615,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;
> @@ -1249,13 +1254,13 @@ static int mxt_check_reg_init(struct mxt_data *data)
>                 data_pos += offset;
>         }
>
> -       if (cfg_info.family_id != data->info.family_id) {
> +       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) {
> +       if (cfg_info.variant_id != data->info->variant_id) {
>                 dev_err(dev, "Variant ID mismatch!\n");
>                 ret = -EINVAL;
>                 goto release;
> @@ -1302,7 +1307,7 @@ static int mxt_check_reg_init(struct mxt_data *data)
>
>         /* Malloc memory to store configuration */
>         cfg_start_ofs = MXT_OBJECT_START
> -               + data->info.object_num * sizeof(struct mxt_object)
> +               + data->info->object_num * sizeof(struct mxt_object)
>                 + MXT_INFO_CHECKSUM_SIZE;
>         config_mem_size = data->mem_size - cfg_start_ofs;
>         config_mem = kzalloc(config_mem_size, GFP_KERNEL);
> @@ -1510,24 +1515,12 @@ static int mxt_acquire_irq(struct mxt_data *data)
>         return 0;
>  }
>
> -static int mxt_get_info(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);
> +       kfree(data->raw_info_block);
>         data->object_table = NULL;
> +       data->info = NULL;
> +       data->raw_info_block = NULL;
>         kfree(data->msg_buf);
>         data->msg_buf = NULL;
>         data->enable_reporting = false;
> @@ -1549,25 +1542,17 @@ static void mxt_free_object_table(struct mxt_data *data)
>         data->max_reportid = 0;
>  }
>
> -static int mxt_get_object_table(struct mxt_data *data)
> +static int mxt_parse_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;
>
> @@ -1591,7 +1576,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 = mxt_obj_size(object);
> @@ -1651,22 +1636,102 @@ 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 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 == 0) || (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);
> +
> +       dev_info(&client->dev,
> +                "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
> +                info->family_id, info->variant_id, info->version >> 4,
> +                info->version & 0xf, info->build, info->object_num);
> +

Use data->info->XXX here,  info was pointing to buf which could have
changed after krealloc.

> +       /* 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;
>         }
>
>         return 0;
>
> -free_object_table:
> -       mxt_free_object_table(data);
> +err_free_mem:
> +       kfree(buf);
>         return error;
>  }
>
> @@ -1721,13 +1786,12 @@ 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;
>         bool alt_bootloader_addr = false;
>         bool retry = false;
>
>  retry_info:
> -       error = mxt_get_info(data);
> +       error = mxt_read_info_block(data);
>         if (error) {
>  retry_bootloader:
>                 error = mxt_probe_bootloader(data, alt_bootloader_addr);
> @@ -1759,21 +1823,6 @@ retry_bootloader:
>                 }
>         }
>
> -       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);
> -               goto err_free_object_table;
> -       }
> -
>         error = mxt_acquire_irq(data);
>         if (error)
>                 goto err_free_object_table;
> @@ -1792,17 +1841,6 @@ retry_bootloader:
>                 goto err_free_object_table;
>         }
>
> -       error = mxt_read_t9_resolution(data);
> -       if (error) {
> -               dev_err(&client->dev, "Failed to initialize T9 resolution\n");
> -               goto err_free_object_table;
> -       }
> -
> -       dev_info(&client->dev,
> -                "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
> -                info->family_id, info->variant_id, info->version >> 4,
> -                info->version & 0xf, info->build, info->object_num);
> -
>         data->enable_reporting = true;
>
>         return 0;
> @@ -1817,9 +1855,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 */
> @@ -1827,9 +1865,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,
> @@ -1866,7 +1903,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))
> @@ -2211,6 +2248,10 @@ static int mxt_initialize_t9_input_device(struct mxt_data *data)
>         unsigned int mt_flags = 0;
>         int i;
>
> +       error = mxt_read_t9_resolution(data);
> +       if (error)
> +               dev_warn(dev, "Failed to initialize T9 resolution\n");
> +
>         input_dev = input_allocate_device();
>         if (!input_dev) {
>                 dev_err(dev, "Failed to allocate memory\n");
> --
> 1.7.10.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org
  2013-06-06 19:46     ` Dmitry Torokhov
@ 2013-06-07 20:21       ` Yufeng Shen
  0 siblings, 0 replies; 93+ messages in thread
From: Yufeng Shen @ 2013-06-07 20:21 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Daniel Kurtz, Henrik Rydberg, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson, Nick Dyer

Acked-by: Yufeng Shen <miletus@chromium.org>

Test the patch series on Chromebook Pixel with kernel 3.8.
Touchscreen & trackpad work, FW/Config update work.

On Thu, Jun 6, 2013 at 3:46 PM, Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
> On Thu, Jun 06, 2013 at 03:40:47PM -0400, Yufeng Shen wrote:
>> On Thu, Jun 6, 2013 at 3:18 PM, Dmitry Torokhov
>> <dmitry.torokhov@gmail.com>wrote:
>>
>> > On Wed, Jun 05, 2013 at 06:36:53PM +0100, Nick Dyer wrote:
>> > > The following patches are an updated series of patches to the
>> > atmel_mxt_ts
>> > > touch driver. They should apply cleanly to input/next.
>> > >
>> > > This is a combined patchset, I've been working to merge my changes with
>> > the
>> > > changes from the Chromium team. It's undergone a lot of testing and
>> > review
>> > > over the last few months and I believe it is now ready to go upstream.
>> > >
>> > > Most of these changes have been maintained and tested out-of-tree in
>> > some form
>> > > for a long time. I apologise for the backlog.
>> > >
>> > > 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
>> > >
>> > > You can see the in-between versions at
>> > >   https://github.com/ndyer/linux/
>> > >
>> >
>> > Daniel, Henrik,
>> >
>> > Any comments befroe I start pulling parts of this in?
>> >
>>
>>
>> Can you hold this on for a few days ?  I would like to verify this patch
>> series from chromium side.
>> I probably would do it tomorrow and next monday and send back ack asap.
>
> Sure, holding on is what I do best ;)
>
> Thanks.
>
> --
> Dmitry

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

* Re: [PATCH 44/53] Input: atmel_mxt_ts - Verify Information Block checksum on probe
  2013-06-07 18:37   ` Yufeng Shen
@ 2013-06-10  9:35     ` Nick Dyer
  0 siblings, 0 replies; 93+ messages in thread
From: Nick Dyer @ 2013-06-10  9:35 UTC (permalink / raw)
  To: Yufeng Shen
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan Bowens, linux-input, linux-kernel, Peter Meerwald,
	Benson Leung, Olof Johansson

Yufeng Shen wrote:
>> +       dev_info(&client->dev,
>> +                "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
>> +                info->family_id, info->variant_id, info->version >> 4,
>> +                info->version & 0xf, info->build, info->object_num);
>> +
> 
> Use data->info->XXX here,  info was pointing to buf which could have
> changed after krealloc.

Thank you, that's a really good spot. Caused when I merged the dev_info
line into that function. It actually explains a report I had about getting
junk in this output but the info_crc check succeeding, hadn't had time to
investigate yet.

I will fix.

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-07 16:47                                   ` Mark Brown
@ 2013-06-11 10:39                                     ` Nick Dyer
  2013-06-11 11:47                                       ` Mark Brown
  0 siblings, 1 reply; 93+ messages in thread
From: Nick Dyer @ 2013-06-11 10:39 UTC (permalink / raw)
  To: Mark Brown
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

Mark Brown wrote:
> I don't think you're using the usual definition of "register map" here.
> You seem to be switching between talking about this object model the
> device has and device registers - perhaps the objects are also registers
> sometimes?

Yes, in Atmel Object Protocol "instances" of "objects" do each have an
assigned register range (they do also correspond to modules of code in the
firmware).

This document is a better description of it than I can give:
http://www.atmel.com/Images/Atmel-9626-AT42-QTouch-BSW-AT421085-Object-Protocol-Guide_Datasheet.pdf

That's a rather old chip now, but the same system is used throughout
maXTouch series chips, and also on some non-touch chips now.

> You appear to be assuming a great deal of familiarity with the specifics
> of this device here.  Where does all thi stuff about reinitialsing the
> device come from?  What are these dependencies and what does all this
> have to do with setting parameters?

I think you're uncomfortable with the idea of giving full access by
default. I'm not sure how I can convince you that that is OK by design, I
can only assert it.

Essentially, the device is designed (and tested) on the assumption that
touch processing can be going on whilst various parameters are changed in a
live fashion. If poking around in the register map caused it to lock up or
behave oddly then that would be considered a firmware bug. In general it
will fail gracefully - for example if you write a configuration that is
invalid it will just stop and emit a CFGERR message.

In my previous messages in this thread, I tried to answer some of the
particular cases in which you might expect the driver to have to cope with
the configuration changing "under it". It's difficult to be exhaustive
without having to impart a huge amount of domain knowledge first.

In the patch under discussion, the driver would have to trap writes to
particular registers and take appropriate action, or provide a mechanism to
be told that it needs to reinitialise itself. In practice (it's been widely
tested outside of mainline) I haven't found a case where doing this has
been essential, although there's nothing about this patch that stops us
adding them.

The absolute worst thing that I can think of is that you can try to beat
the interrupt handler to reading the "message processor" registers, which
would possibly leave touches stuck on screen. But even that operation is
useful in debugging interrupt line issues.

>> OK. I think that the ABI offered to the application layer should also be
>> object protocol, implemented over a binary attribute, which is what the
>> patch under discussion does. Is the problem that I need to provide better
>> documentation of object protocol?
> 
> As Greg says you do need to document any new sysfs ABIs you're adding
> anyway.  However if this is some stateful protocol you're implementing
> then does it really map onto sysfs well, sysfs attributes are normally
> more just data values?

Perhaps it is a little unusual. There was an older ioctl-based
implementation, but I think that would be rejected for different reasons.

> Won't the driver end up getting into a fight with the magic userspace
> stuff if the driver has no idea what the magic userspace is doing?  How
> would suspend and resume work?

On suspend the driver puts chip into "deep sleep" where touch acquisition
is halted and minimal power consumed. But it will still come out of its
sleep state temporarily to service I2C comms if necessary (although one
particular family requires that I2C retry for this case).

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-11 10:39                                     ` Nick Dyer
@ 2013-06-11 11:47                                       ` Mark Brown
  2013-06-11 12:16                                         ` Nick Dyer
  0 siblings, 1 reply; 93+ messages in thread
From: Mark Brown @ 2013-06-11 11:47 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

[-- Attachment #1: Type: text/plain, Size: 2431 bytes --]

On Tue, Jun 11, 2013 at 11:39:37AM +0100, Nick Dyer wrote:
> Mark Brown wrote:

> > I don't think you're using the usual definition of "register map" here.
> > You seem to be switching between talking about this object model the
> > device has and device registers - perhaps the objects are also registers
> > sometimes?

> Yes, in Atmel Object Protocol "instances" of "objects" do each have an
> assigned register range (they do also correspond to modules of code in the
> firmware).

OK, so you're talking about the objects which happen to be implemented
in terms of the register map here.  I think this is confusing to me
because you are moving between the abstraction levels.

> Essentially, the device is designed (and tested) on the assumption that
> touch processing can be going on whilst various parameters are changed in a
> live fashion. If poking around in the register map caused it to lock up or
> behave oddly then that would be considered a firmware bug. In general it
> will fail gracefully - for example if you write a configuration that is
> invalid it will just stop and emit a CFGERR message.

That's not really it, it's the fact that this is being done with no
abstraction - exposing the entire device register map directly to
application layer so the application can totally ignore what's going on
in the kernel doesn't seem like awesome design.

> The absolute worst thing that I can think of is that you can try to beat
> the interrupt handler to reading the "message processor" registers, which
> would possibly leave touches stuck on screen. But even that operation is
> useful in debugging interrupt line issues.

Well, there's also the potential issues with standard application layer
code either not being able to do things that the hardware supports or
getting into a fight with the magic custom stuff.

> > Won't the driver end up getting into a fight with the magic userspace
> > stuff if the driver has no idea what the magic userspace is doing?  How
> > would suspend and resume work?

> On suspend the driver puts chip into "deep sleep" where touch acquisition
> is halted and minimal power consumed. But it will still come out of its
> sleep state temporarily to service I2C comms if necessary (although one
> particular family requires that I2C retry for this case).

So these errors are just part of waking the chip up - in that case
shouldn't the driver be waking the chip up automatically?

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-11 11:47                                       ` Mark Brown
@ 2013-06-11 12:16                                         ` Nick Dyer
  2013-06-19 18:59                                           ` Mark Brown
  0 siblings, 1 reply; 93+ messages in thread
From: Nick Dyer @ 2013-06-11 12:16 UTC (permalink / raw)
  To: Mark Brown
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

Mark Brown wrote:
>> Essentially, the device is designed (and tested) on the assumption that
>> touch processing can be going on whilst various parameters are changed in a
>> live fashion. If poking around in the register map caused it to lock up or
>> behave oddly then that would be considered a firmware bug. In general it
>> will fail gracefully - for example if you write a configuration that is
>> invalid it will just stop and emit a CFGERR message.
> 
> That's not really it, it's the fact that this is being done with no
> abstraction - exposing the entire device register map directly to
> application layer so the application can totally ignore what's going on
> in the kernel doesn't seem like awesome design.

Without being able to name all of the registers (which would require a
large amount of architecture to keep up-to-date and would probably turn
into an unmaintainable mess), you can only split up the register map into
separate parts. You'd end up with binary attributes like this (refer to the
document I linked for explanation):

info_block
object_table
t5
t6
t9instance1
t9instance2
etc

Is that a nicer design from your point of view? I don't personally think
that is really gains anything functional other than making the API more
complex and increasing the number of read/write operations. I guess you
would stop bugs in user space code from accidentally writing into the wrong
object.

>> The absolute worst thing that I can think of is that you can try to beat
>> the interrupt handler to reading the "message processor" registers, which
>> would possibly leave touches stuck on screen. But even that operation is
>> useful in debugging interrupt line issues.
> 
> Well, there's also the potential issues with standard application layer
> code either not being able to do things that the hardware supports or
> getting into a fight with the magic custom stuff.

I think it's better to present a clean API cut at the right level. If you
look at the drivers in various Android trees for these maXTouch chips,
there's an awful lot of phone specific code which is not very general and
it would be impossible to mainline without having a 20,000 line driver full
of #ifdefs. Surely it's better for that to go into a userspace daemon if
possible?

>> On suspend the driver puts chip into "deep sleep" where touch acquisition
>> is halted and minimal power consumed. But it will still come out of its
>> sleep state temporarily to service I2C comms if necessary (although one
>> particular family requires that I2C retry for this case).
> 
> So these errors are just part of waking the chip up - in that case
> shouldn't the driver be waking the chip up automatically?

In the reference design for that particular model of chip (mXT1386), there
is a WAKEUP pin cross-wired to an I2C line. The only way of getting it to
wake up when it is asleep is by trying to perform an I2C operation, which
will fail, and then retrying before it times out and goes back to sleep
again. There isn't any other way of waking it up.

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-11 12:16                                         ` Nick Dyer
@ 2013-06-19 18:59                                           ` Mark Brown
  2013-06-21 16:16                                             ` Nick Dyer
  0 siblings, 1 reply; 93+ messages in thread
From: Mark Brown @ 2013-06-19 18:59 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

[-- Attachment #1: Type: text/plain, Size: 2961 bytes --]

On Tue, Jun 11, 2013 at 01:16:31PM +0100, Nick Dyer wrote:

> Without being able to name all of the registers (which would require a
> large amount of architecture to keep up-to-date and would probably turn
> into an unmaintainable mess), you can only split up the register map into
> separate parts. You'd end up with binary attributes like this (refer to the
> document I linked for explanation):

...

> Is that a nicer design from your point of view? I don't personally think
> that is really gains anything functional other than making the API more
> complex and increasing the number of read/write operations. I guess you

Yes, to be honest.  I'd hope it wouldn't be increasing the number of
read/write operations...

> would stop bugs in user space code from accidentally writing into the wrong
> object.

That seems like a useful thing, and it does allow the driver to
relatively easily understand what any of the attributes is doing and
take it over if it needs to.

> > Well, there's also the potential issues with standard application layer
> > code either not being able to do things that the hardware supports or
> > getting into a fight with the magic custom stuff.

> I think it's better to present a clean API cut at the right level. If you
> look at the drivers in various Android trees for these maXTouch chips,
> there's an awful lot of phone specific code which is not very general and
> it would be impossible to mainline without having a 20,000 line driver full
> of #ifdefs. Surely it's better for that to go into a userspace daemon if
> possible?

Yes, having some of the stuff that understands the contents of the
controls in userspace is sensible.  However the kernel does offer an API
for controlling devices it supports and it seems reasonable to expect
that to work too - callibration and whatnot is a bit different but core
functionality should just work from the kernel.

> >> On suspend the driver puts chip into "deep sleep" where touch acquisition
> >> is halted and minimal power consumed. But it will still come out of its
> >> sleep state temporarily to service I2C comms if necessary (although one
> >> particular family requires that I2C retry for this case).

> > So these errors are just part of waking the chip up - in that case
> > shouldn't the driver be waking the chip up automatically?

> In the reference design for that particular model of chip (mXT1386), there
> is a WAKEUP pin cross-wired to an I2C line. The only way of getting it to
> wake up when it is asleep is by trying to perform an I2C operation, which
> will fail, and then retrying before it times out and goes back to sleep
> again. There isn't any other way of waking it up.

That still sounds like something the driver can handle (for example, by
eating the first error silently if it knows the chip is powered down)
and of course a system integrator may choose not to copy the reference
design in this respect, it does seem a bit odd after all.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-19 18:59                                           ` Mark Brown
@ 2013-06-21 16:16                                             ` Nick Dyer
  2013-07-02 10:11                                               ` Mark Brown
  0 siblings, 1 reply; 93+ messages in thread
From: Nick Dyer @ 2013-06-21 16:16 UTC (permalink / raw)
  To: Mark Brown
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

Mark Brown wrote:
>> Is that a nicer design from your point of view? I don't personally think
>> that is really gains anything functional other than making the API more
>> complex and increasing the number of read/write operations. I guess you
> 
> Yes, to be honest.  I'd hope it wouldn't be increasing the number of
> read/write operations...

For some operations it does. For example updating the whole chip config
(which is a common thing to want to do), it would turn a couple of write
operations into ~20 on recent chips.

>> would stop bugs in user space code from accidentally writing into the wrong
>> object.
> 
> That seems like a useful thing, and it does allow the driver to
> relatively easily understand what any of the attributes is doing and
> take it over if it needs to.

I guess you might save a tiny amount of lookup code.

>>> Well, there's also the potential issues with standard application layer
>>> code either not being able to do things that the hardware supports or
>>> getting into a fight with the magic custom stuff.
> 
>> I think it's better to present a clean API cut at the right level. If you
>> look at the drivers in various Android trees for these maXTouch chips,
>> there's an awful lot of phone specific code which is not very general and
>> it would be impossible to mainline without having a 20,000 line driver full
>> of #ifdefs. Surely it's better for that to go into a userspace daemon if
>> possible?
> 
> Yes, having some of the stuff that understands the contents of the
> controls in userspace is sensible.  However the kernel does offer an API
> for controlling devices it supports and it seems reasonable to expect
> that to work too - callibration and whatnot is a bit different but core
> functionality should just work from the kernel.

I completely agree - I just don't think that the API under discussion
really forces a choice over any of this.

Anyway, I will pull this patch (and the other sysfs interface one) from the
series, and try to come up with something along the lines that we have
discussed.

>> In the reference design for that particular model of chip (mXT1386), there
>> is a WAKEUP pin cross-wired to an I2C line. The only way of getting it to
>> wake up when it is asleep is by trying to perform an I2C operation, which
>> will fail, and then retrying before it times out and goes back to sleep
>> again. There isn't any other way of waking it up.
> 
> That still sounds like something the driver can handle (for example, by
> eating the first error silently if it knows the chip is powered down)

We've tried to implement this idea of tracking the chip power state in
the driver and only eating the first error silently when necessary. But
there are various entertaining corner cases (for example, it may or may
not be in sleep on probe, how do you deal with intermittent i2c glitch). It
would end up either being very brittle or an extremely complex mechanism
involving tracking state and timers, the result of which is only to
suppress a dmesg debug output saying "i2c retry", and to fail very slightly
earlier in the normal i2c failure case. The normal fast path through
this code is exactly the same.

> and of course a system integrator may choose not to copy the reference
> design in this respect, it does seem a bit odd after all.

You're being a bit optimistic there. Examples of devices that require
this are Samsung Galaxy Tab 10.1, Asus Transformer TF101.

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-06-21 16:16                                             ` Nick Dyer
@ 2013-07-02 10:11                                               ` Mark Brown
  2013-07-11  7:41                                                 ` Nick Dyer
  0 siblings, 1 reply; 93+ messages in thread
From: Mark Brown @ 2013-07-02 10:11 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

[-- Attachment #1: Type: text/plain, Size: 1854 bytes --]

On Fri, Jun 21, 2013 at 09:16:16AM -0700, Nick Dyer wrote:
> Mark Brown wrote:

> > Yes, to be honest.  I'd hope it wouldn't be increasing the number of
> > read/write operations...

> For some operations it does. For example updating the whole chip config
> (which is a common thing to want to do), it would turn a couple of write
> operations into ~20 on recent chips.

Is that really happening on peformance critical paths other than initial
power up (which could be handled more neatly anyway).

> > That still sounds like something the driver can handle (for example, by
> > eating the first error silently if it knows the chip is powered down)

> We've tried to implement this idea of tracking the chip power state in
> the driver and only eating the first error silently when necessary. But
> there are various entertaining corner cases (for example, it may or may
> not be in sleep on probe, how do you deal with intermittent i2c glitch). It
> would end up either being very brittle or an extremely complex mechanism
> involving tracking state and timers, the result of which is only to
> suppress a dmesg debug output saying "i2c retry", and to fail very slightly
> earlier in the normal i2c failure case. The normal fast path through
> this code is exactly the same.

It seems very suspicous that this device has all these problems but
others don't...

> > and of course a system integrator may choose not to copy the reference
> > design in this respect, it does seem a bit odd after all.

> You're being a bit optimistic there. Examples of devices that require
> this are Samsung Galaxy Tab 10.1, Asus Transformer TF101.

If absoluely nobody has used the separate wakeup pin then the hardware
designers are wasting a pin there...  my point isn't that nobody would
use the reference design it's that some boards will have the separate
signal.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-07-02 10:11                                               ` Mark Brown
@ 2013-07-11  7:41                                                 ` Nick Dyer
  2013-07-11 10:30                                                   ` Mark Brown
  0 siblings, 1 reply; 93+ messages in thread
From: Nick Dyer @ 2013-07-11  7:41 UTC (permalink / raw)
  To: Mark Brown
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

Mark Brown wrote:
> On Fri, Jun 21, 2013 at 09:16:16AM -0700, Nick Dyer wrote:
>> Mark Brown wrote:
>>> Yes, to be honest.  I'd hope it wouldn't be increasing the number of
>>> read/write operations...
> 
>> For some operations it does. For example updating the whole chip config
>> (which is a common thing to want to do), it would turn a couple of write
>> operations into ~20 on recent chips.
> 
> Is that really happening on peformance critical paths other than initial
> power up (which could be handled more neatly anyway).

Well, you're right that we could probably add more API for performance
critical stuff. But that wasn't your original question.

>>> and of course a system integrator may choose not to copy the reference
>>> design in this respect, it does seem a bit odd after all.
> 
>> You're being a bit optimistic there. Examples of devices that require
>> this are Samsung Galaxy Tab 10.1, Asus Transformer TF101.
> 
> If absoluely nobody has used the separate wakeup pin then the hardware
> designers are wasting a pin there...  my point isn't that nobody would
> use the reference design it's that some boards will have the separate
> signal.

That's entirely hypothetical, and you're wasting our time until you can
actually point to such hardware, happy to write patches to support that
mode of operation as well if you do.

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

* Re: [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs
  2013-07-11  7:41                                                 ` Nick Dyer
@ 2013-07-11 10:30                                                   ` Mark Brown
  0 siblings, 0 replies; 93+ messages in thread
From: Mark Brown @ 2013-07-11 10:30 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Henrik Rydberg, Joonyoung Shim,
	Alan.Bowens, linux-input, linux-kernel, pmeerw, bleung, olofj

[-- Attachment #1: Type: text/plain, Size: 1508 bytes --]

On Thu, Jul 11, 2013 at 08:41:41AM +0100, Nick Dyer wrote:
> Mark Brown wrote:
> > On Fri, Jun 21, 2013 at 09:16:16AM -0700, Nick Dyer wrote:

> >> For some operations it does. For example updating the whole chip config
> >> (which is a common thing to want to do), it would turn a couple of write
> >> operations into ~20 on recent chips.

> > Is that really happening on peformance critical paths other than initial
> > power up (which could be handled more neatly anyway).

> Well, you're right that we could probably add more API for performance
> critical stuff. But that wasn't your original question.

You probably don't need another API here - for example, if the driver
understands that the device is powered off and knows enugh about what
the device is doing to understand that it doesn't need to be running
then it could for example cache what is being written then flush in a
more optimal fashion.

> > If absoluely nobody has used the separate wakeup pin then the hardware
> > designers are wasting a pin there...  my point isn't that nobody would
> > use the reference design it's that some boards will have the separate
> > signal.

> That's entirely hypothetical, and you're wasting our time until you can
> actually point to such hardware, happy to write patches to support that
> mode of operation as well if you do.

See above - it's not just about the possibility that someone might have
done a better job with the hardware design, better power management is
just a good idea in general.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

end of thread, other threads:[~2013-07-11 10:31 UTC | newest]

Thread overview: 93+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-05 17:36 Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Nick Dyer
2013-06-05 17:36 ` [PATCH 01/53] Input: atmel_mxt_ts - Remove unnecessary platform data Nick Dyer
2013-06-05 17:36 ` [PATCH 02/53] Input: atmel_mxt_ts - Improve T19 GPIO keys handling Nick Dyer
2013-06-05 17:36 ` [PATCH 03/53] Input: atmel_mxt_ts - Return IRQ_NONE when interrupt handler fails Nick Dyer
2013-06-05 17:36 ` [PATCH 04/53] Input: atmel_mxt_ts - define helper functions for size and instances Nick Dyer
2013-06-05 17:36 ` [PATCH 05/53] Input: atmel_mxt_ts - Select FW_LOADER for firmware code Nick Dyer
2013-06-05 17:36 ` [PATCH 06/53] Input: atmel_mxt_ts - wait for CHG assert in mxt_check_bootloader Nick Dyer
2013-06-05 17:37 ` [PATCH 07/53] Input: atmel_mxt_ts - wait for CHG after bootloader resets Nick Dyer
2013-06-05 17:37 ` [PATCH 08/53] Input: atmel_mxt_ts - Initialise IRQ before probing Nick Dyer
2013-06-05 17:37 ` [PATCH 09/53] Input: atmel_mxt_ts - Make wait-after-reset period compatible with all chips Nick Dyer
2013-06-05 17:37 ` [PATCH 10/53] Input: atmel_mxt_ts - Add memory access interface via sysfs Nick Dyer
2013-06-05 17:57   ` Dmitry Torokhov
2013-06-05 18:45     ` Nick Dyer
2013-06-05 19:04       ` Dmitry Torokhov
2013-06-05 20:31         ` Nick Dyer
2013-06-05 21:07           ` Dmitry Torokhov
2013-06-05 21:36             ` Nick Dyer
2013-06-06 10:03               ` Mark Brown
2013-06-06 10:31                 ` Nick Dyer
2013-06-06 10:55                   ` Mark Brown
2013-06-06 11:17                     ` Nick Dyer
2013-06-06 13:16                       ` Mark Brown
2013-06-06 16:13                         ` Nick Dyer
2013-06-06 16:46                           ` Mark Brown
2013-06-07 15:12                             ` Nick Dyer
2013-06-07 15:41                               ` Mark Brown
2013-06-07 16:11                                 ` Nick Dyer
2013-06-07 16:47                                   ` Mark Brown
2013-06-11 10:39                                     ` Nick Dyer
2013-06-11 11:47                                       ` Mark Brown
2013-06-11 12:16                                         ` Nick Dyer
2013-06-19 18:59                                           ` Mark Brown
2013-06-21 16:16                                             ` Nick Dyer
2013-07-02 10:11                                               ` Mark Brown
2013-07-11  7:41                                                 ` Nick Dyer
2013-07-11 10:30                                                   ` Mark Brown
2013-06-06  9:48             ` Mark Brown
2013-06-06 10:40               ` Nick Dyer
2013-06-06 10:46                 ` Mark Brown
2013-06-06 11:00                   ` Nick Dyer
2013-06-06 11:14                     ` Mark Brown
2013-06-06 11:34                       ` Nick Dyer
2013-06-06 13:21                         ` Mark Brown
2013-06-06 18:01   ` Greg KH
2013-06-07 14:47     ` Nick Dyer
2013-06-05 17:37 ` [PATCH 11/53] Input: atmel_mxt_ts - Implement debug output for messages Nick Dyer
2013-06-05 17:37 ` [PATCH 12/53] Input: atmel_mxt_ts - Improve error reporting and debug Nick Dyer
2013-06-05 17:37 ` [PATCH 13/53] Input: atmel_mxt_ts - Implement CRC check for configuration data Nick Dyer
2013-06-05 17:37 ` [PATCH 14/53] Input: atmel_mxt_ts - Download device config using firmware loader Nick Dyer
2013-06-05 17:37 ` [PATCH 15/53] Input: atmel_mxt_ts - Calculate and check CRC in config file Nick Dyer
2013-06-05 17:37 ` [PATCH 16/53] Input: atmel_mxt_ts - Add additional bootloader addresses Nick Dyer
2013-06-05 17:37 ` [PATCH 17/53] Input: atmel_mxt_ts - Read and report bootloader version Nick Dyer
2013-06-05 17:37 ` [PATCH 18/53] Input: atmel_mxt_ts - Implement bootloader frame retries Nick Dyer
2013-06-05 17:37 ` [PATCH 19/53] Input: atmel_mxt_ts - Improve bootloader progress output Nick Dyer
2013-06-05 17:37 ` [PATCH 20/53] Input: atmel_mxt_ts - Add check for incorrect firmware file format Nick Dyer
2013-06-05 17:37 ` [PATCH 21/53] Input: atmel_mxt_ts - Read screen config from chip Nick Dyer
2013-06-05 17:37 ` [PATCH 22/53] Input: atmel_mxt_ts - Set default irqflags when there is no pdata Nick Dyer
2013-06-05 17:37 ` [PATCH 23/53] Input: atmel_mxt_ts - Use deep sleep mode when stopped Nick Dyer
2013-06-05 17:37 ` [PATCH 24/53] Input: atmel_mxt_ts - Add shutdown function Nick Dyer
2013-06-05 17:37 ` [PATCH 25/53] Input: atmel_mxt_ts - Rename pressure to amplitude to match spec Nick Dyer
2013-06-05 17:37 ` [PATCH 26/53] Input: atmel_mxt_ts - Rename touchscreen defines to include T9 Nick Dyer
2013-06-05 17:37 ` [PATCH 27/53] Input: atmel_mxt_ts - Handle multiple input reports in one message Nick Dyer
2013-06-05 17:37 ` [PATCH 28/53] Input: atmel_mxt_ts - Move input device init into separate function Nick Dyer
2013-06-05 17:37 ` [PATCH 29/53] Input: atmel_mxt_ts - Handle APP_CRC_FAIL on startup Nick Dyer
2013-06-05 17:37 ` [PATCH 30/53] Input: atmel_mxt_ts - Handle bootloader previously unlocked Nick Dyer
2013-06-05 17:37 ` [PATCH 31/53] Input: atmel_mxt_ts - Add bootloader addresses for new chips Nick Dyer
2013-06-05 17:37 ` [PATCH 32/53] Input: atmel_mxt_ts - Recover from bootloader on probe Nick Dyer
2013-06-05 17:37 ` [PATCH 33/53] Input: atmel_mxt_ts - Add support for dynamic message size Nick Dyer
2013-06-05 17:37 ` [PATCH 34/53] Input: atmel_mxt_ts - Decode T6 status messages Nick Dyer
2013-06-05 17:37 ` [PATCH 35/53] Input: atmel_mxt_ts - Split message handler into separate functions Nick Dyer
2013-06-05 17:37 ` [PATCH 36/53] Input: atmel_mxt_ts - Implement T44 message handling Nick Dyer
2013-06-05 17:37 ` [PATCH 37/53] Input: atmel_mxt_ts - Output status from T48 Noise Supression Nick Dyer
2013-06-05 17:37 ` [PATCH 38/53] Input: atmel_mxt_ts - Output status from T42 Touch Suppression Nick Dyer
2013-06-05 17:37 ` [PATCH 39/53] Input: atmel_mxt_ts - Implement vector/orientation support Nick Dyer
2013-06-05 17:37 ` [PATCH 40/53] Input: atmel_mxt_ts - implement I2C retries Nick Dyer
2013-06-05 17:37 ` [PATCH 41/53] Input: atmel_mxt_ts - Implement T63 Active Stylus support Nick Dyer
2013-06-05 17:37 ` [PATCH 42/53] Input: atmel_mxt_ts - Implement support for T15 Key Array Nick Dyer
2013-06-05 17:37 ` [PATCH 43/53] Input: atmel_mxt_ts - Remove unused defines Nick Dyer
2013-06-05 17:37 ` [PATCH 44/53] Input: atmel_mxt_ts - Verify Information Block checksum on probe Nick Dyer
2013-06-07 18:37   ` Yufeng Shen
2013-06-10  9:35     ` Nick Dyer
2013-06-05 17:37 ` [PATCH 45/53] Input: atmel_mxt_ts - Use T18 RETRIGEN to handle IRQF_TRIGGER_LOW Nick Dyer
2013-06-05 17:37 ` [PATCH 46/53] Input: atmel_mxt_ts - Handle reports from T47 Stylus object Nick Dyer
2013-06-05 17:37 ` [PATCH 47/53] Input: atmel_mxt_ts - Release touch state during suspend Nick Dyer
2013-06-05 17:37 ` [PATCH 48/53] Input: atmel_mxt_ts - Initialize power config before and after downloading cfg Nick Dyer
2013-06-05 17:37 ` [PATCH 49/53] Input: atmel_mxt_ts - Add regulator control support Nick Dyer
2013-06-05 17:37 ` [PATCH 50/53] Input: atmel_mxt_ts - Implement support for T100 touch object Nick Dyer
2013-06-05 17:37 ` [PATCH 51/53] Input: atmel_mxt_ts - Allow specification of firmware file name Nick Dyer
2013-06-05 17:37 ` [PATCH 52/53] Input: atmel_mxt_ts - Handle cfg filename via pdata/sysfs Nick Dyer
2013-06-05 17:37 ` [PATCH 53/53] Input: atmel_mxt_ts - Only use first T9 instance Nick Dyer
2013-06-06 19:18 ` Atmel updates to atmel_mxt_ts touch controller driver - v5 Daniel Kurtz <djkurtz@chromium.org>, Henrik Rydberg <rydberg@euromail.se>, Joonyoung Shim <jy0922.shim@samsung.com>, Alan.Bowens@atmel.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, pmeerw@pmeerw.net, bleung@chromium.org, olofj@chromium.org Dmitry Torokhov
     [not found]   ` <CAPDwgkPdtj0Th8P+y9e5O7swARfzS40sG1A3Ba=pAmeXfMx0Dw@mail.gmail.com>
2013-06-06 19:46     ` Dmitry Torokhov
2013-06-07 20:21       ` Yufeng Shen

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.