All of lore.kernel.org
 help / color / mirror / Atom feed
* Atmel updates to atmel_mxt_ts touch controller driver - v6
@ 2013-06-27 12:48 Nick Dyer
  2013-06-27 12:48 ` [PATCH 01/51] Input: atmel_mxt_ts - Remove unnecessary platform data Nick Dyer
                   ` (52 more replies)
  0 siblings, 53 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

Some minor updates to these patches to address review comments. I've rebased
them on the latest dtor/next tree.

Input: atmel_mxt_ts - Verify Information Block checksum on probe
- Fix bug which might cause erroneous debug output due to use of krealloc (thanks to
  Yufeng Shen for spotting this)

Input: atmel_mxt_ts - Implement T63 Active Stylus support
- Add T63 to #defines since there will be other active stylus objects

Input: atmel_mxt_ts - Implement debug output for messages
Input: atmel_mxt_ts - Add memory access interface via sysfs
- remove from series (move mem_size calculation)

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


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

* [PATCH 01/51] Input: atmel_mxt_ts - Remove unnecessary platform data
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 02/51] Input: atmel_mxt_ts - Improve T19 GPIO keys handling Nick Dyer
                   ` (51 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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] 87+ messages in thread

* [PATCH 02/51] Input: atmel_mxt_ts - Improve T19 GPIO keys handling
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
  2013-06-27 12:48 ` [PATCH 01/51] Input: atmel_mxt_ts - Remove unnecessary platform data Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-07-18 17:11   ` rydberg
  2013-06-27 12:48 ` [PATCH 03/51] Input: atmel_mxt_ts - Return IRQ_NONE when interrupt handler fails Nick Dyer
                   ` (50 subsequent siblings)
  52 siblings, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

 * 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] 87+ messages in thread

* [PATCH 03/51] Input: atmel_mxt_ts - Return IRQ_NONE when interrupt handler fails
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
  2013-06-27 12:48 ` [PATCH 01/51] Input: atmel_mxt_ts - Remove unnecessary platform data Nick Dyer
  2013-06-27 12:48 ` [PATCH 02/51] Input: atmel_mxt_ts - Improve T19 GPIO keys handling Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 04/51] Input: atmel_mxt_ts - define helper functions for size and instances Nick Dyer
                   ` (49 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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] 87+ messages in thread

* [PATCH 04/51] Input: atmel_mxt_ts - define helper functions for size and instances
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (2 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 03/51] Input: atmel_mxt_ts - Return IRQ_NONE when interrupt handler fails Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 05/51] Input: atmel_mxt_ts - Select FW_LOADER for firmware code Nick Dyer
                   ` (48 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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] 87+ messages in thread

* [PATCH 05/51] Input: atmel_mxt_ts - Select FW_LOADER for firmware code
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (3 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 04/51] Input: atmel_mxt_ts - define helper functions for size and instances Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 06/51] Input: atmel_mxt_ts - wait for CHG assert in mxt_check_bootloader Nick Dyer
                   ` (47 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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] 87+ messages in thread

* [PATCH 06/51] Input: atmel_mxt_ts - wait for CHG assert in mxt_check_bootloader
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (4 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 05/51] Input: atmel_mxt_ts - Select FW_LOADER for firmware code Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 07/51] Input: atmel_mxt_ts - wait for CHG after bootloader resets Nick Dyer
                   ` (46 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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] 87+ messages in thread

* [PATCH 07/51] Input: atmel_mxt_ts - wait for CHG after bootloader resets
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (5 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 06/51] Input: atmel_mxt_ts - wait for CHG assert in mxt_check_bootloader Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 08/51] Input: atmel_mxt_ts - Initialise IRQ before probing Nick Dyer
                   ` (45 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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] 87+ messages in thread

* [PATCH 08/51] Input: atmel_mxt_ts - Initialise IRQ before probing
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (6 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 07/51] Input: atmel_mxt_ts - wait for CHG after bootloader resets Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-07-18 17:13   ` rydberg
  2013-06-27 12:48 ` [PATCH 09/51] Input: atmel_mxt_ts - Make wait-after-reset period compatible with all chips Nick Dyer
                   ` (44 subsequent siblings)
  52 siblings, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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] 87+ messages in thread

* [PATCH 09/51] Input: atmel_mxt_ts - Make wait-after-reset period compatible with all chips
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (7 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 08/51] Input: atmel_mxt_ts - Initialise IRQ before probing Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 10/51] Input: atmel_mxt_ts - Improve error reporting and debug Nick Dyer
                   ` (43 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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] 87+ messages in thread

* [PATCH 10/51] Input: atmel_mxt_ts - Improve error reporting and debug
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (8 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 09/51] Input: atmel_mxt_ts - Make wait-after-reset period compatible with all chips Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 11/51] Input: atmel_mxt_ts - Implement CRC check for configuration data Nick Dyer
                   ` (42 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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 11ee78a..471bc4d 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -424,7 +424,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;
 	}
 
@@ -544,7 +545,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;
 }
 
@@ -889,7 +890,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);
@@ -944,8 +945,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)
@@ -953,8 +956,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);
@@ -973,12 +979,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);
 
@@ -1187,7 +1193,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);
@@ -1352,12 +1359,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;
+	}
 
 	return 0;
 
-- 
1.7.10.4


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

* [PATCH 11/51] Input: atmel_mxt_ts - Implement CRC check for configuration data
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (9 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 10/51] Input: atmel_mxt_ts - Improve error reporting and debug Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-09-18 16:59   ` [11/51] " Martin Fuzzey
  2013-06-27 12:48 ` [PATCH 12/51] Input: atmel_mxt_ts - Download device config using firmware loader Nick Dyer
                   ` (41 subsequent siblings)
  52 siblings, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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 471bc4d..ad9fc91 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -189,6 +189,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 */
 
@@ -260,6 +261,7 @@ struct mxt_data {
 	unsigned int max_x;
 	unsigned int max_y;
 	bool in_bootloader;
+	u32 config_crc;
 
 	/* Cached parameters from object table */
 	u8 T6_reportid;
@@ -274,6 +276,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;
 };
@@ -648,7 +653,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);
 }
@@ -666,6 +671,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;
+	u32 crc;
 
 	do {
 		if (mxt_read_message(data, &message)) {
@@ -677,9 +683,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);
@@ -772,6 +784,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;
@@ -786,6 +811,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;
 
@@ -805,6 +840,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;
 }
 
@@ -962,11 +1005,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)
@@ -1292,6 +1330,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] 87+ messages in thread

* [PATCH 12/51] Input: atmel_mxt_ts - Download device config using firmware loader
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (10 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 11/51] Input: atmel_mxt_ts - Implement CRC check for configuration data Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-09-18 17:08   ` [12/51] " Martin Fuzzey
  2013-06-27 12:48 ` [PATCH 13/51] Input: atmel_mxt_ts - Calculate and check CRC in config file Nick Dyer
                   ` (40 subsequent siblings)
  52 siblings, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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 ad9fc91..2054c64 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
@@ -326,37 +328,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)
 {
@@ -550,7 +521,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;
 }
 
@@ -797,58 +768,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] 87+ messages in thread

* [PATCH 13/51] Input: atmel_mxt_ts - Calculate and check CRC in config file
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (11 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 12/51] Input: atmel_mxt_ts - Download device config using firmware loader Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 14/51] Input: atmel_mxt_ts - Add additional bootloader addresses Nick Dyer
                   ` (39 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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 |  224 +++++++++++++++++++++++-------
 1 file changed, 171 insertions(+), 53 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 2054c64..751f446 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -53,6 +53,8 @@
 #define MXT_OBJECT_START	0x07
 
 #define MXT_OBJECT_SIZE		6
+#define MXT_INFO_CHECKSUM_SIZE	3
+#define MXT_MAX_BLOCK_WRITE	256
 
 /* Object types */
 #define MXT_DEBUG_DIAGNOSTIC_T37	37
@@ -263,11 +265,14 @@ struct mxt_data {
 	unsigned int max_x;
 	unsigned int max_y;
 	bool in_bootloader;
+	u16 mem_size;
 	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;
@@ -768,6 +773,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
  *
@@ -795,9 +839,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;
@@ -817,11 +865,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) {
@@ -830,7 +878,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) {
@@ -845,123 +893,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;
@@ -1023,6 +1130,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,
@@ -1032,6 +1140,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;
@@ -1059,6 +1168,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;
@@ -1067,6 +1179,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;
-- 
1.7.10.4


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

* [PATCH 14/51] Input: atmel_mxt_ts - Add additional bootloader addresses
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (12 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 13/51] Input: atmel_mxt_ts - Calculate and check CRC in config file Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 15/51] Input: atmel_mxt_ts - Read and report bootloader version Nick Dyer
                   ` (38 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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 751f446..82327e6 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"
@@ -268,6 +262,7 @@ struct mxt_data {
 	u16 mem_size;
 	u32 config_crc;
 	u32 info_crc;
+	u8 bootloader_addr;
 
 	/* Cached parameters from object table */
 	u8 T6_reportid;
@@ -358,9 +353,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;
 
@@ -381,15 +449,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:
@@ -405,7 +472,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;
 	}
@@ -413,28 +480,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;
 }
@@ -1366,7 +1422,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;
@@ -1378,6 +1433,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;
 
@@ -1387,12 +1446,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);
@@ -1400,7 +1453,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);
@@ -1415,7 +1468,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)
@@ -1443,13 +1498,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] 87+ messages in thread

* [PATCH 15/51] Input: atmel_mxt_ts - Read and report bootloader version
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (13 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 14/51] Input: atmel_mxt_ts - Add additional bootloader addresses Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 16/51] Input: atmel_mxt_ts - Implement bootloader frame retries Nick Dyer
                   ` (37 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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 82327e6..1ad60b6 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -203,6 +203,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)
@@ -426,6 +428,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;
@@ -458,6 +481,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] 87+ messages in thread

* [PATCH 16/51] Input: atmel_mxt_ts - Implement bootloader frame retries
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (14 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 15/51] Input: atmel_mxt_ts - Read and report bootloader version Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 17/51] Input: atmel_mxt_ts - Improve bootloader progress output Nick Dyer
                   ` (36 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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 1ad60b6..3172610 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -490,8 +490,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;
@@ -1451,6 +1455,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);
@@ -1488,9 +1493,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 */
@@ -1499,10 +1502,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] 87+ messages in thread

* [PATCH 17/51] Input: atmel_mxt_ts - Improve bootloader progress output
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (15 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 16/51] Input: atmel_mxt_ts - Implement bootloader frame retries Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 18/51] Input: atmel_mxt_ts - Add check for incorrect firmware file format Nick Dyer
                   ` (35 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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 3172610..99ebdec 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1456,6 +1456,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);
@@ -1515,9 +1516,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. */
@@ -1526,6 +1530,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] 87+ messages in thread

