diff options
author | Lothar Waßmann <LW@KARO-electronics.de> | 2014-03-28 12:31:14 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2014-03-28 12:33:07 -0400 |
commit | fd335ab04b3f1b3309dfbfea71a1a79a7bacc4ad (patch) | |
tree | 7ee9107cdec1eefb5587a3c67429c762e5c08d5a /drivers/input/touchscreen/edt-ft5x06.c | |
parent | ee3e946e31e6df0f9845f9b3d527252003603530 (diff) |
Input: edt-ft5x06 - add support for M09 firmware version
There is a new firmware version for the EDT-FT5x06 chip.
Add support for detecting the firmware version and handle the
differences appropriately.
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/touchscreen/edt-ft5x06.c')
-rw-r--r-- | drivers/input/touchscreen/edt-ft5x06.c | 358 |
1 files changed, 276 insertions, 82 deletions
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index dd94b9eea6e7..75b666bd2654 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de> | 2 | * Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de> |
3 | * Daniel Wagener <daniel.wagener@kernelconcepts.de> (M09 firmware support) | ||
3 | * Lothar Waßmann <LW@KARO-electronics.de> (DT support) | 4 | * Lothar Waßmann <LW@KARO-electronics.de> (DT support) |
4 | * | 5 | * |
5 | * This software is licensed under the terms of the GNU General Public | 6 | * This software is licensed under the terms of the GNU General Public |
@@ -47,6 +48,14 @@ | |||
47 | #define WORK_REGISTER_NUM_X 0x33 | 48 | #define WORK_REGISTER_NUM_X 0x33 |
48 | #define WORK_REGISTER_NUM_Y 0x34 | 49 | #define WORK_REGISTER_NUM_Y 0x34 |
49 | 50 | ||
51 | #define M09_REGISTER_THRESHOLD 0x80 | ||
52 | #define M09_REGISTER_GAIN 0x92 | ||
53 | #define M09_REGISTER_OFFSET 0x93 | ||
54 | #define M09_REGISTER_NUM_X 0x94 | ||
55 | #define M09_REGISTER_NUM_Y 0x95 | ||
56 | |||
57 | #define NO_REGISTER 0xff | ||
58 | |||
50 | #define WORK_REGISTER_OPMODE 0x3c | 59 | #define WORK_REGISTER_OPMODE 0x3c |
51 | #define FACTORY_REGISTER_OPMODE 0x01 | 60 | #define FACTORY_REGISTER_OPMODE 0x01 |
52 | 61 | ||
@@ -61,6 +70,20 @@ | |||
61 | #define EDT_RAW_DATA_RETRIES 100 | 70 | #define EDT_RAW_DATA_RETRIES 100 |
62 | #define EDT_RAW_DATA_DELAY 1 /* msec */ | 71 | #define EDT_RAW_DATA_DELAY 1 /* msec */ |
63 | 72 | ||
73 | enum edt_ver { | ||
74 | M06, | ||
75 | M09, | ||
76 | }; | ||
77 | |||
78 | struct edt_reg_addr { | ||
79 | int reg_threshold; | ||
80 | int reg_report_rate; | ||
81 | int reg_gain; | ||
82 | int reg_offset; | ||
83 | int reg_num_x; | ||
84 | int reg_num_y; | ||
85 | }; | ||
86 | |||
64 | struct edt_ft5x06_ts_data { | 87 | struct edt_ft5x06_ts_data { |
65 | struct i2c_client *client; | 88 | struct i2c_client *client; |
66 | struct input_dev *input; | 89 | struct input_dev *input; |
@@ -85,6 +108,9 @@ struct edt_ft5x06_ts_data { | |||
85 | int report_rate; | 108 | int report_rate; |
86 | 109 | ||
87 | char name[EDT_NAME_LEN]; | 110 | char name[EDT_NAME_LEN]; |
111 | |||
112 | struct edt_reg_addr reg_addr; | ||
113 | enum edt_ver version; | ||
88 | }; | 114 | }; |
89 | 115 | ||
90 | static int edt_ft5x06_ts_readwrite(struct i2c_client *client, | 116 | static int edt_ft5x06_ts_readwrite(struct i2c_client *client, |
@@ -142,33 +168,58 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) | |||
142 | { | 168 | { |
143 | struct edt_ft5x06_ts_data *tsdata = dev_id; | 169 | struct edt_ft5x06_ts_data *tsdata = dev_id; |
144 | struct device *dev = &tsdata->client->dev; | 170 | struct device *dev = &tsdata->client->dev; |
145 | u8 cmd = 0xf9; | 171 | u8 cmd; |
146 | u8 rdbuf[26]; | 172 | u8 rdbuf[29]; |
147 | int i, type, x, y, id; | 173 | int i, type, x, y, id; |
174 | int offset, tplen, datalen; | ||
148 | int error; | 175 | int error; |
149 | 176 | ||
177 | switch (tsdata->version) { | ||
178 | case M06: | ||
179 | cmd = 0xf9; /* tell the controller to send touch data */ | ||
180 | offset = 5; /* where the actual touch data starts */ | ||
181 | tplen = 4; /* data comes in so called frames */ | ||
182 | datalen = 26; /* how much bytes to listen for */ | ||
183 | break; | ||
184 | |||
185 | case M09: | ||
186 | cmd = 0x02; | ||
187 | offset = 1; | ||
188 | tplen = 6; | ||
189 | datalen = 29; | ||
190 | break; | ||
191 | |||
192 | default: | ||
193 | goto out; | ||
194 | } | ||
195 | |||
150 | memset(rdbuf, 0, sizeof(rdbuf)); | 196 | memset(rdbuf, 0, sizeof(rdbuf)); |
151 | 197 | ||
152 | error = edt_ft5x06_ts_readwrite(tsdata->client, | 198 | error = edt_ft5x06_ts_readwrite(tsdata->client, |
153 | sizeof(cmd), &cmd, | 199 | sizeof(cmd), &cmd, |
154 | sizeof(rdbuf), rdbuf); | 200 | datalen, rdbuf); |
155 | if (error) { | 201 | if (error) { |
156 | dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n", | 202 | dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n", |
157 | error); | 203 | error); |
158 | goto out; | 204 | goto out; |
159 | } | 205 | } |
160 | 206 | ||
161 | if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || rdbuf[2] != 26) { | 207 | /* M09 does not send header or CRC */ |
162 | dev_err_ratelimited(dev, "Unexpected header: %02x%02x%02x!\n", | 208 | if (tsdata->version == M06) { |
163 | rdbuf[0], rdbuf[1], rdbuf[2]); | 209 | if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || |
164 | goto out; | 210 | rdbuf[2] != datalen) { |
165 | } | 211 | dev_err_ratelimited(dev, |
212 | "Unexpected header: %02x%02x%02x!\n", | ||
213 | rdbuf[0], rdbuf[1], rdbuf[2]); | ||
214 | goto out; | ||
215 | } | ||
166 | 216 | ||
167 | if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, 26)) | 217 | if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, datalen)) |
168 | goto out; | 218 | goto out; |
219 | } | ||
169 | 220 | ||
170 | for (i = 0; i < MAX_SUPPORT_POINTS; i++) { | 221 | for (i = 0; i < MAX_SUPPORT_POINTS; i++) { |
171 | u8 *buf = &rdbuf[i * 4 + 5]; | 222 | u8 *buf = &rdbuf[i * tplen + offset]; |
172 | bool down; | 223 | bool down; |
173 | 224 | ||
174 | type = buf[0] >> 6; | 225 | type = buf[0] >> 6; |
@@ -176,8 +227,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) | |||
176 | if (type == TOUCH_EVENT_RESERVED) | 227 | if (type == TOUCH_EVENT_RESERVED) |
177 | continue; | 228 | continue; |
178 | 229 | ||
179 | /* ignore TOUCH_DOWN events, might have bogus coordinates */ | 230 | /* M06 sometimes sends bogus coordinates in TOUCH_DOWN */ |
180 | if (type == TOUCH_EVENT_DOWN) | 231 | if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN) |
181 | continue; | 232 | continue; |
182 | 233 | ||
183 | x = ((buf[0] << 8) | buf[1]) & 0x0fff; | 234 | x = ((buf[0] << 8) | buf[1]) & 0x0fff; |
@@ -207,12 +258,25 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, | |||
207 | { | 258 | { |
208 | u8 wrbuf[4]; | 259 | u8 wrbuf[4]; |
209 | 260 | ||
210 | wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; | 261 | switch (tsdata->version) { |
211 | wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; | 262 | case M06: |
212 | wrbuf[2] = value; | 263 | wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; |
213 | wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; | 264 | wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; |
214 | 265 | wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; | |
215 | return edt_ft5x06_ts_readwrite(tsdata->client, 4, wrbuf, 0, NULL); | 266 | wrbuf[2] = value; |
267 | wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; | ||
268 | return edt_ft5x06_ts_readwrite(tsdata->client, 4, | ||
269 | wrbuf, 0, NULL); | ||
270 | case M09: | ||
271 | wrbuf[0] = addr; | ||
272 | wrbuf[1] = value; | ||
273 | |||
274 | return edt_ft5x06_ts_readwrite(tsdata->client, 3, | ||
275 | wrbuf, 0, NULL); | ||
276 | |||
277 | default: | ||
278 | return -EINVAL; | ||
279 | } | ||
216 | } | 280 | } |
217 | 281 | ||
218 | static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, | 282 | static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, |
@@ -221,19 +285,35 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, | |||
221 | u8 wrbuf[2], rdbuf[2]; | 285 | u8 wrbuf[2], rdbuf[2]; |
222 | int error; | 286 | int error; |
223 | 287 | ||
224 | wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; | 288 | switch (tsdata->version) { |
225 | wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; | 289 | case M06: |
226 | wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; | 290 | wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; |
291 | wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; | ||
292 | wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; | ||
227 | 293 | ||
228 | error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, rdbuf); | 294 | error = edt_ft5x06_ts_readwrite(tsdata->client, |
229 | if (error) | 295 | 2, wrbuf, 2, rdbuf); |
230 | return error; | 296 | return error; |
231 | 297 | ||
232 | if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) { | 298 | if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) { |
233 | dev_err(&tsdata->client->dev, | 299 | dev_err(&tsdata->client->dev, |
234 | "crc error: 0x%02x expected, got 0x%02x\n", | 300 | "crc error: 0x%02x expected, got 0x%02x\n", |
235 | wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], rdbuf[1]); | 301 | wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], |
236 | return -EIO; | 302 | rdbuf[1]); |
303 | return -EIO; | ||
304 | } | ||
305 | break; | ||
306 | |||
307 | case M09: | ||
308 | wrbuf[0] = addr; | ||
309 | error = edt_ft5x06_ts_readwrite(tsdata->client, 1, | ||
310 | wrbuf, 1, rdbuf); | ||
311 | if (error) | ||
312 | return error; | ||
313 | break; | ||
314 | |||
315 | default: | ||
316 | return -EINVAL; | ||
237 | } | 317 | } |
238 | 318 | ||
239 | return rdbuf[0]; | 319 | return rdbuf[0]; |
@@ -244,19 +324,21 @@ struct edt_ft5x06_attribute { | |||
244 | size_t field_offset; | 324 | size_t field_offset; |
245 | u8 limit_low; | 325 | u8 limit_low; |
246 | u8 limit_high; | 326 | u8 limit_high; |
247 | u8 addr; | 327 | u8 addr_m06; |
328 | u8 addr_m09; | ||
248 | }; | 329 | }; |
249 | 330 | ||
250 | #define EDT_ATTR(_field, _mode, _addr, _limit_low, _limit_high) \ | 331 | #define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, \ |
332 | _limit_low, _limit_high) \ | ||
251 | struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = { \ | 333 | struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = { \ |
252 | .dattr = __ATTR(_field, _mode, \ | 334 | .dattr = __ATTR(_field, _mode, \ |
253 | edt_ft5x06_setting_show, \ | 335 | edt_ft5x06_setting_show, \ |
254 | edt_ft5x06_setting_store), \ | 336 | edt_ft5x06_setting_store), \ |
255 | .field_offset = \ | 337 | .field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \ |
256 | offsetof(struct edt_ft5x06_ts_data, _field), \ | 338 | .addr_m06 = _addr_m06, \ |
339 | .addr_m09 = _addr_m09, \ | ||
257 | .limit_low = _limit_low, \ | 340 | .limit_low = _limit_low, \ |
258 | .limit_high = _limit_high, \ | 341 | .limit_high = _limit_high, \ |
259 | .addr = _addr, \ | ||
260 | } | 342 | } |
261 | 343 | ||
262 | static ssize_t edt_ft5x06_setting_show(struct device *dev, | 344 | static ssize_t edt_ft5x06_setting_show(struct device *dev, |
@@ -271,6 +353,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, | |||
271 | int val; | 353 | int val; |
272 | size_t count = 0; | 354 | size_t count = 0; |
273 | int error = 0; | 355 | int error = 0; |
356 | u8 addr; | ||
274 | 357 | ||
275 | mutex_lock(&tsdata->mutex); | 358 | mutex_lock(&tsdata->mutex); |
276 | 359 | ||
@@ -279,15 +362,33 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, | |||
279 | goto out; | 362 | goto out; |
280 | } | 363 | } |
281 | 364 | ||
282 | val = edt_ft5x06_register_read(tsdata, attr->addr); | 365 | switch (tsdata->version) { |
283 | if (val < 0) { | 366 | case M06: |
284 | error = val; | 367 | addr = attr->addr_m06; |
285 | dev_err(&tsdata->client->dev, | 368 | break; |
286 | "Failed to fetch attribute %s, error %d\n", | 369 | |
287 | dattr->attr.name, error); | 370 | case M09: |
371 | addr = attr->addr_m09; | ||
372 | break; | ||
373 | |||
374 | default: | ||
375 | error = -ENODEV; | ||
288 | goto out; | 376 | goto out; |
289 | } | 377 | } |
290 | 378 | ||
379 | if (addr != NO_REGISTER) { | ||
380 | val = edt_ft5x06_register_read(tsdata, addr); | ||
381 | if (val < 0) { | ||
382 | error = val; | ||
383 | dev_err(&tsdata->client->dev, | ||
384 | "Failed to fetch attribute %s, error %d\n", | ||
385 | dattr->attr.name, error); | ||
386 | goto out; | ||
387 | } | ||
388 | } else { | ||
389 | val = *field; | ||
390 | } | ||
391 | |||
291 | if (val != *field) { | 392 | if (val != *field) { |
292 | dev_warn(&tsdata->client->dev, | 393 | dev_warn(&tsdata->client->dev, |
293 | "%s: read (%d) and stored value (%d) differ\n", | 394 | "%s: read (%d) and stored value (%d) differ\n", |
@@ -312,6 +413,7 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev, | |||
312 | u8 *field = (u8 *)tsdata + attr->field_offset; | 413 | u8 *field = (u8 *)tsdata + attr->field_offset; |
313 | unsigned int val; | 414 | unsigned int val; |
314 | int error; | 415 | int error; |
416 | u8 addr; | ||
315 | 417 | ||
316 | mutex_lock(&tsdata->mutex); | 418 | mutex_lock(&tsdata->mutex); |
317 | 419 | ||
@@ -329,14 +431,29 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev, | |||
329 | goto out; | 431 | goto out; |
330 | } | 432 | } |
331 | 433 | ||
332 | error = edt_ft5x06_register_write(tsdata, attr->addr, val); | 434 | switch (tsdata->version) { |
333 | if (error) { | 435 | case M06: |
334 | dev_err(&tsdata->client->dev, | 436 | addr = attr->addr_m06; |
335 | "Failed to update attribute %s, error: %d\n", | 437 | break; |
336 | dattr->attr.name, error); | 438 | |
439 | case M09: | ||
440 | addr = attr->addr_m09; | ||
441 | break; | ||
442 | |||
443 | default: | ||
444 | error = -ENODEV; | ||
337 | goto out; | 445 | goto out; |
338 | } | 446 | } |
339 | 447 | ||
448 | if (addr != NO_REGISTER) { | ||
449 | error = edt_ft5x06_register_write(tsdata, addr, val); | ||
450 | if (error) { | ||
451 | dev_err(&tsdata->client->dev, | ||
452 | "Failed to update attribute %s, error: %d\n", | ||
453 | dattr->attr.name, error); | ||
454 | goto out; | ||
455 | } | ||
456 | } | ||
340 | *field = val; | 457 | *field = val; |
341 | 458 | ||
342 | out: | 459 | out: |
@@ -344,12 +461,14 @@ out: | |||
344 | return error ?: count; | 461 | return error ?: count; |
345 | } | 462 | } |
346 | 463 | ||
347 | static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, 0, 31); | 464 | static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, |
348 | static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, 0, 31); | 465 | M09_REGISTER_GAIN, 0, 31); |
349 | static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, | 466 | static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, |
350 | WORK_REGISTER_THRESHOLD, 20, 80); | 467 | M09_REGISTER_OFFSET, 0, 31); |
351 | static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, | 468 | static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD, |
352 | WORK_REGISTER_REPORT_RATE, 3, 14); | 469 | M09_REGISTER_THRESHOLD, 20, 80); |
470 | static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, | ||
471 | NO_REGISTER, 3, 14); | ||
353 | 472 | ||
354 | static struct attribute *edt_ft5x06_attrs[] = { | 473 | static struct attribute *edt_ft5x06_attrs[] = { |
355 | &edt_ft5x06_attr_gain.dattr.attr, | 474 | &edt_ft5x06_attr_gain.dattr.attr, |
@@ -384,6 +503,9 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) | |||
384 | } | 503 | } |
385 | 504 | ||
386 | /* mode register is 0x3c when in the work mode */ | 505 | /* mode register is 0x3c when in the work mode */ |
506 | if (tsdata->version == M09) | ||
507 | goto m09_out; | ||
508 | |||
387 | error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03); | 509 | error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03); |
388 | if (error) { | 510 | if (error) { |
389 | dev_err(&client->dev, | 511 | dev_err(&client->dev, |
@@ -416,12 +538,18 @@ err_out: | |||
416 | enable_irq(client->irq); | 538 | enable_irq(client->irq); |
417 | 539 | ||
418 | return error; | 540 | return error; |
541 | |||
542 | m09_out: | ||
543 | dev_err(&client->dev, "No factory mode support for M09\n"); | ||
544 | return -EINVAL; | ||
545 | |||
419 | } | 546 | } |
420 | 547 | ||
421 | static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) | 548 | static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) |
422 | { | 549 | { |
423 | struct i2c_client *client = tsdata->client; | 550 | struct i2c_client *client = tsdata->client; |
424 | int retries = EDT_SWITCH_MODE_RETRIES; | 551 | int retries = EDT_SWITCH_MODE_RETRIES; |
552 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; | ||
425 | int ret; | 553 | int ret; |
426 | int error; | 554 | int error; |
427 | 555 | ||
@@ -454,13 +582,14 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) | |||
454 | tsdata->raw_buffer = NULL; | 582 | tsdata->raw_buffer = NULL; |
455 | 583 | ||
456 | /* restore parameters */ | 584 | /* restore parameters */ |
457 | edt_ft5x06_register_write(tsdata, WORK_REGISTER_THRESHOLD, | 585 | edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold, |
458 | tsdata->threshold); | 586 | tsdata->threshold); |
459 | edt_ft5x06_register_write(tsdata, WORK_REGISTER_GAIN, | 587 | edt_ft5x06_register_write(tsdata, reg_addr->reg_gain, |
460 | tsdata->gain); | 588 | tsdata->gain); |
461 | edt_ft5x06_register_write(tsdata, WORK_REGISTER_OFFSET, | 589 | edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, |
462 | tsdata->offset); | 590 | tsdata->offset); |
463 | edt_ft5x06_register_write(tsdata, WORK_REGISTER_REPORT_RATE, | 591 | if (reg_addr->reg_report_rate) |
592 | edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate, | ||
464 | tsdata->report_rate); | 593 | tsdata->report_rate); |
465 | 594 | ||
466 | enable_irq(client->irq); | 595 | enable_irq(client->irq); |
@@ -663,30 +792,60 @@ static int edt_ft5x06_ts_reset(struct i2c_client *client, | |||
663 | } | 792 | } |
664 | 793 | ||
665 | static int edt_ft5x06_ts_identify(struct i2c_client *client, | 794 | static int edt_ft5x06_ts_identify(struct i2c_client *client, |
666 | char *model_name, | 795 | struct edt_ft5x06_ts_data *tsdata, |
667 | char *fw_version) | 796 | char *fw_version) |
668 | { | 797 | { |
669 | u8 rdbuf[EDT_NAME_LEN]; | 798 | u8 rdbuf[EDT_NAME_LEN]; |
670 | char *p; | 799 | char *p; |
671 | int error; | 800 | int error; |
801 | char *model_name = tsdata->name; | ||
672 | 802 | ||
803 | /* see what we find if we assume it is a M06 * | ||
804 | * if we get less than EDT_NAME_LEN, we don't want | ||
805 | * to have garbage in there | ||
806 | */ | ||
807 | memset(rdbuf, 0, sizeof(rdbuf)); | ||
673 | error = edt_ft5x06_ts_readwrite(client, 1, "\xbb", | 808 | error = edt_ft5x06_ts_readwrite(client, 1, "\xbb", |
674 | EDT_NAME_LEN - 1, rdbuf); | 809 | EDT_NAME_LEN - 1, rdbuf); |
675 | if (error) | 810 | if (error) |
676 | return error; | 811 | return error; |
677 | 812 | ||
678 | /* remove last '$' end marker */ | 813 | /* if we find something consistent, stay with that assumption |
679 | rdbuf[EDT_NAME_LEN - 1] = '\0'; | 814 | * at least M09 won't send 3 bytes here |
680 | if (rdbuf[EDT_NAME_LEN - 2] == '$') | 815 | */ |
681 | rdbuf[EDT_NAME_LEN - 2] = '\0'; | 816 | if (!(strnicmp(rdbuf + 1, "EP0", 3))) { |
817 | tsdata->version = M06; | ||
818 | |||
819 | /* remove last '$' end marker */ | ||
820 | rdbuf[EDT_NAME_LEN - 1] = '\0'; | ||
821 | if (rdbuf[EDT_NAME_LEN - 2] == '$') | ||
822 | rdbuf[EDT_NAME_LEN - 2] = '\0'; | ||
823 | |||
824 | /* look for Model/Version separator */ | ||
825 | p = strchr(rdbuf, '*'); | ||
826 | if (p) | ||
827 | *p++ = '\0'; | ||
828 | strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN); | ||
829 | strlcpy(fw_version, p ? p : "", EDT_NAME_LEN); | ||
830 | } else { | ||
831 | /* since there are only two versions around (M06, M09) */ | ||
832 | tsdata->version = M09; | ||
833 | |||
834 | error = edt_ft5x06_ts_readwrite(client, 1, "\xA6", | ||
835 | 2, rdbuf); | ||
836 | if (error) | ||
837 | return error; | ||
682 | 838 | ||
683 | /* look for Model/Version separator */ | 839 | strlcpy(fw_version, rdbuf, 2); |
684 | p = strchr(rdbuf, '*'); | ||
685 | if (p) | ||
686 | *p++ = '\0'; | ||
687 | 840 | ||
688 | strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN); | 841 | error = edt_ft5x06_ts_readwrite(client, 1, "\xA8", |
689 | strlcpy(fw_version, p ? p : "", EDT_NAME_LEN); | 842 | 1, rdbuf); |
843 | if (error) | ||
844 | return error; | ||
845 | |||
846 | snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09", | ||
847 | rdbuf[0] >> 4, rdbuf[0] & 0x0F); | ||
848 | } | ||
690 | 849 | ||
691 | return 0; | 850 | return 0; |
692 | } | 851 | } |
@@ -705,36 +864,69 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, | |||
705 | static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np, | 864 | static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np, |
706 | struct edt_ft5x06_ts_data *tsdata) | 865 | struct edt_ft5x06_ts_data *tsdata) |
707 | { | 866 | { |
708 | EDT_GET_PROP(threshold, WORK_REGISTER_THRESHOLD); | 867 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; |
709 | EDT_GET_PROP(gain, WORK_REGISTER_GAIN); | 868 | |
710 | EDT_GET_PROP(offset, WORK_REGISTER_OFFSET); | 869 | EDT_GET_PROP(threshold, reg_addr->reg_threshold); |
870 | EDT_GET_PROP(gain, reg_addr->reg_gain); | ||
871 | EDT_GET_PROP(offset, reg_addr->reg_offset); | ||
711 | } | 872 | } |
712 | 873 | ||
713 | static void | 874 | static void |
714 | edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata, | 875 | edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata, |
715 | const struct edt_ft5x06_platform_data *pdata) | 876 | const struct edt_ft5x06_platform_data *pdata) |
716 | { | 877 | { |
878 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; | ||
879 | |||
717 | if (!pdata->use_parameters) | 880 | if (!pdata->use_parameters) |
718 | return; | 881 | return; |
719 | 882 | ||
720 | /* pick up defaults from the platform data */ | 883 | /* pick up defaults from the platform data */ |
721 | EDT_ATTR_CHECKSET(threshold, WORK_REGISTER_THRESHOLD); | 884 | EDT_ATTR_CHECKSET(threshold, reg_addr->reg_threshold); |
722 | EDT_ATTR_CHECKSET(gain, WORK_REGISTER_GAIN); | 885 | EDT_ATTR_CHECKSET(gain, reg_addr->reg_gain); |
723 | EDT_ATTR_CHECKSET(offset, WORK_REGISTER_OFFSET); | 886 | EDT_ATTR_CHECKSET(offset, reg_addr->reg_offset); |
724 | EDT_ATTR_CHECKSET(report_rate, WORK_REGISTER_REPORT_RATE); | 887 | if (reg_addr->reg_report_rate != NO_REGISTER) |
888 | EDT_ATTR_CHECKSET(report_rate, reg_addr->reg_report_rate); | ||
725 | } | 889 | } |
726 | 890 | ||
727 | static void | 891 | static void |
728 | edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) | 892 | edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) |
729 | { | 893 | { |
894 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; | ||
895 | |||
730 | tsdata->threshold = edt_ft5x06_register_read(tsdata, | 896 | tsdata->threshold = edt_ft5x06_register_read(tsdata, |
731 | WORK_REGISTER_THRESHOLD); | 897 | reg_addr->reg_threshold); |
732 | tsdata->gain = edt_ft5x06_register_read(tsdata, WORK_REGISTER_GAIN); | 898 | tsdata->gain = edt_ft5x06_register_read(tsdata, reg_addr->reg_gain); |
733 | tsdata->offset = edt_ft5x06_register_read(tsdata, WORK_REGISTER_OFFSET); | 899 | tsdata->offset = edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); |
734 | tsdata->report_rate = edt_ft5x06_register_read(tsdata, | 900 | if (reg_addr->reg_report_rate != NO_REGISTER) |
735 | WORK_REGISTER_REPORT_RATE); | 901 | tsdata->report_rate = edt_ft5x06_register_read(tsdata, |
736 | tsdata->num_x = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_X); | 902 | reg_addr->reg_report_rate); |
737 | tsdata->num_y = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_Y); | 903 | tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x); |
904 | tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y); | ||
905 | } | ||
906 | |||
907 | static void | ||
908 | edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) | ||
909 | { | ||
910 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; | ||
911 | |||
912 | switch (tsdata->version) { | ||
913 | case M06: | ||
914 | reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD; | ||
915 | reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE; | ||
916 | reg_addr->reg_gain = WORK_REGISTER_GAIN; | ||
917 | reg_addr->reg_offset = WORK_REGISTER_OFFSET; | ||
918 | reg_addr->reg_num_x = WORK_REGISTER_NUM_X; | ||
919 | reg_addr->reg_num_y = WORK_REGISTER_NUM_Y; | ||
920 | break; | ||
921 | |||
922 | case M09: | ||
923 | reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; | ||
924 | reg_addr->reg_gain = M09_REGISTER_GAIN; | ||
925 | reg_addr->reg_offset = M09_REGISTER_OFFSET; | ||
926 | reg_addr->reg_num_x = M09_REGISTER_NUM_X; | ||
927 | reg_addr->reg_num_y = M09_REGISTER_NUM_Y; | ||
928 | break; | ||
929 | } | ||
738 | } | 930 | } |
739 | 931 | ||
740 | #ifdef CONFIG_OF | 932 | #ifdef CONFIG_OF |
@@ -818,12 +1010,14 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, | |||
818 | tsdata->input = input; | 1010 | tsdata->input = input; |
819 | tsdata->factory_mode = false; | 1011 | tsdata->factory_mode = false; |
820 | 1012 | ||
821 | error = edt_ft5x06_ts_identify(client, tsdata->name, fw_version); | 1013 | error = edt_ft5x06_ts_identify(client, tsdata, fw_version); |
822 | if (error) { | 1014 | if (error) { |
823 | dev_err(&client->dev, "touchscreen probe failed\n"); | 1015 | dev_err(&client->dev, "touchscreen probe failed\n"); |
824 | return error; | 1016 | return error; |
825 | } | 1017 | } |
826 | 1018 | ||
1019 | edt_ft5x06_ts_set_regs(tsdata); | ||
1020 | |||
827 | if (!pdata) | 1021 | if (!pdata) |
828 | edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata); | 1022 | edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata); |
829 | else | 1023 | else |