aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorDudley Du <dudl@cypress.com>2015-01-18 01:02:28 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2015-01-18 03:10:30 -0500
commit87b26d7288cef960a650015ae13771d44d45d202 (patch)
tree2b392ebe61123008077af448a268d20efab23a6f /drivers/input
parentc806b0b84d20a942ee94796e2a9f7f2326ab208f (diff)
Input: cyapa - add gen3 trackpad device firmware update support
Add support for firmware image update for gen3 trackpad devices; the firmware update is initiated by writing to update_fw sysfs attribute. Signed-off-by: Dudley Du <dudl@cypress.com> Tested-by: Jeremiah Mahler <jmmahler@gmail.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/mouse/cyapa_gen3.c309
1 files changed, 309 insertions, 0 deletions
diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c
index 1b62c7d585a2..214d45afc9f2 100644
--- a/drivers/input/mouse/cyapa_gen3.c
+++ b/drivers/input/mouse/cyapa_gen3.c
@@ -20,6 +20,7 @@
20#include <linux/input/mt.h> 20#include <linux/input/mt.h>
21#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/slab.h> 22#include <linux/slab.h>
23#include <linux/unaligned/access_ok.h>
23#include "cyapa.h" 24#include "cyapa.h"
24 25
25 26
@@ -115,6 +116,18 @@ struct cyapa_reg_data {
115 struct cyapa_touch touches[5]; 116 struct cyapa_touch touches[5];
116} __packed; 117} __packed;
117 118
119struct gen3_write_block_cmd {
120 u8 checksum_seed; /* Always be 0xff */
121 u8 cmd_code; /* command code: 0x39 */
122 u8 key[8]; /* 8-byte security key */
123 __be16 block_num;
124 u8 block_data[CYAPA_FW_BLOCK_SIZE];
125 u8 block_checksum; /* Calculated using bytes 12 - 75 */
126 u8 cmd_checksum; /* Calculated using bytes 0-76 */
127} __packed;
128
129static const u8 security_key[] = {
130 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
118static const u8 bl_activate[] = { 0x00, 0xff, 0x38, 0x00, 0x01, 0x02, 0x03, 131static const u8 bl_activate[] = { 0x00, 0xff, 0x38, 0x00, 0x01, 0x02, 0x03,
119 0x04, 0x05, 0x06, 0x07 }; 132 0x04, 0x05, 0x06, 0x07 };
120static const u8 bl_deactivate[] = { 0x00, 0xff, 0x3b, 0x00, 0x01, 0x02, 0x03, 133static const u8 bl_deactivate[] = { 0x00, 0xff, 0x3b, 0x00, 0x01, 0x02, 0x03,
@@ -423,6 +436,87 @@ static int cyapa_gen3_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
423 return -EAGAIN; 436 return -EAGAIN;
424} 437}
425 438
439/*
440 * Enter bootloader by soft resetting the device.
441 *
442 * If device is already in the bootloader, the function just returns.
443 * Otherwise, reset the device; after reset, device enters bootloader idle
444 * state immediately.
445 *
446 * Returns:
447 * 0 on success
448 * -EAGAIN device was reset, but is not now in bootloader idle state
449 * < 0 if the device never responds within the timeout
450 */
451static int cyapa_gen3_bl_enter(struct cyapa *cyapa)
452{
453 int error;
454 int waiting_time;
455
456 error = cyapa_poll_state(cyapa, 500);
457 if (error)
458 return error;
459 if (cyapa->state == CYAPA_STATE_BL_IDLE) {
460 /* Already in BL_IDLE. Skipping reset. */
461 return 0;
462 }
463
464 if (cyapa->state != CYAPA_STATE_OP)
465 return -EAGAIN;
466
467 cyapa->operational = false;
468 cyapa->state = CYAPA_STATE_NO_DEVICE;
469 error = cyapa_write_byte(cyapa, CYAPA_CMD_SOFT_RESET, 0x01);
470 if (error)
471 return -EIO;
472
473 usleep_range(25000, 50000);
474 waiting_time = 2000; /* For some shipset, max waiting time is 1~2s. */
475 do {
476 error = cyapa_poll_state(cyapa, 500);
477 if (error) {
478 if (error == -ETIMEDOUT) {
479 waiting_time -= 500;
480 continue;
481 }
482 return error;
483 }
484
485 if ((cyapa->state == CYAPA_STATE_BL_IDLE) &&
486 !(cyapa->status[REG_BL_STATUS] & BL_STATUS_WATCHDOG))
487 break;
488
489 msleep(100);
490 waiting_time -= 100;
491 } while (waiting_time > 0);
492
493 if ((cyapa->state != CYAPA_STATE_BL_IDLE) ||
494 (cyapa->status[REG_BL_STATUS] & BL_STATUS_WATCHDOG))
495 return -EAGAIN;
496
497 return 0;
498}
499
500static int cyapa_gen3_bl_activate(struct cyapa *cyapa)
501{
502 int error;
503
504 error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_activate),
505 bl_activate);
506 if (error)
507 return error;
508
509 /* Wait for bootloader to activate; takes between 2 and 12 seconds */
510 msleep(2000);
511 error = cyapa_poll_state(cyapa, 11000);
512 if (error)
513 return error;
514 if (cyapa->state != CYAPA_STATE_BL_ACTIVE)
515 return -EAGAIN;
516
517 return 0;
518}
519
426static int cyapa_gen3_bl_deactivate(struct cyapa *cyapa) 520static int cyapa_gen3_bl_deactivate(struct cyapa *cyapa)
427{ 521{
428 int error; 522 int error;
@@ -483,6 +577,212 @@ static int cyapa_gen3_bl_exit(struct cyapa *cyapa)
483 return 0; 577 return 0;
484} 578}
485 579
580static u16 cyapa_gen3_csum(const u8 *buf, size_t count)
581{
582 int i;
583 u16 csum = 0;
584
585 for (i = 0; i < count; i++)
586 csum += buf[i];
587
588 return csum;
589}
590
591/*
592 * Verify the integrity of a CYAPA firmware image file.
593 *
594 * The firmware image file is 30848 bytes, composed of 482 64-byte blocks.
595 *
596 * The first 2 blocks are the firmware header.
597 * The next 480 blocks are the firmware image.
598 *
599 * The first two bytes of the header hold the header checksum, computed by
600 * summing the other 126 bytes of the header.
601 * The last two bytes of the header hold the firmware image checksum, computed
602 * by summing the 30720 bytes of the image modulo 0xffff.
603 *
604 * Both checksums are stored little-endian.
605 */
606static int cyapa_gen3_check_fw(struct cyapa *cyapa, const struct firmware *fw)
607{
608 struct device *dev = &cyapa->client->dev;
609 u16 csum;
610 u16 csum_expected;
611
612 /* Firmware must match exact 30848 bytes = 482 64-byte blocks. */
613 if (fw->size != CYAPA_FW_SIZE) {
614 dev_err(dev, "invalid firmware size = %zu, expected %u.\n",
615 fw->size, CYAPA_FW_SIZE);
616 return -EINVAL;
617 }
618
619 /* Verify header block */
620 csum_expected = (fw->data[0] << 8) | fw->data[1];
621 csum = cyapa_gen3_csum(&fw->data[2], CYAPA_FW_HDR_SIZE - 2);
622 if (csum != csum_expected) {
623 dev_err(dev, "%s %04x, expected: %04x\n",
624 "invalid firmware header checksum = ",
625 csum, csum_expected);
626 return -EINVAL;
627 }
628
629 /* Verify firmware image */
630 csum_expected = (fw->data[CYAPA_FW_HDR_SIZE - 2] << 8) |
631 fw->data[CYAPA_FW_HDR_SIZE - 1];
632 csum = cyapa_gen3_csum(&fw->data[CYAPA_FW_HDR_SIZE],
633 CYAPA_FW_DATA_SIZE);
634 if (csum != csum_expected) {
635 dev_err(dev, "%s %04x, expected: %04x\n",
636 "invalid firmware header checksum = ",
637 csum, csum_expected);
638 return -EINVAL;
639 }
640 return 0;
641}
642
643/*
644 * Write a |len| byte long buffer |buf| to the device, by chopping it up into a
645 * sequence of smaller |CYAPA_CMD_LEN|-length write commands.
646 *
647 * The data bytes for a write command are prepended with the 1-byte offset
648 * of the data relative to the start of |buf|.
649 */
650static int cyapa_gen3_write_buffer(struct cyapa *cyapa,
651 const u8 *buf, size_t len)
652{
653 int error;
654 size_t i;
655 unsigned char cmd[CYAPA_CMD_LEN + 1];
656 size_t cmd_len;
657
658 for (i = 0; i < len; i += CYAPA_CMD_LEN) {
659 const u8 *payload = &buf[i];
660
661 cmd_len = (len - i >= CYAPA_CMD_LEN) ? CYAPA_CMD_LEN : len - i;
662 cmd[0] = i;
663 memcpy(&cmd[1], payload, cmd_len);
664
665 error = cyapa_i2c_reg_write_block(cyapa, 0, cmd_len + 1, cmd);
666 if (error)
667 return error;
668 }
669 return 0;
670}
671
672/*
673 * A firmware block write command writes 64 bytes of data to a single flash
674 * page in the device. The 78-byte block write command has the format:
675 * <0xff> <CMD> <Key> <Start> <Data> <Data-Checksum> <CMD Checksum>
676 *
677 * <0xff> - every command starts with 0xff
678 * <CMD> - the write command value is 0x39
679 * <Key> - write commands include an 8-byte key: { 00 01 02 03 04 05 06 07 }
680 * <Block> - Memory Block number (address / 64) (16-bit, big-endian)
681 * <Data> - 64 bytes of firmware image data
682 * <Data Checksum> - sum of 64 <Data> bytes, modulo 0xff
683 * <CMD Checksum> - sum of 77 bytes, from 0xff to <Data Checksum>
684 *
685 * Each write command is split into 5 i2c write transactions of up to 16 bytes.
686 * Each transaction starts with an i2c register offset: (00, 10, 20, 30, 40).
687 */
688static int cyapa_gen3_write_fw_block(struct cyapa *cyapa,
689 u16 block, const u8 *data)
690{
691 int ret;
692 struct gen3_write_block_cmd write_block_cmd;
693 u8 status[BL_STATUS_SIZE];
694 int tries;
695 u8 bl_status, bl_error;
696
697 /* Set write command and security key bytes. */
698 write_block_cmd.checksum_seed = GEN3_BL_CMD_CHECKSUM_SEED;
699 write_block_cmd.cmd_code = GEN3_BL_CMD_WRITE_BLOCK;
700 memcpy(write_block_cmd.key, security_key, sizeof(security_key));
701 put_unaligned_be16(block, &write_block_cmd.block_num);
702 memcpy(write_block_cmd.block_data, data, CYAPA_FW_BLOCK_SIZE);
703 write_block_cmd.block_checksum = cyapa_gen3_csum(
704 write_block_cmd.block_data, CYAPA_FW_BLOCK_SIZE);
705 write_block_cmd.cmd_checksum = cyapa_gen3_csum((u8 *)&write_block_cmd,
706 sizeof(write_block_cmd) - 1);
707
708 ret = cyapa_gen3_write_buffer(cyapa, (u8 *)&write_block_cmd,
709 sizeof(write_block_cmd));
710 if (ret)
711 return ret;
712
713 /* Wait for write to finish */
714 tries = 11; /* Programming for one block can take about 100ms. */
715 do {
716 usleep_range(10000, 20000);
717
718 /* Check block write command result status. */
719 ret = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET,
720 BL_STATUS_SIZE, status);
721 if (ret != BL_STATUS_SIZE)
722 return (ret < 0) ? ret : -EIO;
723 } while ((status[REG_BL_STATUS] & BL_STATUS_BUSY) && --tries);
724
725 /* Ignore WATCHDOG bit and reserved bits. */
726 bl_status = status[REG_BL_STATUS] & ~BL_STATUS_REV_MASK;
727 bl_error = status[REG_BL_ERROR] & ~BL_ERROR_RESERVED;
728
729 if (bl_status & BL_STATUS_BUSY)
730 ret = -ETIMEDOUT;
731 else if (bl_status != BL_STATUS_RUNNING ||
732 bl_error != BL_ERROR_BOOTLOADING)
733 ret = -EIO;
734 else
735 ret = 0;
736
737 return ret;
738}
739
740static int cyapa_gen3_write_blocks(struct cyapa *cyapa,
741 size_t start_block, size_t block_count,
742 const u8 *image_data)
743{
744 int error;
745 int i;
746
747 for (i = 0; i < block_count; i++) {
748 size_t block = start_block + i;
749 size_t addr = i * CYAPA_FW_BLOCK_SIZE;
750 const u8 *data = &image_data[addr];
751
752 error = cyapa_gen3_write_fw_block(cyapa, block, data);
753 if (error)
754 return error;
755 }
756 return 0;
757}
758
759static int cyapa_gen3_do_fw_update(struct cyapa *cyapa,
760 const struct firmware *fw)
761{
762 struct device *dev = &cyapa->client->dev;
763 int error;
764
765 /* First write data, starting at byte 128 of fw->data */
766 error = cyapa_gen3_write_blocks(cyapa,
767 CYAPA_FW_DATA_BLOCK_START, CYAPA_FW_DATA_BLOCK_COUNT,
768 &fw->data[CYAPA_FW_HDR_BLOCK_COUNT * CYAPA_FW_BLOCK_SIZE]);
769 if (error) {
770 dev_err(dev, "FW update aborted, write image: %d\n", error);
771 return error;
772 }
773
774 /* Then write checksum */
775 error = cyapa_gen3_write_blocks(cyapa,
776 CYAPA_FW_HDR_BLOCK_START, CYAPA_FW_HDR_BLOCK_COUNT,
777 &fw->data[0]);
778 if (error) {
779 dev_err(dev, "FW update aborted, write checksum: %d\n", error);
780 return error;
781 }
782
783 return 0;
784}
785
486/* 786/*
487 * cyapa_get_wait_time_for_pwr_cmd 787 * cyapa_get_wait_time_for_pwr_cmd
488 * 788 *
@@ -791,10 +1091,19 @@ static int cyapa_gen3_irq_handler(struct cyapa *cyapa)
791} 1091}
792 1092
793static int cyapa_gen3_initialize(struct cyapa *cyapa) { return 0; } 1093static int cyapa_gen3_initialize(struct cyapa *cyapa) { return 0; }
1094static int cyapa_gen3_bl_initiate(struct cyapa *cyapa,
1095 const struct firmware *fw) { return 0; }
794static int cyapa_gen3_empty_output_data(struct cyapa *cyapa, 1096static int cyapa_gen3_empty_output_data(struct cyapa *cyapa,
795 u8 *buf, int *len, cb_sort func) { return 0; } 1097 u8 *buf, int *len, cb_sort func) { return 0; }
796 1098
797const struct cyapa_dev_ops cyapa_gen3_ops = { 1099const struct cyapa_dev_ops cyapa_gen3_ops = {
1100 .check_fw = cyapa_gen3_check_fw,
1101 .bl_enter = cyapa_gen3_bl_enter,
1102 .bl_activate = cyapa_gen3_bl_activate,
1103 .update_fw = cyapa_gen3_do_fw_update,
1104 .bl_deactivate = cyapa_gen3_bl_deactivate,
1105 .bl_initiate = cyapa_gen3_bl_initiate,
1106
798 .initialize = cyapa_gen3_initialize, 1107 .initialize = cyapa_gen3_initialize,
799 1108
800 .state_parse = cyapa_gen3_state_parse, 1109 .state_parse = cyapa_gen3_state_parse,