Input: atmel_mxt_ts - implement CRC check for configuration data
authorNick Dyer <nick.dyer@itdev.co.uk>
Mon, 19 May 2014 06:04:46 +0000 (23:04 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Mon, 19 May 2014 06:27:26 +0000 (23:27 -0700)
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>
drivers/input/touchscreen/atmel_mxt_ts.c
include/linux/i2c/atmel_mxt_ts.h

index 278f364ec6e11e9f8b900944425f824f4926f714..61f9ef221d128ef6d66f8a1bd60d769d586a298a 100644 (file)
 #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 */
 
@@ -259,6 +260,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;
@@ -272,6 +274,9 @@ struct mxt_data {
 
        /* for reset handling */
        struct completion reset_completion;
+
+       /* for config update handling */
+       struct completion crc_completion;
 };
 
 static size_t mxt_obj_size(const struct mxt_object *obj)
@@ -636,7 +641,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);
 }
@@ -654,6 +659,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)) {
@@ -665,9 +671,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);
@@ -757,6 +769,24 @@ 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;
+       reinit_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;
@@ -771,6 +801,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;
+       }
+
+       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;
 
@@ -790,6 +830,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 successfully updated\n");
+
        return 0;
 }
 
@@ -929,11 +977,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)
@@ -1263,6 +1306,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);
 
index d26080dc606cae74fc1dedae2f8c2c7dfe1ab4de..9f92135b66203e3d08ed8aca423861f55c83eaef 100644 (file)
@@ -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;