diff options
author | Nick Dyer <nick.dyer@itdev.co.uk> | 2014-07-23 15:41:58 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2014-07-23 17:42:09 -0400 |
commit | a9fdd1e6de62c3c13046c1424d5ed541d7ee745b (patch) | |
tree | 155f2db045051c908086617132c127671b3cda2c /drivers | |
parent | 4ce6fa017f48e892cc3465caa7fbb3dead5a6ca6 (diff) |
Input: atmel_mxt_ts - handle APP_CRC_FAIL on startup
If the bootloader on the touchscreen controller fails to initialise the
firmware image, it stays in bootloader mode and reports a failure. It is
possible to reflash a working firmware image from this state.
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/input/touchscreen/atmel_mxt_ts.c | 53 |
1 files changed, 43 insertions, 10 deletions
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index d2feb9c771a4..95e3ef49ac9b 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c | |||
@@ -404,6 +404,30 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data) | |||
404 | return 0; | 404 | return 0; |
405 | } | 405 | } |
406 | 406 | ||
407 | static int mxt_probe_bootloader(struct mxt_data *data) | ||
408 | { | ||
409 | struct device *dev = &data->client->dev; | ||
410 | int ret; | ||
411 | u8 val; | ||
412 | bool crc_failure; | ||
413 | |||
414 | ret = mxt_lookup_bootloader_address(data); | ||
415 | if (ret) | ||
416 | return ret; | ||
417 | |||
418 | ret = mxt_bootloader_read(data, &val, 1); | ||
419 | if (ret) | ||
420 | return ret; | ||
421 | |||
422 | /* Check app crc fail mode */ | ||
423 | crc_failure = (val & ~MXT_BOOT_STATUS_MASK) == MXT_APP_CRC_FAIL; | ||
424 | |||
425 | dev_err(dev, "Detected bootloader, status:%02X%s\n", | ||
426 | val, crc_failure ? ", APP_CRC_FAIL" : ""); | ||
427 | |||
428 | return 0; | ||
429 | } | ||
430 | |||
407 | static u8 mxt_get_bootloader_version(struct mxt_data *data, u8 val) | 431 | static u8 mxt_get_bootloader_version(struct mxt_data *data, u8 val) |
408 | { | 432 | { |
409 | struct device *dev = &data->client->dev; | 433 | struct device *dev = &data->client->dev; |
@@ -463,6 +487,7 @@ recheck: | |||
463 | switch (state) { | 487 | switch (state) { |
464 | case MXT_WAITING_BOOTLOAD_CMD: | 488 | case MXT_WAITING_BOOTLOAD_CMD: |
465 | case MXT_WAITING_FRAME_DATA: | 489 | case MXT_WAITING_FRAME_DATA: |
490 | case MXT_APP_CRC_FAIL: | ||
466 | val &= ~MXT_BOOT_STATUS_MASK; | 491 | val &= ~MXT_BOOT_STATUS_MASK; |
467 | break; | 492 | break; |
468 | case MXT_FRAME_CRC_PASS: | 493 | case MXT_FRAME_CRC_PASS: |
@@ -1451,8 +1476,14 @@ static int mxt_initialize(struct mxt_data *data) | |||
1451 | int error; | 1476 | int error; |
1452 | 1477 | ||
1453 | error = mxt_get_info(data); | 1478 | error = mxt_get_info(data); |
1454 | if (error) | 1479 | if (error) { |
1455 | return error; | 1480 | error = mxt_probe_bootloader(data); |
1481 | if (error) | ||
1482 | return error; | ||
1483 | |||
1484 | data->in_bootloader = true; | ||
1485 | return 0; | ||
1486 | } | ||
1456 | 1487 | ||
1457 | /* Get object table information */ | 1488 | /* Get object table information */ |
1458 | error = mxt_get_object_table(data); | 1489 | error = mxt_get_object_table(data); |
@@ -1630,15 +1661,19 @@ static int mxt_load_fw(struct device *dev, const char *fn) | |||
1630 | if (ret) | 1661 | if (ret) |
1631 | goto release_firmware; | 1662 | goto release_firmware; |
1632 | 1663 | ||
1633 | /* Change to the bootloader mode */ | 1664 | if (!data->in_bootloader) { |
1634 | data->in_bootloader = true; | 1665 | /* Change to the bootloader mode */ |
1666 | data->in_bootloader = true; | ||
1635 | 1667 | ||
1636 | ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_BOOT_VALUE, false); | 1668 | ret = mxt_t6_command(data, MXT_COMMAND_RESET, |
1637 | if (ret) | 1669 | MXT_BOOT_VALUE, false); |
1638 | goto release_firmware; | 1670 | if (ret) |
1671 | goto release_firmware; | ||
1639 | 1672 | ||
1640 | msleep(MXT_RESET_TIME); | 1673 | msleep(MXT_RESET_TIME); |
1674 | } | ||
1641 | 1675 | ||
1676 | mxt_free_object_table(data); | ||
1642 | reinit_completion(&data->bl_completion); | 1677 | reinit_completion(&data->bl_completion); |
1643 | 1678 | ||
1644 | ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD); | 1679 | ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD); |
@@ -1723,8 +1758,6 @@ static ssize_t mxt_update_fw_store(struct device *dev, | |||
1723 | } else { | 1758 | } else { |
1724 | dev_info(dev, "The firmware update succeeded\n"); | 1759 | dev_info(dev, "The firmware update succeeded\n"); |
1725 | 1760 | ||
1726 | mxt_free_object_table(data); | ||
1727 | |||
1728 | error = mxt_initialize(data); | 1761 | error = mxt_initialize(data); |
1729 | if (error) | 1762 | if (error) |
1730 | return error; | 1763 | return error; |