* [PATCH 18/51] Input: atmel_mxt_ts - Add check for incorrect firmware file format
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (16 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 17/51] Input: atmel_mxt_ts - Improve bootloader progress output Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 19/51] Input: atmel_mxt_ts - Read screen config from chip Nick Dyer
                   ` (34 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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 99ebdec..767050b 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1449,6 +1449,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);
@@ -1465,6 +1487,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] 87+ messages in thread

* [PATCH 19/51] Input: atmel_mxt_ts - Read screen config from chip
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (17 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 18/51] Input: atmel_mxt_ts - Add check for incorrect firmware file format Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata Nick Dyer
                   ` (33 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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 767050b..1334e5b 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -105,33 +105,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
@@ -216,11 +199,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
 
@@ -560,11 +538,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)
 {
@@ -1287,12 +1260,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)
@@ -1325,26 +1345,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;
 
@@ -1355,20 +1365,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)
@@ -1686,8 +1682,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] 87+ messages in thread

* [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (18 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 19/51] Input: atmel_mxt_ts - Read screen config from chip Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-07-18 17:17   ` rydberg
  2013-06-27 12:48 ` [PATCH 21/51] Input: atmel_mxt_ts - Use deep sleep mode when stopped Nick Dyer
                   ` (32 subsequent siblings)
  52 siblings, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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, 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 1334e5b..2645d36 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -232,7 +232,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;
@@ -1640,10 +1640,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;
@@ -1651,9 +1670,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) {
@@ -1675,19 +1691,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);
@@ -1700,13 +1720,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;
 
@@ -1743,7 +1763,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) {
@@ -1767,7 +1786,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);
@@ -1782,6 +1804,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] 87+ messages in thread

* [PATCH 21/51] Input: atmel_mxt_ts - Use deep sleep mode when stopped
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (19 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 22/51] Input: atmel_mxt_ts - Add shutdown function Nick Dyer
                   ` (31 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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 2645d36..ee1e866 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -90,9 +90,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
@@ -104,7 +108,6 @@
 #define MXT_ACQUIRE_ATCHCALSTHR	7
 
 /* MXT_TOUCH_MULTI_T9 field */
-#define MXT_TOUCH_CTRL		0
 #define MXT_T9_ORIENT		9
 #define MXT_T9_RANGE		18
 
@@ -243,6 +246,7 @@ struct mxt_data {
 	u32 config_crc;
 	u32 info_crc;
 	u8 bootloader_addr;
+	struct t7_config t7_cfg;
 
 	/* Cached parameters from object table */
 	u8 T6_reportid;
@@ -604,20 +608,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;
@@ -1133,6 +1123,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;
@@ -1345,6 +1390,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");
@@ -1612,16 +1663,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)
@@ -1834,8 +1884,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] 87+ messages in thread

* [PATCH 22/51] Input: atmel_mxt_ts - Add shutdown function
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (20 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 21/51] Input: atmel_mxt_ts - Use deep sleep mode when stopped Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-07-07  5:29   ` Dmitry Torokhov
  2013-06-27 12:48 ` [PATCH 23/51] Input: atmel_mxt_ts - Rename pressure to amplitude to match spec Nick Dyer
                   ` (30 subsequent siblings)
  52 siblings, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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 ee1e866..76f1c20 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1897,6 +1897,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 },
@@ -1914,6 +1921,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] 87+ messages in thread

* [PATCH 23/51] Input: atmel_mxt_ts - Rename pressure to amplitude to match spec
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (21 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 22/51] Input: atmel_mxt_ts - Add shutdown function Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:48 ` [PATCH 24/51] Input: atmel_mxt_ts - Rename touchscreen defines to include T9 Nick Dyer
                   ` (29 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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 76f1c20..8ccc809de 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -637,7 +637,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)
@@ -651,7 +651,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",
@@ -664,7 +664,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,
@@ -673,7 +673,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] 87+ messages in thread

* [PATCH 24/51] Input: atmel_mxt_ts - Rename touchscreen defines to include T9
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (22 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 23/51] Input: atmel_mxt_ts - Rename pressure to amplitude to match spec Nick Dyer
@ 2013-06-27 12:48 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 25/51] Input: atmel_mxt_ts - Handle multiple input reports in one message Nick Dyer
                   ` (28 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:48 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

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 8ccc809de..5a16383 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -111,13 +111,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
@@ -192,16 +202,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
 
@@ -656,21 +656,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);
@@ -1339,7 +1339,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] 87+ messages in thread

* [PATCH 25/51] Input: atmel_mxt_ts - Handle multiple input reports in one message
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (23 preceding siblings ...)
  2013-06-27 12:48 ` [PATCH 24/51] Input: atmel_mxt_ts - Rename touchscreen defines to include T9 Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-07-18 17:18   ` rydberg
  2013-06-27 12:49 ` [PATCH 26/51] Input: atmel_mxt_ts - Move input device init into separate function Nick Dyer
                   ` (27 subsequent siblings)
  52 siblings, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 5a16383..8632133 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -628,6 +628,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)
 {
@@ -645,10 +651,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];
@@ -667,14 +675,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);
 	}
 }
 
@@ -732,10 +752,8 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 		}
 	} while (reportid != 0xff);
 
-	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] 87+ messages in thread

* [PATCH 26/51] Input: atmel_mxt_ts - Move input device init into separate function
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (24 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 25/51] Input: atmel_mxt_ts - Handle multiple input reports in one message Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-07-07  5:34   ` Dmitry Torokhov
  2013-07-18 17:20   ` rydberg
  2013-06-27 12:49 ` [PATCH 27/51] Input: atmel_mxt_ts - Handle APP_CRC_FAIL on startup Nick Dyer
                   ` (26 subsequent siblings)
  52 siblings, 2 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 8632133..030ebc5 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1728,73 +1728,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;
 
@@ -1819,8 +1785,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,
@@ -1834,11 +1803,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",
@@ -1849,8 +1871,8 @@ static int mxt_probe(struct i2c_client *client,
 	return 0;
 
 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:
@@ -1859,7 +1881,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] 87+ messages in thread

* [PATCH 27/51] Input: atmel_mxt_ts - Handle APP_CRC_FAIL on startup
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (25 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 26/51] Input: atmel_mxt_ts - Move input device init into separate function Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 28/51] Input: atmel_mxt_ts - Handle bootloader previously unlocked Nick Dyer
                   ` (25 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 030ebc5..0c0df6c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -410,6 +410,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;
@@ -469,6 +493,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:
@@ -1378,8 +1403,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),
@@ -1561,15 +1592,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);
@@ -1652,8 +1687,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;
@@ -1857,9 +1890,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] 87+ messages in thread

* [PATCH 28/51] Input: atmel_mxt_ts - Handle bootloader previously unlocked
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (26 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 27/51] Input: atmel_mxt_ts - Handle APP_CRC_FAIL on startup Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 29/51] Input: atmel_mxt_ts - Add bootloader addresses for new chips Nick Dyer
                   ` (24 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 0c0df6c..4385653 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -455,14 +455,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
@@ -1607,15 +1608,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;
 
@@ -1629,7 +1639,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] 87+ messages in thread

* [PATCH 29/51] Input: atmel_mxt_ts - Add bootloader addresses for new chips
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (27 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 28/51] Input: atmel_mxt_ts - Handle bootloader previously unlocked Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 30/51] Input: atmel_mxt_ts - Recover from bootloader on probe Nick Dyer
                   ` (23 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 4385653..780952a 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -393,6 +393,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] 87+ messages in thread

* [PATCH 30/51] Input: atmel_mxt_ts - Recover from bootloader on probe
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (28 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 29/51] Input: atmel_mxt_ts - Add bootloader addresses for new chips Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 31/51] Input: atmel_mxt_ts - Add support for dynamic message size Nick Dyer
                   ` (22 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 780952a..b8e2b04 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -385,7 +385,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;
@@ -394,7 +394,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;
 		}
@@ -416,14 +416,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;
 
@@ -524,13 +524,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)
@@ -1408,15 +1413,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,
@@ -1595,10 +1625,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;
@@ -1609,6 +1635,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);
@@ -1625,7 +1659,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] 87+ messages in thread

* [PATCH 31/51] Input: atmel_mxt_ts - Add support for dynamic message size
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (29 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 30/51] Input: atmel_mxt_ts - Recover from bootloader on probe Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 32/51] Input: atmel_mxt_ts - Decode T6 status messages Nick Dyer
                   ` (21 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 |  114 +++++++++++++++++-------------
 1 file changed, 65 insertions(+), 49 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b8e2b04..688eab3 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -79,6 +79,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
@@ -225,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;
@@ -247,8 +245,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;
@@ -312,11 +312,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, "reportid: %u\tmessage: %*ph\n",
-		message->reportid, 7, message->message);
+	dev_dbg(&data->client->dev, "message: %*ph\n",
+		data->T5_msg_size, message);
 }
 
 static int mxt_wait_for_completion(struct mxt_data *data,
@@ -630,8 +629,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;
@@ -642,10 +640,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;
@@ -660,7 +658,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);
 	}
 }
@@ -671,12 +669,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;
@@ -686,8 +684,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)
@@ -695,8 +695,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",
@@ -740,28 +740,28 @@ static u16 mxt_extract_T6_csum(const u8 *csum)
 	return csum[0] | (csum[1] << 8) | (csum[2] << 16);
 }
 
-static bool mxt_is_T9_message(struct mxt_data *data, struct mxt_message *msg)
+static bool mxt_is_T9_message(struct mxt_data *data, u8 *msg)
 {
-	u8 id = msg->reportid;
+	u8 id = msg[0];
 	return (id >= data->T9_reportid_min && id <= data->T9_reportid_max);
 }
 
 static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 {
-	struct mxt_message message;
-	const u8 *payload = &message.message[0];
+	u8 *message = &data->msg_buf[0];
+	const u8 *payload = &data->msg_buf[1];
 	struct device *dev = &data->client->dev;
 	u8 reportid;
 	bool update_input = false;
 	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];
 
 		if (reportid == data->T6_reportid) {
 			u8 status = payload[0];
@@ -777,17 +777,16 @@ 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 {
-			mxt_dump_message(dev, &message);
+			mxt_dump_message(data, message);
 		}
-	} while (reportid != 0xff);
+	} while (reportid != MXT_RPTID_NOMSG);
 
 	if (data->enable_reporting && update_input)
 		mxt_input_sync(data->input_dev);
@@ -1236,16 +1235,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 != 0xff && --count);
+	} while (data->msg_buf[0] != MXT_RPTID_NOMSG && --count);
 
 	if (!count) {
 		dev_err(dev, "CHG pin isn't cleared\n");
@@ -1282,6 +1280,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;
@@ -1323,6 +1336,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;
@@ -1346,18 +1362,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)
@@ -1959,7 +1975,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:
@@ -1977,7 +1993,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] 87+ messages in thread

* [PATCH 32/51] Input: atmel_mxt_ts - Decode T6 status messages
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (30 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 31/51] Input: atmel_mxt_ts - Add support for dynamic message size Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 33/51] Input: atmel_mxt_ts - Split message handler into separate functions Nick Dyer
                   ` (20 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 688eab3..3890ed5 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 {
@@ -246,6 +251,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;
@@ -629,6 +635,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;
@@ -735,11 +774,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];
@@ -749,11 +783,9 @@ 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;
-	u32 crc;
 
 	do {
 		if (mxt_read_message(data, message)) {
@@ -764,19 +796,7 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
 		reportid = message[0];
 
 		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] 87+ messages in thread

* [PATCH 33/51] Input: atmel_mxt_ts - Split message handler into separate functions
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (31 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 32/51] Input: atmel_mxt_ts - Decode T6 status messages Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 34/51] Input: atmel_mxt_ts - Implement T44 message handling Nick Dyer
                   ` (19 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 |  111 ++++++++++++++++--------------
 1 file changed, 58 insertions(+), 53 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 3890ed5..ef68bf1 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -252,8 +252,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;
@@ -668,20 +670,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;
@@ -708,7 +696,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;
@@ -772,44 +760,61 @@ 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];
+
+	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 {
+		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;
+	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];
+	return mxt_proc_message(data, data->msg_buf);
+}
 
-		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 {
-			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;
 }
@@ -1256,21 +1261,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)
@@ -1307,6 +1310,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;
@@ -1359,6 +1363,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] 87+ messages in thread

* [PATCH 34/51] Input: atmel_mxt_ts - Implement T44 message handling
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (32 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 33/51] Input: atmel_mxt_ts - Split message handler into separate functions Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 35/51] Input: atmel_mxt_ts - Output status from T48 Noise Supression Nick Dyer
                   ` (18 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 ef68bf1..5d51133 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -246,6 +246,7 @@ struct mxt_data {
 	unsigned int max_y;
 	bool in_bootloader;
 	u16 mem_size;
+	u8 max_reportid;
 	u32 config_crc;
 	u32 info_crc;
 	u8 bootloader_addr;
@@ -253,6 +254,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;
@@ -263,6 +266,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;
@@ -786,30 +790,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);
@@ -832,7 +949,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,
@@ -1257,32 +1378,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;
 
@@ -1317,6 +1419,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)
@@ -1361,8 +1465,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;
@@ -1374,6 +1484,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;
@@ -1387,7 +1502,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] 87+ messages in thread

