Commit | Line | Data |
---|---|---|
903ac63f | 1 | // SPDX-License-Identifier: GPL-2.0 |
086959e6 | 2 | /* |
e61c7a1c AS |
3 | * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. |
4 | * All rights reserved. | |
086959e6 GE |
5 | */ |
6 | ||
43a76229 | 7 | #include <linux/spi/spi.h> |
c5c77ba1 | 8 | |
9c800322 | 9 | #include "wilc_wfi_netdevice.h" |
9bc061e8 | 10 | #include "wilc_wfi_cfgoperations.h" |
c5c77ba1 | 11 | |
6a707a9e | 12 | struct wilc_spi { |
c5c77ba1 JK |
13 | int crc_off; |
14 | int nint; | |
15 | int has_thrpt_enh; | |
6a707a9e | 16 | }; |
c5c77ba1 | 17 | |
68a30a63 | 18 | static const struct wilc_hif_func wilc_hif_spi; |
c5c77ba1 | 19 | |
c5c77ba1 JK |
20 | /******************************************** |
21 | * | |
22 | * Crc7 | |
23 | * | |
24 | ********************************************/ | |
25 | ||
51e825f7 | 26 | static const u8 crc7_syndrome_table[256] = { |
c5c77ba1 JK |
27 | 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, |
28 | 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, | |
29 | 0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26, | |
30 | 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e, | |
31 | 0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d, | |
32 | 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45, | |
33 | 0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14, | |
34 | 0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c, | |
35 | 0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b, | |
36 | 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13, | |
37 | 0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42, | |
38 | 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a, | |
39 | 0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69, | |
40 | 0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21, | |
41 | 0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70, | |
42 | 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38, | |
43 | 0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e, | |
44 | 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36, | |
45 | 0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67, | |
46 | 0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f, | |
47 | 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, | |
48 | 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, | |
49 | 0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55, | |
50 | 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d, | |
51 | 0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a, | |
52 | 0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52, | |
53 | 0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03, | |
54 | 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b, | |
55 | 0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28, | |
56 | 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60, | |
57 | 0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31, | |
58 | 0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79 | |
59 | }; | |
60 | ||
51e825f7 | 61 | static u8 crc7_byte(u8 crc, u8 data) |
c5c77ba1 JK |
62 | { |
63 | return crc7_syndrome_table[(crc << 1) ^ data]; | |
64 | } | |
65 | ||
fbc2fe16 | 66 | static u8 crc7(u8 crc, const u8 *buffer, u32 len) |
c5c77ba1 JK |
67 | { |
68 | while (len--) | |
69 | crc = crc7_byte(crc, *buffer++); | |
70 | return crc; | |
71 | } | |
72 | ||
73 | /******************************************** | |
74 | * | |
75 | * Spi protocol Function | |
76 | * | |
77 | ********************************************/ | |
78 | ||
79 | #define CMD_DMA_WRITE 0xc1 | |
80 | #define CMD_DMA_READ 0xc2 | |
1e194027 AS |
81 | #define CMD_INTERNAL_WRITE 0xc3 |
82 | #define CMD_INTERNAL_READ 0xc4 | |
c5c77ba1 | 83 | #define CMD_TERMINATE 0xc5 |
1e194027 AS |
84 | #define CMD_REPEAT 0xc6 |
85 | #define CMD_DMA_EXT_WRITE 0xc7 | |
86 | #define CMD_DMA_EXT_READ 0xc8 | |
c5c77ba1 | 87 | #define CMD_SINGLE_WRITE 0xc9 |
1e194027 AS |
88 | #define CMD_SINGLE_READ 0xca |
89 | #define CMD_RESET 0xcf | |
c5c77ba1 | 90 | |
1e194027 AS |
91 | #define N_OK 1 |
92 | #define N_FAIL 0 | |
93 | #define N_RESET -1 | |
94 | #define N_RETRY -2 | |
c5c77ba1 JK |
95 | |
96 | #define DATA_PKT_SZ_256 256 | |
1e194027 | 97 | #define DATA_PKT_SZ_512 512 |
c5c77ba1 JK |
98 | #define DATA_PKT_SZ_1K 1024 |
99 | #define DATA_PKT_SZ_4K (4 * 1024) | |
100 | #define DATA_PKT_SZ_8K (8 * 1024) | |
1e194027 | 101 | #define DATA_PKT_SZ DATA_PKT_SZ_8K |
c5c77ba1 | 102 | |
1e194027 | 103 | #define USE_SPI_DMA 0 |
43a76229 | 104 | |
43a76229 GL |
105 | static int wilc_bus_probe(struct spi_device *spi) |
106 | { | |
367b9559 | 107 | int ret; |
43a76229 | 108 | struct wilc *wilc; |
367b9559 | 109 | struct gpio_desc *gpio; |
110f4b75 AS |
110 | struct wilc_spi *spi_priv; |
111 | ||
112 | spi_priv = kzalloc(sizeof(*spi_priv), GFP_KERNEL); | |
113 | if (!spi_priv) | |
114 | return -ENOMEM; | |
43a76229 | 115 | |
367b9559 AS |
116 | gpio = gpiod_get(&spi->dev, "irq", GPIOD_IN); |
117 | if (IS_ERR(gpio)) { | |
118 | /* get the GPIO descriptor from hardcode GPIO number */ | |
119 | gpio = gpio_to_desc(GPIO_NUM); | |
120 | if (!gpio) | |
121 | dev_err(&spi->dev, "failed to get the irq gpio\n"); | |
122 | } | |
43a76229 | 123 | |
9bc061e8 | 124 | ret = wilc_cfg80211_init(&wilc, &spi->dev, WILC_HIF_SPI, &wilc_hif_spi); |
110f4b75 AS |
125 | if (ret) { |
126 | kfree(spi_priv); | |
43a76229 | 127 | return ret; |
110f4b75 | 128 | } |
43a76229 GL |
129 | |
130 | spi_set_drvdata(spi, wilc); | |
131 | wilc->dev = &spi->dev; | |
110f4b75 | 132 | wilc->bus_data = spi_priv; |
4b6cfa87 | 133 | wilc->gpio_irq = gpio; |
43a76229 GL |
134 | |
135 | return 0; | |
136 | } | |
137 | ||
138 | static int wilc_bus_remove(struct spi_device *spi) | |
139 | { | |
367b9559 AS |
140 | struct wilc *wilc = spi_get_drvdata(spi); |
141 | ||
142 | /* free the GPIO in module remove */ | |
143 | if (wilc->gpio_irq) | |
144 | gpiod_put(wilc->gpio_irq); | |
145 | wilc_netdev_cleanup(wilc); | |
43a76229 GL |
146 | return 0; |
147 | } | |
148 | ||
8dfaf859 AS |
149 | static const struct of_device_id wilc_of_match[] = { |
150 | { .compatible = "microchip,wilc1000-spi", }, | |
151 | { /* sentinel */ } | |
43a76229 | 152 | }; |
8dfaf859 | 153 | MODULE_DEVICE_TABLE(of, wilc_of_match); |
43a76229 | 154 | |
8dfaf859 | 155 | static struct spi_driver wilc_spi_driver = { |
43a76229 GL |
156 | .driver = { |
157 | .name = MODALIAS, | |
8dfaf859 | 158 | .of_match_table = wilc_of_match, |
43a76229 GL |
159 | }, |
160 | .probe = wilc_bus_probe, | |
161 | .remove = wilc_bus_remove, | |
162 | }; | |
8dfaf859 | 163 | module_spi_driver(wilc_spi_driver); |
43a76229 GL |
164 | MODULE_LICENSE("GPL"); |
165 | ||
166 | static int wilc_spi_tx(struct wilc *wilc, u8 *b, u32 len) | |
167 | { | |
168 | struct spi_device *spi = to_spi_device(wilc->dev); | |
169 | int ret; | |
170 | struct spi_message msg; | |
171 | ||
172 | if (len > 0 && b) { | |
173 | struct spi_transfer tr = { | |
174 | .tx_buf = b, | |
175 | .len = len, | |
176 | .delay_usecs = 0, | |
177 | }; | |
178 | char *r_buffer = kzalloc(len, GFP_KERNEL); | |
179 | ||
180 | if (!r_buffer) | |
181 | return -ENOMEM; | |
182 | ||
183 | tr.rx_buf = r_buffer; | |
184 | dev_dbg(&spi->dev, "Request writing %d bytes\n", len); | |
185 | ||
186 | memset(&msg, 0, sizeof(msg)); | |
187 | spi_message_init(&msg); | |
188 | msg.spi = spi; | |
189 | msg.is_dma_mapped = USE_SPI_DMA; | |
190 | spi_message_add_tail(&tr, &msg); | |
191 | ||
192 | ret = spi_sync(spi, &msg); | |
193 | if (ret < 0) | |
194 | dev_err(&spi->dev, "SPI transaction failed\n"); | |
195 | ||
196 | kfree(r_buffer); | |
197 | } else { | |
198 | dev_err(&spi->dev, | |
199 | "can't write data with the following length: %d\n", | |
200 | len); | |
43a76229 GL |
201 | ret = -EINVAL; |
202 | } | |
203 | ||
204 | return ret; | |
205 | } | |
206 | ||
207 | static int wilc_spi_rx(struct wilc *wilc, u8 *rb, u32 rlen) | |
208 | { | |
209 | struct spi_device *spi = to_spi_device(wilc->dev); | |
210 | int ret; | |
211 | ||
212 | if (rlen > 0) { | |
213 | struct spi_message msg; | |
214 | struct spi_transfer tr = { | |
215 | .rx_buf = rb, | |
216 | .len = rlen, | |
217 | .delay_usecs = 0, | |
218 | ||
219 | }; | |
220 | char *t_buffer = kzalloc(rlen, GFP_KERNEL); | |
221 | ||
222 | if (!t_buffer) | |
223 | return -ENOMEM; | |
224 | ||
225 | tr.tx_buf = t_buffer; | |
226 | ||
227 | memset(&msg, 0, sizeof(msg)); | |
228 | spi_message_init(&msg); | |
229 | msg.spi = spi; | |
230 | msg.is_dma_mapped = USE_SPI_DMA; | |
231 | spi_message_add_tail(&tr, &msg); | |
232 | ||
233 | ret = spi_sync(spi, &msg); | |
234 | if (ret < 0) | |
235 | dev_err(&spi->dev, "SPI transaction failed\n"); | |
236 | kfree(t_buffer); | |
237 | } else { | |
238 | dev_err(&spi->dev, | |
239 | "can't read data with the following length: %u\n", | |
240 | rlen); | |
241 | ret = -EINVAL; | |
242 | } | |
243 | ||
244 | return ret; | |
245 | } | |
246 | ||
247 | static int wilc_spi_tx_rx(struct wilc *wilc, u8 *wb, u8 *rb, u32 rlen) | |
248 | { | |
249 | struct spi_device *spi = to_spi_device(wilc->dev); | |
250 | int ret; | |
251 | ||
252 | if (rlen > 0) { | |
253 | struct spi_message msg; | |
254 | struct spi_transfer tr = { | |
255 | .rx_buf = rb, | |
256 | .tx_buf = wb, | |
257 | .len = rlen, | |
258 | .bits_per_word = 8, | |
259 | .delay_usecs = 0, | |
260 | ||
261 | }; | |
262 | ||
263 | memset(&msg, 0, sizeof(msg)); | |
264 | spi_message_init(&msg); | |
265 | msg.spi = spi; | |
266 | msg.is_dma_mapped = USE_SPI_DMA; | |
267 | ||
268 | spi_message_add_tail(&tr, &msg); | |
269 | ret = spi_sync(spi, &msg); | |
270 | if (ret < 0) | |
271 | dev_err(&spi->dev, "SPI transaction failed\n"); | |
272 | } else { | |
273 | dev_err(&spi->dev, | |
274 | "can't read data with the following length: %u\n", | |
275 | rlen); | |
276 | ret = -EINVAL; | |
277 | } | |
278 | ||
279 | return ret; | |
280 | } | |
281 | ||
49dcd0dd GL |
282 | static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz, |
283 | u8 clockless) | |
c5c77ba1 | 284 | { |
ac1da162 | 285 | struct spi_device *spi = to_spi_device(wilc->dev); |
110f4b75 | 286 | struct wilc_spi *spi_priv = wilc->bus_data; |
51e825f7 CL |
287 | u8 wb[32], rb[32]; |
288 | u8 wix, rix; | |
fbc2fe16 | 289 | u32 len2; |
51e825f7 | 290 | u8 rsp; |
c5c77ba1 JK |
291 | int len = 0; |
292 | int result = N_OK; | |
169ed7ee AS |
293 | int retry; |
294 | u8 crc[2]; | |
c5c77ba1 JK |
295 | |
296 | wb[0] = cmd; | |
297 | switch (cmd) { | |
169ed7ee | 298 | case CMD_SINGLE_READ: /* single word (4 bytes) read */ |
51e825f7 CL |
299 | wb[1] = (u8)(adr >> 16); |
300 | wb[2] = (u8)(adr >> 8); | |
301 | wb[3] = (u8)adr; | |
c5c77ba1 JK |
302 | len = 5; |
303 | break; | |
304 | ||
169ed7ee | 305 | case CMD_INTERNAL_READ: /* internal register read */ |
51e825f7 | 306 | wb[1] = (u8)(adr >> 8); |
c5c77ba1 | 307 | if (clockless == 1) |
ffda203c | 308 | wb[1] |= BIT(7); |
51e825f7 | 309 | wb[2] = (u8)adr; |
c5c77ba1 JK |
310 | wb[3] = 0x00; |
311 | len = 5; | |
312 | break; | |
313 | ||
169ed7ee | 314 | case CMD_TERMINATE: |
c5c77ba1 JK |
315 | wb[1] = 0x00; |
316 | wb[2] = 0x00; | |
317 | wb[3] = 0x00; | |
318 | len = 5; | |
319 | break; | |
320 | ||
169ed7ee | 321 | case CMD_REPEAT: |
c5c77ba1 JK |
322 | wb[1] = 0x00; |
323 | wb[2] = 0x00; | |
324 | wb[3] = 0x00; | |
325 | len = 5; | |
326 | break; | |
327 | ||
169ed7ee | 328 | case CMD_RESET: |
c5c77ba1 JK |
329 | wb[1] = 0xff; |
330 | wb[2] = 0xff; | |
331 | wb[3] = 0xff; | |
332 | len = 5; | |
333 | break; | |
334 | ||
169ed7ee AS |
335 | case CMD_DMA_WRITE: /* dma write */ |
336 | case CMD_DMA_READ: /* dma read */ | |
51e825f7 CL |
337 | wb[1] = (u8)(adr >> 16); |
338 | wb[2] = (u8)(adr >> 8); | |
339 | wb[3] = (u8)adr; | |
340 | wb[4] = (u8)(sz >> 8); | |
341 | wb[5] = (u8)(sz); | |
c5c77ba1 JK |
342 | len = 7; |
343 | break; | |
344 | ||
169ed7ee AS |
345 | case CMD_DMA_EXT_WRITE: /* dma extended write */ |
346 | case CMD_DMA_EXT_READ: /* dma extended read */ | |
51e825f7 CL |
347 | wb[1] = (u8)(adr >> 16); |
348 | wb[2] = (u8)(adr >> 8); | |
349 | wb[3] = (u8)adr; | |
350 | wb[4] = (u8)(sz >> 16); | |
351 | wb[5] = (u8)(sz >> 8); | |
352 | wb[6] = (u8)(sz); | |
c5c77ba1 JK |
353 | len = 8; |
354 | break; | |
355 | ||
169ed7ee | 356 | case CMD_INTERNAL_WRITE: /* internal register write */ |
51e825f7 | 357 | wb[1] = (u8)(adr >> 8); |
c5c77ba1 | 358 | if (clockless == 1) |
ffda203c | 359 | wb[1] |= BIT(7); |
51e825f7 | 360 | wb[2] = (u8)(adr); |
c5c77ba1 JK |
361 | wb[3] = b[3]; |
362 | wb[4] = b[2]; | |
363 | wb[5] = b[1]; | |
364 | wb[6] = b[0]; | |
365 | len = 8; | |
366 | break; | |
367 | ||
169ed7ee | 368 | case CMD_SINGLE_WRITE: /* single word write */ |
51e825f7 CL |
369 | wb[1] = (u8)(adr >> 16); |
370 | wb[2] = (u8)(adr >> 8); | |
371 | wb[3] = (u8)(adr); | |
c5c77ba1 JK |
372 | wb[4] = b[3]; |
373 | wb[5] = b[2]; | |
374 | wb[6] = b[1]; | |
375 | wb[7] = b[0]; | |
376 | len = 9; | |
377 | break; | |
378 | ||
379 | default: | |
380 | result = N_FAIL; | |
381 | break; | |
382 | } | |
383 | ||
e0a30008 | 384 | if (result != N_OK) |
c5c77ba1 | 385 | return result; |
c5c77ba1 | 386 | |
110f4b75 | 387 | if (!spi_priv->crc_off) |
51e825f7 | 388 | wb[len - 1] = (crc7(0x7f, (const u8 *)&wb[0], len - 1)) << 1; |
78174ada | 389 | else |
c5c77ba1 | 390 | len -= 1; |
c5c77ba1 JK |
391 | |
392 | #define NUM_SKIP_BYTES (1) | |
393 | #define NUM_RSP_BYTES (2) | |
394 | #define NUM_DATA_HDR_BYTES (1) | |
395 | #define NUM_DATA_BYTES (4) | |
396 | #define NUM_CRC_BYTES (2) | |
397 | #define NUM_DUMMY_BYTES (3) | |
7bf0242a AS |
398 | if (cmd == CMD_RESET || |
399 | cmd == CMD_TERMINATE || | |
400 | cmd == CMD_REPEAT) { | |
c5c77ba1 | 401 | len2 = len + (NUM_SKIP_BYTES + NUM_RSP_BYTES + NUM_DUMMY_BYTES); |
7bf0242a | 402 | } else if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ) { |
169ed7ee AS |
403 | int tmp = NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES |
404 | + NUM_DUMMY_BYTES; | |
110f4b75 | 405 | if (!spi_priv->crc_off) |
169ed7ee AS |
406 | len2 = len + tmp + NUM_CRC_BYTES; |
407 | else | |
408 | len2 = len + tmp; | |
c5c77ba1 JK |
409 | } else { |
410 | len2 = len + (NUM_RSP_BYTES + NUM_DUMMY_BYTES); | |
411 | } | |
412 | #undef NUM_DUMMY_BYTES | |
413 | ||
5cc59d29 | 414 | if (len2 > ARRAY_SIZE(wb)) { |
ac1da162 | 415 | dev_err(&spi->dev, "spi buffer size too small (%d) (%zu)\n", |
27f2d03e | 416 | len2, ARRAY_SIZE(wb)); |
d37843d1 | 417 | return N_FAIL; |
c5c77ba1 JK |
418 | } |
419 | /* zero spi write buffers. */ | |
e0a30008 | 420 | for (wix = len; wix < len2; wix++) |
c5c77ba1 | 421 | wb[wix] = 0; |
c5c77ba1 JK |
422 | rix = len; |
423 | ||
d4312b6f | 424 | if (wilc_spi_tx_rx(wilc, wb, rb, len2)) { |
ac1da162 | 425 | dev_err(&spi->dev, "Failed cmd write, bus error...\n"); |
8244d269 | 426 | return N_FAIL; |
c5c77ba1 JK |
427 | } |
428 | ||
00c2903b | 429 | /* |
c5c77ba1 | 430 | * Command/Control response |
00c2903b | 431 | */ |
169ed7ee AS |
432 | if (cmd == CMD_RESET || cmd == CMD_TERMINATE || cmd == CMD_REPEAT) |
433 | rix++; /* skip 1 byte */ | |
c5c77ba1 | 434 | |
c5c77ba1 | 435 | rsp = rb[rix++]; |
c5c77ba1 JK |
436 | |
437 | if (rsp != cmd) { | |
8779bf84 AJ |
438 | dev_err(&spi->dev, |
439 | "Failed cmd response, cmd (%02x), resp (%02x)\n", | |
440 | cmd, rsp); | |
8244d269 | 441 | return N_FAIL; |
c5c77ba1 JK |
442 | } |
443 | ||
00c2903b | 444 | /* |
c5c77ba1 | 445 | * State response |
00c2903b | 446 | */ |
c5c77ba1 JK |
447 | rsp = rb[rix++]; |
448 | if (rsp != 0x00) { | |
ac1da162 GL |
449 | dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", |
450 | rsp); | |
8244d269 | 451 | return N_FAIL; |
c5c77ba1 JK |
452 | } |
453 | ||
7bf0242a AS |
454 | if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ || |
455 | cmd == CMD_DMA_READ || cmd == CMD_DMA_EXT_READ) { | |
00c2903b | 456 | /* |
c5c77ba1 | 457 | * Data Respnose header |
00c2903b | 458 | */ |
c5c77ba1 JK |
459 | retry = 100; |
460 | do { | |
00c2903b AS |
461 | /* |
462 | * ensure there is room in buffer later | |
463 | * to read data and crc | |
464 | */ | |
c5c77ba1 JK |
465 | if (rix < len2) { |
466 | rsp = rb[rix++]; | |
467 | } else { | |
468 | retry = 0; | |
469 | break; | |
470 | } | |
471 | if (((rsp >> 4) & 0xf) == 0xf) | |
472 | break; | |
473 | } while (retry--); | |
474 | ||
475 | if (retry <= 0) { | |
ac1da162 GL |
476 | dev_err(&spi->dev, |
477 | "Error, data read response (%02x)\n", rsp); | |
8244d269 | 478 | return N_RESET; |
c5c77ba1 | 479 | } |
169ed7ee AS |
480 | } |
481 | ||
482 | if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ) { | |
483 | /* | |
484 | * Read bytes | |
485 | */ | |
486 | if ((rix + 3) < len2) { | |
487 | b[0] = rb[rix++]; | |
488 | b[1] = rb[rix++]; | |
489 | b[2] = rb[rix++]; | |
490 | b[3] = rb[rix++]; | |
491 | } else { | |
492 | dev_err(&spi->dev, | |
493 | "buffer overrun when reading data.\n"); | |
494 | return N_FAIL; | |
495 | } | |
c5c77ba1 | 496 | |
110f4b75 | 497 | if (!spi_priv->crc_off) { |
00c2903b | 498 | /* |
169ed7ee | 499 | * Read Crc |
00c2903b | 500 | */ |
169ed7ee AS |
501 | if ((rix + 1) < len2) { |
502 | crc[0] = rb[rix++]; | |
503 | crc[1] = rb[rix++]; | |
c5c77ba1 | 504 | } else { |
ac1da162 | 505 | dev_err(&spi->dev, |
169ed7ee | 506 | "buffer overrun when reading crc.\n"); |
8244d269 | 507 | return N_FAIL; |
c5c77ba1 | 508 | } |
169ed7ee AS |
509 | } |
510 | } else if ((cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) { | |
511 | int ix; | |
c5c77ba1 | 512 | |
169ed7ee AS |
513 | /* some data may be read in response to dummy bytes. */ |
514 | for (ix = 0; (rix < len2) && (ix < sz); ) | |
515 | b[ix++] = rb[rix++]; | |
c5c77ba1 | 516 | |
169ed7ee | 517 | sz -= ix; |
61500fbd | 518 | |
169ed7ee AS |
519 | if (sz > 0) { |
520 | int nbytes; | |
c5c77ba1 | 521 | |
169ed7ee AS |
522 | if (sz <= (DATA_PKT_SZ - ix)) |
523 | nbytes = sz; | |
524 | else | |
525 | nbytes = DATA_PKT_SZ - ix; | |
c5c77ba1 | 526 | |
169ed7ee AS |
527 | /* |
528 | * Read bytes | |
529 | */ | |
530 | if (wilc_spi_rx(wilc, &b[ix], nbytes)) { | |
531 | dev_err(&spi->dev, | |
532 | "Failed block read, bus err\n"); | |
e0f2e9ce | 533 | return N_FAIL; |
169ed7ee | 534 | } |
c5c77ba1 | 535 | |
169ed7ee AS |
536 | /* |
537 | * Read Crc | |
538 | */ | |
110f4b75 | 539 | if (!spi_priv->crc_off && wilc_spi_rx(wilc, crc, 2)) { |
169ed7ee AS |
540 | dev_err(&spi->dev, |
541 | "Failed block crc read, bus err\n"); | |
e0f2e9ce | 542 | return N_FAIL; |
169ed7ee | 543 | } |
c5c77ba1 | 544 | |
169ed7ee AS |
545 | ix += nbytes; |
546 | sz -= nbytes; | |
547 | } | |
c5c77ba1 | 548 | |
169ed7ee AS |
549 | /* |
550 | * if any data in left unread, | |
551 | * then read the rest using normal DMA code. | |
552 | */ | |
553 | while (sz > 0) { | |
554 | int nbytes; | |
555 | ||
556 | if (sz <= DATA_PKT_SZ) | |
557 | nbytes = sz; | |
558 | else | |
559 | nbytes = DATA_PKT_SZ; | |
c5c77ba1 | 560 | |
00c2903b | 561 | /* |
169ed7ee AS |
562 | * read data response only on the next DMA cycles not |
563 | * the first DMA since data response header is already | |
564 | * handled above for the first DMA. | |
00c2903b | 565 | */ |
169ed7ee AS |
566 | /* |
567 | * Data Respnose header | |
568 | */ | |
569 | retry = 10; | |
570 | do { | |
571 | if (wilc_spi_rx(wilc, &rsp, 1)) { | |
572 | dev_err(&spi->dev, | |
573 | "Failed resp read, bus err\n"); | |
c5c77ba1 JK |
574 | result = N_FAIL; |
575 | break; | |
576 | } | |
169ed7ee AS |
577 | if (((rsp >> 4) & 0xf) == 0xf) |
578 | break; | |
579 | } while (retry--); | |
c5c77ba1 | 580 | |
169ed7ee AS |
581 | if (result == N_FAIL) |
582 | break; | |
583 | ||
584 | /* | |
585 | * Read bytes | |
586 | */ | |
587 | if (wilc_spi_rx(wilc, &b[ix], nbytes)) { | |
588 | dev_err(&spi->dev, | |
589 | "Failed block read, bus err\n"); | |
590 | result = N_FAIL; | |
591 | break; | |
592 | } | |
c5c77ba1 | 593 | |
169ed7ee AS |
594 | /* |
595 | * Read Crc | |
596 | */ | |
110f4b75 | 597 | if (!spi_priv->crc_off && wilc_spi_rx(wilc, crc, 2)) { |
169ed7ee AS |
598 | dev_err(&spi->dev, |
599 | "Failed block crc read, bus err\n"); | |
600 | result = N_FAIL; | |
601 | break; | |
c5c77ba1 | 602 | } |
169ed7ee AS |
603 | |
604 | ix += nbytes; | |
605 | sz -= nbytes; | |
c5c77ba1 JK |
606 | } |
607 | } | |
c5c77ba1 JK |
608 | return result; |
609 | } | |
610 | ||
49dcd0dd | 611 | static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz) |
c5c77ba1 | 612 | { |
ac1da162 | 613 | struct spi_device *spi = to_spi_device(wilc->dev); |
110f4b75 | 614 | struct wilc_spi *spi_priv = wilc->bus_data; |
c5c77ba1 JK |
615 | int ix, nbytes; |
616 | int result = 1; | |
51e825f7 | 617 | u8 cmd, order, crc[2] = {0}; |
c5c77ba1 | 618 | |
00c2903b AS |
619 | /* |
620 | * Data | |
621 | */ | |
c5c77ba1 JK |
622 | ix = 0; |
623 | do { | |
eaa5f7be | 624 | if (sz <= DATA_PKT_SZ) { |
c5c77ba1 | 625 | nbytes = sz; |
eaa5f7be AS |
626 | order = 0x3; |
627 | } else { | |
c5c77ba1 | 628 | nbytes = DATA_PKT_SZ; |
eaa5f7be AS |
629 | if (ix == 0) |
630 | order = 0x1; | |
631 | else | |
632 | order = 0x02; | |
633 | } | |
c5c77ba1 | 634 | |
00c2903b AS |
635 | /* |
636 | * Write command | |
637 | */ | |
c5c77ba1 | 638 | cmd = 0xf0; |
c5c77ba1 | 639 | cmd |= order; |
eaa5f7be | 640 | |
d4312b6f | 641 | if (wilc_spi_tx(wilc, &cmd, 1)) { |
ac1da162 GL |
642 | dev_err(&spi->dev, |
643 | "Failed data block cmd write, bus error...\n"); | |
c5c77ba1 JK |
644 | result = N_FAIL; |
645 | break; | |
646 | } | |
647 | ||
00c2903b AS |
648 | /* |
649 | * Write data | |
650 | */ | |
d4312b6f | 651 | if (wilc_spi_tx(wilc, &b[ix], nbytes)) { |
ac1da162 GL |
652 | dev_err(&spi->dev, |
653 | "Failed data block write, bus error...\n"); | |
c5c77ba1 JK |
654 | result = N_FAIL; |
655 | break; | |
656 | } | |
657 | ||
00c2903b AS |
658 | /* |
659 | * Write Crc | |
660 | */ | |
110f4b75 | 661 | if (!spi_priv->crc_off) { |
d4312b6f | 662 | if (wilc_spi_tx(wilc, crc, 2)) { |
5142a14e | 663 | dev_err(&spi->dev, "Failed data block crc write, bus error...\n"); |
c5c77ba1 JK |
664 | result = N_FAIL; |
665 | break; | |
666 | } | |
667 | } | |
668 | ||
00c2903b AS |
669 | /* |
670 | * No need to wait for response | |
671 | */ | |
c5c77ba1 JK |
672 | ix += nbytes; |
673 | sz -= nbytes; | |
674 | } while (sz); | |
675 | ||
c5c77ba1 JK |
676 | return result; |
677 | } | |
678 | ||
679 | /******************************************** | |
680 | * | |
681 | * Spi Internal Read/Write Function | |
682 | * | |
683 | ********************************************/ | |
684 | ||
49dcd0dd | 685 | static int spi_internal_write(struct wilc *wilc, u32 adr, u32 dat) |
c5c77ba1 | 686 | { |
ac1da162 | 687 | struct spi_device *spi = to_spi_device(wilc->dev); |
c5c77ba1 JK |
688 | int result; |
689 | ||
02211edc | 690 | cpu_to_le32s(&dat); |
49dcd0dd GL |
691 | result = spi_cmd_complete(wilc, CMD_INTERNAL_WRITE, adr, (u8 *)&dat, 4, |
692 | 0); | |
e0a30008 | 693 | if (result != N_OK) |
ac1da162 | 694 | dev_err(&spi->dev, "Failed internal write cmd...\n"); |
c5c77ba1 | 695 | |
c5c77ba1 JK |
696 | return result; |
697 | } | |
698 | ||
49dcd0dd | 699 | static int spi_internal_read(struct wilc *wilc, u32 adr, u32 *data) |
c5c77ba1 | 700 | { |
ac1da162 | 701 | struct spi_device *spi = to_spi_device(wilc->dev); |
c5c77ba1 JK |
702 | int result; |
703 | ||
49dcd0dd GL |
704 | result = spi_cmd_complete(wilc, CMD_INTERNAL_READ, adr, (u8 *)data, 4, |
705 | 0); | |
c5c77ba1 | 706 | if (result != N_OK) { |
ac1da162 | 707 | dev_err(&spi->dev, "Failed internal read cmd...\n"); |
c5c77ba1 JK |
708 | return 0; |
709 | } | |
c5c77ba1 | 710 | |
3f285135 | 711 | le32_to_cpus(data); |
c5c77ba1 JK |
712 | |
713 | return 1; | |
714 | } | |
715 | ||
716 | /******************************************** | |
717 | * | |
718 | * Spi interfaces | |
719 | * | |
720 | ********************************************/ | |
721 | ||
49dcd0dd | 722 | static int wilc_spi_write_reg(struct wilc *wilc, u32 addr, u32 data) |
c5c77ba1 | 723 | { |
ac1da162 | 724 | struct spi_device *spi = to_spi_device(wilc->dev); |
c5c77ba1 | 725 | int result = N_OK; |
51e825f7 CL |
726 | u8 cmd = CMD_SINGLE_WRITE; |
727 | u8 clockless = 0; | |
c5c77ba1 | 728 | |
02211edc | 729 | cpu_to_le32s(&data); |
c5c77ba1 | 730 | if (addr < 0x30) { |
00c2903b | 731 | /* Clockless register */ |
c5c77ba1 JK |
732 | cmd = CMD_INTERNAL_WRITE; |
733 | clockless = 1; | |
734 | } | |
735 | ||
49dcd0dd | 736 | result = spi_cmd_complete(wilc, cmd, addr, (u8 *)&data, 4, clockless); |
e0a30008 | 737 | if (result != N_OK) |
ac1da162 | 738 | dev_err(&spi->dev, "Failed cmd, write reg (%08x)...\n", addr); |
c5c77ba1 JK |
739 | |
740 | return result; | |
c5c77ba1 JK |
741 | } |
742 | ||
d4312b6f | 743 | static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) |
c5c77ba1 | 744 | { |
ac1da162 | 745 | struct spi_device *spi = to_spi_device(wilc->dev); |
c5c77ba1 | 746 | int result; |
c5c77ba1 | 747 | |
00c2903b AS |
748 | /* |
749 | * has to be greated than 4 | |
750 | */ | |
c5c77ba1 JK |
751 | if (size <= 4) |
752 | return 0; | |
753 | ||
ad8cab74 | 754 | result = spi_cmd_complete(wilc, CMD_DMA_EXT_WRITE, addr, NULL, size, 0); |
c5c77ba1 | 755 | if (result != N_OK) { |
ac1da162 GL |
756 | dev_err(&spi->dev, |
757 | "Failed cmd, write block (%08x)...\n", addr); | |
c5c77ba1 JK |
758 | return 0; |
759 | } | |
c5c77ba1 | 760 | |
00c2903b AS |
761 | /* |
762 | * Data | |
763 | */ | |
49dcd0dd | 764 | result = spi_data_write(wilc, buf, size); |
e0a30008 | 765 | if (result != N_OK) |
ac1da162 | 766 | dev_err(&spi->dev, "Failed block data write...\n"); |
c5c77ba1 JK |
767 | |
768 | return 1; | |
769 | } | |
770 | ||
49dcd0dd | 771 | static int wilc_spi_read_reg(struct wilc *wilc, u32 addr, u32 *data) |
c5c77ba1 | 772 | { |
ac1da162 | 773 | struct spi_device *spi = to_spi_device(wilc->dev); |
c5c77ba1 | 774 | int result = N_OK; |
51e825f7 CL |
775 | u8 cmd = CMD_SINGLE_READ; |
776 | u8 clockless = 0; | |
c5c77ba1 | 777 | |
c5c77ba1 | 778 | if (addr < 0x30) { |
00c2903b | 779 | /* Clockless register */ |
c5c77ba1 JK |
780 | cmd = CMD_INTERNAL_READ; |
781 | clockless = 1; | |
782 | } | |
783 | ||
49dcd0dd | 784 | result = spi_cmd_complete(wilc, cmd, addr, (u8 *)data, 4, clockless); |
c5c77ba1 | 785 | if (result != N_OK) { |
ac1da162 | 786 | dev_err(&spi->dev, "Failed cmd, read reg (%08x)...\n", addr); |
c5c77ba1 JK |
787 | return 0; |
788 | } | |
c5c77ba1 | 789 | |
3f285135 | 790 | le32_to_cpus(data); |
c5c77ba1 JK |
791 | |
792 | return 1; | |
793 | } | |
794 | ||
d4312b6f | 795 | static int wilc_spi_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size) |
c5c77ba1 | 796 | { |
ac1da162 | 797 | struct spi_device *spi = to_spi_device(wilc->dev); |
c5c77ba1 JK |
798 | int result; |
799 | ||
800 | if (size <= 4) | |
801 | return 0; | |
802 | ||
ad8cab74 | 803 | result = spi_cmd_complete(wilc, CMD_DMA_EXT_READ, addr, buf, size, 0); |
c5c77ba1 | 804 | if (result != N_OK) { |
ac1da162 | 805 | dev_err(&spi->dev, "Failed cmd, read block (%08x)...\n", addr); |
c5c77ba1 JK |
806 | return 0; |
807 | } | |
c5c77ba1 JK |
808 | |
809 | return 1; | |
810 | } | |
811 | ||
812 | /******************************************** | |
813 | * | |
814 | * Bus interfaces | |
815 | * | |
816 | ********************************************/ | |
817 | ||
f5436ede | 818 | static int wilc_spi_deinit(struct wilc *wilc) |
c5c77ba1 | 819 | { |
00c2903b AS |
820 | /* |
821 | * TODO: | |
822 | */ | |
c5c77ba1 JK |
823 | return 1; |
824 | } | |
825 | ||
5397cbc2 | 826 | static int wilc_spi_init(struct wilc *wilc, bool resume) |
c5c77ba1 | 827 | { |
ac1da162 | 828 | struct spi_device *spi = to_spi_device(wilc->dev); |
110f4b75 | 829 | struct wilc_spi *spi_priv = wilc->bus_data; |
fbc2fe16 CL |
830 | u32 reg; |
831 | u32 chipid; | |
c5c77ba1 JK |
832 | static int isinit; |
833 | ||
834 | if (isinit) { | |
49dcd0dd | 835 | if (!wilc_spi_read_reg(wilc, 0x1000, &chipid)) { |
ac1da162 | 836 | dev_err(&spi->dev, "Fail cmd read chip id...\n"); |
c5c77ba1 JK |
837 | return 0; |
838 | } | |
839 | return 1; | |
840 | } | |
841 | ||
00c2903b AS |
842 | /* |
843 | * configure protocol | |
844 | */ | |
c5c77ba1 | 845 | |
00c2903b AS |
846 | /* |
847 | * TODO: We can remove the CRC trials if there is a definite | |
848 | * way to reset | |
849 | */ | |
c5c77ba1 | 850 | /* the SPI to it's initial value. */ |
49dcd0dd | 851 | if (!spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, ®)) { |
00c2903b AS |
852 | /* |
853 | * Read failed. Try with CRC off. This might happen when module | |
10426351 EL |
854 | * is removed but chip isn't reset |
855 | */ | |
110f4b75 | 856 | spi_priv->crc_off = 1; |
c73f5950 AS |
857 | dev_err(&spi->dev, |
858 | "Failed read with CRC on, retrying with CRC off\n"); | |
49dcd0dd | 859 | if (!spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, ®)) { |
c73f5950 AS |
860 | /* |
861 | * Read failed with both CRC on and off, | |
862 | * something went bad | |
863 | */ | |
864 | dev_err(&spi->dev, "Failed internal read protocol\n"); | |
c5c77ba1 JK |
865 | return 0; |
866 | } | |
867 | } | |
110f4b75 | 868 | if (spi_priv->crc_off == 0) { |
00c2903b | 869 | reg &= ~0xc; /* disable crc checking */ |
c5c77ba1 JK |
870 | reg &= ~0x70; |
871 | reg |= (0x5 << 4); | |
49dcd0dd | 872 | if (!spi_internal_write(wilc, WILC_SPI_PROTOCOL_OFFSET, reg)) { |
c73f5950 AS |
873 | dev_err(&spi->dev, |
874 | "[wilc spi %d]: Failed internal write reg\n", | |
875 | __LINE__); | |
c5c77ba1 JK |
876 | return 0; |
877 | } | |
110f4b75 | 878 | spi_priv->crc_off = 1; |
c5c77ba1 JK |
879 | } |
880 | ||
00c2903b AS |
881 | /* |
882 | * make sure can read back chip id correctly | |
883 | */ | |
49dcd0dd | 884 | if (!wilc_spi_read_reg(wilc, 0x1000, &chipid)) { |
ac1da162 | 885 | dev_err(&spi->dev, "Fail cmd read chip id...\n"); |
c5c77ba1 JK |
886 | return 0; |
887 | } | |
c5c77ba1 | 888 | |
110f4b75 | 889 | spi_priv->has_thrpt_enh = 1; |
c5c77ba1 JK |
890 | |
891 | isinit = 1; | |
892 | ||
893 | return 1; | |
894 | } | |
895 | ||
49dcd0dd | 896 | static int wilc_spi_read_size(struct wilc *wilc, u32 *size) |
c5c77ba1 | 897 | { |
ac1da162 | 898 | struct spi_device *spi = to_spi_device(wilc->dev); |
110f4b75 | 899 | struct wilc_spi *spi_priv = wilc->bus_data; |
c5c77ba1 | 900 | int ret; |
8dfaafd6 | 901 | |
110f4b75 | 902 | if (spi_priv->has_thrpt_enh) { |
49dcd0dd GL |
903 | ret = spi_internal_read(wilc, 0xe840 - WILC_SPI_REG_BASE, |
904 | size); | |
c5c77ba1 JK |
905 | *size = *size & IRQ_DMA_WD_CNT_MASK; |
906 | } else { | |
fbc2fe16 CL |
907 | u32 tmp; |
908 | u32 byte_cnt; | |
c5c77ba1 | 909 | |
49dcd0dd GL |
910 | ret = wilc_spi_read_reg(wilc, WILC_VMM_TO_HOST_SIZE, |
911 | &byte_cnt); | |
c5c77ba1 | 912 | if (!ret) { |
ac1da162 GL |
913 | dev_err(&spi->dev, |
914 | "Failed read WILC_VMM_TO_HOST_SIZE ...\n"); | |
a7d355f3 | 915 | return ret; |
c5c77ba1 JK |
916 | } |
917 | tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK; | |
918 | *size = tmp; | |
919 | } | |
920 | ||
c5c77ba1 JK |
921 | return ret; |
922 | } | |
923 | ||
49dcd0dd | 924 | static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status) |
c5c77ba1 | 925 | { |
ac1da162 | 926 | struct spi_device *spi = to_spi_device(wilc->dev); |
110f4b75 | 927 | struct wilc_spi *spi_priv = wilc->bus_data; |
c5c77ba1 | 928 | int ret; |
5844e42c TD |
929 | u32 tmp; |
930 | u32 byte_cnt; | |
6bbb77a8 MS |
931 | bool unexpected_irq; |
932 | int j; | |
5844e42c TD |
933 | u32 unknown_mask; |
934 | u32 irq_flags; | |
12ec07a4 | 935 | int k = IRG_FLAGS_OFFSET + 5; |
8dfaafd6 | 936 | |
283a9e4b ND |
937 | if (spi_priv->has_thrpt_enh) |
938 | return spi_internal_read(wilc, 0xe840 - WILC_SPI_REG_BASE, | |
939 | int_status); | |
12ec07a4 AS |
940 | ret = wilc_spi_read_reg(wilc, WILC_VMM_TO_HOST_SIZE, &byte_cnt); |
941 | if (!ret) { | |
942 | dev_err(&spi->dev, | |
943 | "Failed read WILC_VMM_TO_HOST_SIZE ...\n"); | |
b417dcd7 | 944 | return ret; |
12ec07a4 AS |
945 | } |
946 | tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK; | |
c5c77ba1 | 947 | |
12ec07a4 AS |
948 | j = 0; |
949 | do { | |
12ec07a4 AS |
950 | wilc_spi_read_reg(wilc, 0x1a90, &irq_flags); |
951 | tmp |= ((irq_flags >> 27) << IRG_FLAGS_OFFSET); | |
c5c77ba1 | 952 | |
110f4b75 | 953 | if (spi_priv->nint > 5) { |
12ec07a4 AS |
954 | wilc_spi_read_reg(wilc, 0x1a94, &irq_flags); |
955 | tmp |= (((irq_flags >> 0) & 0x7) << k); | |
956 | } | |
0e8af100 | 957 | |
110f4b75 | 958 | unknown_mask = ~((1ul << spi_priv->nint) - 1); |
0e8af100 | 959 | |
6bbb77a8 MS |
960 | unexpected_irq = (tmp >> IRG_FLAGS_OFFSET) & unknown_mask; |
961 | if (unexpected_irq) { | |
12ec07a4 AS |
962 | dev_err(&spi->dev, |
963 | "Unexpected interrupt(2):j=%d,tmp=%x,mask=%x\n", | |
964 | j, tmp, unknown_mask); | |
12ec07a4 | 965 | } |
0e8af100 | 966 | |
12ec07a4 | 967 | j++; |
6bbb77a8 | 968 | } while (unexpected_irq); |
c5c77ba1 | 969 | |
12ec07a4 | 970 | *int_status = tmp; |
c5c77ba1 | 971 | |
c5c77ba1 JK |
972 | return ret; |
973 | } | |
974 | ||
49dcd0dd | 975 | static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val) |
c5c77ba1 | 976 | { |
ac1da162 | 977 | struct spi_device *spi = to_spi_device(wilc->dev); |
110f4b75 | 978 | struct wilc_spi *spi_priv = wilc->bus_data; |
c5c77ba1 | 979 | int ret; |
773b4869 AS |
980 | u32 flags; |
981 | u32 tbl_ctl; | |
c5c77ba1 | 982 | |
110f4b75 | 983 | if (spi_priv->has_thrpt_enh) { |
283a9e4b ND |
984 | return spi_internal_write(wilc, 0xe844 - WILC_SPI_REG_BASE, |
985 | val); | |
773b4869 AS |
986 | } |
987 | ||
988 | flags = val & (BIT(MAX_NUM_INT) - 1); | |
989 | if (flags) { | |
990 | int i; | |
991 | ||
992 | ret = 1; | |
110f4b75 | 993 | for (i = 0; i < spi_priv->nint; i++) { |
773b4869 AS |
994 | /* |
995 | * No matter what you write 1 or 0, | |
996 | * it will clear interrupt. | |
997 | */ | |
998 | if (flags & 1) | |
999 | ret = wilc_spi_write_reg(wilc, | |
1000 | 0x10c8 + i * 4, 1); | |
1001 | if (!ret) | |
1002 | break; | |
1003 | flags >>= 1; | |
1004 | } | |
1005 | if (!ret) { | |
1006 | dev_err(&spi->dev, | |
1007 | "Failed wilc_spi_write_reg, set reg %x ...\n", | |
1008 | 0x10c8 + i * 4); | |
a448f658 | 1009 | return ret; |
773b4869 | 1010 | } |
110f4b75 | 1011 | for (i = spi_priv->nint; i < MAX_NUM_INT; i++) { |
773b4869 | 1012 | if (flags & 1) |
ac1da162 | 1013 | dev_err(&spi->dev, |
773b4869 AS |
1014 | "Unexpected interrupt cleared %d...\n", |
1015 | i); | |
1016 | flags >>= 1; | |
c5c77ba1 | 1017 | } |
773b4869 | 1018 | } |
c5c77ba1 | 1019 | |
773b4869 AS |
1020 | tbl_ctl = 0; |
1021 | /* select VMM table 0 */ | |
bb87c84c | 1022 | if (val & SEL_VMM_TBL0) |
773b4869 AS |
1023 | tbl_ctl |= BIT(0); |
1024 | /* select VMM table 1 */ | |
bb87c84c | 1025 | if (val & SEL_VMM_TBL1) |
773b4869 | 1026 | tbl_ctl |= BIT(1); |
c5c77ba1 | 1027 | |
773b4869 AS |
1028 | ret = wilc_spi_write_reg(wilc, WILC_VMM_TBL_CTL, tbl_ctl); |
1029 | if (!ret) { | |
1030 | dev_err(&spi->dev, "fail write reg vmm_tbl_ctl...\n"); | |
a448f658 | 1031 | return ret; |
773b4869 | 1032 | } |
c5c77ba1 | 1033 | |
bb87c84c | 1034 | if (val & EN_VMM) { |
773b4869 AS |
1035 | /* |
1036 | * enable vmm transfer. | |
1037 | */ | |
1038 | ret = wilc_spi_write_reg(wilc, WILC_VMM_CORE_CTL, 1); | |
1039 | if (!ret) { | |
1040 | dev_err(&spi->dev, "fail write reg vmm_core_ctl...\n"); | |
a448f658 | 1041 | return ret; |
c5c77ba1 JK |
1042 | } |
1043 | } | |
a448f658 | 1044 | |
c5c77ba1 JK |
1045 | return ret; |
1046 | } | |
1047 | ||
49dcd0dd | 1048 | static int wilc_spi_sync_ext(struct wilc *wilc, int nint) |
c5c77ba1 | 1049 | { |
ac1da162 | 1050 | struct spi_device *spi = to_spi_device(wilc->dev); |
110f4b75 | 1051 | struct wilc_spi *spi_priv = wilc->bus_data; |
fbc2fe16 | 1052 | u32 reg; |
c5c77ba1 JK |
1053 | int ret, i; |
1054 | ||
1055 | if (nint > MAX_NUM_INT) { | |
95b8cb89 | 1056 | dev_err(&spi->dev, "Too many interrupts (%d)...\n", nint); |
c5c77ba1 JK |
1057 | return 0; |
1058 | } | |
1059 | ||
110f4b75 | 1060 | spi_priv->nint = nint; |
c5c77ba1 | 1061 | |
00c2903b AS |
1062 | /* |
1063 | * interrupt pin mux select | |
1064 | */ | |
49dcd0dd | 1065 | ret = wilc_spi_read_reg(wilc, WILC_PIN_MUX_0, ®); |
c5c77ba1 | 1066 | if (!ret) { |
ac1da162 GL |
1067 | dev_err(&spi->dev, "Failed read reg (%08x)...\n", |
1068 | WILC_PIN_MUX_0); | |
c5c77ba1 JK |
1069 | return 0; |
1070 | } | |
ffda203c | 1071 | reg |= BIT(8); |
49dcd0dd | 1072 | ret = wilc_spi_write_reg(wilc, WILC_PIN_MUX_0, reg); |
c5c77ba1 | 1073 | if (!ret) { |
ac1da162 GL |
1074 | dev_err(&spi->dev, "Failed write reg (%08x)...\n", |
1075 | WILC_PIN_MUX_0); | |
c5c77ba1 JK |
1076 | return 0; |
1077 | } | |
1078 | ||
00c2903b AS |
1079 | /* |
1080 | * interrupt enable | |
1081 | */ | |
49dcd0dd | 1082 | ret = wilc_spi_read_reg(wilc, WILC_INTR_ENABLE, ®); |
c5c77ba1 | 1083 | if (!ret) { |
ac1da162 GL |
1084 | dev_err(&spi->dev, "Failed read reg (%08x)...\n", |
1085 | WILC_INTR_ENABLE); | |
c5c77ba1 JK |
1086 | return 0; |
1087 | } | |
1088 | ||
e0a30008 | 1089 | for (i = 0; (i < 5) && (nint > 0); i++, nint--) |
ffda203c | 1090 | reg |= (BIT((27 + i))); |
e0a30008 | 1091 | |
49dcd0dd | 1092 | ret = wilc_spi_write_reg(wilc, WILC_INTR_ENABLE, reg); |
c5c77ba1 | 1093 | if (!ret) { |
ac1da162 GL |
1094 | dev_err(&spi->dev, "Failed write reg (%08x)...\n", |
1095 | WILC_INTR_ENABLE); | |
c5c77ba1 JK |
1096 | return 0; |
1097 | } | |
1098 | if (nint) { | |
49dcd0dd | 1099 | ret = wilc_spi_read_reg(wilc, WILC_INTR2_ENABLE, ®); |
c5c77ba1 | 1100 | if (!ret) { |
ac1da162 GL |
1101 | dev_err(&spi->dev, "Failed read reg (%08x)...\n", |
1102 | WILC_INTR2_ENABLE); | |
c5c77ba1 JK |
1103 | return 0; |
1104 | } | |
1105 | ||
e0a30008 | 1106 | for (i = 0; (i < 3) && (nint > 0); i++, nint--) |
ffda203c | 1107 | reg |= BIT(i); |
c5c77ba1 | 1108 | |
49dcd0dd | 1109 | ret = wilc_spi_read_reg(wilc, WILC_INTR2_ENABLE, ®); |
c5c77ba1 | 1110 | if (!ret) { |
ac1da162 GL |
1111 | dev_err(&spi->dev, "Failed write reg (%08x)...\n", |
1112 | WILC_INTR2_ENABLE); | |
c5c77ba1 JK |
1113 | return 0; |
1114 | } | |
1115 | } | |
1116 | ||
1117 | return 1; | |
1118 | } | |
6847fc05 GE |
1119 | |
1120 | /* Global spi HIF function table */ | |
68a30a63 | 1121 | static const struct wilc_hif_func wilc_hif_spi = { |
2769d942 | 1122 | .hif_init = wilc_spi_init, |
f5436ede | 1123 | .hif_deinit = wilc_spi_deinit, |
7d37a4a1 AB |
1124 | .hif_read_reg = wilc_spi_read_reg, |
1125 | .hif_write_reg = wilc_spi_write_reg, | |
d4312b6f GL |
1126 | .hif_block_rx = wilc_spi_read, |
1127 | .hif_block_tx = wilc_spi_write, | |
7d37a4a1 AB |
1128 | .hif_read_int = wilc_spi_read_int, |
1129 | .hif_clear_int_ext = wilc_spi_clear_int_ext, | |
1130 | .hif_read_size = wilc_spi_read_size, | |
d4312b6f GL |
1131 | .hif_block_tx_ext = wilc_spi_write, |
1132 | .hif_block_rx_ext = wilc_spi_read, | |
7d37a4a1 | 1133 | .hif_sync_ext = wilc_spi_sync_ext, |
c5c77ba1 | 1134 | }; |