diff options
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r-- | drivers/input/touchscreen/atmel_mxt_ts.c | 278 |
1 files changed, 204 insertions, 74 deletions
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 4317273c2138..c6b5e7dbd942 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * Atmel maXTouch Touchscreen driver | 2 | * Atmel maXTouch Touchscreen driver |
3 | * | 3 | * |
4 | * Copyright (C) 2010 Samsung Electronics Co.Ltd | 4 | * Copyright (C) 2010 Samsung Electronics Co.Ltd |
5 | * Copyright (C) 2011-2014 Atmel Corporation | ||
5 | * Copyright (C) 2012 Google, Inc. | 6 | * Copyright (C) 2012 Google, Inc. |
6 | * | 7 | * |
7 | * Author: Joonyoung Shim <jy0922.shim@samsung.com> | 8 | * Author: Joonyoung Shim <jy0922.shim@samsung.com> |
@@ -30,8 +31,10 @@ | |||
30 | #define MXT_VER_21 21 | 31 | #define MXT_VER_21 21 |
31 | #define MXT_VER_22 22 | 32 | #define MXT_VER_22 22 |
32 | 33 | ||
33 | /* Firmware */ | 34 | /* Firmware files */ |
34 | #define MXT_FW_NAME "maxtouch.fw" | 35 | #define MXT_FW_NAME "maxtouch.fw" |
36 | #define MXT_CFG_NAME "maxtouch.cfg" | ||
37 | #define MXT_CFG_MAGIC "OBP_RAW V1" | ||
35 | 38 | ||
36 | /* Registers */ | 39 | /* Registers */ |
37 | #define MXT_INFO 0x00 | 40 | #define MXT_INFO 0x00 |
@@ -298,37 +301,6 @@ static bool mxt_object_readable(unsigned int type) | |||
298 | } | 301 | } |
299 | } | 302 | } |
300 | 303 | ||
301 | static bool mxt_object_writable(unsigned int type) | ||
302 | { | ||
303 | switch (type) { | ||
304 | case MXT_GEN_COMMAND_T6: | ||
305 | case MXT_GEN_POWER_T7: | ||
306 | case MXT_GEN_ACQUIRE_T8: | ||
307 | case MXT_TOUCH_MULTI_T9: | ||
308 | case MXT_TOUCH_KEYARRAY_T15: | ||
309 | case MXT_TOUCH_PROXIMITY_T23: | ||
310 | case MXT_TOUCH_PROXKEY_T52: | ||
311 | case MXT_PROCI_GRIPFACE_T20: | ||
312 | case MXT_PROCG_NOISE_T22: | ||
313 | case MXT_PROCI_ONETOUCH_T24: | ||
314 | case MXT_PROCI_TWOTOUCH_T27: | ||
315 | case MXT_PROCI_GRIP_T40: | ||
316 | case MXT_PROCI_PALM_T41: | ||
317 | case MXT_PROCI_TOUCHSUPPRESSION_T42: | ||
318 | case MXT_PROCI_STYLUS_T47: | ||
319 | case MXT_PROCG_NOISESUPPRESSION_T48: | ||
320 | case MXT_SPT_COMMSCONFIG_T18: | ||
321 | case MXT_SPT_GPIOPWM_T19: | ||
322 | case MXT_SPT_SELFTEST_T25: | ||
323 | case MXT_SPT_CTECONFIG_T28: | ||
324 | case MXT_SPT_DIGITIZER_T43: | ||
325 | case MXT_SPT_CTECONFIG_T46: | ||
326 | return true; | ||
327 | default: | ||
328 | return false; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | static void mxt_dump_message(struct device *dev, | 304 | static void mxt_dump_message(struct device *dev, |
333 | struct mxt_message *message) | 305 | struct mxt_message *message) |
334 | { | 306 | { |
@@ -606,7 +578,7 @@ mxt_get_object(struct mxt_data *data, u8 type) | |||
606 | return object; | 578 | return object; |
607 | } | 579 | } |
608 | 580 | ||
609 | dev_err(&data->client->dev, "Invalid object type T%u\n", type); | 581 | dev_warn(&data->client->dev, "Invalid object type T%u\n", type); |
610 | return NULL; | 582 | return NULL; |
611 | } | 583 | } |
612 | 584 | ||
@@ -877,58 +849,197 @@ static void mxt_update_crc(struct mxt_data *data, u8 cmd, u8 value) | |||
877 | mxt_wait_for_completion(data, &data->crc_completion, MXT_CRC_TIMEOUT); | 849 | mxt_wait_for_completion(data, &data->crc_completion, MXT_CRC_TIMEOUT); |
878 | } | 850 | } |
879 | 851 | ||
880 | static int mxt_check_reg_init(struct mxt_data *data) | 852 | /* |
853 | * mxt_update_cfg - download configuration to chip | ||
854 | * | ||
855 | * Atmel Raw Config File Format | ||
856 | * | ||
857 | * The first four lines of the raw config file contain: | ||
858 | * 1) Version | ||
859 | * 2) Chip ID Information (first 7 bytes of device memory) | ||
860 | * 3) Chip Information Block 24-bit CRC Checksum | ||
861 | * 4) Chip Configuration 24-bit CRC Checksum | ||
862 | * | ||
863 | * The rest of the file consists of one line per object instance: | ||
864 | * <TYPE> <INSTANCE> <SIZE> <CONTENTS> | ||
865 | * | ||
866 | * <TYPE> - 2-byte object type as hex | ||
867 | * <INSTANCE> - 2-byte object instance number as hex | ||
868 | * <SIZE> - 2-byte object size as hex | ||
869 | * <CONTENTS> - array of <SIZE> 1-byte hex values | ||
870 | */ | ||
871 | static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) | ||
881 | { | 872 | { |
882 | const struct mxt_platform_data *pdata = data->pdata; | ||
883 | struct mxt_object *object; | ||
884 | struct device *dev = &data->client->dev; | 873 | struct device *dev = &data->client->dev; |
885 | int index = 0; | 874 | struct mxt_info cfg_info; |
886 | int i, size; | 875 | struct mxt_object *object; |
887 | int ret; | 876 | int ret; |
877 | int offset; | ||
878 | int pos; | ||
879 | int i; | ||
880 | u32 info_crc, config_crc; | ||
881 | unsigned int type, instance, size; | ||
882 | u8 val; | ||
883 | u16 reg; | ||
888 | 884 | ||
889 | if (!pdata->config) { | 885 | mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1); |
890 | dev_dbg(dev, "No cfg data defined, skipping reg init\n"); | 886 | |
891 | return 0; | 887 | if (strncmp(cfg->data, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) { |
888 | dev_err(dev, "Unrecognised config file\n"); | ||
889 | ret = -EINVAL; | ||
890 | goto release; | ||
892 | } | 891 | } |
893 | 892 | ||
894 | mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1); | 893 | pos = strlen(MXT_CFG_MAGIC); |
894 | |||
895 | /* Load information block and check */ | ||
896 | for (i = 0; i < sizeof(struct mxt_info); i++) { | ||
897 | ret = sscanf(cfg->data + pos, "%hhx%n", | ||
898 | (unsigned char *)&cfg_info + i, | ||
899 | &offset); | ||
900 | if (ret != 1) { | ||
901 | dev_err(dev, "Bad format\n"); | ||
902 | ret = -EINVAL; | ||
903 | goto release; | ||
904 | } | ||
895 | 905 | ||
896 | if (data->config_crc == pdata->config_crc) { | 906 | pos += offset; |
897 | dev_info(dev, "Config CRC 0x%06X: OK\n", data->config_crc); | 907 | } |
898 | return 0; | 908 | |
909 | if (cfg_info.family_id != data->info.family_id) { | ||
910 | dev_err(dev, "Family ID mismatch!\n"); | ||
911 | ret = -EINVAL; | ||
912 | goto release; | ||
899 | } | 913 | } |
900 | 914 | ||
901 | dev_info(dev, "Config CRC 0x%06X: does not match 0x%06X\n", | 915 | if (cfg_info.variant_id != data->info.variant_id) { |
902 | data->config_crc, pdata->config_crc); | 916 | dev_err(dev, "Variant ID mismatch!\n"); |
917 | ret = -EINVAL; | ||
918 | goto release; | ||
919 | } | ||
903 | 920 | ||
904 | for (i = 0; i < data->info.object_num; i++) { | 921 | if (cfg_info.version != data->info.version) |
905 | object = data->object_table + i; | 922 | dev_err(dev, "Warning: version mismatch!\n"); |
906 | 923 | ||
907 | if (!mxt_object_writable(object->type)) | 924 | if (cfg_info.build != data->info.build) |
925 | dev_err(dev, "Warning: build num mismatch!\n"); | ||
926 | |||
927 | ret = sscanf(cfg->data + pos, "%x%n", &info_crc, &offset); | ||
928 | if (ret != 1) { | ||
929 | dev_err(dev, "Bad format: failed to parse Info CRC\n"); | ||
930 | ret = -EINVAL; | ||
931 | goto release; | ||
932 | } | ||
933 | pos += offset; | ||
934 | |||
935 | /* Check config CRC */ | ||
936 | ret = sscanf(cfg->data + pos, "%x%n", &config_crc, &offset); | ||
937 | if (ret != 1) { | ||
938 | dev_err(dev, "Bad format: failed to parse Config CRC\n"); | ||
939 | ret = -EINVAL; | ||
940 | goto release; | ||
941 | } | ||
942 | pos += offset; | ||
943 | |||
944 | if (data->config_crc == config_crc) { | ||
945 | dev_dbg(dev, "Config CRC 0x%06X: OK\n", config_crc); | ||
946 | ret = 0; | ||
947 | goto release; | ||
948 | } | ||
949 | |||
950 | dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n", | ||
951 | data->config_crc, config_crc); | ||
952 | |||
953 | while (pos < cfg->size) { | ||
954 | /* Read type, instance, length */ | ||
955 | ret = sscanf(cfg->data + pos, "%x %x %x%n", | ||
956 | &type, &instance, &size, &offset); | ||
957 | if (ret == 0) { | ||
958 | /* EOF */ | ||
959 | ret = 1; | ||
960 | goto release; | ||
961 | } else if (ret != 3) { | ||
962 | dev_err(dev, "Bad format: failed to parse object\n"); | ||
963 | ret = -EINVAL; | ||
964 | goto release; | ||
965 | } | ||
966 | pos += offset; | ||
967 | |||
968 | object = mxt_get_object(data, type); | ||
969 | if (!object) { | ||
970 | /* Skip object */ | ||
971 | for (i = 0; i < size; i++) { | ||
972 | ret = sscanf(cfg->data + pos, "%hhx%n", | ||
973 | &val, | ||
974 | &offset); | ||
975 | pos += offset; | ||
976 | } | ||
908 | continue; | 977 | continue; |
978 | } | ||
909 | 979 | ||
910 | size = mxt_obj_size(object) * mxt_obj_instances(object); | 980 | if (size > mxt_obj_size(object)) { |
911 | if (index + size > pdata->config_length) { | 981 | dev_err(dev, "Discarding %zu byte(s) in T%u\n", |
912 | dev_err(dev, "Not enough config data!\n"); | 982 | size - mxt_obj_size(object), type); |
913 | return -EINVAL; | ||
914 | } | 983 | } |
915 | 984 | ||
916 | ret = __mxt_write_reg(data->client, object->start_address, | 985 | if (instance >= mxt_obj_instances(object)) { |
917 | size, &pdata->config[index]); | 986 | dev_err(dev, "Object instances exceeded!\n"); |
918 | if (ret) | 987 | ret = -EINVAL; |
919 | return ret; | 988 | goto release; |
920 | index += size; | 989 | } |
990 | |||
991 | reg = object->start_address + mxt_obj_size(object) * instance; | ||
992 | |||
993 | for (i = 0; i < size; i++) { | ||
994 | ret = sscanf(cfg->data + pos, "%hhx%n", | ||
995 | &val, | ||
996 | &offset); | ||
997 | if (ret != 1) { | ||
998 | dev_err(dev, "Bad format in T%d\n", type); | ||
999 | ret = -EINVAL; | ||
1000 | goto release; | ||
1001 | } | ||
1002 | pos += offset; | ||
1003 | |||
1004 | if (i > mxt_obj_size(object)) | ||
1005 | continue; | ||
1006 | |||
1007 | ret = mxt_write_reg(data->client, reg + i, val); | ||
1008 | if (ret) | ||
1009 | goto release; | ||
1010 | |||
1011 | } | ||
1012 | |||
1013 | /* | ||
1014 | * If firmware is upgraded, new bytes may be added to end of | ||
1015 | * objects. It is generally forward compatible to zero these | ||
1016 | * bytes - previous behaviour will be retained. However | ||
1017 | * this does invalidate the CRC and will force a config | ||
1018 | * download every time until the configuration is updated. | ||
1019 | */ | ||
1020 | if (size < mxt_obj_size(object)) { | ||
1021 | dev_info(dev, "Zeroing %zu byte(s) in T%d\n", | ||
1022 | mxt_obj_size(object) - size, type); | ||
1023 | |||
1024 | for (i = size + 1; i < mxt_obj_size(object); i++) { | ||
1025 | ret = mxt_write_reg(data->client, reg + i, 0); | ||
1026 | if (ret) | ||
1027 | goto release; | ||
1028 | } | ||
1029 | } | ||
921 | } | 1030 | } |
922 | 1031 | ||
923 | mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE); | 1032 | mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE); |
924 | 1033 | ||
925 | ret = mxt_soft_reset(data); | 1034 | ret = mxt_soft_reset(data); |
926 | if (ret) | 1035 | if (ret) |
927 | return ret; | 1036 | goto release; |
928 | 1037 | ||
929 | dev_info(dev, "Config successfully updated\n"); | 1038 | dev_info(dev, "Config successfully updated\n"); |
930 | 1039 | ||
931 | return 0; | 1040 | release: |
1041 | release_firmware(cfg); | ||
1042 | return ret; | ||
932 | } | 1043 | } |
933 | 1044 | ||
934 | static int mxt_make_highchg(struct mxt_data *data) | 1045 | static int mxt_make_highchg(struct mxt_data *data) |
@@ -1204,10 +1315,17 @@ err_free_mem: | |||
1204 | return error; | 1315 | return error; |
1205 | } | 1316 | } |
1206 | 1317 | ||
1318 | static int mxt_configure_objects(struct mxt_data *data, | ||
1319 | const struct firmware *cfg); | ||
1320 | |||
1321 | static void mxt_config_cb(const struct firmware *cfg, void *ctx) | ||
1322 | { | ||
1323 | mxt_configure_objects(ctx, cfg); | ||
1324 | } | ||
1325 | |||
1207 | static int mxt_initialize(struct mxt_data *data) | 1326 | static int mxt_initialize(struct mxt_data *data) |
1208 | { | 1327 | { |
1209 | struct i2c_client *client = data->client; | 1328 | struct i2c_client *client = data->client; |
1210 | struct mxt_info *info = &data->info; | ||
1211 | int error; | 1329 | int error; |
1212 | 1330 | ||
1213 | error = mxt_get_info(data); | 1331 | error = mxt_get_info(data); |
@@ -1225,28 +1343,40 @@ static int mxt_initialize(struct mxt_data *data) | |||
1225 | if (error) | 1343 | if (error) |
1226 | goto err_free_object_table; | 1344 | goto err_free_object_table; |
1227 | 1345 | ||
1228 | /* Check register init values */ | 1346 | request_firmware_nowait(THIS_MODULE, true, MXT_CFG_NAME, |
1229 | error = mxt_check_reg_init(data); | 1347 | &data->client->dev, GFP_KERNEL, data, |
1230 | if (error) { | 1348 | mxt_config_cb); |
1231 | dev_err(&client->dev, "Error %d initializing configuration\n", | 1349 | |
1232 | error); | 1350 | return 0; |
1233 | goto err_free_object_table; | 1351 | |
1352 | err_free_object_table: | ||
1353 | mxt_free_object_table(data); | ||
1354 | return error; | ||
1355 | } | ||
1356 | |||
1357 | static int mxt_configure_objects(struct mxt_data *data, | ||
1358 | const struct firmware *cfg) | ||
1359 | { | ||
1360 | struct device *dev = &data->client->dev; | ||
1361 | struct mxt_info *info = &data->info; | ||
1362 | int error; | ||
1363 | |||
1364 | if (cfg) { | ||
1365 | error = mxt_update_cfg(data, cfg); | ||
1366 | if (error) | ||
1367 | dev_warn(dev, "Error %d updating config\n", error); | ||
1234 | } | 1368 | } |
1235 | 1369 | ||
1236 | error = mxt_initialize_t9_input_device(data); | 1370 | error = mxt_initialize_t9_input_device(data); |
1237 | if (error) | 1371 | if (error) |
1238 | goto err_free_object_table; | 1372 | return error; |
1239 | 1373 | ||
1240 | dev_info(&client->dev, | 1374 | dev_info(dev, |
1241 | "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n", | 1375 | "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n", |
1242 | info->family_id, info->variant_id, info->version >> 4, | 1376 | info->family_id, info->variant_id, info->version >> 4, |
1243 | info->version & 0xf, info->build, info->object_num); | 1377 | info->version & 0xf, info->build, info->object_num); |
1244 | 1378 | ||
1245 | return 0; | 1379 | return 0; |
1246 | |||
1247 | err_free_object_table: | ||
1248 | mxt_free_object_table(data); | ||
1249 | return error; | ||
1250 | } | 1380 | } |
1251 | 1381 | ||
1252 | /* Firmware Version is returned as Major.Minor.Build */ | 1382 | /* Firmware Version is returned as Major.Minor.Build */ |