* [PATCH 35/51] Input: atmel_mxt_ts - Output status from T48 Noise Supression
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (33 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 34/51] Input: atmel_mxt_ts - Implement T44 message handling Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 36/51] Input: atmel_mxt_ts - Output status from T42 Touch Suppression Nick Dyer
                   ` (17 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 5d51133..d7ce38d 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -267,6 +267,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;
@@ -768,6 +769,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];
@@ -783,6 +804,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 {
 		mxt_dump_message(data, message);
 	}
@@ -1420,6 +1443,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;
 }
 
@@ -1493,6 +1517,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] 87+ messages in thread

* [PATCH 36/51] Input: atmel_mxt_ts - Output status from T42 Touch Suppression
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (34 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 35/51] Input: atmel_mxt_ts - Output status from T48 Noise Supression Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 37/51] Input: atmel_mxt_ts - Implement vector/orientation support Nick Dyer
                   ` (16 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 d7ce38d..1c5e640 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 */
@@ -266,6 +269,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;
 
@@ -769,6 +774,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;
@@ -804,6 +820,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 {
@@ -1442,6 +1461,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;
@@ -1511,6 +1532,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] 87+ messages in thread

* [PATCH 37/51] Input: atmel_mxt_ts - Implement vector/orientation support
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (35 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 36/51] Input: atmel_mxt_ts - Output status from T42 Touch Suppression Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-07-18 17:20   ` rydberg
  2013-06-27 12:49 ` [PATCH 38/51] Input: atmel_mxt_ts - implement I2C retries Nick Dyer
                   ` (15 subsequent siblings)
  52 siblings, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 1c5e640..9188cf7 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -716,6 +716,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)
@@ -734,9 +735,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' : '.',
@@ -746,7 +748,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);
 
@@ -766,6 +768,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);
@@ -2100,6 +2103,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] 87+ messages in thread

* [PATCH 38/51] Input: atmel_mxt_ts - implement I2C retries
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (36 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 37/51] Input: atmel_mxt_ts - Implement vector/orientation support Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 39/51] Input: atmel_mxt_ts - Implement T63 Active Stylus support Nick Dyer
                   ` (14 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 9188cf7..b63f227 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
@@ -567,6 +568,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;
@@ -583,17 +585,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,
@@ -602,6 +609,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);
@@ -612,14 +620,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] 87+ messages in thread

* [PATCH 39/51] Input: atmel_mxt_ts - Implement T63 Active Stylus support
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (37 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 38/51] Input: atmel_mxt_ts - implement I2C retries Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-07-18 17:21   ` rydberg
  2013-06-27 12:49 ` [PATCH 40/51] Input: atmel_mxt_ts - Implement support for T15 Key Array Nick Dyer
                   ` (13 subsequent siblings)
  52 siblings, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 +++++++++++++++++++++++++++++-
 1 file changed, 94 insertions(+), 1 deletion(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b63f227..2e6118a 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_T63_STYLUS_PRESS	(1 << 0)
+#define MXT_T63_STYLUS_RELEASE	(1 << 1)
+#define MXT_T63_STYLUS_MOVE		(1 << 2)
+#define MXT_T63_STYLUS_SUPPRESS	(1 << 3)
+
+#define MXT_T63_STYLUS_DETECT	(1 << 4)
+#define MXT_T63_STYLUS_TIP		(1 << 5)
+#define MXT_T63_STYLUS_ERASER	(1 << 6)
+#define MXT_T63_STYLUS_BARREL	(1 << 7)
+
+#define MXT_T63_STYLUS_PRESSURE_MASK	0x3F
+
 /* Delay times */
 #define MXT_BACKUP_TIME		50	/* msec */
 #define MXT_RESET_TIME		200	/* msec */
@@ -260,6 +274,7 @@ struct mxt_data {
 	bool update_input;
 	u8 last_message_count;
 	u8 num_touchids;
+	u8 num_stylusids;
 
 	/* Cached parameters from object table */
 	u16 T5_address;
@@ -274,6 +289,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;
@@ -823,6 +840,63 @@ 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_T63_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_T63_STYLUS_SUPPRESS) ? 'S' : '.',
+		(msg[1] & MXT_T63_STYLUS_MOVE)     ? 'M' : '.',
+		(msg[1] & MXT_T63_STYLUS_RELEASE)  ? 'R' : '.',
+		(msg[1] & MXT_T63_STYLUS_PRESS)    ? 'P' : '.',
+		x, y, pressure,
+		(msg[2] & MXT_T63_STYLUS_BARREL) ? 'B' : '.',
+		(msg[2] & MXT_T63_STYLUS_ERASER) ? 'E' : '.',
+		(msg[2] & MXT_T63_STYLUS_TIP)    ? 'T' : '.',
+		(msg[2] & MXT_T63_STYLUS_DETECT) ? 'D' : '.');
+
+	input_mt_slot(input_dev, id);
+
+	if (msg[2] & MXT_T63_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_T63_STYLUS_ERASER));
+	input_report_key(input_dev, BTN_STYLUS2,
+			 (msg[2] & MXT_T63_STYLUS_BARREL));
+
+	mxt_input_sync(input_dev);
+}
+
 static int mxt_proc_message(struct mxt_data *data, u8 *message)
 {
 	u8 report_id = message[0];
@@ -838,6 +912,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);
@@ -1483,6 +1560,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;
 }
 
@@ -1563,6 +1642,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
@@ -2103,7 +2188,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);
@@ -2121,6 +2206,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] 87+ messages in thread

* [PATCH 40/51] Input: atmel_mxt_ts - Implement support for T15 Key Array
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (38 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 39/51] Input: atmel_mxt_ts - Implement T63 Active Stylus support Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 41/51] Input: atmel_mxt_ts - Remove unused defines Nick Dyer
                   ` (12 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 2e6118a..2eaa9d3 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -275,6 +275,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;
@@ -284,6 +285,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;
@@ -809,6 +812,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;
@@ -920,6 +959,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 {
 		mxt_dump_message(data, message);
 	}
@@ -1555,6 +1597,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;
@@ -1629,6 +1673,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;
@@ -2214,6 +2262,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] 87+ messages in thread

* [PATCH 41/51] Input: atmel_mxt_ts - Remove unused defines
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (39 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 40/51] Input: atmel_mxt_ts - Implement support for T15 Key Array Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 42/51] Input: atmel_mxt_ts - Verify Information Block checksum on probe Nick Dyer
                   ` (11 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 2eaa9d3..c01a457 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
@@ -1577,7 +1513,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] 87+ messages in thread

* [PATCH 42/51] Input: atmel_mxt_ts - Verify Information Block checksum on probe
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (40 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 41/51] Input: atmel_mxt_ts - Remove unused defines Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 43/51] Input: atmel_mxt_ts - Use T18 RETRIGEN to handle IRQF_TRIGGER_LOW Nick Dyer
                   ` (10 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 |  182 ++++++++++++++++++------------
 1 file changed, 112 insertions(+), 70 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index c01a457..8827bbd 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;
@@ -363,12 +364,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;
 		}
@@ -608,7 +613,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;
@@ -1245,13 +1250,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;
@@ -1298,7 +1303,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);
@@ -1506,24 +1511,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;
@@ -1545,25 +1538,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;
 
@@ -1587,7 +1572,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);
@@ -1647,22 +1632,103 @@ 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;
+	uint8_t num_objects;
+	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 */
+	num_objects = ((struct mxt_info *)buf)->object_num;
+	size += (num_objects * 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",
+		 data->info->family_id, data->info->variant_id,
+		 data->info->version >> 4, data->info->version & 0xf,
+		 data->info->build, data->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;
 }
 
@@ -1717,13 +1783,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);
@@ -1755,21 +1820,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;
@@ -1788,17 +1838,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;
@@ -1813,9 +1852,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 */
@@ -1823,9 +1862,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,
@@ -1862,7 +1900,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))
@@ -2127,6 +2165,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] 87+ messages in thread

