blob: 5a18148a593e3f2b6416138b6fee4a95bc6b78cc [file] [log] [blame]
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001/* ////////////////////////////////////////////////////////////////////////// */
2/* */
3/* Copyright (c) Atmel Corporation. All rights reserved. */
4/* */
5/* Module Name: wilc_sdio.c */
6/* */
7/* */
8/* //////////////////////////////////////////////////////////////////////////// */
9
10#include "wilc_wlan_if.h"
11#include "wilc_wlan.h"
12
Tony Cho229d7402015-07-28 17:47:26 +090013#define WILC_SDIO_BLOCK_SIZE 512
Johnny Kimc5c77ba2015-05-11 14:30:56 +090014
15typedef struct {
16 void *os_context;
17 wilc_wlan_os_func_t os_func;
18 uint32_t block_size;
19 int (*sdio_cmd52)(sdio_cmd52_t *);
20 int (*sdio_cmd53)(sdio_cmd53_t *);
21 int (*sdio_set_max_speed)(void);
22 int (*sdio_set_default_speed)(void);
23 wilc_debug_func dPrint;
24 int nint;
25#define MAX_NUN_INT_THRPT_ENH2 (5) /* Max num interrupts allowed in registers 0xf7, 0xf8 */
26 int has_thrpt_enh3;
27} wilc_sdio_t;
28
29static wilc_sdio_t g_sdio;
30
31#ifdef WILC_SDIO_IRQ_GPIO
32static int sdio_write_reg(uint32_t addr, uint32_t data);
33static int sdio_read_reg(uint32_t addr, uint32_t *data);
34#endif
35extern unsigned int int_clrd;
36
37/********************************************
38 *
39 * Function 0
40 *
41 ********************************************/
42
43static int sdio_set_func0_csa_address(uint32_t adr)
44{
45 sdio_cmd52_t cmd;
46
47 /**
48 * Review: BIG ENDIAN
49 **/
50 cmd.read_write = 1;
51 cmd.function = 0;
52 cmd.raw = 0;
53 cmd.address = 0x10c;
54 cmd.data = (uint8_t)adr;
55 if (!g_sdio.sdio_cmd52(&cmd)) {
56 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10c data...\n");
57 goto _fail_;
58 }
59
60 cmd.address = 0x10d;
61 cmd.data = (uint8_t)(adr >> 8);
62 if (!g_sdio.sdio_cmd52(&cmd)) {
63 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10d data...\n");
64 goto _fail_;
65 }
66
67 cmd.address = 0x10e;
68 cmd.data = (uint8_t)(adr >> 16);
69 if (!g_sdio.sdio_cmd52(&cmd)) {
70 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10e data...\n");
71 goto _fail_;
72 }
73
74 return 1;
75_fail_:
76 return 0;
77}
78
79static int sdio_set_func0_csa_address_byte0(uint32_t adr)
80{
81 sdio_cmd52_t cmd;
82
Johnny Kimc5c77ba2015-05-11 14:30:56 +090083 /**
84 * Review: BIG ENDIAN
85 **/
86 cmd.read_write = 1;
87 cmd.function = 0;
88 cmd.raw = 0;
89 cmd.address = 0x10c;
90 cmd.data = (uint8_t)adr;
91 if (!g_sdio.sdio_cmd52(&cmd)) {
92 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10c data...\n");
93 goto _fail_;
94 }
95
96 return 1;
97_fail_:
98 return 0;
99}
Tony Cho4aa857722015-07-28 17:47:25 +0900100
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900101static int sdio_set_func0_block_size(uint32_t block_size)
102{
103 sdio_cmd52_t cmd;
104
105 cmd.read_write = 1;
106 cmd.function = 0;
107 cmd.raw = 0;
108 cmd.address = 0x10;
109 cmd.data = (uint8_t)block_size;
110 if (!g_sdio.sdio_cmd52(&cmd)) {
111 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10 data...\n");
112 goto _fail_;
113 }
114
115 cmd.address = 0x11;
116 cmd.data = (uint8_t)(block_size >> 8);
117 if (!g_sdio.sdio_cmd52(&cmd)) {
118 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x11 data...\n");
119 goto _fail_;
120 }
121
122 return 1;
123_fail_:
124 return 0;
125}
126
127/********************************************
128 *
129 * Function 1
130 *
131 ********************************************/
132
133static int sdio_set_func1_block_size(uint32_t block_size)
134{
135 sdio_cmd52_t cmd;
136
137 cmd.read_write = 1;
138 cmd.function = 0;
139 cmd.raw = 0;
140 cmd.address = 0x110;
141 cmd.data = (uint8_t)block_size;
142 if (!g_sdio.sdio_cmd52(&cmd)) {
143 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x110 data...\n");
144 goto _fail_;
145 }
146 cmd.address = 0x111;
147 cmd.data = (uint8_t)(block_size >> 8);
148 if (!g_sdio.sdio_cmd52(&cmd)) {
149 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x111 data...\n");
150 goto _fail_;
151 }
152
153 return 1;
154_fail_:
155 return 0;
156}
157
158static int sdio_clear_int(void)
159{
160#ifndef WILC_SDIO_IRQ_GPIO
161 /* uint32_t sts; */
162 sdio_cmd52_t cmd;
Tony Cho9c844692015-07-28 17:47:24 +0900163
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900164 cmd.read_write = 0;
165 cmd.function = 1;
166 cmd.raw = 0;
167 cmd.address = 0x4;
168 cmd.data = 0;
169 g_sdio.sdio_cmd52(&cmd);
170 int_clrd++;
171
172 return cmd.data;
173#else
174 uint32_t reg;
Tony Cho9c844692015-07-28 17:47:24 +0900175
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900176 if (!sdio_read_reg(WILC_HOST_RX_CTRL_0, &reg)) {
177 g_sdio.dPrint(N_ERR, "[wilc spi]: Failed read reg (%08x)...\n", WILC_HOST_RX_CTRL_0);
178 return 0;
179 }
180 reg &= ~0x1;
181 sdio_write_reg(WILC_HOST_RX_CTRL_0, reg);
182 int_clrd++;
183 return 1;
184#endif
185
186}
187
188uint32_t sdio_xfer_cnt(void)
189{
190 uint32_t cnt = 0;
191 sdio_cmd52_t cmd;
Tony Cho9c844692015-07-28 17:47:24 +0900192
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900193 cmd.read_write = 0;
194 cmd.function = 1;
195 cmd.raw = 0;
196 cmd.address = 0x1C;
197 cmd.data = 0;
198 g_sdio.sdio_cmd52(&cmd);
199 cnt = cmd.data;
200
201 cmd.read_write = 0;
202 cmd.function = 1;
203 cmd.raw = 0;
204 cmd.address = 0x1D;
205 cmd.data = 0;
206 g_sdio.sdio_cmd52(&cmd);
207 cnt |= (cmd.data << 8);
208
209 cmd.read_write = 0;
210 cmd.function = 1;
211 cmd.raw = 0;
212 cmd.address = 0x1E;
213 cmd.data = 0;
214 g_sdio.sdio_cmd52(&cmd);
215 cnt |= (cmd.data << 16);
216
217 return cnt;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900218}
219
220/********************************************
221 *
222 * Sdio interfaces
223 *
224 ********************************************/
225int sdio_check_bs(void)
226{
227 sdio_cmd52_t cmd;
228
229 /**
230 * poll until BS is 0
231 **/
232 cmd.read_write = 0;
233 cmd.function = 0;
234 cmd.raw = 0;
235 cmd.address = 0xc;
236 cmd.data = 0;
237 if (!g_sdio.sdio_cmd52(&cmd)) {
238 g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, get BS register...\n");
239 goto _fail_;
240 }
241
242 return 1;
243
244_fail_:
245
246 return 0;
247}
248
249static int sdio_write_reg(uint32_t addr, uint32_t data)
250{
251#ifdef BIG_ENDIAN
252 data = BYTE_SWAP(data);
253#endif
254
255 if ((addr >= 0xf0) && (addr <= 0xff)) {
256 sdio_cmd52_t cmd;
Tony Cho9c844692015-07-28 17:47:24 +0900257
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900258 cmd.read_write = 1;
259 cmd.function = 0;
260 cmd.raw = 0;
261 cmd.address = addr;
262 cmd.data = data;
263 if (!g_sdio.sdio_cmd52(&cmd)) {
264 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd 52, read reg (%08x) ...\n", addr);
265 goto _fail_;
266 }
267 } else {
268 sdio_cmd53_t cmd;
269
270 /**
271 * set the AHB address
272 **/
273 if (!sdio_set_func0_csa_address(addr))
274 goto _fail_;
275
276 cmd.read_write = 1;
277 cmd.function = 0;
278 cmd.address = 0x10f;
279 cmd.block_mode = 0;
280 cmd.increment = 1;
281 cmd.count = 4;
282 cmd.buffer = (uint8_t *)&data;
283 cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */
284
285 if (!g_sdio.sdio_cmd53(&cmd)) {
286 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53, write reg (%08x)...\n", addr);
287 goto _fail_;
288 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900289 }
290
291 return 1;
292
293_fail_:
294
295 return 0;
296}
297
298static int sdio_write(uint32_t addr, uint8_t *buf, uint32_t size)
299{
300 uint32_t block_size = g_sdio.block_size;
301 sdio_cmd53_t cmd;
302 int nblk, nleft;
303
304 cmd.read_write = 1;
305 if (addr > 0) {
306 /**
307 * has to be word aligned...
308 **/
309 if (size & 0x3) {
310 size += 4;
311 size &= ~0x3;
312 }
313
314 /**
315 * func 0 access
316 **/
317 cmd.function = 0;
318 cmd.address = 0x10f;
319 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900320 /**
321 * has to be word aligned...
322 **/
323 if (size & 0x3) {
324 size += 4;
325 size &= ~0x3;
326 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900327
328 /**
329 * func 1 access
330 **/
331 cmd.function = 1;
332 cmd.address = 0;
333 }
334
335 nblk = size / block_size;
336 nleft = size % block_size;
337
338 if (nblk > 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900339 cmd.block_mode = 1;
340 cmd.increment = 1;
341 cmd.count = nblk;
342 cmd.buffer = buf;
343 cmd.block_size = block_size;
344 if (addr > 0) {
345 if (!sdio_set_func0_csa_address(addr))
346 goto _fail_;
347 }
348 if (!g_sdio.sdio_cmd53(&cmd)) {
349 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block send...\n", addr);
350 goto _fail_;
351 }
352 if (addr > 0)
353 addr += nblk * block_size;
354 buf += nblk * block_size;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900355 }
356
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900357 if (nleft > 0) {
358 cmd.block_mode = 0;
359 cmd.increment = 1;
360 cmd.count = nleft;
361 cmd.buffer = buf;
362
363 cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */
364
365 if (addr > 0) {
366 if (!sdio_set_func0_csa_address(addr))
367 goto _fail_;
368 }
369 if (!g_sdio.sdio_cmd53(&cmd)) {
370 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], bytes send...\n", addr);
371 goto _fail_;
372 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900373 }
374
375 return 1;
376
377_fail_:
378
379 return 0;
380}
381
382static int sdio_read_reg(uint32_t addr, uint32_t *data)
383{
384 if ((addr >= 0xf0) && (addr <= 0xff)) {
385 sdio_cmd52_t cmd;
Tony Cho9c844692015-07-28 17:47:24 +0900386
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900387 cmd.read_write = 0;
388 cmd.function = 0;
389 cmd.raw = 0;
390 cmd.address = addr;
391 if (!g_sdio.sdio_cmd52(&cmd)) {
392 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd 52, read reg (%08x) ...\n", addr);
393 goto _fail_;
394 }
395 *data = cmd.data;
396 } else {
397 sdio_cmd53_t cmd;
398
399 if (!sdio_set_func0_csa_address(addr))
400 goto _fail_;
401
402 cmd.read_write = 0;
403 cmd.function = 0;
404 cmd.address = 0x10f;
405 cmd.block_mode = 0;
406 cmd.increment = 1;
407 cmd.count = 4;
408 cmd.buffer = (uint8_t *)data;
409
410 cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */
411
412 if (!g_sdio.sdio_cmd53(&cmd)) {
413 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53, read reg (%08x)...\n", addr);
414 goto _fail_;
415 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900416 }
417
418#ifdef BIG_ENDIAN
419 *data = BYTE_SWAP(*data);
420#endif
421
422 return 1;
423
424_fail_:
425
426 return 0;
427}
428
429static int sdio_read(uint32_t addr, uint8_t *buf, uint32_t size)
430{
431 uint32_t block_size = g_sdio.block_size;
432 sdio_cmd53_t cmd;
433 int nblk, nleft;
434
435 cmd.read_write = 0;
436 if (addr > 0) {
437 /**
438 * has to be word aligned...
439 **/
440 if (size & 0x3) {
441 size += 4;
442 size &= ~0x3;
443 }
444
445 /**
446 * func 0 access
447 **/
448 cmd.function = 0;
449 cmd.address = 0x10f;
450 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900451 /**
452 * has to be word aligned...
453 **/
454 if (size & 0x3) {
455 size += 4;
456 size &= ~0x3;
457 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900458
459 /**
460 * func 1 access
461 **/
462 cmd.function = 1;
463 cmd.address = 0;
464 }
465
466 nblk = size / block_size;
467 nleft = size % block_size;
468
469 if (nblk > 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900470 cmd.block_mode = 1;
471 cmd.increment = 1;
472 cmd.count = nblk;
473 cmd.buffer = buf;
474 cmd.block_size = block_size;
475 if (addr > 0) {
476 if (!sdio_set_func0_csa_address(addr))
477 goto _fail_;
478 }
479 if (!g_sdio.sdio_cmd53(&cmd)) {
480 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block read...\n", addr);
481 goto _fail_;
482 }
483 if (addr > 0)
484 addr += nblk * block_size;
485 buf += nblk * block_size;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900486 } /* if (nblk > 0) */
487
488 if (nleft > 0) {
489 cmd.block_mode = 0;
490 cmd.increment = 1;
491 cmd.count = nleft;
492 cmd.buffer = buf;
493
494 cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */
495
496 if (addr > 0) {
497 if (!sdio_set_func0_csa_address(addr))
498 goto _fail_;
499 }
500 if (!g_sdio.sdio_cmd53(&cmd)) {
501 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], bytes read...\n", addr);
502 goto _fail_;
503 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900504 }
505
506 return 1;
507
508_fail_:
509
510 return 0;
511}
512
513/********************************************
514 *
515 * Bus interfaces
516 *
517 ********************************************/
518
519static int sdio_deinit(void *pv)
520{
521 return 1;
522}
523
524static int sdio_sync(void)
525{
526 uint32_t reg;
527
528 /**
529 * Disable power sequencer
530 **/
531 if (!sdio_read_reg(WILC_MISC, &reg)) {
532 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read misc reg...\n");
533 return 0;
534 }
535
536 reg &= ~(1 << 8);
537 if (!sdio_write_reg(WILC_MISC, reg)) {
538 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write misc reg...\n");
539 return 0;
540 }
541
542#ifdef WILC_SDIO_IRQ_GPIO
543 {
544 uint32_t reg;
545 int ret;
546
547 /**
548 * interrupt pin mux select
549 **/
550 ret = sdio_read_reg(WILC_PIN_MUX_0, &reg);
551 if (!ret) {
552 g_sdio.dPrint(N_ERR, "[wilc spi]: Failed read reg (%08x)...\n", WILC_PIN_MUX_0);
553 return 0;
554 }
555 reg |= (1 << 8);
556 ret = sdio_write_reg(WILC_PIN_MUX_0, reg);
557 if (!ret) {
558 g_sdio.dPrint(N_ERR, "[wilc spi]: Failed write reg (%08x)...\n", WILC_PIN_MUX_0);
559 return 0;
560 }
561
562 /**
563 * interrupt enable
564 **/
565 ret = sdio_read_reg(WILC_INTR_ENABLE, &reg);
566 if (!ret) {
567 g_sdio.dPrint(N_ERR, "[wilc spi]: Failed read reg (%08x)...\n", WILC_INTR_ENABLE);
568 return 0;
569 }
570 reg |= (1 << 16);
571 ret = sdio_write_reg(WILC_INTR_ENABLE, reg);
572 if (!ret) {
573 g_sdio.dPrint(N_ERR, "[wilc spi]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE);
574 return 0;
575 }
576 }
577#endif
578
579 return 1;
580}
581
582static int sdio_init(wilc_wlan_inp_t *inp, wilc_debug_func func)
583{
584 sdio_cmd52_t cmd;
585 int loop;
586 uint32_t chipid;
Tony Cho9c844692015-07-28 17:47:24 +0900587
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900588 memset(&g_sdio, 0, sizeof(wilc_sdio_t));
589
590 g_sdio.dPrint = func;
591 g_sdio.os_context = inp->os_context.os_private;
592 memcpy((void *)&g_sdio.os_func, (void *)&inp->os_func, sizeof(wilc_wlan_os_func_t));
593
594 if (inp->io_func.io_init) {
595 if (!inp->io_func.io_init(g_sdio.os_context)) {
596 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed io init bus...\n");
597 return 0;
598 }
599 } else {
600 return 0;
601 }
602
603 g_sdio.sdio_cmd52 = inp->io_func.u.sdio.sdio_cmd52;
604 g_sdio.sdio_cmd53 = inp->io_func.u.sdio.sdio_cmd53;
605 g_sdio.sdio_set_max_speed = inp->io_func.u.sdio.sdio_set_max_speed;
606 g_sdio.sdio_set_default_speed = inp->io_func.u.sdio.sdio_set_default_speed;
607
608 /**
609 * function 0 csa enable
610 **/
611 cmd.read_write = 1;
612 cmd.function = 0;
613 cmd.raw = 1;
614 cmd.address = 0x100;
615 cmd.data = 0x80;
616 if (!g_sdio.sdio_cmd52(&cmd)) {
617 g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, enable csa...\n");
618 goto _fail_;
619 }
620
621 /**
622 * function 0 block size
623 **/
624 if (!sdio_set_func0_block_size(WILC_SDIO_BLOCK_SIZE)) {
625 g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, set func 0 block size...\n");
626 goto _fail_;
627 }
628 g_sdio.block_size = WILC_SDIO_BLOCK_SIZE;
629
630 /**
631 * enable func1 IO
632 **/
633 cmd.read_write = 1;
634 cmd.function = 0;
635 cmd.raw = 1;
636 cmd.address = 0x2;
637 cmd.data = 0x2;
638 if (!g_sdio.sdio_cmd52(&cmd)) {
639 g_sdio.dPrint(N_ERR, "[wilc sdio] Fail cmd 52, set IOE register...\n");
640 goto _fail_;
641 }
642
643 /**
644 * make sure func 1 is up
645 **/
646 cmd.read_write = 0;
647 cmd.function = 0;
648 cmd.raw = 0;
649 cmd.address = 0x3;
650 loop = 3;
651 do {
652 cmd.data = 0;
653 if (!g_sdio.sdio_cmd52(&cmd)) {
654 g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, get IOR register...\n");
655 goto _fail_;
656 }
657 if (cmd.data == 0x2)
658 break;
659 } while (loop--);
660
661 if (loop <= 0) {
662 g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail func 1 is not ready...\n");
663 goto _fail_;
664 }
665
666 /**
667 * func 1 is ready, set func 1 block size
668 **/
669 if (!sdio_set_func1_block_size(WILC_SDIO_BLOCK_SIZE)) {
670 g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail set func 1 block size...\n");
671 goto _fail_;
672 }
673
674 /**
675 * func 1 interrupt enable
676 **/
677 cmd.read_write = 1;
678 cmd.function = 0;
679 cmd.raw = 1;
680 cmd.address = 0x4;
681 cmd.data = 0x3;
682 if (!g_sdio.sdio_cmd52(&cmd)) {
683 g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, set IEN register...\n");
684 goto _fail_;
685 }
686
687 /**
688 * make sure can read back chip id correctly
689 **/
690 if (!sdio_read_reg(0x1000, &chipid)) {
691 g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd read chip id...\n");
692 goto _fail_;
693 }
694 g_sdio.dPrint(N_ERR, "[wilc sdio]: chipid (%08x)\n", chipid);
Tony Choa0261e02015-07-28 17:47:33 +0900695 if ((chipid & 0xfff) > 0x2a0)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900696 g_sdio.has_thrpt_enh3 = 1;
Tony Choa0261e02015-07-28 17:47:33 +0900697 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900698 g_sdio.has_thrpt_enh3 = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900699 g_sdio.dPrint(N_ERR, "[wilc sdio]: has_thrpt_enh3 = %d...\n", g_sdio.has_thrpt_enh3);
700
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900701 return 1;
702
703_fail_:
704
705 return 0;
706}
707
708static void sdio_set_max_speed(void)
709{
710 g_sdio.sdio_set_max_speed();
711}
712
713static void sdio_set_default_speed(void)
714{
715 g_sdio.sdio_set_default_speed();
716}
717
718static int sdio_read_size(uint32_t *size)
719{
720
721 uint32_t tmp;
722 sdio_cmd52_t cmd;
723
724 /**
725 * Read DMA count in words
726 **/
Tony Cho202f66a2015-07-28 17:47:35 +0900727 cmd.read_write = 0;
728 cmd.function = 0;
729 cmd.raw = 0;
730 cmd.address = 0xf2;
731 cmd.data = 0;
732 g_sdio.sdio_cmd52(&cmd);
733 tmp = cmd.data;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900734
Tony Cho202f66a2015-07-28 17:47:35 +0900735 /* cmd.read_write = 0; */
736 /* cmd.function = 0; */
737 /* cmd.raw = 0; */
738 cmd.address = 0xf3;
739 cmd.data = 0;
740 g_sdio.sdio_cmd52(&cmd);
741 tmp |= (cmd.data << 8);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900742
743 *size = tmp;
744 return 1;
745}
746
747static int sdio_read_int(uint32_t *int_status)
748{
749
750 uint32_t tmp;
751 sdio_cmd52_t cmd;
752
753 sdio_read_size(&tmp);
754
755 /**
756 * Read IRQ flags
757 **/
758#ifndef WILC_SDIO_IRQ_GPIO
759 /* cmd.read_write = 0; */
760 cmd.function = 1;
761 /* cmd.raw = 0; */
762 cmd.address = 0x04;
763 cmd.data = 0;
764 g_sdio.sdio_cmd52(&cmd);
765
Tony Cho4aa857722015-07-28 17:47:25 +0900766 if (cmd.data & (1 << 0))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900767 tmp |= INT_0;
Tony Cho4aa857722015-07-28 17:47:25 +0900768 if (cmd.data & (1 << 2))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900769 tmp |= INT_1;
Tony Cho4aa857722015-07-28 17:47:25 +0900770 if (cmd.data & (1 << 3))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900771 tmp |= INT_2;
Tony Cho4aa857722015-07-28 17:47:25 +0900772 if (cmd.data & (1 << 4))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900773 tmp |= INT_3;
Tony Cho4aa857722015-07-28 17:47:25 +0900774 if (cmd.data & (1 << 5))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900775 tmp |= INT_4;
Tony Cho4aa857722015-07-28 17:47:25 +0900776 if (cmd.data & (1 << 6))
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900777 tmp |= INT_5;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900778 {
779 int i;
Tony Cho9c844692015-07-28 17:47:24 +0900780
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900781 for (i = g_sdio.nint; i < MAX_NUM_INT; i++) {
782 if ((tmp >> (IRG_FLAGS_OFFSET + i)) & 0x1) {
783 g_sdio.dPrint(N_ERR, "[wilc sdio]: Unexpected interrupt (1) : tmp=%x, data=%x\n", tmp, cmd.data);
784 break;
785 }
786 }
787 }
788#else
789 {
790 uint32_t irq_flags;
791
792 cmd.read_write = 0;
793 cmd.function = 0;
794 cmd.raw = 0;
795 cmd.address = 0xf7;
796 cmd.data = 0;
797 g_sdio.sdio_cmd52(&cmd);
798 irq_flags = cmd.data & 0x1f;
799 tmp |= ((irq_flags >> 0) << IRG_FLAGS_OFFSET);
800 }
801
802#endif
803
804 *int_status = tmp;
805
806 return 1;
807}
808
809static int sdio_clear_int_ext(uint32_t val)
810{
811 int ret;
812
813 if (g_sdio.has_thrpt_enh3) {
814 uint32_t reg;
815
816#ifdef WILC_SDIO_IRQ_GPIO
817 {
818 uint32_t flags;
Tony Cho9c844692015-07-28 17:47:24 +0900819
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900820 flags = val & ((1 << MAX_NUN_INT_THRPT_ENH2) - 1);
821 reg = flags;
822 }
823#else
824 reg = 0;
825#endif
826 /* select VMM table 0 */
827 if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0)
828 reg |= (1 << 5);
829 /* select VMM table 1 */
830 if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1)
831 reg |= (1 << 6);
832 /* enable VMM */
833 if ((val & EN_VMM) == EN_VMM)
834 reg |= (1 << 7);
835 if (reg) {
836 sdio_cmd52_t cmd;
Tony Cho9c844692015-07-28 17:47:24 +0900837
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900838 cmd.read_write = 1;
839 cmd.function = 0;
840 cmd.raw = 0;
841 cmd.address = 0xf8;
842 cmd.data = reg;
843
844 ret = g_sdio.sdio_cmd52(&cmd);
845 if (!ret) {
846 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0xf8 data (%d) ...\n", __LINE__);
847 goto _fail_;
848 }
849
850 }
851 } else {
852#ifdef WILC_SDIO_IRQ_GPIO
853 {
854 /* see below. has_thrpt_enh2 uses register 0xf8 to clear interrupts. */
855 /* Cannot clear multiple interrupts. Must clear each interrupt individually */
856 uint32_t flags;
Tony Cho9c844692015-07-28 17:47:24 +0900857
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900858 flags = val & ((1 << MAX_NUM_INT) - 1);
859 if (flags) {
860 int i;
861
862 ret = 1;
863 for (i = 0; i < g_sdio.nint; i++) {
864 if (flags & 1) {
865 sdio_cmd52_t cmd;
Tony Cho9c844692015-07-28 17:47:24 +0900866
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900867 cmd.read_write = 1;
868 cmd.function = 0;
869 cmd.raw = 0;
870 cmd.address = 0xf8;
871 cmd.data = (1 << i);
872
873 ret = g_sdio.sdio_cmd52(&cmd);
874 if (!ret) {
875 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0xf8 data (%d) ...\n", __LINE__);
876 goto _fail_;
877 }
878
879 }
880 if (!ret)
881 break;
882 flags >>= 1;
883 }
Tony Cho4aa857722015-07-28 17:47:25 +0900884 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900885 goto _fail_;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900886 for (i = g_sdio.nint; i < MAX_NUM_INT; i++) {
887 if (flags & 1)
888 g_sdio.dPrint(N_ERR, "[wilc sdio]: Unexpected interrupt cleared %d...\n", i);
889 flags >>= 1;
890 }
891 }
892 }
893#endif /* WILC_SDIO_IRQ_GPIO */
894
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900895 {
896 uint32_t vmm_ctl;
897
898 vmm_ctl = 0;
899 /* select VMM table 0 */
900 if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0)
901 vmm_ctl |= (1 << 0);
902 /* select VMM table 1 */
903 if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1)
904 vmm_ctl |= (1 << 1);
905 /* enable VMM */
906 if ((val & EN_VMM) == EN_VMM)
907 vmm_ctl |= (1 << 2);
908
909 if (vmm_ctl) {
910 sdio_cmd52_t cmd;
911
912 cmd.read_write = 1;
913 cmd.function = 0;
914 cmd.raw = 0;
915 cmd.address = 0xf6;
916 cmd.data = vmm_ctl;
917 ret = g_sdio.sdio_cmd52(&cmd);
918 if (!ret) {
919 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0xf6 data (%d) ...\n", __LINE__);
920 goto _fail_;
921 }
922 }
923 }
924 }
925
926 return 1;
927_fail_:
928 return 0;
929}
930
931static int sdio_sync_ext(int nint /* how mant interrupts to enable. */)
932{
933 uint32_t reg;
934
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900935 if (nint > MAX_NUM_INT) {
936 g_sdio.dPrint(N_ERR, "[wilc sdio]: Too many interupts (%d)...\n", nint);
937 return 0;
938 }
939 if (nint > MAX_NUN_INT_THRPT_ENH2) {
940 g_sdio.dPrint(N_ERR, "[wilc sdio]: Error: Cannot support more than 5 interrupts when has_thrpt_enh2=1.\n");
941 return 0;
942 }
943
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900944 g_sdio.nint = nint;
945
946 /**
947 * Disable power sequencer
948 **/
949 if (!sdio_read_reg(WILC_MISC, &reg)) {
950 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read misc reg...\n");
951 return 0;
952 }
953
954 reg &= ~(1 << 8);
955 if (!sdio_write_reg(WILC_MISC, reg)) {
956 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write misc reg...\n");
957 return 0;
958 }
959
960#ifdef WILC_SDIO_IRQ_GPIO
961 {
962 uint32_t reg;
963 int ret, i;
964
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900965 /**
966 * interrupt pin mux select
967 **/
968 ret = sdio_read_reg(WILC_PIN_MUX_0, &reg);
969 if (!ret) {
970 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read reg (%08x)...\n", WILC_PIN_MUX_0);
971 return 0;
972 }
973 reg |= (1 << 8);
974 ret = sdio_write_reg(WILC_PIN_MUX_0, reg);
975 if (!ret) {
976 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write reg (%08x)...\n", WILC_PIN_MUX_0);
977 return 0;
978 }
979
980 /**
981 * interrupt enable
982 **/
983 ret = sdio_read_reg(WILC_INTR_ENABLE, &reg);
984 if (!ret) {
985 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read reg (%08x)...\n", WILC_INTR_ENABLE);
986 return 0;
987 }
988
Tony Cho4aa857722015-07-28 17:47:25 +0900989 for (i = 0; (i < 5) && (nint > 0); i++, nint--)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900990 reg |= (1 << (27 + i));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900991 ret = sdio_write_reg(WILC_INTR_ENABLE, reg);
992 if (!ret) {
993 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE);
994 return 0;
995 }
996 if (nint) {
997 ret = sdio_read_reg(WILC_INTR2_ENABLE, &reg);
998 if (!ret) {
999 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read reg (%08x)...\n", WILC_INTR2_ENABLE);
1000 return 0;
1001 }
1002
Tony Cho4aa857722015-07-28 17:47:25 +09001003 for (i = 0; (i < 3) && (nint > 0); i++, nint--)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001004 reg |= (1 << i);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001005
1006 ret = sdio_read_reg(WILC_INTR2_ENABLE, &reg);
1007 if (!ret) {
1008 g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write reg (%08x)...\n", WILC_INTR2_ENABLE);
1009 return 0;
1010 }
1011 }
1012 }
1013#endif /* WILC_SDIO_IRQ_GPIO */
1014 return 1;
1015}
1016
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001017/********************************************
1018 *
1019 * Global sdio HIF function table
1020 *
1021 ********************************************/
1022
1023wilc_hif_func_t hif_sdio = {
1024 sdio_init,
1025 sdio_deinit,
1026 sdio_read_reg,
1027 sdio_write_reg,
1028 sdio_read,
1029 sdio_write,
1030 sdio_sync,
1031 sdio_clear_int,
1032 sdio_read_int,
1033 sdio_clear_int_ext,
1034 sdio_read_size,
1035 sdio_write,
1036 sdio_read,
1037 sdio_sync_ext,
1038
1039 sdio_set_max_speed,
1040 sdio_set_default_speed,
1041};
1042