diff options
author | Nick Dyer <nick.dyer@itdev.co.uk> | 2014-05-19 02:04:46 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2014-05-19 02:27:26 -0400 |
commit | c3f78043d5aea39205a14c580babd87fbdcfa148 (patch) | |
tree | a04d28b1eae6a4da2d528c9f9e2f343e88ba88f9 | |
parent | 7bed6805615a215c3e23d5819ec3003b2fd8b98c (diff) |
Input: atmel_mxt_ts - implement CRC check for configuration data
The configuration is stored in NVRAM on the maXTouch chip. When the device
is reset it reports a CRC of the stored configuration values. Therefore it
isn't necessary to send the configuration on each probe - we can check the
CRC matches and avoid a timeconsuming backup/reset cycle.
Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
Acked-by: Yufeng Shen <miletus@chromium.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r-- | drivers/input/touchscreen/atmel_mxt_ts.c | 60 | ||||
-rw-r--r-- | include/linux/i2c/atmel_mxt_ts.h | 1 |
2 files changed, 53 insertions, 8 deletions
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 278f364ec6e1..61f9ef221d12 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c | |||
@@ -188,6 +188,7 @@ | |||
188 | #define MXT_BACKUP_TIME 50 /* msec */ | 188 | #define MXT_BACKUP_TIME 50 /* msec */ |
189 | #define MXT_RESET_TIME 200 /* msec */ | 189 | #define MXT_RESET_TIME 200 /* msec */ |
190 | #define MXT_RESET_TIMEOUT 3000 /* msec */ | 190 | #define MXT_RESET_TIMEOUT 3000 /* msec */ |
191 | #define MXT_CRC_TIMEOUT 1000 /* msec */ | ||
191 | #define MXT_FW_RESET_TIME 3000 /* msec */ | 192 | #define MXT_FW_RESET_TIME 3000 /* msec */ |
192 | #define MXT_FW_CHG_TIMEOUT 300 /* msec */ | 193 | #define MXT_FW_CHG_TIMEOUT 300 /* msec */ |
193 | 194 | ||
@@ -259,6 +260,7 @@ struct mxt_data { | |||
259 | unsigned int max_x; | 260 | unsigned int max_x; |
260 | unsigned int max_y; | 261 | unsigned int max_y; |
261 | bool in_bootloader; | 262 | bool in_bootloader; |
263 | u32 config_crc; | ||
262 | 264 | ||
263 | /* Cached parameters from object table */ | 265 | /* Cached parameters from object table */ |
264 | u8 T6_reportid; | 266 | u8 T6_reportid; |
@@ -272,6 +274,9 @@ struct mxt_data { | |||
272 | 274 | ||
273 | /* for reset handling */ | 275 | /* for reset handling */ |
274 | struct completion reset_completion; | 276 | struct completion reset_completion; |
277 | |||
278 | /* for config update handling */ | ||
279 | struct completion crc_completion; | ||
275 | }; | 280 | }; |
276 | 281 | ||
277 | static size_t mxt_obj_size(const struct mxt_object *obj) | 282 | static size_t mxt_obj_size(const struct mxt_object *obj) |
@@ -636,7 +641,7 @@ static void mxt_input_touchevent(struct mxt_data *data, | |||
636 | } | 641 | } |
637 | } | 642 | } |
638 | 643 | ||
639 | static unsigned mxt_extract_T6_csum(const u8 *csum) | 644 | static u16 mxt_extract_T6_csum(const u8 *csum) |
640 | { | 645 | { |
641 | return csum[0] | (csum[1] << 8) | (csum[2] << 16); | 646 | return csum[0] | (csum[1] << 8) | (csum[2] << 16); |
642 | } | 647 | } |
@@ -654,6 +659,7 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data) | |||
654 | struct device *dev = &data->client->dev; | 659 | struct device *dev = &data->client->dev; |
655 | u8 reportid; | 660 | u8 reportid; |
656 | bool update_input = false; | 661 | bool update_input = false; |
662 | u32 crc; | ||
657 | 663 | ||
658 | do { | 664 | do { |
659 | if (mxt_read_message(data, &message)) { | 665 | if (mxt_read_message(data, &message)) { |
@@ -665,9 +671,15 @@ static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data) | |||
665 | 671 | ||
666 | if (reportid == data->T6_reportid) { | 672 | if (reportid == data->T6_reportid) { |
667 | u8 status = payload[0]; | 673 | u8 status = payload[0]; |
668 | unsigned csum = mxt_extract_T6_csum(&payload[1]); | 674 | |
675 | crc = mxt_extract_T6_csum(&payload[1]); | ||
676 | if (crc != data->config_crc) { | ||
677 | data->config_crc = crc; | ||
678 | complete(&data->crc_completion); | ||
679 | } | ||
680 | |||
669 | dev_dbg(dev, "Status: %02x Config Checksum: %06x\n", | 681 | dev_dbg(dev, "Status: %02x Config Checksum: %06x\n", |
670 | status, csum); | 682 | status, data->config_crc); |
671 | 683 | ||
672 | if (status & MXT_T6_STATUS_RESET) | 684 | if (status & MXT_T6_STATUS_RESET) |
673 | complete(&data->reset_completion); | 685 | complete(&data->reset_completion); |
@@ -757,6 +769,24 @@ static int mxt_soft_reset(struct mxt_data *data) | |||
757 | return 0; | 769 | return 0; |
758 | } | 770 | } |
759 | 771 | ||
772 | static void mxt_update_crc(struct mxt_data *data, u8 cmd, u8 value) | ||
773 | { | ||
774 | /* | ||
775 | * On failure, CRC is set to 0 and config will always be | ||
776 | * downloaded. | ||
777 | */ | ||
778 | data->config_crc = 0; | ||
779 | reinit_completion(&data->crc_completion); | ||
780 | |||
781 | mxt_t6_command(data, cmd, value, true); | ||
782 | |||
783 | /* | ||
784 | * Wait for crc message. On failure, CRC is set to 0 and config will | ||
785 | * always be downloaded. | ||
786 | */ | ||
787 | mxt_wait_for_completion(data, &data->crc_completion, MXT_CRC_TIMEOUT); | ||
788 | } | ||
789 | |||
760 | static int mxt_check_reg_init(struct mxt_data *data) | 790 | static int mxt_check_reg_init(struct mxt_data *data) |
761 | { | 791 | { |
762 | const struct mxt_platform_data *pdata = data->pdata; | 792 | const struct mxt_platform_data *pdata = data->pdata; |
@@ -771,6 +801,16 @@ static int mxt_check_reg_init(struct mxt_data *data) | |||
771 | return 0; | 801 | return 0; |
772 | } | 802 | } |
773 | 803 | ||
804 | mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1); | ||
805 | |||
806 | if (data->config_crc == pdata->config_crc) { | ||
807 | dev_info(dev, "Config CRC 0x%06X: OK\n", data->config_crc); | ||
808 | return 0; | ||
809 | } | ||
810 | |||
811 | dev_info(dev, "Config CRC 0x%06X: does not match 0x%06X\n", | ||
812 | data->config_crc, pdata->config_crc); | ||
813 | |||
774 | for (i = 0; i < data->info.object_num; i++) { | 814 | for (i = 0; i < data->info.object_num; i++) { |
775 | object = data->object_table + i; | 815 | object = data->object_table + i; |
776 | 816 | ||
@@ -790,6 +830,14 @@ static int mxt_check_reg_init(struct mxt_data *data) | |||
790 | index += size; | 830 | index += size; |
791 | } | 831 | } |
792 | 832 | ||
833 | mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE); | ||
834 | |||
835 | ret = mxt_soft_reset(data); | ||
836 | if (ret) | ||
837 | return ret; | ||
838 | |||
839 | dev_info(dev, "Config successfully updated\n"); | ||
840 | |||
793 | return 0; | 841 | return 0; |
794 | } | 842 | } |
795 | 843 | ||
@@ -929,11 +977,6 @@ static int mxt_initialize(struct mxt_data *data) | |||
929 | goto err_free_object_table; | 977 | goto err_free_object_table; |
930 | } | 978 | } |
931 | 979 | ||
932 | error = mxt_t6_command(data, MXT_COMMAND_BACKUPNV, | ||
933 | MXT_BACKUP_VALUE, false); | ||
934 | if (!error) | ||
935 | mxt_soft_reset(data); | ||
936 | |||
937 | /* Update matrix size at info struct */ | 980 | /* Update matrix size at info struct */ |
938 | error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val); | 981 | error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val); |
939 | if (error) | 982 | if (error) |
@@ -1263,6 +1306,7 @@ static int mxt_probe(struct i2c_client *client, | |||
1263 | 1306 | ||
1264 | init_completion(&data->bl_completion); | 1307 | init_completion(&data->bl_completion); |
1265 | init_completion(&data->reset_completion); | 1308 | init_completion(&data->reset_completion); |
1309 | init_completion(&data->crc_completion); | ||
1266 | 1310 | ||
1267 | mxt_calc_resolution(data); | 1311 | mxt_calc_resolution(data); |
1268 | 1312 | ||
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h index d26080dc606c..9f92135b6620 100644 --- a/include/linux/i2c/atmel_mxt_ts.h +++ b/include/linux/i2c/atmel_mxt_ts.h | |||
@@ -29,6 +29,7 @@ | |||
29 | struct mxt_platform_data { | 29 | struct mxt_platform_data { |
30 | const u8 *config; | 30 | const u8 *config; |
31 | size_t config_length; | 31 | size_t config_length; |
32 | u32 config_crc; | ||
32 | 33 | ||
33 | unsigned int x_size; | 34 | unsigned int x_size; |
34 | unsigned int y_size; | 35 | unsigned int y_size; |