* [PATCH 43/51] Input: atmel_mxt_ts - Use T18 RETRIGEN to handle IRQF_TRIGGER_LOW
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (41 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 42/51] Input: atmel_mxt_ts - Verify Information Block checksum on probe Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 44/51] Input: atmel_mxt_ts - Handle reports from T47 Stylus object Nick Dyer
                   ` (9 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 8827bbd..ee39683 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
@@ -213,6 +214,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;
@@ -224,6 +226,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;
@@ -1181,6 +1184,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
  *
@@ -1430,6 +1458,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;
@@ -1504,9 +1536,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;
 }
@@ -1528,6 +1562,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;
@@ -1598,6 +1633,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;
@@ -1820,6 +1858,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] 87+ messages in thread

* [PATCH 44/51] Input: atmel_mxt_ts - Handle reports from T47 Stylus object
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (42 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 43/51] Input: atmel_mxt_ts - Use T18 RETRIGEN to handle IRQF_TRIGGER_LOW Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-07-18 17:23   ` rydberg
  2013-06-27 12:49 ` [PATCH 45/51] Input: atmel_mxt_ts - Release touch state during suspend Nick Dyer
                   ` (8 subsequent siblings)
  52 siblings, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 ee39683..ceb090a 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_T63_STYLUS_PRESS	(1 << 0)
 #define MXT_T63_STYLUS_RELEASE	(1 << 1)
@@ -696,6 +699,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)
@@ -713,6 +717,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
 		y >>= 2;
 
 	area = message[5];
+
 	amplitude = message[6];
 	vector = message[7];
 
@@ -741,8 +746,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] 87+ messages in thread

* [PATCH 45/51] Input: atmel_mxt_ts - Release touch state during suspend
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (43 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 44/51] Input: atmel_mxt_ts - Handle reports from T47 Stylus object Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-07-18 17:29   ` rydberg
  2013-06-27 12:49 ` [PATCH 46/51] Input: atmel_mxt_ts - Initialize power config before and after downloading cfg Nick Dyer
                   ` (7 subsequent siblings)
  52 siblings, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 ceb090a..b4ecd1d 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -249,6 +249,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)
@@ -2025,6 +2028,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;
@@ -2137,6 +2145,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;
@@ -2162,17 +2172,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] 87+ messages in thread

* [PATCH 46/51] Input: atmel_mxt_ts - Initialize power config before and after downloading cfg
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (44 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 45/51] Input: atmel_mxt_ts - Release touch state during suspend Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 47/51] Input: atmel_mxt_ts - Add regulator control support Nick Dyer
                   ` (6 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 b4ecd1d..5ab3861 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1226,6 +1226,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
  *
@@ -1485,6 +1487,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:
@@ -1883,17 +1888,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] 87+ messages in thread

* [PATCH 47/51] Input: atmel_mxt_ts - Add regulator control support
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (45 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 46/51] Input: atmel_mxt_ts - Initialize power config before and after downloading cfg Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 48/51] Input: atmel_mxt_ts - Implement support for T100 touch object Nick Dyer
                   ` (5 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 5ab3861..b75cf38 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
@@ -218,6 +222,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;
@@ -1840,6 +1847,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;
@@ -2034,6 +2101,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;
 	}
@@ -2198,14 +2268,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;
@@ -2220,7 +2294,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;
@@ -2408,6 +2485,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);
@@ -2451,6 +2530,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] 87+ messages in thread

* [PATCH 48/51] Input: atmel_mxt_ts - Implement support for T100 touch object
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (46 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 47/51] Input: atmel_mxt_ts - Add regulator control support Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 49/51] Input: atmel_mxt_ts - Allow specification of firmware file name Nick Dyer
                   ` (4 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 b75cf38..cb6fe8f 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_T63_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;
 	u8 max_reportid;
 	u32 config_crc;
 	u32 info_crc;
@@ -244,6 +265,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;
@@ -780,6 +803,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;
@@ -916,6 +1012,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;
@@ -1582,6 +1681,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;
@@ -1599,6 +1704,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;
 }
 
@@ -1684,6 +1791,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
@@ -1907,6 +2020,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;
@@ -1969,6 +2244,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;
@@ -2493,24 +2780,15 @@ 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;
 	}
 
 	return 0;
 
-err_unregister_device:
-	input_unregister_device(data->input_dev);
-	data->input_dev = NULL;
 err_free_object:
 	mxt_free_object_table(data);
 err_free_irq:
@@ -2529,7 +2807,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] 87+ messages in thread

* [PATCH 49/51] Input: atmel_mxt_ts - Allow specification of firmware file name
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (47 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 48/51] Input: atmel_mxt_ts - Implement support for T100 touch object Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 50/51] Input: atmel_mxt_ts - Handle cfg filename via pdata/sysfs Nick Dyer
                   ` (3 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 cb6fe8f..9aa3a26 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"
 
@@ -246,6 +245,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;
@@ -2366,7 +2366,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;
@@ -2376,9 +2376,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;
 	}
 
@@ -2493,6 +2493,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)
@@ -2500,7 +2529,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] 87+ messages in thread

* [PATCH 50/51] Input: atmel_mxt_ts - Handle cfg filename via pdata/sysfs
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (48 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 49/51] Input: atmel_mxt_ts - Allow specification of firmware file name Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 12:49 ` [PATCH 51/51] Input: atmel_mxt_ts - Only use first T9 instance Nick Dyer
                   ` (2 subsequent siblings)
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 9aa3a26..9a5ac2c 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 */
@@ -246,6 +245,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;
@@ -1372,10 +1372,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;
 	}
 
@@ -1673,6 +1678,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);
@@ -1682,10 +1695,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;
@@ -2181,6 +2191,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)
 {
@@ -2224,16 +2235,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 */
@@ -2241,28 +2264,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 */
@@ -2550,16 +2568,57 @@ 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 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 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_update_cfg.attr,
 	NULL
 };
 
@@ -2644,8 +2703,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] 87+ messages in thread

* [PATCH 51/51] Input: atmel_mxt_ts - Only use first T9 instance
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (49 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 50/51] Input: atmel_mxt_ts - Handle cfg filename via pdata/sysfs Nick Dyer
@ 2013-06-27 12:49 ` Nick Dyer
  2013-06-27 15:17 ` Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
  2013-07-18 19:47 ` rydberg
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 12:49 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

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 9a5ac2c..7380a40 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1770,10 +1770,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;
@@ -1796,10 +1797,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] 87+ messages in thread

* Re: Atmel updates to atmel_mxt_ts touch controller driver - v6
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (50 preceding siblings ...)
  2013-06-27 12:49 ` [PATCH 51/51] Input: atmel_mxt_ts - Only use first T9 instance Nick Dyer
@ 2013-06-27 15:17 ` Nick Dyer
  2013-07-18 19:47 ` rydberg
  52 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-06-27 15:17 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

Hi Dimitry-

Nick Dyer wrote:
> Some minor updates to these patches to address review comments. I've rebased
> them on the latest dtor/next tree.

Apologies, I forgot to add Yufeng's Acked-by lines. To save cluttering up
the list, I've pushed a new version with just that change to

git@github.com:ndyer/linux.git

the tag is

for-next-20130627-v7

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

* Re: [PATCH 22/51] Input: atmel_mxt_ts - Add shutdown function
  2013-06-27 12:48 ` [PATCH 22/51] Input: atmel_mxt_ts - Add shutdown function Nick Dyer
@ 2013-07-07  5:29   ` Dmitry Torokhov
  2013-07-08  9:56     ` Nick Dyer
  0 siblings, 1 reply; 87+ messages in thread
From: Dmitry Torokhov @ 2013-07-07  5:29 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Daniel Kurtz, Henrik Rydberg, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson

Hi Nick,

On Thu, Jun 27, 2013 at 01:48:57PM +0100, Nick Dyer wrote:
> Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
> Acked-by: Benson Leung <bleung@chromium.org>

Why is this needed?

Thanks.

> ---
>  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 ee1e866..76f1c20 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -1897,6 +1897,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 },
> @@ -1914,6 +1921,7 @@ static struct i2c_driver mxt_driver = {
>  	},
>  	.probe		= mxt_probe,
>  	.remove		= mxt_remove,
> +	.shutdown	= mxt_shutdown,
>  	.id_table	= mxt_id,
>  };
>  
> -- 
> 1.7.10.4
> 

-- 
Dmitry

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

* Re: [PATCH 26/51] Input: atmel_mxt_ts - Move input device init into separate function
  2013-06-27 12:49 ` [PATCH 26/51] Input: atmel_mxt_ts - Move input device init into separate function Nick Dyer
@ 2013-07-07  5:34   ` Dmitry Torokhov
  2013-07-08  9:41     ` Nick Dyer
  2013-07-18 17:20   ` rydberg
  1 sibling, 1 reply; 87+ messages in thread
From: Dmitry Torokhov @ 2013-07-07  5:34 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Daniel Kurtz, Henrik Rydberg, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson

On Thu, Jun 27, 2013 at 01:49:01PM +0100, Nick Dyer wrote:
> Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>

So before we allocated input device before requesting IRQ, now we fo it
afterwards so there is moment where the interrupt is requested and not
disabled and input device is not allocated yet. Is it possible for
interrupt to happen at that moment?

Thanks.

