aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/nfc/pn544/i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/nfc/pn544/i2c.c')
-rw-r--r--drivers/nfc/pn544/i2c.c194
1 files changed, 187 insertions, 7 deletions
diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c
index d6185ff2f87b..f2acd85be86e 100644
--- a/drivers/nfc/pn544/i2c.c
+++ b/drivers/nfc/pn544/i2c.c
@@ -58,8 +58,19 @@ MODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table);
58 58
59#define PN544_HCI_I2C_DRIVER_NAME "pn544_hci_i2c" 59#define PN544_HCI_I2C_DRIVER_NAME "pn544_hci_i2c"
60 60
61/*
62 * Exposed through the 4 most significant bytes
63 * from the HCI SW_VERSION first byte, a.k.a.
64 * SW RomLib.
65 */
66#define PN544_HW_VARIANT_C2 0xa
67#define PN544_HW_VARIANT_C3 0xb
68
69#define PN544_FW_CMD_RESET 0x01
61#define PN544_FW_CMD_WRITE 0x08 70#define PN544_FW_CMD_WRITE 0x08
62#define PN544_FW_CMD_CHECK 0x06 71#define PN544_FW_CMD_CHECK 0x06
72#define PN544_FW_CMD_SECURE_WRITE 0x0C
73#define PN544_FW_CMD_SECURE_CHUNK_WRITE 0x0D
63 74
64struct pn544_i2c_fw_frame_write { 75struct pn544_i2c_fw_frame_write {
65 u8 cmd; 76 u8 cmd;
@@ -88,13 +99,31 @@ struct pn544_i2c_fw_blob {
88 u8 data[]; 99 u8 data[];
89}; 100};
90 101
102struct pn544_i2c_fw_secure_frame {
103 u8 cmd;
104 u16 be_datalen;
105 u8 data[];
106} __packed;
107
108struct pn544_i2c_fw_secure_blob {
109 u64 header;
110 u8 data[];
111};
112
91#define PN544_FW_CMD_RESULT_TIMEOUT 0x01 113#define PN544_FW_CMD_RESULT_TIMEOUT 0x01
92#define PN544_FW_CMD_RESULT_BAD_CRC 0x02 114#define PN544_FW_CMD_RESULT_BAD_CRC 0x02
93#define PN544_FW_CMD_RESULT_ACCESS_DENIED 0x08 115#define PN544_FW_CMD_RESULT_ACCESS_DENIED 0x08
94#define PN544_FW_CMD_RESULT_PROTOCOL_ERROR 0x0B 116#define PN544_FW_CMD_RESULT_PROTOCOL_ERROR 0x0B
95#define PN544_FW_CMD_RESULT_INVALID_PARAMETER 0x11 117#define PN544_FW_CMD_RESULT_INVALID_PARAMETER 0x11
118#define PN544_FW_CMD_RESULT_UNSUPPORTED_COMMAND 0x13
96#define PN544_FW_CMD_RESULT_INVALID_LENGTH 0x18 119#define PN544_FW_CMD_RESULT_INVALID_LENGTH 0x18
120#define PN544_FW_CMD_RESULT_CRYPTOGRAPHIC_ERROR 0x19
121#define PN544_FW_CMD_RESULT_VERSION_CONDITIONS_ERROR 0x1D
122#define PN544_FW_CMD_RESULT_MEMORY_ERROR 0x20
123#define PN544_FW_CMD_RESULT_CHUNK_OK 0x21
97#define PN544_FW_CMD_RESULT_WRITE_FAILED 0x74 124#define PN544_FW_CMD_RESULT_WRITE_FAILED 0x74
125#define PN544_FW_CMD_RESULT_COMMAND_REJECTED 0xE0
126#define PN544_FW_CMD_RESULT_CHUNK_ERROR 0xE6
98 127
99#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) 128#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
100 129
@@ -104,11 +133,17 @@ struct pn544_i2c_fw_blob {
104#define PN544_FW_I2C_WRITE_DATA_MAX_LEN MIN((PN544_FW_I2C_MAX_PAYLOAD -\ 133#define PN544_FW_I2C_WRITE_DATA_MAX_LEN MIN((PN544_FW_I2C_MAX_PAYLOAD -\
105 PN544_FW_I2C_WRITE_FRAME_HEADER_LEN),\ 134 PN544_FW_I2C_WRITE_FRAME_HEADER_LEN),\
106 PN544_FW_WRITE_BUFFER_MAX_LEN) 135 PN544_FW_WRITE_BUFFER_MAX_LEN)
136#define PN544_FW_SECURE_CHUNK_WRITE_HEADER_LEN 3
137#define PN544_FW_SECURE_CHUNK_WRITE_DATA_MAX_LEN (PN544_FW_I2C_MAX_PAYLOAD -\
138 PN544_FW_SECURE_CHUNK_WRITE_HEADER_LEN)
139#define PN544_FW_SECURE_FRAME_HEADER_LEN 3
140#define PN544_FW_SECURE_BLOB_HEADER_LEN 8
107 141
108#define FW_WORK_STATE_IDLE 1 142#define FW_WORK_STATE_IDLE 1
109#define FW_WORK_STATE_START 2 143#define FW_WORK_STATE_START 2
110#define FW_WORK_STATE_WAIT_WRITE_ANSWER 3 144#define FW_WORK_STATE_WAIT_WRITE_ANSWER 3
111#define FW_WORK_STATE_WAIT_CHECK_ANSWER 4 145#define FW_WORK_STATE_WAIT_CHECK_ANSWER 4
146#define FW_WORK_STATE_WAIT_SECURE_WRITE_ANSWER 5
112 147
113struct pn544_i2c_phy { 148struct pn544_i2c_phy {
114 struct i2c_client *i2c_dev; 149 struct i2c_client *i2c_dev;
@@ -119,6 +154,8 @@ struct pn544_i2c_phy {
119 unsigned int gpio_fw; 154 unsigned int gpio_fw;
120 unsigned int en_polarity; 155 unsigned int en_polarity;
121 156
157 u8 hw_variant;
158
122 struct work_struct fw_work; 159 struct work_struct fw_work;
123 int fw_work_state; 160 int fw_work_state;
124 char firmware_name[NFC_FIRMWARE_NAME_MAXSIZE + 1]; 161 char firmware_name[NFC_FIRMWARE_NAME_MAXSIZE + 1];
@@ -127,6 +164,8 @@ struct pn544_i2c_phy {
127 size_t fw_blob_size; 164 size_t fw_blob_size;
128 const u8 *fw_blob_data; 165 const u8 *fw_blob_data;
129 size_t fw_written; 166 size_t fw_written;
167 size_t fw_size;
168
130 int fw_cmd_result; 169 int fw_cmd_result;
131 170
132 int powered; 171 int powered;
@@ -390,6 +429,8 @@ static int pn544_hci_i2c_fw_read_status(struct pn544_i2c_phy *phy)
390 switch (response.status) { 429 switch (response.status) {
391 case 0: 430 case 0:
392 return 0; 431 return 0;
432 case PN544_FW_CMD_RESULT_CHUNK_OK:
433 return response.status;
393 case PN544_FW_CMD_RESULT_TIMEOUT: 434 case PN544_FW_CMD_RESULT_TIMEOUT:
394 return -ETIMEDOUT; 435 return -ETIMEDOUT;
395 case PN544_FW_CMD_RESULT_BAD_CRC: 436 case PN544_FW_CMD_RESULT_BAD_CRC:
@@ -400,9 +441,20 @@ static int pn544_hci_i2c_fw_read_status(struct pn544_i2c_phy *phy)
400 return -EPROTO; 441 return -EPROTO;
401 case PN544_FW_CMD_RESULT_INVALID_PARAMETER: 442 case PN544_FW_CMD_RESULT_INVALID_PARAMETER:
402 return -EINVAL; 443 return -EINVAL;
444 case PN544_FW_CMD_RESULT_UNSUPPORTED_COMMAND:
445 return -ENOTSUPP;
403 case PN544_FW_CMD_RESULT_INVALID_LENGTH: 446 case PN544_FW_CMD_RESULT_INVALID_LENGTH:
404 return -EBADMSG; 447 return -EBADMSG;
448 case PN544_FW_CMD_RESULT_CRYPTOGRAPHIC_ERROR:
449 return -ENOKEY;
450 case PN544_FW_CMD_RESULT_VERSION_CONDITIONS_ERROR:
451 return -EINVAL;
452 case PN544_FW_CMD_RESULT_MEMORY_ERROR:
453 return -ENOMEM;
454 case PN544_FW_CMD_RESULT_COMMAND_REJECTED:
455 return -EACCES;
405 case PN544_FW_CMD_RESULT_WRITE_FAILED: 456 case PN544_FW_CMD_RESULT_WRITE_FAILED:
457 case PN544_FW_CMD_RESULT_CHUNK_ERROR:
406 return -EIO; 458 return -EIO;
407 default: 459 default:
408 return -EIO; 460 return -EIO;
@@ -469,7 +521,8 @@ static struct nfc_phy_ops i2c_phy_ops = {
469 .disable = pn544_hci_i2c_disable, 521 .disable = pn544_hci_i2c_disable,
470}; 522};
471 523
472static int pn544_hci_i2c_fw_download(void *phy_id, const char *firmware_name) 524static int pn544_hci_i2c_fw_download(void *phy_id, const char *firmware_name,
525 u8 hw_variant)
473{ 526{
474 struct pn544_i2c_phy *phy = phy_id; 527 struct pn544_i2c_phy *phy = phy_id;
475 528
@@ -477,6 +530,7 @@ static int pn544_hci_i2c_fw_download(void *phy_id, const char *firmware_name)
477 530
478 strcpy(phy->firmware_name, firmware_name); 531 strcpy(phy->firmware_name, firmware_name);
479 532
533 phy->hw_variant = hw_variant;
480 phy->fw_work_state = FW_WORK_STATE_START; 534 phy->fw_work_state = FW_WORK_STATE_START;
481 535
482 schedule_work(&phy->fw_work); 536 schedule_work(&phy->fw_work);
@@ -598,12 +652,93 @@ static int pn544_hci_i2c_fw_write_chunk(struct pn544_i2c_phy *phy)
598 return 0; 652 return 0;
599} 653}
600 654
655static int pn544_hci_i2c_fw_secure_write_frame_cmd(struct pn544_i2c_phy *phy,
656 const u8 *data, u16 datalen)
657{
658 u8 buf[PN544_FW_I2C_MAX_PAYLOAD];
659 struct pn544_i2c_fw_secure_frame *chunk;
660 int chunklen;
661 int r;
662
663 if (datalen > PN544_FW_SECURE_CHUNK_WRITE_DATA_MAX_LEN)
664 datalen = PN544_FW_SECURE_CHUNK_WRITE_DATA_MAX_LEN;
665
666 chunk = (struct pn544_i2c_fw_secure_frame *) buf;
667
668 chunk->cmd = PN544_FW_CMD_SECURE_CHUNK_WRITE;
669
670 put_unaligned_be16(datalen, &chunk->be_datalen);
671
672 memcpy(chunk->data, data, datalen);
673
674 chunklen = sizeof(chunk->cmd) + sizeof(chunk->be_datalen) + datalen;
675
676 r = i2c_master_send(phy->i2c_dev, buf, chunklen);
677
678 if (r == chunklen)
679 return datalen;
680 else if (r < 0)
681 return r;
682 else
683 return -EIO;
684
685}
686
687static int pn544_hci_i2c_fw_secure_write_frame(struct pn544_i2c_phy *phy)
688{
689 struct pn544_i2c_fw_secure_frame *framep;
690 int r;
691
692 framep = (struct pn544_i2c_fw_secure_frame *) phy->fw_blob_data;
693 if (phy->fw_written == 0)
694 phy->fw_blob_size = get_unaligned_be16(&framep->be_datalen)
695 + PN544_FW_SECURE_FRAME_HEADER_LEN;
696
697 /* Only secure write command can be chunked*/
698 if (phy->fw_blob_size > PN544_FW_I2C_MAX_PAYLOAD &&
699 framep->cmd != PN544_FW_CMD_SECURE_WRITE)
700 return -EINVAL;
701
702 /* The firmware also have other commands, we just send them directly */
703 if (phy->fw_blob_size < PN544_FW_I2C_MAX_PAYLOAD) {
704 r = i2c_master_send(phy->i2c_dev,
705 (const char *) phy->fw_blob_data, phy->fw_blob_size);
706
707 if (r == phy->fw_blob_size)
708 goto exit;
709 else if (r < 0)
710 return r;
711 else
712 return -EIO;
713 }
714
715 r = pn544_hci_i2c_fw_secure_write_frame_cmd(phy,
716 phy->fw_blob_data + phy->fw_written,
717 phy->fw_blob_size - phy->fw_written);
718 if (r < 0)
719 return r;
720
721exit:
722 phy->fw_written += r;
723 phy->fw_work_state = FW_WORK_STATE_WAIT_SECURE_WRITE_ANSWER;
724
725 /* SW reset command will not trig any response from PN544 */
726 if (framep->cmd == PN544_FW_CMD_RESET) {
727 pn544_hci_i2c_enable_mode(phy, PN544_FW_MODE);
728 phy->fw_cmd_result = 0;
729 schedule_work(&phy->fw_work);
730 }
731
732 return 0;
733}
734
601static void pn544_hci_i2c_fw_work(struct work_struct *work) 735static void pn544_hci_i2c_fw_work(struct work_struct *work)
602{ 736{
603 struct pn544_i2c_phy *phy = container_of(work, struct pn544_i2c_phy, 737 struct pn544_i2c_phy *phy = container_of(work, struct pn544_i2c_phy,
604 fw_work); 738 fw_work);
605 int r; 739 int r;
606 struct pn544_i2c_fw_blob *blob; 740 struct pn544_i2c_fw_blob *blob;
741 struct pn544_i2c_fw_secure_blob *secure_blob;
607 742
608 switch (phy->fw_work_state) { 743 switch (phy->fw_work_state) {
609 case FW_WORK_STATE_START: 744 case FW_WORK_STATE_START:
@@ -614,13 +749,29 @@ static void pn544_hci_i2c_fw_work(struct work_struct *work)
614 if (r < 0) 749 if (r < 0)
615 goto exit_state_start; 750 goto exit_state_start;
616 751
617 blob = (struct pn544_i2c_fw_blob *) phy->fw->data;
618 phy->fw_blob_size = get_unaligned_be32(&blob->be_size);
619 phy->fw_blob_dest_addr = get_unaligned_be32(&blob->be_destaddr);
620 phy->fw_blob_data = blob->data;
621
622 phy->fw_written = 0; 752 phy->fw_written = 0;
623 r = pn544_hci_i2c_fw_write_chunk(phy); 753
754 switch (phy->hw_variant) {
755 case PN544_HW_VARIANT_C2:
756 blob = (struct pn544_i2c_fw_blob *) phy->fw->data;
757 phy->fw_blob_size = get_unaligned_be32(&blob->be_size);
758 phy->fw_blob_dest_addr = get_unaligned_be32(
759 &blob->be_destaddr);
760 phy->fw_blob_data = blob->data;
761
762 r = pn544_hci_i2c_fw_write_chunk(phy);
763 break;
764 case PN544_HW_VARIANT_C3:
765 secure_blob = (struct pn544_i2c_fw_secure_blob *)
766 phy->fw->data;
767 phy->fw_blob_data = secure_blob->data;
768 phy->fw_size = phy->fw->size;
769 r = pn544_hci_i2c_fw_secure_write_frame(phy);
770 break;
771 default:
772 r = -ENOTSUPP;
773 break;
774 }
624 775
625exit_state_start: 776exit_state_start:
626 if (r < 0) 777 if (r < 0)
@@ -672,6 +823,35 @@ exit_state_wait_check_answer:
672 pn544_hci_i2c_fw_work_complete(phy, r); 823 pn544_hci_i2c_fw_work_complete(phy, r);
673 break; 824 break;
674 825
826 case FW_WORK_STATE_WAIT_SECURE_WRITE_ANSWER:
827 r = phy->fw_cmd_result;
828 if (r < 0)
829 goto exit_state_wait_secure_write_answer;
830
831 if (r == PN544_FW_CMD_RESULT_CHUNK_OK) {
832 r = pn544_hci_i2c_fw_secure_write_frame(phy);
833 goto exit_state_wait_secure_write_answer;
834 }
835
836 if (phy->fw_written == phy->fw_blob_size) {
837 secure_blob = (struct pn544_i2c_fw_secure_blob *)
838 (phy->fw_blob_data + phy->fw_blob_size);
839 phy->fw_size -= phy->fw_blob_size +
840 PN544_FW_SECURE_BLOB_HEADER_LEN;
841 if (phy->fw_size >= PN544_FW_SECURE_BLOB_HEADER_LEN
842 + PN544_FW_SECURE_FRAME_HEADER_LEN) {
843 phy->fw_blob_data = secure_blob->data;
844
845 phy->fw_written = 0;
846 r = pn544_hci_i2c_fw_secure_write_frame(phy);
847 }
848 }
849
850exit_state_wait_secure_write_answer:
851 if (r < 0 || phy->fw_size == 0)
852 pn544_hci_i2c_fw_work_complete(phy, r);
853 break;
854
675 default: 855 default:
676 break; 856 break;
677 } 857 }