diff options
author | Simon Budig <simon.budig@kernelconcepts.de> | 2017-10-09 23:58:11 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2017-10-19 20:17:46 -0400 |
commit | 169110c3645621497ca0b1d0d7bc80dcea8ff9d4 (patch) | |
tree | 54f0b52dbb369d13792f50d0352668774ccf0f69 | |
parent | adb77b3e5118d2760621d8cc740524b816f9006b (diff) |
Input: edt-ft5x06 - make distinction between m06/m09/generic more clear
Since the driver also is useful for some non-EDT touchscreens based on
the focaltec chips introduce the concept of a "generic" focaltec based
touch.
Use a better heuristics for model detection and be more specific in the
source.
Signed-off-by: Simon Budig <simon.budig@kernelconcepts.de>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r-- | drivers/input/touchscreen/edt-ft5x06.c | 122 |
1 files changed, 93 insertions, 29 deletions
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index f879d14f7ffc..56bfd0c14c91 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c | |||
@@ -70,8 +70,9 @@ | |||
70 | #define EDT_RAW_DATA_DELAY 1000 /* usec */ | 70 | #define EDT_RAW_DATA_DELAY 1000 /* usec */ |
71 | 71 | ||
72 | enum edt_ver { | 72 | enum edt_ver { |
73 | M06, | 73 | EDT_M06, |
74 | M09, | 74 | EDT_M09, |
75 | GENERIC_FT, | ||
75 | }; | 76 | }; |
76 | 77 | ||
77 | struct edt_reg_addr { | 78 | struct edt_reg_addr { |
@@ -179,14 +180,15 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) | |||
179 | int error; | 180 | int error; |
180 | 181 | ||
181 | switch (tsdata->version) { | 182 | switch (tsdata->version) { |
182 | case M06: | 183 | case EDT_M06: |
183 | cmd = 0xf9; /* tell the controller to send touch data */ | 184 | cmd = 0xf9; /* tell the controller to send touch data */ |
184 | offset = 5; /* where the actual touch data starts */ | 185 | offset = 5; /* where the actual touch data starts */ |
185 | tplen = 4; /* data comes in so called frames */ | 186 | tplen = 4; /* data comes in so called frames */ |
186 | crclen = 1; /* length of the crc data */ | 187 | crclen = 1; /* length of the crc data */ |
187 | break; | 188 | break; |
188 | 189 | ||
189 | case M09: | 190 | case EDT_M09: |
191 | case GENERIC_FT: | ||
190 | cmd = 0x0; | 192 | cmd = 0x0; |
191 | offset = 3; | 193 | offset = 3; |
192 | tplen = 6; | 194 | tplen = 6; |
@@ -210,7 +212,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) | |||
210 | } | 212 | } |
211 | 213 | ||
212 | /* M09 does not send header or CRC */ | 214 | /* M09 does not send header or CRC */ |
213 | if (tsdata->version == M06) { | 215 | if (tsdata->version == EDT_M06) { |
214 | if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || | 216 | if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || |
215 | rdbuf[2] != datalen) { | 217 | rdbuf[2] != datalen) { |
216 | dev_err_ratelimited(dev, | 218 | dev_err_ratelimited(dev, |
@@ -233,7 +235,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) | |||
233 | continue; | 235 | continue; |
234 | 236 | ||
235 | /* M06 sometimes sends bogus coordinates in TOUCH_DOWN */ | 237 | /* M06 sometimes sends bogus coordinates in TOUCH_DOWN */ |
236 | if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN) | 238 | if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN) |
237 | continue; | 239 | continue; |
238 | 240 | ||
239 | x = ((buf[0] << 8) | buf[1]) & 0x0fff; | 241 | x = ((buf[0] << 8) | buf[1]) & 0x0fff; |
@@ -264,14 +266,15 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, | |||
264 | u8 wrbuf[4]; | 266 | u8 wrbuf[4]; |
265 | 267 | ||
266 | switch (tsdata->version) { | 268 | switch (tsdata->version) { |
267 | case M06: | 269 | case EDT_M06: |
268 | wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; | 270 | wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; |
269 | wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; | 271 | wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; |
270 | wrbuf[2] = value; | 272 | wrbuf[2] = value; |
271 | wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; | 273 | wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; |
272 | return edt_ft5x06_ts_readwrite(tsdata->client, 4, | 274 | return edt_ft5x06_ts_readwrite(tsdata->client, 4, |
273 | wrbuf, 0, NULL); | 275 | wrbuf, 0, NULL); |
274 | case M09: | 276 | case EDT_M09: |
277 | case GENERIC_FT: | ||
275 | wrbuf[0] = addr; | 278 | wrbuf[0] = addr; |
276 | wrbuf[1] = value; | 279 | wrbuf[1] = value; |
277 | 280 | ||
@@ -290,7 +293,7 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, | |||
290 | int error; | 293 | int error; |
291 | 294 | ||
292 | switch (tsdata->version) { | 295 | switch (tsdata->version) { |
293 | case M06: | 296 | case EDT_M06: |
294 | wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; | 297 | wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; |
295 | wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; | 298 | wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; |
296 | wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; | 299 | wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; |
@@ -309,7 +312,8 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, | |||
309 | } | 312 | } |
310 | break; | 313 | break; |
311 | 314 | ||
312 | case M09: | 315 | case EDT_M09: |
316 | case GENERIC_FT: | ||
313 | wrbuf[0] = addr; | 317 | wrbuf[0] = addr; |
314 | error = edt_ft5x06_ts_readwrite(tsdata->client, 1, | 318 | error = edt_ft5x06_ts_readwrite(tsdata->client, 1, |
315 | wrbuf, 1, rdbuf); | 319 | wrbuf, 1, rdbuf); |
@@ -368,11 +372,12 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, | |||
368 | } | 372 | } |
369 | 373 | ||
370 | switch (tsdata->version) { | 374 | switch (tsdata->version) { |
371 | case M06: | 375 | case EDT_M06: |
372 | addr = attr->addr_m06; | 376 | addr = attr->addr_m06; |
373 | break; | 377 | break; |
374 | 378 | ||
375 | case M09: | 379 | case EDT_M09: |
380 | case GENERIC_FT: | ||
376 | addr = attr->addr_m09; | 381 | addr = attr->addr_m09; |
377 | break; | 382 | break; |
378 | 383 | ||
@@ -437,11 +442,12 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev, | |||
437 | } | 442 | } |
438 | 443 | ||
439 | switch (tsdata->version) { | 444 | switch (tsdata->version) { |
440 | case M06: | 445 | case EDT_M06: |
441 | addr = attr->addr_m06; | 446 | addr = attr->addr_m06; |
442 | break; | 447 | break; |
443 | 448 | ||
444 | case M09: | 449 | case EDT_M09: |
450 | case GENERIC_FT: | ||
445 | addr = attr->addr_m09; | 451 | addr = attr->addr_m09; |
446 | break; | 452 | break; |
447 | 453 | ||
@@ -508,7 +514,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) | |||
508 | } | 514 | } |
509 | 515 | ||
510 | /* mode register is 0x3c when in the work mode */ | 516 | /* mode register is 0x3c when in the work mode */ |
511 | if (tsdata->version == M09) | 517 | if (tsdata->version != EDT_M06) |
512 | goto m09_out; | 518 | goto m09_out; |
513 | 519 | ||
514 | error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03); | 520 | error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03); |
@@ -545,7 +551,7 @@ err_out: | |||
545 | return error; | 551 | return error; |
546 | 552 | ||
547 | m09_out: | 553 | m09_out: |
548 | dev_err(&client->dev, "No factory mode support for M09\n"); | 554 | dev_err(&client->dev, "No factory mode support for M09/GENERIC_FT\n"); |
549 | return -EINVAL; | 555 | return -EINVAL; |
550 | 556 | ||
551 | } | 557 | } |
@@ -779,7 +785,7 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, | |||
779 | * at least M09 won't send 3 bytes here | 785 | * at least M09 won't send 3 bytes here |
780 | */ | 786 | */ |
781 | if (!(strncasecmp(rdbuf + 1, "EP0", 3))) { | 787 | if (!(strncasecmp(rdbuf + 1, "EP0", 3))) { |
782 | tsdata->version = M06; | 788 | tsdata->version = EDT_M06; |
783 | 789 | ||
784 | /* remove last '$' end marker */ | 790 | /* remove last '$' end marker */ |
785 | rdbuf[EDT_NAME_LEN - 1] = '\0'; | 791 | rdbuf[EDT_NAME_LEN - 1] = '\0'; |
@@ -793,8 +799,16 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, | |||
793 | strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN); | 799 | strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN); |
794 | strlcpy(fw_version, p ? p : "", EDT_NAME_LEN); | 800 | strlcpy(fw_version, p ? p : "", EDT_NAME_LEN); |
795 | } else { | 801 | } else { |
796 | /* since there are only two versions around (M06, M09) */ | 802 | /* If it is not an EDT M06 touchscreen, then the model |
797 | tsdata->version = M09; | 803 | * detection is a bit hairy. The different ft5x06 |
804 | * firmares around don't reliably implement the | ||
805 | * identification registers. Well, we'll take a shot. | ||
806 | * | ||
807 | * The main difference between generic focaltec based | ||
808 | * touches and EDT M09 is that we know how to retrieve | ||
809 | * the max coordinates for the latter. | ||
810 | */ | ||
811 | tsdata->version = GENERIC_FT; | ||
798 | 812 | ||
799 | error = edt_ft5x06_ts_readwrite(client, 1, "\xA6", | 813 | error = edt_ft5x06_ts_readwrite(client, 1, "\xA6", |
800 | 2, rdbuf); | 814 | 2, rdbuf); |
@@ -808,8 +822,34 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, | |||
808 | if (error) | 822 | if (error) |
809 | return error; | 823 | return error; |
810 | 824 | ||
811 | snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09", | 825 | /* This "model identification" is not exact. Unfortunately |
812 | rdbuf[0] >> 4, rdbuf[0] & 0x0F); | 826 | * not all firmwares for the ft5x06 put useful values in |
827 | * the identification registers. | ||
828 | */ | ||
829 | switch (rdbuf[0]) { | ||
830 | case 0x35: /* EDT EP0350M09 */ | ||
831 | case 0x43: /* EDT EP0430M09 */ | ||
832 | case 0x50: /* EDT EP0500M09 */ | ||
833 | case 0x57: /* EDT EP0570M09 */ | ||
834 | case 0x70: /* EDT EP0700M09 */ | ||
835 | tsdata->version = EDT_M09; | ||
836 | snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09", | ||
837 | rdbuf[0] >> 4, rdbuf[0] & 0x0F); | ||
838 | break; | ||
839 | case 0xa1: /* EDT EP1010ML00 */ | ||
840 | tsdata->version = EDT_M09; | ||
841 | snprintf(model_name, EDT_NAME_LEN, "EP%i%i0ML00", | ||
842 | rdbuf[0] >> 4, rdbuf[0] & 0x0F); | ||
843 | break; | ||
844 | case 0x5a: /* Solomon Goldentek Display */ | ||
845 | snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0"); | ||
846 | break; | ||
847 | default: | ||
848 | snprintf(model_name, EDT_NAME_LEN, | ||
849 | "generic ft5x06 (%02x)", | ||
850 | rdbuf[0]); | ||
851 | break; | ||
852 | } | ||
813 | } | 853 | } |
814 | 854 | ||
815 | return 0; | 855 | return 0; |
@@ -853,8 +893,16 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) | |||
853 | if (reg_addr->reg_report_rate != NO_REGISTER) | 893 | if (reg_addr->reg_report_rate != NO_REGISTER) |
854 | tsdata->report_rate = edt_ft5x06_register_read(tsdata, | 894 | tsdata->report_rate = edt_ft5x06_register_read(tsdata, |
855 | reg_addr->reg_report_rate); | 895 | reg_addr->reg_report_rate); |
856 | tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x); | 896 | if (tsdata->version == EDT_M06 || |
857 | tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y); | 897 | tsdata->version == EDT_M09) { |
898 | tsdata->num_x = edt_ft5x06_register_read(tsdata, | ||
899 | reg_addr->reg_num_x); | ||
900 | tsdata->num_y = edt_ft5x06_register_read(tsdata, | ||
901 | reg_addr->reg_num_y); | ||
902 | } else { | ||
903 | tsdata->num_x = -1; | ||
904 | tsdata->num_y = -1; | ||
905 | } | ||
858 | } | 906 | } |
859 | 907 | ||
860 | static void | 908 | static void |
@@ -863,7 +911,7 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) | |||
863 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; | 911 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; |
864 | 912 | ||
865 | switch (tsdata->version) { | 913 | switch (tsdata->version) { |
866 | case M06: | 914 | case EDT_M06: |
867 | reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD; | 915 | reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD; |
868 | reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE; | 916 | reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE; |
869 | reg_addr->reg_gain = WORK_REGISTER_GAIN; | 917 | reg_addr->reg_gain = WORK_REGISTER_GAIN; |
@@ -872,7 +920,7 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) | |||
872 | reg_addr->reg_num_y = WORK_REGISTER_NUM_Y; | 920 | reg_addr->reg_num_y = WORK_REGISTER_NUM_Y; |
873 | break; | 921 | break; |
874 | 922 | ||
875 | case M09: | 923 | case EDT_M09: |
876 | reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; | 924 | reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; |
877 | reg_addr->reg_report_rate = NO_REGISTER; | 925 | reg_addr->reg_report_rate = NO_REGISTER; |
878 | reg_addr->reg_gain = M09_REGISTER_GAIN; | 926 | reg_addr->reg_gain = M09_REGISTER_GAIN; |
@@ -880,6 +928,13 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) | |||
880 | reg_addr->reg_num_x = M09_REGISTER_NUM_X; | 928 | reg_addr->reg_num_x = M09_REGISTER_NUM_X; |
881 | reg_addr->reg_num_y = M09_REGISTER_NUM_Y; | 929 | reg_addr->reg_num_y = M09_REGISTER_NUM_Y; |
882 | break; | 930 | break; |
931 | |||
932 | case GENERIC_FT: | ||
933 | /* this is a guesswork */ | ||
934 | reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; | ||
935 | reg_addr->reg_gain = M09_REGISTER_GAIN; | ||
936 | reg_addr->reg_offset = M09_REGISTER_OFFSET; | ||
937 | break; | ||
883 | } | 938 | } |
884 | } | 939 | } |
885 | 940 | ||
@@ -969,10 +1024,19 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, | |||
969 | input->id.bustype = BUS_I2C; | 1024 | input->id.bustype = BUS_I2C; |
970 | input->dev.parent = &client->dev; | 1025 | input->dev.parent = &client->dev; |
971 | 1026 | ||
972 | input_set_abs_params(input, ABS_MT_POSITION_X, | 1027 | if (tsdata->version == EDT_M06 || |
973 | 0, tsdata->num_x * 64 - 1, 0, 0); | 1028 | tsdata->version == EDT_M09) { |
974 | input_set_abs_params(input, ABS_MT_POSITION_Y, | 1029 | input_set_abs_params(input, ABS_MT_POSITION_X, |
975 | 0, tsdata->num_y * 64 - 1, 0, 0); | 1030 | 0, tsdata->num_x * 64 - 1, 0, 0); |
1031 | input_set_abs_params(input, ABS_MT_POSITION_Y, | ||
1032 | 0, tsdata->num_y * 64 - 1, 0, 0); | ||
1033 | } else { | ||
1034 | /* Unknown maximum values. Specify via devicetree */ | ||
1035 | input_set_abs_params(input, ABS_MT_POSITION_X, | ||
1036 | 0, 65535, 0, 0); | ||
1037 | input_set_abs_params(input, ABS_MT_POSITION_Y, | ||
1038 | 0, 65535, 0, 0); | ||
1039 | } | ||
976 | 1040 | ||
977 | touchscreen_parse_properties(input, true, &tsdata->prop); | 1041 | touchscreen_parse_properties(input, true, &tsdata->prop); |
978 | 1042 | ||