> ---
>  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 8632133..030ebc5 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -1728,73 +1728,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;
>  
> @@ -1819,8 +1785,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,
> @@ -1834,11 +1803,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",
> @@ -1849,8 +1871,8 @@ static int mxt_probe(struct i2c_client *client,
>  	return 0;
>  
>  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:
> @@ -1859,7 +1881,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
> 

-- 
Dmitry

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

* Re: [PATCH 26/51] Input: atmel_mxt_ts - Move input device init into separate function
  2013-07-07  5:34   ` Dmitry Torokhov
@ 2013-07-08  9:41     ` Nick Dyer
  2013-07-10 16:53       ` Dmitry Torokhov
  0 siblings, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2013-07-08  9:41 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

Dmitry Torokhov wrote:
> On Thu, Jun 27, 2013 at 01:49:01PM +0100, Nick Dyer wrote:
>> Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
> 
> So before we allocated input device before requesting IRQ, now we fo it
> afterwards so there is moment where the interrupt is requested and not
> disabled and input device is not allocated yet. Is it possible for
> interrupt to happen at that moment?

Yes, and it will be handled correctly, there are guards in the correct
places to ensure the input device will not be used before being registered.

It is registered at this point since there are several paths that might
need the interrupt handler (for example, to handle flash if device is in
failed state, or to upload configuration if necessary).

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

* Re: [PATCH 22/51] Input: atmel_mxt_ts - Add shutdown function
  2013-07-07  5:29   ` Dmitry Torokhov
@ 2013-07-08  9:56     ` Nick Dyer
  2013-07-10 16:55       ` Dmitry Torokhov
  0 siblings, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2013-07-08  9:56 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

Dmitry Torokhov wrote:
> On Thu, Jun 27, 2013 at 01:48:57PM +0100, Nick Dyer wrote:
>> Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
>> Acked-by: Benson Leung <bleung@chromium.org>
> 
> Why is this needed?

The patch disables the interrupt handler on shutdown.

One of our customers reported a bug caused by input events being generated
during shutdown (for example if the user was touching the device whilst it
was turning off), which was solved by putting in this change.

However, now you've drawn my attention to it again, it seems to me that
probably a better thing for us to be doing would be to power off the
touchscreen controller here, and let the interrupt disable be handled by
core code - do you agree?

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

* Re: [PATCH 26/51] Input: atmel_mxt_ts - Move input device init into separate function
  2013-07-08  9:41     ` Nick Dyer
@ 2013-07-10 16:53       ` Dmitry Torokhov
  0 siblings, 0 replies; 87+ messages in thread
From: Dmitry Torokhov @ 2013-07-10 16:53 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Daniel Kurtz, Henrik Rydberg, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson

On Mon, Jul 08, 2013 at 10:41:33AM +0100, Nick Dyer wrote:
> Dmitry Torokhov wrote:
> > On Thu, Jun 27, 2013 at 01:49:01PM +0100, Nick Dyer wrote:
> >> Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
> > 
> > So before we allocated input device before requesting IRQ, now we fo it
> > afterwards so there is moment where the interrupt is requested and not
> > disabled and input device is not allocated yet. Is it possible for
> > interrupt to happen at that moment?
> 
> Yes, and it will be handled correctly, there are guards in the correct
> places to ensure the input device will not be used before being registered.
> 
> It is registered at this point since there are several paths that might
> need the interrupt handler (for example, to handle flash if device is in
> failed state, or to upload configuration if necessary).

OK, thanks.

-- 
Dmitry

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

* Re: [PATCH 22/51] Input: atmel_mxt_ts - Add shutdown function
  2013-07-08  9:56     ` Nick Dyer
@ 2013-07-10 16:55       ` Dmitry Torokhov
  2013-07-10 18:32         ` Nick Dyer
  0 siblings, 1 reply; 87+ messages in thread
From: Dmitry Torokhov @ 2013-07-10 16:55 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Daniel Kurtz, Henrik Rydberg, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson

On Mon, Jul 08, 2013 at 10:56:06AM +0100, Nick Dyer wrote:
> Dmitry Torokhov wrote:
> > On Thu, Jun 27, 2013 at 01:48:57PM +0100, Nick Dyer wrote:
> >> Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
> >> Acked-by: Benson Leung <bleung@chromium.org>
> > 
> > Why is this needed?
> 
> The patch disables the interrupt handler on shutdown.
> 
> One of our customers reported a bug caused by input events being generated
> during shutdown (for example if the user was touching the device whilst it
> was turning off), which was solved by putting in this change.

What kind of bug? Could you please be more precise?

> 
> However, now you've drawn my attention to it again, it seems to me that
> probably a better thing for us to be doing would be to power off the
> touchscreen controller here, and let the interrupt disable be handled by
> core code - do you agree?

We'd be powering off everything in a moment anyway, no? Or is there a
concern that the device will stay powered up even if the system is in off
state?

Thanks.

-- 
Dmitry

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

* Re: [PATCH 22/51] Input: atmel_mxt_ts - Add shutdown function
  2013-07-10 16:55       ` Dmitry Torokhov
@ 2013-07-10 18:32         ` Nick Dyer
  0 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-07-10 18:32 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

Dmitry Torokhov wrote:
>> The patch disables the interrupt handler on shutdown.
>>
>> One of our customers reported a bug caused by input events being generated
>> during shutdown (for example if the user was touching the device whilst it
>> was turning off), which was solved by putting in this change.
> 
> What kind of bug? Could you please be more precise?

I did some more digging. Unfortunately the original problem report (some
time around March 2012) was in a customer ticket system that I no longer
have access to. It could well be trying to paper over a problem in their
app layer, to be honest.

>> However, now you've drawn my attention to it again, it seems to me that
>> probably a better thing for us to be doing would be to power off the
>> touchscreen controller here, and let the interrupt disable be handled by
>> core code - do you agree?
> 
> We'd be powering off everything in a moment anyway, no? Or is there a
> concern that the device will stay powered up even if the system is in off
> state?

I agree. I think it's best to not apply this patch for the moment, until we
can prove it's actually required.

Let me know if you want me to generate a new pull request.

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

* Re: [PATCH 02/51] Input: atmel_mxt_ts - Improve T19 GPIO keys handling
  2013-06-27 12:48 ` [PATCH 02/51] Input: atmel_mxt_ts - Improve T19 GPIO keys handling Nick Dyer
@ 2013-07-18 17:11   ` rydberg
  0 siblings, 0 replies; 87+ messages in thread
From: rydberg @ 2013-07-18 17:11 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson

On Thu, Jun 27, 2013 at 01:48:37PM +0100, Nick Dyer wrote:
> 
>  * 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(-)

    Reviewed-by: Henrik Rydberg <rydberg@euromail.se>

Thanks,
Henrik

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

* Re: [PATCH 08/51] Input: atmel_mxt_ts - Initialise IRQ before probing
  2013-06-27 12:48 ` [PATCH 08/51] Input: atmel_mxt_ts - Initialise IRQ before probing Nick Dyer
@ 2013-07-18 17:13   ` rydberg
  0 siblings, 0 replies; 87+ messages in thread
From: rydberg @ 2013-07-18 17:13 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson

Hi Nick,

> 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;

Regardless of the rationale, this test seems to create complex logic
further down the patchset. Any chance it could be done differently?

> +
>  	/* 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;
> +}
> +

Strange error handling; the name suggests that an error means the irq
has not been enabled, which it clearly does anyways. Also, the error
is not checked everywhere later in the patchset. Opencode instead?

>  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);

It is unclear what portion of the code should be executed with irqs
off. A better framing of the sensitive code path would be nice.

> +
>  	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
> 

Thanks,
Henrik

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

* Re: [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
  2013-06-27 12:48 ` [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata Nick Dyer
@ 2013-07-18 17:17   ` rydberg
  2013-09-16  2:25     ` Dmitry Torokhov
  0 siblings, 1 reply; 87+ messages in thread
From: rydberg @ 2013-07-18 17:17 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson, Yufeng Shen

Hi Nick,

> 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 1334e5b..2645d36 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -232,7 +232,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;
> @@ -1640,10 +1640,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;
> +	}

Any chance this could be a static instead?

> +
> +	/* Set default parameters */
> +	data->pdata->irqflags = IRQF_TRIGGER_FALLING;
> +
> +	return 0;
> +}
> +

Opencode instead?

>  static int mxt_probe(struct i2c_client *client,
>  		const struct i2c_device_id *id)
>  {
> -	const struct mxt_platform_data *pdata = client->dev.platform_data;

This line keeps reappearing in various versions of this
function. Perhaps it should simply stay as is instead?

>  	struct mxt_data *data;
>  	struct input_dev *input_dev;
>  	int error;
> @@ -1651,9 +1670,6 @@ static int mxt_probe(struct i2c_client *client,
>  	unsigned int mt_flags = 0;
>  	int i;
>  
> -	if (!pdata)

Why not just initialize the default here instead?

> -		return -EINVAL;
> -
>  	data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL);
>  	input_dev = input_allocate_device();
>  	if (!data || !input_dev) {
> @@ -1675,19 +1691,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;

then this would go away

>  
>  	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);

and this hunk

>  	if (error) {
>  		dev_err(&client->dev, "Failed to register interrupt\n");
> -		goto err_free_mem;
> +		goto err_free_pdata;
>  	}
>  
>  	disable_irq(client->irq);
> @@ -1700,13 +1720,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) {

and this hunk

>  		__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;
>  
> @@ -1743,7 +1763,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) {
> @@ -1767,7 +1786,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);
> @@ -1782,6 +1804,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);

Shared ownership should perhaps be signalled in a more robust way?

>  	kfree(data);
>  
>  	return 0;
> -- 
> 1.7.10.4
> 

Thanks,
Henrik

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

* Re: [PATCH 25/51] Input: atmel_mxt_ts - Handle multiple input reports in one message
  2013-06-27 12:49 ` [PATCH 25/51] Input: atmel_mxt_ts - Handle multiple input reports in one message Nick Dyer
@ 2013-07-18 17:18   ` rydberg
  0 siblings, 0 replies; 87+ messages in thread
From: rydberg @ 2013-07-18 17:18 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson

Hi Nick,

> 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 5a16383..8632133 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -628,6 +628,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);
> +}

Why not handle the enable_reporting and update_input logic here as
well? The logic is inconsistent with the rest of the patchset.

> +
>  static void mxt_input_touchevent(struct mxt_data *data,
>  				      struct mxt_message *message, int id)
>  {
> @@ -645,10 +651,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;

Unrelated changes.

>  
>  	area = message->message[4];
>  	amplitude = message->message[5];
> @@ -667,14 +675,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);

What are the guarantees that nobody else expects the frame to not be
cut off here? What is the update_input state after this operation?

