Atmel updates to atmel_mxt_ts touch controller driver - v6
Subsystems (8)
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)
Signature · 2 lines
Nick Dyer Senior Software Engineer ITDev Hardware and Software Development Consultancy http://www.itdev.co.uk
PATCH 1/51 Input: atmel_mxt_ts - Remove unnecessary platform data
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.
--- 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(-)
arch/arm/mach-exynos/mach-nuri.c +0 -5
@@ -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 , };
arch/arm/mach-exynos/mach-universal_c210.c +0 -5
@@ -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 , };
arch/arm/mach-s5pv210/mach-goni.c +0 -5
@@ -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 , };
drivers/input/touchscreen/atmel_mxt_ts.c +0 -50
62 lines not on this page · raw message
drivers/platform/x86/chromeos_laptop.c +0 -10
@@ -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,
include/linux/i2c/atmel_mxt_ts.h +1 -5
@@ -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 ];
Signature · 1 line
1.7.10.4
PATCH 2/51 Input: atmel_mxt_ts - Improve T19 GPIO keys handling
In reply to 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.
--- 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(-)
drivers/input/touchscreen/atmel_mxt_ts.c +17 -27
@@ -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,
drivers/platform/x86/chromeos_laptop.c +11 -6
@@ -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, };
include/linux/i2c/atmel_mxt_ts.h +2 -5
@@ -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 */
Signature · 1 line
1.7.10.4
Re: [PATCH 02/51] Input: atmel_mxt_ts - Improve T19 GPIO keys handling
Quoted 12 lines · 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.
Quoted 6 lines
Signed-off-by Nick Dyer <[email protected]>--- 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(-)
Thanks,
Henrik
PATCH 3/51 Input: atmel_mxt_ts - Return IRQ_NONE when interrupt handler fails
In reply to Nick Dyer--- drivers/input/touchscreen/atmel_mxt_ts.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +1 -2
@@ -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 ; }
Signature · 1 line
1.7.10.4
PATCH 4/51 Input: atmel_mxt_ts - define helper functions for size and instances
In reply to Nick DyerFrom: Daniel Kurtz <[email protected]>
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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 35 ++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 11 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +24 -11
@@ -2,6 +2,8 @@* Atmel maXTouch Touchscreen driver * * Copyright (C) 2010 Samsung Electronics Co.Ltd +* Copyright (C) 2012 Google, Inc. +* * Author: Joonyoung Shim <[email protected]> * * 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);
Signature · 1 line
1.7.10.4
PATCH 5/51 Input: atmel_mxt_ts - Select FW_LOADER for firmware code
In reply to Nick Dyer--- drivers/input/touchscreen/Kconfig | 1 + 1 file changed, 1 insertion(+)
drivers/input/touchscreen/Kconfig +1 -0
@@ -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.
Signature · 1 line
1.7.10.4
PATCH 6/51 Input: atmel_mxt_ts - wait for CHG assert in mxt_check_bootloader
In reply to Nick DyerFrom: Benson Leung <[email protected]>
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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 102 ++++++++++++++++++++++++------ 1 file changed, 81 insertions(+), 21 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +81 -21
@@ -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);
Signature · 1 line
1.7.10.4
PATCH 7/51 Input: atmel_mxt_ts - wait for CHG after bootloader resets
In reply to Nick DyerFrom: Benson Leung <[email protected]>
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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +12 -7
@@ -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);
Signature · 1 line
1.7.10.4
PATCH 8/51 Input: atmel_mxt_ts - Initialise IRQ before probing
In reply to Nick DyerThis 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).
--- drivers/input/touchscreen/atmel_mxt_ts.c | 73 +++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 22 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +51 -22
@@ -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 <[email protected]>
@@ -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);
Signature · 1 line
1.7.10.4
Re: [PATCH 08/51] Input: atmel_mxt_ts - Initialise IRQ before probing
Hi Nick,
Quoted 37 lines
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_reportingis checked in each of the possible message handling function paths rather than higher up (such as atmxt_proc_message) because some objects may be used for completions (T6).Signed-off-by Nick Dyer <[email protected]>Acked-by Benson Leung <[email protected]>--- drivers/input/touchscreen/atmel_mxt_ts.c | 73 +++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 22 deletions(-)drivers/input/touchscreen/atmel_mxt_ts.c +4
-0@@ -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 <[email protected]> @@ -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)
drivers/input/touchscreen/atmel_mxt_ts.c static void mxt_input_button(struct mxt_data *data, struct mxt_message *message) · line 577
Quoted 6 lines
drivers/input/touchscreen/atmel_mxt_ts.c +3
-0@@ -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?
Quoted 41 lines
drivers/input/touchscreen/atmel_mxt_ts.c +12
-1+/* 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;
drivers/input/touchscreen/atmel_mxt_ts.c static int mxt_make_highchg(struct mxt_data *data) · line 776
Quoted 10 lines
drivers/input/touchscreen/atmel_mxt_ts.c +10
-0+ +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?
Quoted 47 lines
drivers/input/touchscreen/atmel_mxt_ts.c +8
-5static 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);
drivers/input/touchscreen/atmel_mxt_ts.c static int mxt_probe(struct i2c_client *client, · line 1230
Quoted 10 lines
drivers/input/touchscreen/atmel_mxt_ts.c +9
-0+ 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.
Quoted 47 lines
drivers/input/touchscreen/atmel_mxt_ts.c +5
-16+ 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);Signature · 1 line
1.7.10.4
Thanks,
Henrik
PATCH 9/51 Input: atmel_mxt_ts - Make wait-after-reset period compatible with all chips
In reply to Nick DyerFrom: Iiro Valkonen <[email protected]>
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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 109 ++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 22 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +87 -22
@@ -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);
Signature · 1 line
1.7.10.4
PATCH 10/51 Input: atmel_mxt_ts - Improve error reporting and debug
In reply to Nick DyerAdd error messages for probe errors
Report type in invalid object type
Tweak some other debug output messages
--- drivers/input/touchscreen/atmel_mxt_ts.c | 33 +++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 10 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +23 -10
@@ -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 ;
Signature · 1 line
1.7.10.4
PATCH 11/51 Input: atmel_mxt_ts - Implement CRC check for configuration data
In reply to Nick DyerThe 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 55 +++++++++++++++++++++++++----- include/linux/i2c/atmel_mxt_ts.h | 1 + 2 files changed, 48 insertions(+), 8 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +47 -8
@@ -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);
include/linux/i2c/atmel_mxt_ts.h +1 -0
@@ -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;
Signature · 1 line
1.7.10.4
Re: [11/51] Input: atmel_mxt_ts - Implement CRC check for configuration data
drivers/input/touchscreen/atmel_mxt_ts.c static void mxt_input_touchevent(struct mxt_data *data, · line 659
Quoted 12 lines · 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 <[email protected]>Acked-by Benson Leung <[email protected]>drivers/input/touchscreen/atmel_mxt_ts.c +1
-1-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.
PATCH 12/51 Input: atmel_mxt_ts - Download device config using firmware loader
In reply to Nick DyerThe 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.
--- 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(-)
drivers/input/touchscreen/atmel_mxt_ts.c +175 -59
@@ -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)
drivers/platform/x86/chromeos_laptop.c +0 -4
@@ -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 = {
include/linux/i2c/atmel_mxt_ts.h +0 -4
@@ -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;
Signature · 1 line
1.7.10.4
Re: [12/51] Input: atmel_mxt_ts - Download device config using firmware loader
Quoted 8 lines · 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.
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.
drivers/input/touchscreen/atmel_mxt_ts.c static void mxt_update_crc(struct mxt_data *data, u8 cmd, u8 value) · line 805
Quoted 5 lines
---
drivers/input/touchscreen/atmel_mxt_ts.c +1
-1-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() ?
PATCH 13/51 Input: atmel_mxt_ts - Calculate and check CRC in config file
In reply to Nick DyerBy 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 224 +++++++++++++++++++++++------- 1 file changed, 171 insertions(+), 53 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +171 -53
@@ -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 ;
Signature · 1 line
1.7.10.4
PATCH 14/51 Input: atmel_mxt_ts - Add additional bootloader addresses
In reply to Nick DyerMove 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 138 ++++++++++++++++++++---------- 1 file changed, 93 insertions(+), 45 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +93 -45
@@ -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; }
Signature · 1 line
1.7.10.4
PATCH 15/51 Input: atmel_mxt_ts - Read and report bootloader version
In reply to Nick Dyer--- drivers/input/touchscreen/atmel_mxt_ts.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
drivers/input/touchscreen/atmel_mxt_ts.c +26 -0
@@ -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 :
Signature · 1 line
1.7.10.4
PATCH 16/51 Input: atmel_mxt_ts - Implement bootloader frame retries
In reply to Nick Dyer--- drivers/input/touchscreen/atmel_mxt_ts.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +20 -7
@@ -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); }
Signature · 1 line
1.7.10.4
PATCH 17/51 Input: atmel_mxt_ts - Improve bootloader progress output
In reply to Nick DyerBy implementing a frame counter, print out fewer debug messages (the firmware may contain hundreds of frames).
--- drivers/input/touchscreen/atmel_mxt_ts.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/input/touchscreen/atmel_mxt_ts.c +7 -1
@@ -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,
Signature · 1 line
1.7.10.4
PATCH 18/51 Input: atmel_mxt_ts - Add check for incorrect firmware file format
In reply to Nick DyerAtmel 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
drivers/input/touchscreen/atmel_mxt_ts.c +27 -0
@@ -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;
Signature · 1 line
1.7.10.4
PATCH 19/51 Input: atmel_mxt_ts - Read screen config from chip
In reply to Nick DyerBy 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.
--- 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(-)
arch/arm/mach-exynos/mach-nuri.c +0 -3
@@ -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 , };
arch/arm/mach-exynos/mach-universal_c210.c +0 -3
@@ -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 , };
arch/arm/mach-s5pv210/mach-goni.c +0 -3
@@ -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 , };
drivers/input/touchscreen/atmel_mxt_ts.c +65 -71
186 lines not on this page · raw message
drivers/platform/x86/chromeos_laptop.c +0 -6
@@ -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 , };
include/linux/i2c/atmel_mxt_ts.h +0 -14
@@ -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;
Signature · 1 line
1.7.10.4
PATCH 20/51 Input: atmel_mxt_ts - Set default irqflags when there is no pdata
In reply to Nick DyerFrom: Yufeng Shen <[email protected]>
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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 54 +++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 15 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +39 -15
@@ -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 ;
Signature · 1 line
1.7.10.4
Re: [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
Hi Nick,
Quoted 37 lines
From: Yufeng Shen <[email protected]>
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_FALLINGif no platform data is provided.Signed-off-by Yufeng Shen <[email protected]>Signed-off-by Daniel Kurtz <[email protected]>Signed-off-by Nick Dyer <[email protected]>Acked-by Benson Leung <[email protected]>--- drivers/input/touchscreen/atmel_mxt_ts.c | 54 +++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 15 deletions(-)drivers/input/touchscreen/atmel_mxt_ts.c +4
-1@@ -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);
drivers/input/touchscreen/atmel_mxt_ts.c static void mxt_input_close(struct input_dev *dev) · line 1655
Quoted 10 lines
drivers/input/touchscreen/atmel_mxt_ts.c +10
-0+ +/* 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?
drivers/input/touchscreen/atmel_mxt_ts.c static void mxt_input_close(struct input_dev *dev) · line 1662
Quoted 7 lines
drivers/input/touchscreen/atmel_mxt_ts.c +7
-0+ +/* Set default parameters */ + data->pdata->irqflags =IRQF_TRIGGER_FALLING ; + +return 0 ; +} +
Opencode instead?
drivers/input/touchscreen/atmel_mxt_ts.c static void mxt_input_close(struct input_dev *dev) · line 1646
Quoted 4 lines
drivers/input/touchscreen/atmel_mxt_ts.c +0
-1static 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?
drivers/input/touchscreen/atmel_mxt_ts.c static int mxt_probe(struct i2c_client *client, · line 1654
Quoted 8 lines
drivers/input/touchscreen/atmel_mxt_ts.c +0
-1struct 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?
Quoted 6 lines
drivers/input/touchscreen/atmel_mxt_ts.c +0
-2-return -EINVAL ; - data =kzalloc (sizeof (struct mxt_data ),GFP_KERNEL ); input_dev =input_allocate_device ();if (!data || !input_dev) {
drivers/input/touchscreen/atmel_mxt_ts.c static int mxt_probe(struct i2c_client *client, · line 1699
Quoted 10 lines
drivers/input/touchscreen/atmel_mxt_ts.c +5
-1@@ -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
drivers/input/touchscreen/atmel_mxt_ts.c static int mxt_probe(struct i2c_client *client, · line 1707
Quoted 10 lines
drivers/input/touchscreen/atmel_mxt_ts.c +2
-2init_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
drivers/input/touchscreen/atmel_mxt_ts.c static int mxt_probe(struct i2c_client *client, · line 1723
Quoted 13 lines
drivers/input/touchscreen/atmel_mxt_ts.c +2
-2if (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
Quoted 33 lines
drivers/input/touchscreen/atmel_mxt_ts.c +7
-5__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);
drivers/input/touchscreen/atmel_mxt_ts.c static int mxt_remove(struct i2c_client *client) · line 1808
Quoted 5 lines
drivers/input/touchscreen/atmel_mxt_ts.c +2
-0@@ -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?
Quoted 6 lines
drivers/input/touchscreen/atmel_mxt_ts.c +0
-0kfree (data);return 0 ;Signature · 1 line
1.7.10.4
Thanks,
Henrik
Dmitry Torokhov
maintainerRe: [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
Quoted 10 lines · On Thu, Jul 18, 2013 at 07:17:44PM +0200, [email protected] wrote:
Hi Nick,
Quoted 8 lines
From: Yufeng Shen <[email protected]>
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_FALLINGif 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.
Signature · 1 line
Dmitry
Re: [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
Quoted 6 lines · Dmitry Torokhov
Quoted 5 lines · On Thu, Jul 18, 2013 at 07:17:44PM +0200, [email protected] wrote:
Quoted 5 lines
From: Yufeng Shen <[email protected]>
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.
Quoted 6 lines
Quoted 2 lines
Quoted 2 lines
Make the irqflags default to be
IRQF_TRIGGER_FALLINGif 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.
Re: [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
Quoted 11 lines · Nick Dyer
Quoted 9 lines · Dmitry Torokhov
Quoted 7 lines · On Thu, Jul 18, 2013 at 07:17:44PM +0200, [email protected] wrote:
Quoted 7 lines
From: Yufeng Shen <[email protected]>
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_FALLINGif no platform data is provided.
Quoted 7 lines
Quoted 3 lines
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 ?
Re: [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
Quoted 13 lines · Yufeng Shen
Quoted 11 lines · Nick Dyer
Quoted 6 lines · Dmitry Torokhov
Quoted 2 lines
Quoted 2 lines
Make the irqflags default to be
IRQF_TRIGGER_FALLINGif 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.
Quoted 6 lines
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.
Re: [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
Quoted 21 lines · Nick Dyer
Quoted 13 lines · Yufeng Shen
Quoted 11 lines · Nick Dyer
Quoted 6 lines · Dmitry Torokhov
Quoted 2 lines
Quoted 2 lines
Make the irqflags default to be
IRQF_TRIGGER_FALLINGif 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.
Quoted 6 lines
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?
Quoted 8 lines
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_LOWfor these chips, notIRQF_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.
Dmitry Torokhov
maintainerRe: [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
In reply to Yufeng ShenQuoted 21 lines · Yufeng Shen
Quoted 11 lines · Nick Dyer
Quoted 9 lines · Dmitry Torokhov
Quoted 7 lines · On Thu, Jul 18, 2013 at 07:17:44PM +0200, [email protected] wrote:
Quoted 7 lines
From: Yufeng Shen <[email protected]>
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_FALLINGif no platform data is provided.Quoted 7 lines
Quoted 3 lines
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.
Quoted 9 lines
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.
Signature · 1 line
Dmitry
Re: [PATCH 20/51] Input: atmel_mxt_ts - Set default irqflags when there is no pdata
Quoted 34 lines · Dmitry Torokhov
Quoted 21 lines · Yufeng Shen
Quoted 11 lines · Nick Dyer
Quoted 9 lines · Dmitry Torokhov
Quoted 7 lines · On Thu, Jul 18, 2013 at 07:17:44PM +0200, [email protected] wrote:
Quoted 7 lines
From: Yufeng Shen <[email protected]>
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_FALLINGif no platform data is provided.Quoted 7 lines
Quoted 3 lines
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.
Quoted 9 lines
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 ?
Quoted 7 lines
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 inrequest_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.
Quoted 6 lines
--
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 21/51 Input: atmel_mxt_ts - Use deep sleep mode when stopped
In reply to Nick DyerBy 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 100 ++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 26 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +74 -26
@@ -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)
Signature · 1 line
1.7.10.4
PATCH 22/51 Input: atmel_mxt_ts - Add shutdown function
In reply to Nick Dyer--- drivers/input/touchscreen/atmel_mxt_ts.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/input/touchscreen/atmel_mxt_ts.c +8 -0
@@ -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, };
Signature · 1 line
1.7.10.4
Dmitry Torokhov
maintainerRe: [PATCH 22/51] Input: atmel_mxt_ts - Add shutdown function
Hi Nick,
Quoted 2 lines · Nick Dyer
Signed-off-by Nick Dyer <[email protected]>Acked-by Benson Leung <[email protected]>
Why is this needed?
Thanks.
Quoted 33 lines
--- drivers/input/touchscreen/atmel_mxt_ts.c | 8 ++++++++ 1 file changed, 8 insertions(+)drivers/input/touchscreen/atmel_mxt_ts.c +8
-0@@ -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, };Signature · 1 line
1.7.10.4
Signature · 1 line
Dmitry
Re: [PATCH 22/51] Input: atmel_mxt_ts - Add shutdown function
Quoted 5 lines · Dmitry Torokhov
Quoted 2 lines · Nick Dyer
Signed-off-by Nick Dyer <[email protected]>Acked-by Benson Leung <[email protected]>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?
Dmitry Torokhov
maintainerRe: [PATCH 22/51] Input: atmel_mxt_ts - Add shutdown function
Quoted 5 lines · Nick Dyer
Quoted 4 lines · Dmitry Torokhov
Quoted 2 lines · Nick Dyer
Signed-off-by Nick Dyer <[email protected]>Acked-by Benson Leung <[email protected]>
Quoted 7 lines
Quoted 1 line
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?
Quoted 5 lines
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.
Signature · 1 line
Dmitry
Re: [PATCH 22/51] Input: atmel_mxt_ts - Add shutdown function
Quoted 7 lines · Dmitry Torokhov
Quoted 5 lines
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.
Quoted 8 lines
Quoted 4 lines
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.
PATCH 23/51 Input: atmel_mxt_ts - Rename pressure to amplitude to match spec
In reply to Nick Dyer--- drivers/input/touchscreen/atmel_mxt_ts.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +4 -4
@@ -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); } }
Signature · 1 line
1.7.10.4
PATCH 24/51 Input: atmel_mxt_ts - Rename touchscreen defines to include T9
In reply to Nick DyerThis avoids confusion with the newer T100 touchscreen object.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 46 +++++++++++++++--------------- 1 file changed, 23 insertions(+), 23 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +23 -23
@@ -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 {
Signature · 1 line
1.7.10.4
PATCH 25/51 Input: atmel_mxt_ts - Handle multiple input reports in one message
In reply to Nick Dyer--- drivers/input/touchscreen/atmel_mxt_ts.c | 34 +++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 8 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +26 -8
@@ -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 ; }
Signature · 1 line
1.7.10.4
Re: [PATCH 25/51] Input: atmel_mxt_ts - Handle multiple input reports in one message
Hi Nick,
Quoted 11 lines
Signed-off-by Nick Dyer <[email protected]>Acked-by Benson Leung <[email protected]>--- drivers/input/touchscreen/atmel_mxt_ts.c | 34 +++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 8 deletions(-)drivers/input/touchscreen/atmel_mxt_ts.c +0
-0
drivers/input/touchscreen/atmel_mxt_ts.c static void mxt_input_button(struct mxt_data *data, struct mxt_message *message) · line 635
Quoted 8 lines
drivers/input/touchscreen/atmel_mxt_ts.c +5
-0@@ -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.
Quoted 6 lines
drivers/input/touchscreen/atmel_mxt_ts.c +1
-0+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,
drivers/input/touchscreen/atmel_mxt_ts.c static void mxt_input_touchevent(struct mxt_data *data, · line 659
Quoted 10 lines
drivers/input/touchscreen/atmel_mxt_ts.c +4
-2x = (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.
Quoted 8 lines
drivers/input/touchscreen/atmel_mxt_ts.c +0
-1area = 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,
drivers/input/touchscreen/atmel_mxt_ts.c static void mxt_input_touchevent(struct mxt_data *data, · line 686
Quoted 10 lines
drivers/input/touchscreen/atmel_mxt_ts.c +7
-1- 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?
Quoted 30 lines
drivers/input/touchscreen/atmel_mxt_ts.c +9
-4+ } + +/* 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 ; }Signature · 1 line
1.7.10.4
Thanks,
Henrik
PATCH 26/51 Input: atmel_mxt_ts - Move input device init into separate function
In reply to Nick Dyer--- drivers/input/touchscreen/atmel_mxt_ts.c | 129 +++++++++++++++++------------- 1 file changed, 75 insertions(+), 54 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +75 -54
@@ -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; }
Signature · 1 line
1.7.10.4
Dmitry Torokhov
maintainerRe: [PATCH 26/51] Input: atmel_mxt_ts - Move input device init into separate function
Quoted 1 line · Nick Dyer
Signed-off-by Nick Dyer <[email protected]>
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.
Quoted 198 lines
--- drivers/input/touchscreen/atmel_mxt_ts.c | 129 +++++++++++++++++------------- 1 file changed, 75 insertions(+), 54 deletions(-)drivers/input/touchscreen/atmel_mxt_ts.c +75
-54@@ -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; }Signature · 1 line
1.7.10.4
Signature · 1 line
Dmitry
Re: [PATCH 26/51] Input: atmel_mxt_ts - Move input device init into separate function
Quoted 7 lines · Dmitry Torokhov
Quoted 1 line · Nick Dyer
Signed-off-by Nick Dyer <[email protected]>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).
Dmitry Torokhov
maintainerRe: [PATCH 26/51] Input: atmel_mxt_ts - Move input device init into separate function
Quoted 9 lines · Nick Dyer
Quoted 7 lines · Dmitry Torokhov
Quoted 1 line · Nick Dyer
Signed-off-by Nick Dyer <[email protected]>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?
Quoted 6 lines
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.
Signature · 1 line
Dmitry
Re: [PATCH 26/51] Input: atmel_mxt_ts - Move input device init into separate function
In reply to Nick DyerQuoted 10 lines · Nick Dyer
Signed-off-by Nick Dyer <[email protected]>--- drivers/input/touchscreen/atmel_mxt_ts.c | 129 +++++++++++++++++------------- 1 file changed, 75 insertions(+), 54 deletions(-)drivers/input/touchscreen/atmel_mxt_ts.c +0
-0
drivers/input/touchscreen/atmel_mxt_ts.c static int mxt_handle_pdata(struct mxt_data *data) · line 1734
Quoted 10 lines
drivers/input/touchscreen/atmel_mxt_ts.c +3
-3@@ -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.
Quoted 179 lines
drivers/input/touchscreen/atmel_mxt_ts.c +72
-51struct 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; }Signature · 1 line
1.7.10.4
In what way does this patch simplify things?
Thanks,
Henrik
PATCH 27/51 Input: atmel_mxt_ts - Handle APP_CRC_FAIL on startup
In reply to Nick DyerIf 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 61 +++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 13 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +48 -13
@@ -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) {
Signature · 1 line
1.7.10.4
PATCH 28/51 Input: atmel_mxt_ts - Handle bootloader previously unlocked
In reply to Nick Dyer--- drivers/input/touchscreen/atmel_mxt_ts.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +19 -9
@@ -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++;
Signature · 1 line
1.7.10.4
PATCH 29/51 Input: atmel_mxt_ts - Add bootloader addresses for new chips
In reply to Nick DyerLater 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/input/touchscreen/atmel_mxt_ts.c +6 -0
@@ -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 :
Signature · 1 line
1.7.10.4
PATCH 30/51 Input: atmel_mxt_ts - Recover from bootloader on probe
In reply to Nick DyerThe 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 68 ++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 17 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +51 -17
@@ -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; }
Signature · 1 line
1.7.10.4
PATCH 31/51 Input: atmel_mxt_ts - Add support for dynamic message size
In reply to Nick DyerThe 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 114 +++++++++++++++++------------- 1 file changed, 65 insertions(+), 49 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +65 -49
@@ -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);
Signature · 1 line
1.7.10.4
PATCH 32/51 Input: atmel_mxt_ts - Decode T6 status messages
In reply to Nick DyerBy 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).
--- drivers/input/touchscreen/atmel_mxt_ts.c | 60 ++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 20 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +40 -20
@@ -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;
Signature · 1 line
1.7.10.4
PATCH 33/51 Input: atmel_mxt_ts - Split message handler into separate functions
In reply to Nick DyerThis is in preparation for support of the T44 message count object.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 111 ++++++++++++++++-------------- 1 file changed, 58 insertions(+), 53 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +58 -53
@@ -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;
Signature · 1 line
1.7.10.4
PATCH 34/51 Input: atmel_mxt_ts - Implement T44 message handling
In reply to Nick DyermaXTouch 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 190 +++++++++++++++++++++++++----- 1 file changed, 158 insertions(+), 32 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +158 -32
@@ -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 ;
Signature · 1 line
1.7.10.4
PATCH 35/51 Input: atmel_mxt_ts - Output status from T48 Noise Supression
In reply to Nick Dyer--- drivers/input/touchscreen/atmel_mxt_ts.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
drivers/input/touchscreen/atmel_mxt_ts.c +27 -0
@@ -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
Signature · 1 line
1.7.10.4
PATCH 36/51 Input: atmel_mxt_ts - Output status from T42 Touch Suppression
In reply to Nick Dyer--- drivers/input/touchscreen/atmel_mxt_ts.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
drivers/input/touchscreen/atmel_mxt_ts.c +25 -0
@@ -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 ;
Signature · 1 line
1.7.10.4
PATCH 37/51 Input: atmel_mxt_ts - Implement vector/orientation support
In reply to Nick DyerThe 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +7 -2
@@ -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);
Signature · 1 line
1.7.10.4
Re: [PATCH 37/51] Input: atmel_mxt_ts - Implement vector/orientation support
Quoted 10 lines · 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#touchorientationcalibrationThis 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?
Quoted 60 lines
Signed-off-by Nick Dyer <[email protected]>Acked-by Benson Leung <[email protected]>--- drivers/input/touchscreen/atmel_mxt_ts.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)drivers/input/touchscreen/atmel_mxt_ts.c +7
-2@@ -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);Signature · 1 line
1.7.10.4
Thanks,
Henrik
Re: [PATCH 37/51] Input: atmel_mxt_ts - Implement vector/orientation support
Quoted 5 lines · [email protected] wrote:
Quoted 4 lines · 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
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)
Quoted 7 lines
Quoted 5 lines
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) ?
PATCH 38/51 Input: atmel_mxt_ts - implement I2C retries
In reply to Nick DyerSome 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 45 ++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 15 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +30 -15
@@ -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);
Signature · 1 line
1.7.10.4
PATCH 39/51 Input: atmel_mxt_ts - Implement T63 Active Stylus support
In reply to Nick Dyer--- drivers/input/touchscreen/atmel_mxt_ts.c | 95 +++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-)
drivers/input/touchscreen/atmel_mxt_ts.c +94 -1
@@ -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);
Signature · 1 line
1.7.10.4
Re: [PATCH 39/51] Input: atmel_mxt_ts - Implement T63 Active Stylus support
Quoted 178 lines · Nick Dyer
Signed-off-by Nick Dyer <[email protected]>Acked-by Benson Leung <[email protected]>--- drivers/input/touchscreen/atmel_mxt_ts.c | 95 +++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-)drivers/input/touchscreen/atmel_mxt_ts.c +94
-1@@ -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);Signature · 1 line
1.7.10.4
Thanks,
Henrik
PATCH 40/51 Input: atmel_mxt_ts - Implement support for T15 Key Array
In reply to Nick DyerThere 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 57 ++++++++++++++++++++++++++++++ include/linux/i2c/atmel_mxt_ts.h | 2 ++ 2 files changed, 59 insertions(+)
drivers/input/touchscreen/atmel_mxt_ts.c +57 -0
@@ -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);
include/linux/i2c/atmel_mxt_ts.h +2 -0
@@ -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 */
Signature · 1 line
1.7.10.4
PATCH 41/51 Input: atmel_mxt_ts - Remove unused defines
In reply to Nick DyerMany 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 66 +----------------------------- 1 file changed, 1 insertion(+), 65 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +1 -65
@@ -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;
Signature · 1 line
1.7.10.4
PATCH 42/51 Input: atmel_mxt_ts - Verify Information Block checksum on probe
In reply to Nick DyerBy 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 182 ++++++++++++++++++------------ 1 file changed, 112 insertions(+), 70 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +112 -70
@@ -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" );
Signature · 1 line
1.7.10.4
PATCH 43/51 Input: atmel_mxt_ts - Use T18 RETRIGEN to handle IRQF_TRIGGER_LOW
In reply to Nick DyerThe 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 48 ++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +45 -3
@@ -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;
Signature · 1 line
1.7.10.4
PATCH 44/51 Input: atmel_mxt_ts - Handle reports from T47 Stylus object
In reply to Nick Dyer--- drivers/input/touchscreen/atmel_mxt_ts.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
drivers/input/touchscreen/atmel_mxt_ts.c +15 -1
@@ -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);
Signature · 1 line
1.7.10.4
Re: [PATCH 44/51] Input: atmel_mxt_ts - Handle reports from T47 Stylus object
Quoted 11 lines · Nick Dyer
Signed-off-by Nick Dyer <[email protected]>Acked-by Benson Leung <[email protected]>--- drivers/input/touchscreen/atmel_mxt_ts.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)drivers/input/touchscreen/atmel_mxt_ts.c +0
-0
drivers/input/touchscreen/atmel_mxt_ts.c struct t9_range { · line 133
Quoted 6 lines
drivers/input/touchscreen/atmel_mxt_ts.c +3
-0@@ -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.
Quoted 41 lines
drivers/input/touchscreen/atmel_mxt_ts.c +12
-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);Signature · 1 line
1.7.10.4
Thanks,
Henrik
PATCH 45/51 Input: atmel_mxt_ts - Release touch state during suspend
In reply to Nick DyerIf 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
--- drivers/input/touchscreen/atmel_mxt_ts.c | 46 ++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+)
drivers/input/touchscreen/atmel_mxt_ts.c +46 -0
@@ -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)
Signature · 1 line
1.7.10.4
Re: [PATCH 45/51] Input: atmel_mxt_ts - Release touch state during suspend
Quoted 4 lines · 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.
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?
Quoted 103 lines
So:
- disable irq during suspend
- flush any messages created after suspend
- tell app layer that slots were released at suspendSigned-off-by Nick Dyer <[email protected]>Acked-by Benson Leung <[email protected]>--- drivers/input/touchscreen/atmel_mxt_ts.c | 46 ++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+)drivers/input/touchscreen/atmel_mxt_ts.c +46
-0@@ -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)Signature · 1 line
1.7.10.4
Thanks,
Henrik
Re: [PATCH 45/51] Input: atmel_mxt_ts - Release touch state during suspend
Quoted 8 lines · [email protected] wrote:
Quoted 4 lines · 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.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?
PATCH 46/51 Input: atmel_mxt_ts - Initialize power config before and after downloading cfg
In reply to Nick DyerIf 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +11 -6
@@ -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; }
Signature · 1 line
1.7.10.4
PATCH 47/51 Input: atmel_mxt_ts - Add regulator control support
In reply to Nick DyerAllow 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 95 +++++++++++++++++++++++++++--- include/linux/i2c/atmel_mxt_ts.h | 1 + 2 files changed, 89 insertions(+), 7 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +88 -7
@@ -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);
include/linux/i2c/atmel_mxt_ts.h +1 -0
@@ -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 */
Signature · 1 line
1.7.10.4
PATCH 48/51 Input: atmel_mxt_ts - Implement support for T100 touch object
In reply to Nick DyerThe T100 object replaces the old T9 multitouch touchscreen object in new chips.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 299 ++++++++++++++++++++++++++++-- 1 file changed, 288 insertions(+), 11 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +288 -11
@@ -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);
Signature · 1 line
1.7.10.4
PATCH 49/51 Input: atmel_mxt_ts - Allow specification of firmware file name
In reply to Nick DyerOn 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 45 ++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 6 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +39 -6
@@ -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;
Signature · 1 line
1.7.10.4
PATCH 50/51 Input: atmel_mxt_ts - Handle cfg filename via pdata/sysfs
In reply to Nick DyerThere 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 104 ++++++++++++++++++++++++------ include/linux/i2c/atmel_mxt_ts.h | 1 + 2 files changed, 86 insertions(+), 19 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +85 -19
@@ -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) {
include/linux/i2c/atmel_mxt_ts.h +1 -0
@@ -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 */
Signature · 1 line
1.7.10.4
PATCH 51/51 Input: atmel_mxt_ts - Only use first T9 instance
In reply to Nick DyerThe 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.
--- drivers/input/touchscreen/atmel_mxt_ts.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
drivers/input/touchscreen/atmel_mxt_ts.c +7 -6
@@ -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;
Signature · 1 line
1.7.10.4
Hi Dimitry-
Quoted 2 lines · Nick Dyer
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
[email protected]:ndyer/linux.git
the tag is
for-next-20130627-v7
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
Quoted 1 line · [email protected] wrote:
First: thanks for the patches and you work on this driver.
Thank you for your time in looking at these changes.
Quoted 10 lines
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.
Dmitry Torokhov
maintainerQuoted 10 lines · Nick Dyer
Quoted 1 line · [email protected] wrote:
First: thanks for the patches and you work on this driver.
Thank you for your time in looking at these changes.
Quoted 5 lines
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!!!***
Quoted 7 lines
Quoted 5 lines
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...
Signature · 1 line
Dmitry
Quoted 10 lines · Dmitry Torokhov
Quoted 9 lines · Nick Dyer
Quoted 7 lines · [email protected] 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,
Quoted 3 lines
Quoted 1 line
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.
Quoted 17 lines · Dmitry Torokhov
Quoted 16 lines · Nick Dyer
Quoted 1 line · [email protected] wrote:
First: thanks for the patches and you work on this driver.
Thank you for your time in looking at these changes.
Quoted 10 lines
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,
Quoted 3 lines
Quoted 1 line
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
Signature · 1 line
Nick Dyer
A message that is not in the archive (sent off-list or not yet received): CAPDwgkOo7FYLujk16kJM=BqmXRKvZ2S_LOYURW0cXT5t=cmi6w@mail.gmail.com
Quoted 39 lines · Yufeng Shen
Quoted 11 lines · On Tue, Sep 10, 2013 at 9:58 AM, Nick Dyer <[email protected]…
Quoted 10 lines · Dmitry Torokhov
Quoted 9 lines · Nick Dyer
Quoted 1 line · [email protected] <mailto:[email protected]> wrote:
First: thanks for the patches and you work on this driver.
Thank you for your time in looking at these changes.
Quoted 4 lines
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!!!***
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 6 lines
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.
Quoted 5 lines
Quoted 2 lines
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.
Quoted 6 lines
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?
A message that is not in the archive (sent off-list or not yet received): CAPDwgkOsP4K7r0-Mo-U52X9knRbGgbuD4dGptmj3x-LMTN75BA@mail.gmail.com
Quoted 6 lines · Yufeng Shen
Quoted 3 lines · On Wed, Jan 15, 2014 at 5:44 AM, Nick Dyer <[email protected]…
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.
Quoted 6 lines
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.