diff options
Diffstat (limited to 'drivers/nfc/port100.c')
-rw-r--r-- | drivers/nfc/port100.c | 366 |
1 files changed, 363 insertions, 3 deletions
diff --git a/drivers/nfc/port100.c b/drivers/nfc/port100.c index 251a2c112299..99a6dd79393d 100644 --- a/drivers/nfc/port100.c +++ b/drivers/nfc/port100.c | |||
@@ -71,6 +71,12 @@ static u8 ack_frame[PORT100_FRAME_ACK_SIZE] = { | |||
71 | #define PORT100_CMD_GET_COMMAND_TYPE 0x28 | 71 | #define PORT100_CMD_GET_COMMAND_TYPE 0x28 |
72 | #define PORT100_CMD_SET_COMMAND_TYPE 0x2A | 72 | #define PORT100_CMD_SET_COMMAND_TYPE 0x2A |
73 | 73 | ||
74 | #define PORT100_CMD_IN_SET_RF 0x00 | ||
75 | #define PORT100_CMD_IN_SET_PROTOCOL 0x02 | ||
76 | #define PORT100_CMD_IN_COMM_RF 0x04 | ||
77 | |||
78 | #define PORT100_CMD_SWITCH_RF 0x06 | ||
79 | |||
74 | #define PORT100_CMD_RESPONSE(cmd) (cmd + 1) | 80 | #define PORT100_CMD_RESPONSE(cmd) (cmd + 1) |
75 | 81 | ||
76 | #define PORT100_CMD_TYPE_IS_SUPPORTED(mask, cmd_type) \ | 82 | #define PORT100_CMD_TYPE_IS_SUPPORTED(mask, cmd_type) \ |
@@ -78,11 +84,204 @@ static u8 ack_frame[PORT100_FRAME_ACK_SIZE] = { | |||
78 | #define PORT100_CMD_TYPE_0 0 | 84 | #define PORT100_CMD_TYPE_0 0 |
79 | #define PORT100_CMD_TYPE_1 1 | 85 | #define PORT100_CMD_TYPE_1 1 |
80 | 86 | ||
87 | #define PORT100_CMD_STATUS_OK 0x00 | ||
88 | #define PORT100_CMD_STATUS_TIMEOUT 0x80 | ||
89 | |||
81 | struct port100; | 90 | struct port100; |
82 | 91 | ||
83 | typedef void (*port100_send_async_complete_t)(struct port100 *dev, void *arg, | 92 | typedef void (*port100_send_async_complete_t)(struct port100 *dev, void *arg, |
84 | struct sk_buff *resp); | 93 | struct sk_buff *resp); |
85 | 94 | ||
95 | /** | ||
96 | * Setting sets structure for in_set_rf command | ||
97 | * | ||
98 | * @in_*_set_number: Represent the entry indexes in the port-100 RF Base Table. | ||
99 | * This table contains multiple RF setting sets required for RF | ||
100 | * communication. | ||
101 | * | ||
102 | * @in_*_comm_type: Theses fields set the communication type to be used. | ||
103 | */ | ||
104 | struct port100_in_rf_setting { | ||
105 | u8 in_send_set_number; | ||
106 | u8 in_send_comm_type; | ||
107 | u8 in_recv_set_number; | ||
108 | u8 in_recv_comm_type; | ||
109 | } __packed; | ||
110 | |||
111 | #define PORT100_COMM_TYPE_IN_212F 0x01 | ||
112 | #define PORT100_COMM_TYPE_IN_424F 0x02 | ||
113 | #define PORT100_COMM_TYPE_IN_106A 0x03 | ||
114 | |||
115 | static const struct port100_in_rf_setting in_rf_settings[] = { | ||
116 | [NFC_DIGITAL_RF_TECH_212F] = { | ||
117 | .in_send_set_number = 1, | ||
118 | .in_send_comm_type = PORT100_COMM_TYPE_IN_212F, | ||
119 | .in_recv_set_number = 15, | ||
120 | .in_recv_comm_type = PORT100_COMM_TYPE_IN_212F, | ||
121 | }, | ||
122 | [NFC_DIGITAL_RF_TECH_424F] = { | ||
123 | .in_send_set_number = 1, | ||
124 | .in_send_comm_type = PORT100_COMM_TYPE_IN_424F, | ||
125 | .in_recv_set_number = 15, | ||
126 | .in_recv_comm_type = PORT100_COMM_TYPE_IN_424F, | ||
127 | }, | ||
128 | [NFC_DIGITAL_RF_TECH_106A] = { | ||
129 | .in_send_set_number = 2, | ||
130 | .in_send_comm_type = PORT100_COMM_TYPE_IN_106A, | ||
131 | .in_recv_set_number = 15, | ||
132 | .in_recv_comm_type = PORT100_COMM_TYPE_IN_106A, | ||
133 | }, | ||
134 | }; | ||
135 | |||
136 | #define PORT100_IN_PROT_INITIAL_GUARD_TIME 0x00 | ||
137 | #define PORT100_IN_PROT_ADD_CRC 0x01 | ||
138 | #define PORT100_IN_PROT_CHECK_CRC 0x02 | ||
139 | #define PORT100_IN_PROT_MULTI_CARD 0x03 | ||
140 | #define PORT100_IN_PROT_ADD_PARITY 0x04 | ||
141 | #define PORT100_IN_PROT_CHECK_PARITY 0x05 | ||
142 | #define PORT100_IN_PROT_BITWISE_AC_RECV_MODE 0x06 | ||
143 | #define PORT100_IN_PROT_VALID_BIT_NUMBER 0x07 | ||
144 | #define PORT100_IN_PROT_CRYPTO1 0x08 | ||
145 | #define PORT100_IN_PROT_ADD_SOF 0x09 | ||
146 | #define PORT100_IN_PROT_CHECK_SOF 0x0A | ||
147 | #define PORT100_IN_PROT_ADD_EOF 0x0B | ||
148 | #define PORT100_IN_PROT_CHECK_EOF 0x0C | ||
149 | #define PORT100_IN_PROT_DEAF_TIME 0x0E | ||
150 | #define PORT100_IN_PROT_CRM 0x0F | ||
151 | #define PORT100_IN_PROT_CRM_MIN_LEN 0x10 | ||
152 | #define PORT100_IN_PROT_T1_TAG_FRAME 0x11 | ||
153 | #define PORT100_IN_PROT_RFCA 0x12 | ||
154 | #define PORT100_IN_PROT_GUARD_TIME_AT_INITIATOR 0x13 | ||
155 | #define PORT100_IN_PROT_END 0x14 | ||
156 | |||
157 | #define PORT100_IN_MAX_NUM_PROTOCOLS 19 | ||
158 | |||
159 | struct port100_protocol { | ||
160 | u8 number; | ||
161 | u8 value; | ||
162 | } __packed; | ||
163 | |||
164 | static struct port100_protocol | ||
165 | in_protocols[][PORT100_IN_MAX_NUM_PROTOCOLS + 1] = { | ||
166 | [NFC_DIGITAL_FRAMING_NFCA_SHORT] = { | ||
167 | { PORT100_IN_PROT_INITIAL_GUARD_TIME, 6 }, | ||
168 | { PORT100_IN_PROT_ADD_CRC, 0 }, | ||
169 | { PORT100_IN_PROT_CHECK_CRC, 0 }, | ||
170 | { PORT100_IN_PROT_MULTI_CARD, 0 }, | ||
171 | { PORT100_IN_PROT_ADD_PARITY, 0 }, | ||
172 | { PORT100_IN_PROT_CHECK_PARITY, 1 }, | ||
173 | { PORT100_IN_PROT_BITWISE_AC_RECV_MODE, 0 }, | ||
174 | { PORT100_IN_PROT_VALID_BIT_NUMBER, 7 }, | ||
175 | { PORT100_IN_PROT_CRYPTO1, 0 }, | ||
176 | { PORT100_IN_PROT_ADD_SOF, 0 }, | ||
177 | { PORT100_IN_PROT_CHECK_SOF, 0 }, | ||
178 | { PORT100_IN_PROT_ADD_EOF, 0 }, | ||
179 | { PORT100_IN_PROT_CHECK_EOF, 0 }, | ||
180 | { PORT100_IN_PROT_DEAF_TIME, 4 }, | ||
181 | { PORT100_IN_PROT_CRM, 0 }, | ||
182 | { PORT100_IN_PROT_CRM_MIN_LEN, 0 }, | ||
183 | { PORT100_IN_PROT_T1_TAG_FRAME, 0 }, | ||
184 | { PORT100_IN_PROT_RFCA, 0 }, | ||
185 | { PORT100_IN_PROT_GUARD_TIME_AT_INITIATOR, 6 }, | ||
186 | { PORT100_IN_PROT_END, 0 }, | ||
187 | }, | ||
188 | [NFC_DIGITAL_FRAMING_NFCA_STANDARD] = { | ||
189 | { PORT100_IN_PROT_INITIAL_GUARD_TIME, 6 }, | ||
190 | { PORT100_IN_PROT_ADD_CRC, 0 }, | ||
191 | { PORT100_IN_PROT_CHECK_CRC, 0 }, | ||
192 | { PORT100_IN_PROT_MULTI_CARD, 0 }, | ||
193 | { PORT100_IN_PROT_ADD_PARITY, 1 }, | ||
194 | { PORT100_IN_PROT_CHECK_PARITY, 1 }, | ||
195 | { PORT100_IN_PROT_BITWISE_AC_RECV_MODE, 0 }, | ||
196 | { PORT100_IN_PROT_VALID_BIT_NUMBER, 8 }, | ||
197 | { PORT100_IN_PROT_CRYPTO1, 0 }, | ||
198 | { PORT100_IN_PROT_ADD_SOF, 0 }, | ||
199 | { PORT100_IN_PROT_CHECK_SOF, 0 }, | ||
200 | { PORT100_IN_PROT_ADD_EOF, 0 }, | ||
201 | { PORT100_IN_PROT_CHECK_EOF, 0 }, | ||
202 | { PORT100_IN_PROT_DEAF_TIME, 4 }, | ||
203 | { PORT100_IN_PROT_CRM, 0 }, | ||
204 | { PORT100_IN_PROT_CRM_MIN_LEN, 0 }, | ||
205 | { PORT100_IN_PROT_T1_TAG_FRAME, 0 }, | ||
206 | { PORT100_IN_PROT_RFCA, 0 }, | ||
207 | { PORT100_IN_PROT_GUARD_TIME_AT_INITIATOR, 6 }, | ||
208 | { PORT100_IN_PROT_END, 0 }, | ||
209 | }, | ||
210 | [NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A] = { | ||
211 | { PORT100_IN_PROT_INITIAL_GUARD_TIME, 6 }, | ||
212 | { PORT100_IN_PROT_ADD_CRC, 1 }, | ||
213 | { PORT100_IN_PROT_CHECK_CRC, 1 }, | ||
214 | { PORT100_IN_PROT_MULTI_CARD, 0 }, | ||
215 | { PORT100_IN_PROT_ADD_PARITY, 1 }, | ||
216 | { PORT100_IN_PROT_CHECK_PARITY, 1 }, | ||
217 | { PORT100_IN_PROT_BITWISE_AC_RECV_MODE, 0 }, | ||
218 | { PORT100_IN_PROT_VALID_BIT_NUMBER, 8 }, | ||
219 | { PORT100_IN_PROT_CRYPTO1, 0 }, | ||
220 | { PORT100_IN_PROT_ADD_SOF, 0 }, | ||
221 | { PORT100_IN_PROT_CHECK_SOF, 0 }, | ||
222 | { PORT100_IN_PROT_ADD_EOF, 0 }, | ||
223 | { PORT100_IN_PROT_CHECK_EOF, 0 }, | ||
224 | { PORT100_IN_PROT_DEAF_TIME, 4 }, | ||
225 | { PORT100_IN_PROT_CRM, 0 }, | ||
226 | { PORT100_IN_PROT_CRM_MIN_LEN, 0 }, | ||
227 | { PORT100_IN_PROT_T1_TAG_FRAME, 0 }, | ||
228 | { PORT100_IN_PROT_RFCA, 0 }, | ||
229 | { PORT100_IN_PROT_GUARD_TIME_AT_INITIATOR, 6 }, | ||
230 | { PORT100_IN_PROT_END, 0 }, | ||
231 | }, | ||
232 | [NFC_DIGITAL_FRAMING_NFCA_T1T] = { | ||
233 | /* nfc_digital_framing_nfca_short */ | ||
234 | { PORT100_IN_PROT_ADD_CRC, 2 }, | ||
235 | { PORT100_IN_PROT_CHECK_CRC, 2 }, | ||
236 | { PORT100_IN_PROT_VALID_BIT_NUMBER, 8 }, | ||
237 | { PORT100_IN_PROT_T1_TAG_FRAME, 2 }, | ||
238 | { PORT100_IN_PROT_END, 0 }, | ||
239 | }, | ||
240 | [NFC_DIGITAL_FRAMING_NFCA_T2T] = { | ||
241 | /* nfc_digital_framing_nfca_standard */ | ||
242 | { PORT100_IN_PROT_ADD_CRC, 1 }, | ||
243 | { PORT100_IN_PROT_CHECK_CRC, 0 }, | ||
244 | { PORT100_IN_PROT_END, 0 }, | ||
245 | }, | ||
246 | [NFC_DIGITAL_FRAMING_NFCA_NFC_DEP] = { | ||
247 | /* nfc_digital_framing_nfca_standard */ | ||
248 | { PORT100_IN_PROT_END, 0 }, | ||
249 | }, | ||
250 | [NFC_DIGITAL_FRAMING_NFCF] = { | ||
251 | { PORT100_IN_PROT_INITIAL_GUARD_TIME, 18 }, | ||
252 | { PORT100_IN_PROT_ADD_CRC, 1 }, | ||
253 | { PORT100_IN_PROT_CHECK_CRC, 1 }, | ||
254 | { PORT100_IN_PROT_MULTI_CARD, 0 }, | ||
255 | { PORT100_IN_PROT_ADD_PARITY, 0 }, | ||
256 | { PORT100_IN_PROT_CHECK_PARITY, 0 }, | ||
257 | { PORT100_IN_PROT_BITWISE_AC_RECV_MODE, 0 }, | ||
258 | { PORT100_IN_PROT_VALID_BIT_NUMBER, 8 }, | ||
259 | { PORT100_IN_PROT_CRYPTO1, 0 }, | ||
260 | { PORT100_IN_PROT_ADD_SOF, 0 }, | ||
261 | { PORT100_IN_PROT_CHECK_SOF, 0 }, | ||
262 | { PORT100_IN_PROT_ADD_EOF, 0 }, | ||
263 | { PORT100_IN_PROT_CHECK_EOF, 0 }, | ||
264 | { PORT100_IN_PROT_DEAF_TIME, 4 }, | ||
265 | { PORT100_IN_PROT_CRM, 0 }, | ||
266 | { PORT100_IN_PROT_CRM_MIN_LEN, 0 }, | ||
267 | { PORT100_IN_PROT_T1_TAG_FRAME, 0 }, | ||
268 | { PORT100_IN_PROT_RFCA, 0 }, | ||
269 | { PORT100_IN_PROT_GUARD_TIME_AT_INITIATOR, 6 }, | ||
270 | { PORT100_IN_PROT_END, 0 }, | ||
271 | }, | ||
272 | [NFC_DIGITAL_FRAMING_NFCF_T3T] = { | ||
273 | /* nfc_digital_framing_nfcf */ | ||
274 | { PORT100_IN_PROT_END, 0 }, | ||
275 | }, | ||
276 | [NFC_DIGITAL_FRAMING_NFCF_NFC_DEP] = { | ||
277 | /* nfc_digital_framing_nfcf */ | ||
278 | { PORT100_IN_PROT_END, 0 }, | ||
279 | }, | ||
280 | [NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED] = { | ||
281 | { PORT100_IN_PROT_END, 0 }, | ||
282 | }, | ||
283 | }; | ||
284 | |||
86 | struct port100 { | 285 | struct port100 { |
87 | struct nfc_digital_dev *nfc_digital_dev; | 286 | struct nfc_digital_dev *nfc_digital_dev; |
88 | 287 | ||
@@ -626,20 +825,181 @@ static u16 port100_get_firmware_version(struct port100 *dev) | |||
626 | 825 | ||
627 | static int port100_switch_rf(struct nfc_digital_dev *ddev, bool on) | 826 | static int port100_switch_rf(struct nfc_digital_dev *ddev, bool on) |
628 | { | 827 | { |
629 | return -EOPNOTSUPP; | 828 | struct port100 *dev = nfc_digital_get_drvdata(ddev); |
829 | struct sk_buff *skb, *resp; | ||
830 | |||
831 | skb = port100_alloc_skb(dev, 1); | ||
832 | if (!skb) | ||
833 | return -ENOMEM; | ||
834 | |||
835 | *skb_put(skb, 1) = on ? 1 : 0; | ||
836 | |||
837 | resp = port100_send_cmd_sync(dev, PORT100_CMD_SWITCH_RF, skb); | ||
838 | |||
839 | if (IS_ERR(resp)) | ||
840 | return PTR_ERR(resp); | ||
841 | |||
842 | dev_kfree_skb(resp); | ||
843 | |||
844 | return 0; | ||
845 | } | ||
846 | |||
847 | static int port100_in_set_rf(struct nfc_digital_dev *ddev, u8 rf) | ||
848 | { | ||
849 | struct port100 *dev = nfc_digital_get_drvdata(ddev); | ||
850 | struct sk_buff *skb; | ||
851 | struct sk_buff *resp; | ||
852 | int rc; | ||
853 | |||
854 | if (rf >= NFC_DIGITAL_RF_TECH_LAST) | ||
855 | return -EINVAL; | ||
856 | |||
857 | skb = port100_alloc_skb(dev, sizeof(struct port100_in_rf_setting)); | ||
858 | if (!skb) | ||
859 | return -ENOMEM; | ||
860 | |||
861 | memcpy(skb_put(skb, sizeof(struct port100_in_rf_setting)), | ||
862 | &in_rf_settings[rf], | ||
863 | sizeof(struct port100_in_rf_setting)); | ||
864 | |||
865 | resp = port100_send_cmd_sync(dev, PORT100_CMD_IN_SET_RF, skb); | ||
866 | |||
867 | if (IS_ERR(resp)) | ||
868 | return PTR_ERR(resp); | ||
869 | |||
870 | rc = resp->data[0]; | ||
871 | |||
872 | dev_kfree_skb(resp); | ||
873 | |||
874 | return rc; | ||
875 | } | ||
876 | |||
877 | static int port100_in_set_framing(struct nfc_digital_dev *ddev, int param) | ||
878 | { | ||
879 | struct port100 *dev = nfc_digital_get_drvdata(ddev); | ||
880 | struct port100_protocol *protocols; | ||
881 | struct sk_buff *skb; | ||
882 | struct sk_buff *resp; | ||
883 | int num_protocols; | ||
884 | size_t size; | ||
885 | int rc; | ||
886 | |||
887 | if (param >= NFC_DIGITAL_FRAMING_LAST) | ||
888 | return -EINVAL; | ||
889 | |||
890 | protocols = in_protocols[param]; | ||
891 | |||
892 | num_protocols = 0; | ||
893 | while (protocols[num_protocols].number != PORT100_IN_PROT_END) | ||
894 | num_protocols++; | ||
895 | |||
896 | if (!num_protocols) | ||
897 | return 0; | ||
898 | |||
899 | size = sizeof(struct port100_protocol) * num_protocols; | ||
900 | |||
901 | skb = port100_alloc_skb(dev, size); | ||
902 | if (!skb) | ||
903 | return -ENOMEM; | ||
904 | |||
905 | memcpy(skb_put(skb, size), protocols, size); | ||
906 | |||
907 | resp = port100_send_cmd_sync(dev, PORT100_CMD_IN_SET_PROTOCOL, skb); | ||
908 | |||
909 | if (IS_ERR(resp)) | ||
910 | return PTR_ERR(resp); | ||
911 | |||
912 | rc = resp->data[0]; | ||
913 | |||
914 | dev_kfree_skb(resp); | ||
915 | |||
916 | return rc; | ||
630 | } | 917 | } |
631 | 918 | ||
632 | static int port100_in_configure_hw(struct nfc_digital_dev *ddev, int type, | 919 | static int port100_in_configure_hw(struct nfc_digital_dev *ddev, int type, |
633 | int param) | 920 | int param) |
634 | { | 921 | { |
635 | return -EOPNOTSUPP; | 922 | if (type == NFC_DIGITAL_CONFIG_RF_TECH) |
923 | return port100_in_set_rf(ddev, param); | ||
924 | |||
925 | if (type == NFC_DIGITAL_CONFIG_FRAMING) | ||
926 | return port100_in_set_framing(ddev, param); | ||
927 | |||
928 | return -EINVAL; | ||
929 | } | ||
930 | |||
931 | static void port100_in_comm_rf_complete(struct port100 *dev, void *arg, | ||
932 | struct sk_buff *resp) | ||
933 | { | ||
934 | struct port100_cb_arg *cb_arg = arg; | ||
935 | nfc_digital_cmd_complete_t cb = cb_arg->complete_cb; | ||
936 | u32 status; | ||
937 | int rc; | ||
938 | |||
939 | if (IS_ERR(resp)) { | ||
940 | rc = PTR_ERR(resp); | ||
941 | goto exit; | ||
942 | } | ||
943 | |||
944 | if (resp->len < 4) { | ||
945 | nfc_err(&dev->interface->dev, | ||
946 | "Invalid packet length received.\n"); | ||
947 | rc = -EIO; | ||
948 | goto error; | ||
949 | } | ||
950 | |||
951 | status = le32_to_cpu(*(__le32 *)resp->data); | ||
952 | |||
953 | skb_pull(resp, sizeof(u32)); | ||
954 | |||
955 | if (status == PORT100_CMD_STATUS_TIMEOUT) { | ||
956 | rc = -ETIMEDOUT; | ||
957 | goto error; | ||
958 | } | ||
959 | |||
960 | if (status != PORT100_CMD_STATUS_OK) { | ||
961 | nfc_err(&dev->interface->dev, | ||
962 | "in_comm_rf failed with status 0x%08x\n", status); | ||
963 | rc = -EIO; | ||
964 | goto error; | ||
965 | } | ||
966 | |||
967 | /* Remove collision bits byte */ | ||
968 | skb_pull(resp, 1); | ||
969 | |||
970 | goto exit; | ||
971 | |||
972 | error: | ||
973 | kfree_skb(resp); | ||
974 | resp = ERR_PTR(rc); | ||
975 | |||
976 | exit: | ||
977 | cb(dev->nfc_digital_dev, cb_arg->complete_arg, resp); | ||
978 | |||
979 | kfree(cb_arg); | ||
636 | } | 980 | } |
637 | 981 | ||
638 | static int port100_in_send_cmd(struct nfc_digital_dev *ddev, | 982 | static int port100_in_send_cmd(struct nfc_digital_dev *ddev, |
639 | struct sk_buff *skb, u16 _timeout, | 983 | struct sk_buff *skb, u16 _timeout, |
640 | nfc_digital_cmd_complete_t cb, void *arg) | 984 | nfc_digital_cmd_complete_t cb, void *arg) |
641 | { | 985 | { |
642 | return -EOPNOTSUPP; | 986 | struct port100 *dev = nfc_digital_get_drvdata(ddev); |
987 | struct port100_cb_arg *cb_arg; | ||
988 | __le16 timeout; | ||
989 | |||
990 | cb_arg = kzalloc(sizeof(struct port100_cb_arg), GFP_KERNEL); | ||
991 | if (!cb_arg) | ||
992 | return -ENOMEM; | ||
993 | |||
994 | cb_arg->complete_cb = cb; | ||
995 | cb_arg->complete_arg = arg; | ||
996 | |||
997 | timeout = cpu_to_le16(_timeout * 10); | ||
998 | |||
999 | memcpy(skb_push(skb, sizeof(__le16)), &timeout, sizeof(__le16)); | ||
1000 | |||
1001 | return port100_send_cmd_async(dev, PORT100_CMD_IN_COMM_RF, skb, | ||
1002 | port100_in_comm_rf_complete, cb_arg); | ||
643 | } | 1003 | } |
644 | 1004 | ||
645 | static int port100_tg_configure_hw(struct nfc_digital_dev *ddev, int type, | 1005 | static int port100_tg_configure_hw(struct nfc_digital_dev *ddev, int type, |