> +		}
> +
> +		/* 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);
>  	}
>  }
>  
> @@ -732,10 +752,8 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
>  		}
>  	} while (reportid != 0xff);
>  
> -	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
> 

Thanks,
Henrik

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

* Re: [PATCH 26/51] Input: atmel_mxt_ts - Move input device init into separate function
  2013-06-27 12:49 ` [PATCH 26/51] Input: atmel_mxt_ts - Move input device init into separate function Nick Dyer
  2013-07-07  5:34   ` Dmitry Torokhov
@ 2013-07-18 17:20   ` rydberg
  1 sibling, 0 replies; 87+ messages in thread
From: rydberg @ 2013-07-18 17:20 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson

On Thu, Jun 27, 2013 at 01:49:01PM +0100, Nick Dyer wrote:
> 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 8632133..030ebc5 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -1728,73 +1728,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;

Similar code was removed from mxt_initialize(), some consistency would be nice.

>  	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;
>  
> @@ -1819,8 +1785,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,
> @@ -1834,11 +1803,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",
> @@ -1849,8 +1871,8 @@ static int mxt_probe(struct i2c_client *client,
>  	return 0;
>  
>  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:
> @@ -1859,7 +1881,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
> 

In what way does this patch simplify things?

Thanks,
Henrik

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

* Re: [PATCH 37/51] Input: atmel_mxt_ts - Implement vector/orientation support
  2013-06-27 12:49 ` [PATCH 37/51] Input: atmel_mxt_ts - Implement vector/orientation support Nick Dyer
@ 2013-07-18 17:20   ` rydberg
  2013-08-15 16:18     ` Nick Dyer
  0 siblings, 1 reply; 87+ messages in thread
From: rydberg @ 2013-07-18 17:20 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson

On Thu, Jun 27, 2013 at 01:49:12PM +0100, Nick Dyer wrote:
> 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.

How does this compare to the input mt documentation?

> 
> 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 1c5e640..9188cf7 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -716,6 +716,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)
> @@ -734,9 +735,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' : '.',
> @@ -746,7 +748,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);
>  
> @@ -766,6 +768,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);
> @@ -2100,6 +2103,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
> 

Thanks,
Henrik

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

* Re: [PATCH 39/51] Input: atmel_mxt_ts - Implement T63 Active Stylus support
  2013-06-27 12:49 ` [PATCH 39/51] Input: atmel_mxt_ts - Implement T63 Active Stylus support Nick Dyer
@ 2013-07-18 17:21   ` rydberg
  0 siblings, 0 replies; 87+ messages in thread
From: rydberg @ 2013-07-18 17:21 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson

On Thu, Jun 27, 2013 at 01:49:14PM +0100, Nick Dyer wrote:
> 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 +++++++++++++++++++++++++++++-
>  1 file changed, 94 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
> index b63f227..2e6118a 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_T63_STYLUS_PRESS	(1 << 0)
> +#define MXT_T63_STYLUS_RELEASE	(1 << 1)
> +#define MXT_T63_STYLUS_MOVE		(1 << 2)
> +#define MXT_T63_STYLUS_SUPPRESS	(1 << 3)
> +
> +#define MXT_T63_STYLUS_DETECT	(1 << 4)
> +#define MXT_T63_STYLUS_TIP		(1 << 5)
> +#define MXT_T63_STYLUS_ERASER	(1 << 6)
> +#define MXT_T63_STYLUS_BARREL	(1 << 7)
> +
> +#define MXT_T63_STYLUS_PRESSURE_MASK	0x3F
> +
>  /* Delay times */
>  #define MXT_BACKUP_TIME		50	/* msec */
>  #define MXT_RESET_TIME		200	/* msec */
> @@ -260,6 +274,7 @@ struct mxt_data {
>  	bool update_input;
>  	u8 last_message_count;
>  	u8 num_touchids;
> +	u8 num_stylusids;
>  
>  	/* Cached parameters from object table */
>  	u16 T5_address;
> @@ -274,6 +289,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;
> @@ -823,6 +840,63 @@ 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_T63_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_T63_STYLUS_SUPPRESS) ? 'S' : '.',
> +		(msg[1] & MXT_T63_STYLUS_MOVE)     ? 'M' : '.',
> +		(msg[1] & MXT_T63_STYLUS_RELEASE)  ? 'R' : '.',
> +		(msg[1] & MXT_T63_STYLUS_PRESS)    ? 'P' : '.',
> +		x, y, pressure,
> +		(msg[2] & MXT_T63_STYLUS_BARREL) ? 'B' : '.',
> +		(msg[2] & MXT_T63_STYLUS_ERASER) ? 'E' : '.',
> +		(msg[2] & MXT_T63_STYLUS_TIP)    ? 'T' : '.',
> +		(msg[2] & MXT_T63_STYLUS_DETECT) ? 'D' : '.');
> +
> +	input_mt_slot(input_dev, id);
> +
> +	if (msg[2] & MXT_T63_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_T63_STYLUS_ERASER));
> +	input_report_key(input_dev, BTN_STYLUS2,
> +			 (msg[2] & MXT_T63_STYLUS_BARREL));
> +
> +	mxt_input_sync(input_dev);
> +}
> +
>  static int mxt_proc_message(struct mxt_data *data, u8 *message)
>  {
>  	u8 report_id = message[0];
> @@ -838,6 +912,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);
> @@ -1483,6 +1560,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;
>  }
>  
> @@ -1563,6 +1642,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
> @@ -2103,7 +2188,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);
> @@ -2121,6 +2206,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
> 

    Reviewed-by: Henrik Rydberg <rydberg@euromail.se>

Thanks,
Henrik

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

* Re: [PATCH 44/51] Input: atmel_mxt_ts - Handle reports from T47 Stylus object
  2013-06-27 12:49 ` [PATCH 44/51] Input: atmel_mxt_ts - Handle reports from T47 Stylus object Nick Dyer
@ 2013-07-18 17:23   ` rydberg
  0 siblings, 0 replies; 87+ messages in thread
From: rydberg @ 2013-07-18 17:23 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson

On Thu, Jun 27, 2013 at 01:49:19PM +0100, Nick Dyer wrote:
> 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 ee39683..ceb090a 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
> +

Ok - normally, creating dummy values is not recommended, but for the
shared touch/stylys implementation there is obviously no alternative.

>  /* T63 Stylus */
>  #define MXT_T63_STYLUS_PRESS	(1 << 0)
>  #define MXT_T63_STYLUS_RELEASE	(1 << 1)
> @@ -696,6 +699,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)
> @@ -713,6 +717,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
>  		y >>= 2;
>  
>  	area = message[5];
> +
>  	amplitude = message[6];
>  	vector = message[7];
>  
> @@ -741,8 +746,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
> 

    Reviewed-by: Henrik Rydberg <rydberg@euromail.se>

Thanks,
Henrik

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

* Re: [PATCH 45/51] Input: atmel_mxt_ts - Release touch state during suspend
  2013-06-27 12:49 ` [PATCH 45/51] Input: atmel_mxt_ts - Release touch state during suspend Nick Dyer
@ 2013-07-18 17:29   ` rydberg
  2013-08-15 15:52     ` Nick Dyer
  0 siblings, 1 reply; 87+ messages in thread
From: rydberg @ 2013-07-18 17:29 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson

On Thu, Jun 27, 2013 at 01:49:20PM +0100, Nick Dyer wrote:
> 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.

How long is the window of possible stray interrupts? Could this be
done with a small delay instead of keeping track of the suspend state?

> 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 ceb090a..b4ecd1d 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -249,6 +249,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)
> @@ -2025,6 +2028,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;
> @@ -2137,6 +2145,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;
> @@ -2162,17 +2172,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
> 

    Reviewed-by: Henrik Rydberg <rydberg@euromail.se>

Thanks,
Henrik

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

* Re: Atmel updates to atmel_mxt_ts touch controller driver - v6
  2013-06-27 12:48 Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
                   ` (51 preceding siblings ...)
  2013-06-27 15:17 ` Atmel updates to atmel_mxt_ts touch controller driver - v6 Nick Dyer
@ 2013-07-18 19:47 ` rydberg
  2013-08-15 15:55   ` Nick Dyer
  52 siblings, 1 reply; 87+ messages in thread
From: rydberg @ 2013-07-18 19:47 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Daniel Kurtz, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson

Hi Nick,

First: thanks for the patches and you work on this driver.

Now, I don't swear much, but I would like to emphasize line 161 of
Documentation/SubmittingPatches:

**Do not send more than 15 patches at once to the vger mailing lists!!!***

One reason that should be obvious by now is that your work will be
attended to much quicker. One may think that it is more efficient to
send the whole backlog at once, but in fact, the time it takes to get
a patchset accepted is inversely proportional to the length of the
patchset. So please, keep it small and simple next time,

Thanks,
Henrik

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

* Re: [PATCH 45/51] Input: atmel_mxt_ts - Release touch state during suspend
  2013-07-18 17:29   ` rydberg
@ 2013-08-15 15:52     ` Nick Dyer
  0 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-08-15 15:52 UTC (permalink / raw)
  To: rydberg
  Cc: Dmitry Torokhov, Daniel Kurtz, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson

rydberg@euromail.se wrote:
> On Thu, Jun 27, 2013 at 01:49:20PM +0100, Nick Dyer wrote:
>> 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.
> 
> How long is the window of possible stray interrupts? Could this be
> done with a small delay instead of keeping track of the suspend state?

The touch controller has its own acquisition scheduling which switches
between active/idle modes. Which mode it is in isn't explicitly
communicated to the driver.

If we could tell it was in active mode (which would involve some hairier
code than this patch involves), we might have to wait ~20ms on a modern
device. But the worst case is that we would have to wait for the idle scan
interval plus some margin, so a couple of hundred ms. I think that is too
long, right?

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

* Re: Atmel updates to atmel_mxt_ts touch controller driver - v6
  2013-07-18 19:47 ` rydberg
@ 2013-08-15 15:55   ` Nick Dyer
  2013-08-15 16:07     ` Dmitry Torokhov
  0 siblings, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2013-08-15 15:55 UTC (permalink / raw)
  To: rydberg
  Cc: Dmitry Torokhov, Daniel Kurtz, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson

rydberg@euromail.se wrote:
> First: thanks for the patches and you work on this driver.

Thank you for your time in looking at these changes.

> Now, I don't swear much, but I would like to emphasize line 161 of
> Documentation/SubmittingPatches:
> 
> **Do not send more than 15 patches at once to the vger mailing lists!!!***
> 
> One reason that should be obvious by now is that your work will be
> attended to much quicker. One may think that it is more efficient to
> send the whole backlog at once, but in fact, the time it takes to get
> a patchset accepted is inversely proportional to the length of the
> patchset. So please, keep it small and simple next time,

Apologies. I will split this lot up into several smaller series of patches.

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

* Re: Atmel updates to atmel_mxt_ts touch controller driver - v6
  2013-08-15 15:55   ` Nick Dyer
@ 2013-08-15 16:07     ` Dmitry Torokhov
  2013-08-19 14:24       ` Nick Dyer
  2013-09-10 13:58       ` Nick Dyer
  0 siblings, 2 replies; 87+ messages in thread
From: Dmitry Torokhov @ 2013-08-15 16:07 UTC (permalink / raw)
  To: Nick Dyer
  Cc: rydberg, Daniel Kurtz, Joonyoung Shim, Alan Bowens, linux-input,
	linux-kernel, Peter Meerwald, Benson Leung, Olof Johansson

On Thu, Aug 15, 2013 at 04:55:57PM +0100, Nick Dyer wrote:
> rydberg@euromail.se wrote:
> > First: thanks for the patches and you work on this driver.
> 
> Thank you for your time in looking at these changes.
> 
> > Now, I don't swear much, but I would like to emphasize line 161 of
> > Documentation/SubmittingPatches:
> > 
> > **Do not send more than 15 patches at once to the vger mailing lists!!!***
> > 
> > One reason that should be obvious by now is that your work will be
> > attended to much quicker. One may think that it is more efficient to
> > send the whole backlog at once, but in fact, the time it takes to get
> > a patchset accepted is inversely proportional to the length of the
> > patchset. So please, keep it small and simple next time,
> 
> Apologies. I will split this lot up into several smaller series of patches.

Wait, I am in the process of applying it actually...

-- 
Dmitry

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

* Re: [PATCH 37/51] Input: atmel_mxt_ts - Implement vector/orientation support
  2013-07-18 17:20   ` rydberg
@ 2013-08-15 16:18     ` Nick Dyer
  0 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-08-15 16:18 UTC (permalink / raw)
  To: rydberg
  Cc: Dmitry Torokhov, Daniel Kurtz, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson

rydberg@euromail.se wrote:
> On Thu, Jun 27, 2013 at 01:49:12PM +0100, Nick Dyer wrote:
>> 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

Except they've changed the URL, should be:
https://source.android.com/devices/tech/input/touch-devices.html#touchorientationcalibration

The Atmel format is two 4-bit signed values packed into 1 byte, you use
inverse tan to work out the angle, and pythagoras theorem to work out the
magnitude of the vector (giving a confidence level)

>> 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.
> 
> How does this compare to the input mt documentation?

http://lxr.free-electrons.com/source/Documentation/input/multi-touch-protocol.txt#L263

So yes, we don't meet the documented format. Options:
1. Leave out this patch entirely and support out of tree
2. Update multi-touch-protocol.txt to include the Atmel format
3. Convert in driver to match documented protocol. Presumably via a LUT of
the 256 possible values. Although this loses the confidence level that is
implied.
4. Getting the firmware changed is not a valid option I'm afraid (too many
devices already out there).

Which do you prefer (I suspect 3) ?

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

* Re: Atmel updates to atmel_mxt_ts touch controller driver - v6
  2013-08-15 16:07     ` Dmitry Torokhov
@ 2013-08-19 14:24       ` Nick Dyer
  2013-09-10 13:58       ` Nick Dyer
  1 sibling, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2013-08-19 14:24 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: rydberg, Daniel Kurtz, Joonyoung Shim, Alan Bowens, linux-input,
	linux-kernel, Peter Meerwald, Benson Leung, Olof Johansson

Dmitry Torokhov wrote:
> On Thu, Aug 15, 2013 at 04:55:57PM +0100, Nick Dyer wrote:
>> rydberg@euromail.se wrote:
>>> **Do not send more than 15 patches at once to the vger mailing lists!!!***
>>>
>>> One reason that should be obvious by now is that your work will be
>>> attended to much quicker. One may think that it is more efficient to
>>> send the whole backlog at once, but in fact, the time it takes to get
>>> a patchset accepted is inversely proportional to the length of the
>>> patchset. So please, keep it small and simple next time,
>>
>> Apologies. I will split this lot up into several smaller series of patches.
> 
> Wait, I am in the process of applying it actually...

OK, will hang on for the moment. Let me know if you need anything from me.

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

* Re: Atmel updates to atmel_mxt_ts touch controller driver - v6
  2013-08-15 16:07     ` Dmitry Torokhov
  2013-08-19 14:24       ` Nick Dyer
@ 2013-09-10 13:58       ` Nick Dyer
       [not found]         ` <CAPDwgkOo7FYLujk16kJM=BqmXRKvZ2S_LOYURW0cXT5t=cmi6w@mail.gmail.com>
  1 sibling, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2013-09-10 13:58 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: rydberg, Daniel Kurtz, Joonyoung Shim, Alan Bowens, linux-input,
	linux-kernel, Peter Meerwald, Benson Leung, Olof Johansson

Dmitry Torokhov wrote:
> On Thu, Aug 15, 2013 at 04:55:57PM +0100, Nick Dyer wrote:
>> rydberg@euromail.se wrote:
>>> First: thanks for the patches and you work on this driver.
>>
>> Thank you for your time in looking at these changes.
>>
>>> Now, I don't swear much, but I would like to emphasize line 161 of
>>> Documentation/SubmittingPatches:
>>>
>>> **Do not send more than 15 patches at once to the vger mailing lists!!!***
>>>
>>> One reason that should be obvious by now is that your work will be
>>> attended to much quicker. One may think that it is more efficient to
>>> send the whole backlog at once, but in fact, the time it takes to get
>>> a patchset accepted is inversely proportional to the length of the
>>> patchset. So please, keep it small and simple next time,
>>
>> Apologies. I will split this lot up into several smaller series of patches.
> 
> Wait, I am in the process of applying it actually...

I wonder, have you made any progress with this? Is there any way I can assist?

Thanks

-- 
Nick Dyer

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

* Re: [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
  2013-07-18 17:17   ` rydberg
@ 2013-09-16  2:25     ` Dmitry Torokhov
  2014-05-22 14:29       ` Nick Dyer
  0 siblings, 1 reply; 87+ messages in thread
From: Dmitry Torokhov @ 2013-09-16  2:25 UTC (permalink / raw)
  To: rydberg
  Cc: Nick Dyer, Daniel Kurtz, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson, Yufeng Shen

On Thu, Jul 18, 2013 at 07:17:44PM +0200, rydberg@euromail.se wrote:
> Hi Nick,
> 
> > 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.

I think if there is no platform data we should use 0 as IRQ falgs and
assume that IRQ line is properly configured by the board code or via
device tree.

Thanks.

-- 
Dmitry

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

* Re: [11/51] Input: atmel_mxt_ts - Implement CRC check for configuration data
  2013-06-27 12:48 ` [PATCH 11/51] Input: atmel_mxt_ts - Implement CRC check for configuration data Nick Dyer
@ 2013-09-18 16:59   ` Martin Fuzzey
  0 siblings, 0 replies; 87+ messages in thread
From: Martin Fuzzey @ 2013-09-18 16:59 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 27/06/13 14:48, Nick Dyer wrote:
> 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>
> -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);
>   }

Shouldn't this be u32?
It's losing data causing the checksums not to match for me.


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

* Re: [12/51] Input: atmel_mxt_ts - Download device config using firmware loader
  2013-06-27 12:48 ` [PATCH 12/51] Input: atmel_mxt_ts - Download device config using firmware loader Nick Dyer
@ 2013-09-18 17:08   ` Martin Fuzzey
  0 siblings, 0 replies; 87+ messages in thread
From: Martin Fuzzey @ 2013-09-18 17:08 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 27/06/13 14:48, Nick Dyer wrote:
> 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.

I am using the mxt-app tool (v1.13) from 
git://github.com/atmel-maxtouch/obp-utils.git
However when an existing config is dumped using that tool's --save 
option the
config CRC is always zero.

That means that with this patch the config is loaded every time unless the
dumped file is manually tweaked to set the correct CRC.

>
> ---
> -		dev_dbg(dev, "No cfg data defined, skipping reg init\n");
> +	ret = request_firmware(&cfg, MXT_CFG_NAME, dev);
>
When building the driver into the kernel this just hangs for 60 seconds 
then fails.
Wouldn't it be better to use request_firmware_nowait() ?


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

* Re: Atmel updates to atmel_mxt_ts touch controller driver - v6
       [not found]         ` <CAPDwgkOo7FYLujk16kJM=BqmXRKvZ2S_LOYURW0cXT5t=cmi6w@mail.gmail.com>
@ 2014-01-15 10:44           ` Nick Dyer
       [not found]             ` <CAPDwgkOsP4K7r0-Mo-U52X9knRbGgbuD4dGptmj3x-LMTN75BA@mail.gmail.com>
  0 siblings, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2014-01-15 10:44 UTC (permalink / raw)
  To: Yufeng Shen, Dmitry Torokhov
  Cc: Henrik Rydberg, Daniel Kurtz, Joonyoung Shim, Alan Bowens,
	linux-input, linux-kernel, Peter Meerwald, Benson Leung,
	Olof Johansson, adlr

Yufeng Shen wrote:
> On Tue, Sep 10, 2013 at 9:58 AM, Nick Dyer <nick.dyer@itdev.co.uk
> <mailto:nick.dyer@itdev.co.uk>> wrote:
>> Dmitry Torokhov wrote:
>> > On Thu, Aug 15, 2013 at 04:55:57PM +0100, Nick Dyer wrote:
>> >> rydberg@euromail.se <mailto:rydberg@euromail.se> wrote:
>> >>> First: thanks for the patches and you work on this driver.
>> >>
>> >> Thank you for your time in looking at these changes.
>> >>
>> >>> Now, I don't swear much, but I would like to emphasize line 161 of
>> >>> Documentation/SubmittingPatches:
>> >>>
>> >>> **Do not send more than 15 patches at once to the vger mailing
> lists!!!***
>> >>>
>> >>> One reason that should be obvious by now is that your work will be
>> >>> attended to much quicker. One may think that it is more efficient to
>> >>> send the whole backlog at once, but in fact, the time it takes to get
>> >>> a patchset accepted is inversely proportional to the length of the
>> >>> patchset. So please, keep it small and simple next time,
>> >>
>> >> Apologies. I will split this lot up into several smaller series of
> patches.
>> >
>> > Wait, I am in the process of applying it actually...
>>
>> I wonder, have you made any progress with this? Is there any way I can
>> assist?
>
> Hey Dimitry,
> 
> What's the status on this ?
> 
> I noticed that at  /pub/scm/linux/kernel/git/dtor/input, branch
> atmel-mxt-ts has part of Nick's patches applied
> but not all. The upstream tree and Nick's tree
>  https://github.com/ndyer/linux/commits/for-next are still
> significantly diverged.
> 
> I am wondering any plan on your side to apply more patches that sent out by
> Nick ?
> 
> We (Chromium authors) are planning on bringing our local tree of atmel
> driver to be as close as possible to
> upstream and trying to figure out what's the best tree to rebase against.

I was considering picking up the patches that Dimitry has already reviewed
and rebasing them against the current mainline to try and get things moving
again - would that be useful?

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

* Re: Atmel updates to atmel_mxt_ts touch controller driver - v6
       [not found]             ` <CAPDwgkOsP4K7r0-Mo-U52X9knRbGgbuD4dGptmj3x-LMTN75BA@mail.gmail.com>
@ 2014-01-17 20:01               ` Nick Dyer
  0 siblings, 0 replies; 87+ messages in thread
From: Nick Dyer @ 2014-01-17 20:01 UTC (permalink / raw)
  To: Yufeng Shen
  Cc: Dmitry Torokhov, Henrik Rydberg, Daniel Kurtz, Joonyoung Shim,
	Alan Bowens, linux-input, linux-kernel, Peter Meerwald,
	Benson Leung, Olof Johansson, adlr

Yufeng Shen wrote:
> On Wed, Jan 15, 2014 at 5:44 AM, Nick Dyer <nick.dyer@itdev.co.uk
> <mailto:nick.dyer@itdev.co.uk>> wrote:
>     > We (Chromium authors) are planning on bringing our local tree of atmel
>     > driver to be as close as possible to
>     > upstream and trying to figure out what's the best tree to rebase against.
> 
>     I was considering picking up the patches that Dimitry has already reviewed
>     and rebasing them against the current mainline to try and get things moving
>     again - would that be useful?
> 
> That would certainly be useful. Please let me know the branch/tag name once
> you finish that.

I've rebased Dimitry's atmel-mxt-ts branch against his dtor/next tree. You
can find it at

https://github.com/ndyer/linux/tree/for-next-20140117-dtor-rebase

I needed to update the INIT_COMPLETION api. So far I have verified it
builds, will do some testing on it next week.

I will also need to port my previous patchset on top of this branch.

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

* Re: [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
  2013-09-16  2:25     ` Dmitry Torokhov
@ 2014-05-22 14:29       ` Nick Dyer
  2014-05-23 16:37         ` Yufeng Shen
  0 siblings, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2014-05-22 14:29 UTC (permalink / raw)
  To: Benson Leung, Yufeng Shen
  Cc: Dmitry Torokhov, rydberg, Daniel Kurtz, Joonyoung Shim,
	Alan Bowens, linux-input, linux-kernel, Peter Meerwald,
	Olof Johansson

Dmitry Torokhov wrote:
> On Thu, Jul 18, 2013 at 07:17:44PM +0200, rydberg@euromail.se wrote:
>>> 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.
> 
> I think if there is no platform data we should use 0 as IRQ falgs and
> assume that IRQ line is properly configured by the board code or via
> device tree.

Beson/Yufeng - do you still have a requirement to probe without platform
data or device tree? I'm just merging in some changes to add device tree
support, and it would simplify things a bit if I can drop this patch.

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

* Re: [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
  2014-05-22 14:29       ` Nick Dyer
@ 2014-05-23 16:37         ` Yufeng Shen
  2014-05-24 12:41           ` Nick Dyer
  2014-05-26  5:23           ` Dmitry Torokhov
  0 siblings, 2 replies; 87+ messages in thread
From: Yufeng Shen @ 2014-05-23 16:37 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Benson Leung, Dmitry Torokhov, Henrik Rydberg, Daniel Kurtz,
	Joonyoung Shim, Alan Bowens, linux-input, linux-kernel,
	Peter Meerwald, Olof Johansson

On Thu, May 22, 2014 at 10:29 AM, Nick Dyer <nick.dyer@itdev.co.uk> wrote:
>
> Dmitry Torokhov wrote:
> > On Thu, Jul 18, 2013 at 07:17:44PM +0200, rydberg@euromail.se wrote:
> >>> 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.
> >
> > I think if there is no platform data we should use 0 as IRQ falgs and
> > assume that IRQ line is properly configured by the board code or via
> > device tree.
>
> Beson/Yufeng - do you still have a requirement to probe without platform
> data or device tree? I'm just merging in some changes to add device tree
> support, and it would simplify things a bit if I can drop this patch.


It has been working for quite a while for boards/devices that don't
provide platform
data. If we drop the default IRQ flags, sure we can add code for each
board to configure
the IRQ separately, but that's just adding extra work. Is there strong
reason why we
should not do the default setting in the driver if it is not already
configured in platform
data ?

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

* Re: [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
  2014-05-23 16:37         ` Yufeng Shen
@ 2014-05-24 12:41           ` Nick Dyer
  2014-05-26 18:17             ` Yufeng Shen
  2014-05-26  5:23           ` Dmitry Torokhov
  1 sibling, 1 reply; 87+ messages in thread
From: Nick Dyer @ 2014-05-24 12:41 UTC (permalink / raw)
  To: Yufeng Shen
  Cc: Benson Leung, Dmitry Torokhov, Henrik Rydberg, Daniel Kurtz,
	Joonyoung Shim, Alan Bowens, linux-input, linux-kernel,
	Peter Meerwald, Olof Johansson

Yufeng Shen wrote:
> On Thu, May 22, 2014 at 10:29 AM, Nick Dyer <nick.dyer@itdev.co.uk> wrote:
>> Dmitry Torokhov wrote:
>>>>> Make the irqflags default to be IRQF_TRIGGER_FALLING if no platform data is
>>>>> provided.
>>>
>>> I think if there is no platform data we should use 0 as IRQ falgs and
>>> assume that IRQ line is properly configured by the board code or via
>>> device tree.
>>
>> Benson/Yufeng - do you still have a requirement to probe without platform
>> data or device tree? I'm just merging in some changes to add device tree
>> support, and it would simplify things a bit if I can drop this patch.
> 
> It has been working for quite a while for boards/devices that don't 
> provide platform data. If we drop the default IRQ flags, sure we can add
> code for each board to configure the IRQ separately, but that's just
> adding extra work. Is there strong reason why we should not do the
> default setting in the driver if it is not already configured in
> platform data?

OK, I will keep it in my tree for the moment, since you are using it.

The reason I checked is that in general, I would like to be conservative
about what is pushed upstream, because it will need maintaining for a long
time.

The other reason is that in fact Atmel recommend IRQF_TRIGGER_LOW for these
chips, not IRQF_TRIGGER_FALLING, so there is a bit of an inconsistency here.

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

* Re: [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
  2014-05-23 16:37         ` Yufeng Shen
  2014-05-24 12:41           ` Nick Dyer
@ 2014-05-26  5:23           ` Dmitry Torokhov
  2014-05-26 18:13             ` Yufeng Shen
  1 sibling, 1 reply; 87+ messages in thread
From: Dmitry Torokhov @ 2014-05-26  5:23 UTC (permalink / raw)
  To: Yufeng Shen
  Cc: Nick Dyer, Benson Leung, Henrik Rydberg, Daniel Kurtz,
	Joonyoung Shim, Alan Bowens, linux-input, linux-kernel,
	Peter Meerwald, Olof Johansson

On Fri, May 23, 2014 at 12:37:46PM -0400, Yufeng Shen wrote:
> On Thu, May 22, 2014 at 10:29 AM, Nick Dyer <nick.dyer@itdev.co.uk> wrote:
> >
> > Dmitry Torokhov wrote:
> > > On Thu, Jul 18, 2013 at 07:17:44PM +0200, rydberg@euromail.se wrote:
> > >>> 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.
> > >
> > > I think if there is no platform data we should use 0 as IRQ falgs and
> > > assume that IRQ line is properly configured by the board code or via
> > > device tree.
> >
> > Beson/Yufeng - do you still have a requirement to probe without platform
> > data or device tree? I'm just merging in some changes to add device tree
> > support, and it would simplify things a bit if I can drop this patch.
> 
> 
> It has been working for quite a while for boards/devices that don't
> provide platform
> data. If we drop the default IRQ flags, sure we can add code for each
> board to configure
> the IRQ separately, but that's just adding extra work. Is there strong
> reason why we
> should not do the default setting in the driver if it is not already
> configured in platform
> data ?


I am not saying that board code needs to add platform data. I am saying
that the board code needs to set up interrupt properly (via
irq_set_irq_type() or similar) and then the driver can use 0 as irqflags
argument in request_irq() in absence of DT/platform data.

Thanks.

-- 
Dmitry

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

* Re: [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
  2014-05-26  5:23           ` Dmitry Torokhov
@ 2014-05-26 18:13             ` Yufeng Shen
  0 siblings, 0 replies; 87+ messages in thread
From: Yufeng Shen @ 2014-05-26 18:13 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Nick Dyer, Benson Leung, Henrik Rydberg, Daniel Kurtz,
	Joonyoung Shim, Alan Bowens, linux-input, linux-kernel,
	Peter Meerwald, Olof Johansson

On Mon, May 26, 2014 at 1:23 AM, Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
>
> On Fri, May 23, 2014 at 12:37:46PM -0400, Yufeng Shen wrote:
> > On Thu, May 22, 2014 at 10:29 AM, Nick Dyer <nick.dyer@itdev.co.uk> wrote:
> > >
> > > Dmitry Torokhov wrote:
> > > > On Thu, Jul 18, 2013 at 07:17:44PM +0200, rydberg@euromail.se wrote:
> > > >>> 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.
> > > >
> > > > I think if there is no platform data we should use 0 as IRQ falgs and
> > > > assume that IRQ line is properly configured by the board code or via
> > > > device tree.
> > >
> > > Beson/Yufeng - do you still have a requirement to probe without platform
> > > data or device tree? I'm just merging in some changes to add device tree
> > > support, and it would simplify things a bit if I can drop this patch.
> >
> >
> > It has been working for quite a while for boards/devices that don't
> > provide platform
> > data. If we drop the default IRQ flags, sure we can add code for each
> > board to configure
> > the IRQ separately, but that's just adding extra work. Is there strong
> > reason why we
> > should not do the default setting in the driver if it is not already
> > configured in platform
> > data ?
>
>
> I am not saying that board code needs to add platform data. I am saying
> that the board code needs to set up interrupt properly (via
> irq_set_irq_type() or similar) and then the driver can use 0 as irqflags
> argument in request_irq() in absence of DT/platform data.
>
> Thanks.
>

So my argument is mainly based on that the existing code is working (boards
that do not have platform data are relying on the driver to set the
default irq),
and change the default value would need extra work to setup the irq, say as you
suggested through irq_set_irq_type(). I am no expert in irq so it could be true
that your suggested way is indeed better. I am in favor of keeping
this patch is only
because it requires no extra change for existing code that are using it.



> --
> Dmitry
> --
> 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] 87+ messages in thread

* Re: [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
  2014-05-24 12:41           ` Nick Dyer
@ 2014-05-26 18:17             ` Yufeng Shen
  0 siblings, 0 replies; 87+ messages in thread
From: Yufeng Shen @ 2014-05-26 18:17 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Benson Leung, Dmitry Torokhov, Henrik Rydberg, Daniel Kurtz,
	Joonyoung Shim, Alan Bowens, linux-input, linux-kernel,
	Peter Meerwald, Olof Johansson

On Sat, May 24, 2014 at 8:41 AM, Nick Dyer <nick.dyer@itdev.co.uk> wrote:
> Yufeng Shen wrote:
>> On Thu, May 22, 2014 at 10:29 AM, Nick Dyer <nick.dyer@itdev.co.uk> wrote:
>>> Dmitry Torokhov wrote:
>>>>>> Make the irqflags default to be IRQF_TRIGGER_FALLING if no platform data is
>>>>>> provided.
>>>>
>>>> I think if there is no platform data we should use 0 as IRQ falgs and
>>>> assume that IRQ line is properly configured by the board code or via
>>>> device tree.
>>>
>>> Benson/Yufeng - do you still have a requirement to probe without platform
>>> data or device tree? I'm just merging in some changes to add device tree
>>> support, and it would simplify things a bit if I can drop this patch.
>>
>> It has been working for quite a while for boards/devices that don't
>> provide platform data. If we drop the default IRQ flags, sure we can add
>> code for each board to configure the IRQ separately, but that's just
>> adding extra work. Is there strong reason why we should not do the
>> default setting in the driver if it is not already configured in
>> platform data?
>
> OK, I will keep it in my tree for the moment, since you are using it.
>
> The reason I checked is that in general, I would like to be conservative
> about what is pushed upstream, because it will need maintaining for a long
> time.
>
> The other reason is that in fact Atmel recommend IRQF_TRIGGER_LOW for these
> chips, not IRQF_TRIGGER_FALLING, so there is a bit of an inconsistency here.

I think I chose IRQF_TRIGGER_FALLING is because when I do a search in
the upstream
code where platform is configured, the irq is always set to be
IRQF_TRIGGER_FALLING
so I was assuming  IRQF_TRIGGER_FALLING is a safe bet.

But you would definitely know better than me on this since the atmel
chips that I have
access to are quite limited.

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

end of thread, other threads:[~2014-05-26 18:18 UTC | newest]

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

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