1 /** @file moal_sdio_mmc.c
2 *
3 * @brief This file contains SDIO MMC IF (interface) module
4 * related functions.
5 *
6 * Copyright (C) 2008-2017, Marvell International Ltd.
7 *
8 * This software file (the "File") is distributed by Marvell International
9 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
10 * (the "License"). You may use, redistribute and/or modify this File in
11 * accordance with the terms and conditions of the License, a copy of which
12 * is available by writing to the Free Software Foundation, Inc.,
13 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
14 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
15 *
16 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
18 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
19 * this warranty disclaimer.
20 *
21 */
22 /****************************************************
23 Change log:
24 02/25/09: Initial creation -
25 This file supports SDIO MMC only
26 ****************************************************/
27
28 #include <linux/firmware.h>
29
30 #include "moal_sdio.h"
31
32 /** define marvell vendor id */
33 #define MARVELL_VENDOR_ID 0x02df
34
35 /* The macros below are hardware platform dependent.
36 The definition should match the actual platform */
37 /** Initialize GPIO port */
38 #define GPIO_PORT_INIT()
39 /** Set GPIO port to high */
40 #define GPIO_PORT_TO_HIGH()
41 /** Set GPIO port to low */
42 #define GPIO_PORT_TO_LOW()
43
44 /********************************************************
45 Local Variables
46 ********************************************************/
47
48 /********************************************************
49 Global Variables
50 ********************************************************/
51
52 #ifdef SDIO_SUSPEND_RESUME
53 /** PM keep power */
54 extern int pm_keep_power;
55 extern int shutdown_hs;
56 #endif
57
58 extern int disconnect_on_suspend;
59
60 /** Device ID for SD8977 */
61 #define SD_DEVICE_ID_8977 (0x9145)
62
63 /** WLAN IDs */
64 static const struct sdio_device_id wlan_ids[] = {
65 {SDIO_DEVICE(MARVELL_VENDOR_ID, SD_DEVICE_ID_8977)},
66 {},
67 };
68
69 MODULE_DEVICE_TABLE(sdio, wlan_ids);
70
71 int woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id);
72 void woal_sdio_remove(struct sdio_func *func);
73
74 #ifdef SDIO_SUSPEND_RESUME
75 #ifdef MMC_PM_KEEP_POWER
76 int woal_sdio_suspend(struct device *dev);
77 int woal_sdio_resume(struct device *dev);
78
79 static struct dev_pm_ops wlan_sdio_pm_ops = {
80 .suspend = woal_sdio_suspend,
81 .resume = woal_sdio_resume,
82 };
83
84 void woal_sdio_shutdown(struct device *dev);
85 #endif
86 #endif
87 static struct sdio_driver REFDATA wlan_sdio = {
88 .name = "wlan_sdio",
89 .id_table = wlan_ids,
90 .probe = woal_sdio_probe,
91 .remove = woal_sdio_remove,
92 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
93 .drv = {
94 .owner = THIS_MODULE,
95 #ifdef SDIO_SUSPEND_RESUME
96 #ifdef MMC_PM_KEEP_POWER
97 .pm = &wlan_sdio_pm_ops,
98 .shutdown = woal_sdio_shutdown,
99 #endif
100 #endif
101
102 }
103 #else
104 #ifdef SDIO_SUSPEND_RESUME
105 #ifdef MMC_PM_KEEP_POWER
106 .drv = {
107 .pm = &wlan_sdio_pm_ops,
108 .shutdown = woal_sdio_shutdown,
109 }
110 #endif
111 #endif
112 #endif
113 };
114
115 /********************************************************
116 Local Functions
117 ********************************************************/
118 /** @brief This function dump the sdio register
119 *
120 * @param handle A Pointer to the moal_handle structure
121 * @return N/A
122 */
123 void
woal_dump_sdio_reg(moal_handle * handle)124 woal_dump_sdio_reg(moal_handle *handle)
125 {
126 int ret = 0;
127 t_u8 data, i;
128 int fun0_reg[] = { 0x05, 0x04 };
129 t_u8 array_size = 0;
130 int fun1_reg[] = { 0x03, 0x04, 0x05, 0x60, 0x61 };
131
132 for (i = 0; i < ARRAY_SIZE(fun0_reg); i++) {
133 data = sdio_f0_readb(((struct sdio_mmc_card *)handle->card)->
134 func, fun0_reg[i], &ret);
135 PRINTM(MMSG, "fun0: reg 0x%02x=0x%02x ret=%d\n", fun0_reg[i],
136 data, ret);
137 }
138
139 array_size = ARRAY_SIZE(fun1_reg);
140 for (i = 0; i < array_size; i++) {
141 data = sdio_readb(((struct sdio_mmc_card *)handle->card)->func,
142 fun1_reg[i], &ret);
143 PRINTM(MMSG, "fun1: reg 0x%02x=0x%02x ret=%d\n", fun1_reg[i],
144 data, ret);
145 }
146 return;
147 }
148
149 /********************************************************
150 Global Functions
151 ********************************************************/
152
153 /**
154 * @brief This function handles the interrupt.
155 *
156 * @param func A pointer to the sdio_func structure
157 * @return N/A
158 */
159 static void
woal_sdio_interrupt(struct sdio_func * func)160 woal_sdio_interrupt(struct sdio_func *func)
161 {
162 moal_handle *handle;
163 struct sdio_mmc_card *card;
164
165 ENTER();
166
167 card = sdio_get_drvdata(func);
168 if (!card || !card->handle) {
169 PRINTM(MINFO,
170 "sdio_mmc_interrupt(func = %p) card or handle is NULL, card=%p\n",
171 func, card);
172 LEAVE();
173 return;
174 }
175 handle = card->handle;
176
177 PRINTM(MINFO, "*** IN SDIO IRQ ***\n");
178 woal_interrupt(handle);
179
180 LEAVE();
181 }
182
183 /** @brief This function handles client driver probe.
184 *
185 * @param func A pointer to sdio_func structure.
186 * @param id A pointer to sdio_device_id structure.
187 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE/error code
188 */
189 int
woal_sdio_probe(struct sdio_func * func,const struct sdio_device_id * id)190 woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
191 {
192 int ret = MLAN_STATUS_SUCCESS;
193 struct sdio_mmc_card *card = NULL;
194
195 ENTER();
196
197 PRINTM(MMSG, "vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
198 func->vendor, func->device, func->class, func->num);
199
200 card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
201 if (!card) {
202 PRINTM(MFATAL,
203 "Failed to allocate memory in probe function!\n");
204 LEAVE();
205 return -ENOMEM;
206 }
207
208 card->func = func;
209
210 #ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE
211 /* The byte mode patch is available in kernel MMC driver
212 * which fixes one issue in MP-A transfer.
213 * bit1: use func->cur_blksize for byte mode
214 */
215 func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
216 #endif
217 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
218 func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
219 #endif
220
221 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
222 /* wait for chip fully wake up */
223 if (!func->enable_timeout)
224 func->enable_timeout = 200;
225 #endif
226 sdio_claim_host(func);
227 ret = sdio_enable_func(func);
228 if (ret) {
229 sdio_disable_func(func);
230 sdio_release_host(func);
231 kfree(card);
232 PRINTM(MFATAL, "sdio_enable_func() failed: ret=%d\n", ret);
233 LEAVE();
234 return -EIO;
235 }
236 sdio_release_host(func);
237 if (NULL == woal_add_card(card)) {
238 PRINTM(MERROR, "woal_add_card failed\n");
239 kfree(card);
240 sdio_claim_host(func);
241 sdio_disable_func(func);
242 sdio_release_host(func);
243 ret = MLAN_STATUS_FAILURE;
244 }
245
246 LEAVE();
247 return ret;
248 }
249
250 /** @brief This function handles client driver remove.
251 *
252 * @param func A pointer to sdio_func structure.
253 * @return N/A
254 */
255 void
woal_sdio_remove(struct sdio_func * func)256 woal_sdio_remove(struct sdio_func *func)
257 {
258 struct sdio_mmc_card *card;
259
260 ENTER();
261
262 if (func) {
263 PRINTM(MINFO, "SDIO func=%d\n", func->num);
264 card = sdio_get_drvdata(func);
265 if (card) {
266 woal_remove_card(card);
267 kfree(card);
268 }
269 }
270
271 LEAVE();
272 }
273
274 #ifdef SDIO_SUSPEND_RESUME
275 #ifdef MMC_PM_KEEP_POWER
276 #ifdef MMC_PM_FUNC_SUSPENDED
277 /** @brief This function tells lower driver that WLAN is suspended
278 *
279 * @param handle A Pointer to the moal_handle structure
280 * @return N/A
281 */
282 void
woal_wlan_is_suspended(moal_handle * handle)283 woal_wlan_is_suspended(moal_handle *handle)
284 {
285 ENTER();
286 if (handle->suspend_notify_req == MTRUE) {
287 handle->is_suspended = MTRUE;
288 sdio_func_suspended(((struct sdio_mmc_card *)handle->card)->
289 func);
290 }
291 LEAVE();
292 }
293 #endif
294
295 #define SHUTDOWN_HOST_SLEEP_DEF_GAP 100
296 #define SHUTDOWN_HOST_SLEEP_DEF_GPIO 0x3
297 #define SHUTDOWN_HOST_SLEEP_DEF_COND 0x0
298
299 /** @brief This function handles client driver shutdown
300 *
301 * @param dev A pointer to device structure
302 * @return N/A
303 */
304 void
woal_sdio_shutdown(struct device * dev)305 woal_sdio_shutdown(struct device *dev)
306 {
307 struct sdio_func *func = dev_to_sdio_func(dev);
308 moal_handle *handle = NULL;
309 struct sdio_mmc_card *cardp;
310 mlan_ds_ps_info pm_info;
311 int timeout = 0;
312 int i, retry_num = 8;
313
314 ENTER();
315 PRINTM(MCMND, "<--- Enter woal_sdio_shutdown --->\n");
316 cardp = sdio_get_drvdata(func);
317 if (!cardp || !cardp->handle) {
318 PRINTM(MERROR, "Card or moal_handle structure is not valid\n");
319 LEAVE();
320 return;
321 }
322 handle = cardp->handle;
323 for (i = 0; i < handle->priv_num; i++)
324 netif_device_detach(handle->priv[i]->netdev);
325
326 if (shutdown_hs) {
327 memset(&pm_info, 0, sizeof(pm_info));
328 for (i = 0; i < retry_num; i++) {
329 if (MLAN_STATUS_SUCCESS ==
330 woal_get_pm_info(woal_get_priv
331 (handle, MLAN_BSS_ROLE_ANY),
332 &pm_info)) {
333 if (pm_info.is_suspend_allowed == MTRUE)
334 break;
335 else
336 PRINTM(MMSG,
337 "Shutdown not allowed and retry again\n");
338 }
339 woal_sched_timeout(100);
340 }
341 if (pm_info.is_suspend_allowed == MFALSE) {
342 PRINTM(MMSG, "Shutdown not allowed\n");
343 goto done;
344 }
345 woal_enable_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY));
346
347 timeout =
348 wait_event_interruptible_timeout(handle->
349 hs_activate_wait_q,
350 handle->
351 hs_activate_wait_q_woken,
352 HS_ACTIVE_TIMEOUT);
353 if (handle->hs_activated == MTRUE)
354 PRINTM(MMSG, "HS actived in shutdown\n");
355 else
356 PRINTM(MMSG, "Fail to enable HS in shutdown\n");
357 } else {
358 for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
359 if (handle->priv[i]) {
360 if (handle->priv[i]->media_connected == MTRUE
361 #ifdef UAP_SUPPORT
362 || (GET_BSS_ROLE(handle->priv[i]) ==
363 MLAN_BSS_ROLE_UAP)
364 #endif
365 ) {
366 PRINTM(MIOCTL,
367 "disconnect on suspend\n");
368 woal_disconnect(handle->priv[i],
369 MOAL_NO_WAIT, NULL,
370 DEF_DEAUTH_REASON_CODE);
371 }
372 }
373 }
374 }
375
376 done:
377 PRINTM(MCMND, "<--- Leave woal_sdio_shutdown --->\n");
378 LEAVE();
379 return;
380 }
381
382 /** @brief This function handles client driver suspend
383 *
384 * @param dev A pointer to device structure
385 * @return MLAN_STATUS_SUCCESS or error code
386 */
387 int
woal_sdio_suspend(struct device * dev)388 woal_sdio_suspend(struct device *dev)
389 {
390 struct sdio_func *func = dev_to_sdio_func(dev);
391 mmc_pm_flag_t pm_flags = 0;
392 moal_handle *handle = NULL;
393 struct sdio_mmc_card *cardp;
394 int i, retry_num = 8;
395 int ret = MLAN_STATUS_SUCCESS;
396 int hs_actived = 0;
397 mlan_ds_ps_info pm_info;
398
399 ENTER();
400 PRINTM(MCMND, "<--- Enter woal_sdio_suspend --->\n");
401 pm_flags = sdio_get_host_pm_caps(func);
402 PRINTM(MCMND, "%s: suspend: PM flags = 0x%x\n", sdio_func_id(func),
403 pm_flags);
404 if (!(pm_flags & MMC_PM_KEEP_POWER)) {
405 PRINTM(MERROR,
406 "%s: cannot remain alive while host is suspended\n",
407 sdio_func_id(func));
408 LEAVE();
409 return -ENOSYS;
410 }
411 cardp = sdio_get_drvdata(func);
412 if (!cardp || !cardp->handle) {
413 PRINTM(MERROR, "Card or moal_handle structure is not valid\n");
414 LEAVE();
415 return MLAN_STATUS_SUCCESS;
416 }
417
418 handle = cardp->handle;
419 if (handle->is_suspended == MTRUE) {
420 PRINTM(MWARN, "Device already suspended\n");
421 LEAVE();
422 return MLAN_STATUS_SUCCESS;
423 }
424 if (handle->fw_dump) {
425 PRINTM(MMSG, "suspend not allowed while FW dump!");
426 ret = -EBUSY;
427 goto done;
428 }
429 #ifdef STA_SUPPORT
430 for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
431 if (handle->priv[i] &&
432 (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA))
433 woal_cancel_scan(handle->priv[i], MOAL_IOCTL_WAIT);
434 }
435 #endif
436 handle->suspend_fail = MFALSE;
437 memset(&pm_info, 0, sizeof(pm_info));
438 for (i = 0; i < retry_num; i++) {
439 if (MLAN_STATUS_SUCCESS ==
440 woal_get_pm_info(woal_get_priv(handle, MLAN_BSS_ROLE_ANY),
441 &pm_info)) {
442 if (pm_info.is_suspend_allowed == MTRUE)
443 break;
444 else
445 PRINTM(MMSG,
446 "Suspend not allowed and retry again\n");
447 }
448 woal_sched_timeout(100);
449 }
450 if (pm_info.is_suspend_allowed == MFALSE) {
451 PRINTM(MMSG, "Suspend not allowed\n");
452 ret = -EBUSY;
453 goto done;
454 }
455
456 for (i = 0; i < handle->priv_num; i++)
457 netif_device_detach(handle->priv[i]->netdev);
458
459 if (pm_keep_power) {
460 /* Enable the Host Sleep */
461 #ifdef MMC_PM_FUNC_SUSPENDED
462 handle->suspend_notify_req = MTRUE;
463 #endif
464 hs_actived =
465 woal_enable_hs(woal_get_priv
466 (handle, MLAN_BSS_ROLE_ANY));
467 #ifdef MMC_PM_FUNC_SUSPENDED
468 handle->suspend_notify_req = MFALSE;
469 #endif
470 if (hs_actived) {
471 #ifdef MMC_PM_SKIP_RESUME_PROBE
472 PRINTM(MCMND,
473 "suspend with MMC_PM_KEEP_POWER and MMC_PM_SKIP_RESUME_PROBE\n");
474 ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER |
475 MMC_PM_SKIP_RESUME_PROBE);
476 #else
477 PRINTM(MCMND, "suspend with MMC_PM_KEEP_POWER\n");
478 ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
479 #endif
480 } else {
481 PRINTM(MMSG, "HS not actived, suspend fail!");
482 handle->suspend_fail = MTRUE;
483 for (i = 0; i < handle->priv_num; i++)
484 netif_device_attach(handle->priv[i]->netdev);
485 ret = -EBUSY;
486 goto done;
487 }
488 }
489
490 /* Indicate device suspended */
491 handle->is_suspended = MTRUE;
492 done:
493 PRINTM(MCMND, "<--- Leave woal_sdio_suspend --->\n");
494 LEAVE();
495 return ret;
496 }
497
498 /** @brief This function handles client driver resume
499 *
500 * @param dev A pointer to device structure
501 * @return MLAN_STATUS_SUCCESS
502 */
503 int
woal_sdio_resume(struct device * dev)504 woal_sdio_resume(struct device *dev)
505 {
506 struct sdio_func *func = dev_to_sdio_func(dev);
507 mmc_pm_flag_t pm_flags = 0;
508 moal_handle *handle = NULL;
509 struct sdio_mmc_card *cardp;
510 int i;
511
512 ENTER();
513 PRINTM(MCMND, "<--- Enter woal_sdio_resume --->\n");
514 pm_flags = sdio_get_host_pm_caps(func);
515 PRINTM(MCMND, "%s: resume: PM flags = 0x%x\n", sdio_func_id(func),
516 pm_flags);
517 cardp = sdio_get_drvdata(func);
518 if (!cardp || !cardp->handle) {
519 PRINTM(MERROR, "Card or moal_handle structure is not valid\n");
520 LEAVE();
521 return MLAN_STATUS_SUCCESS;
522 }
523 handle = cardp->handle;
524
525 if (handle->is_suspended == MFALSE) {
526 PRINTM(MWARN, "Device already resumed\n");
527 LEAVE();
528 return MLAN_STATUS_SUCCESS;
529 }
530 handle->is_suspended = MFALSE;
531 if (woal_check_driver_status(handle)) {
532 PRINTM(MERROR, "Resuem, device is in hang state\n");
533 LEAVE();
534 return MLAN_STATUS_SUCCESS;
535 }
536 for (i = 0; i < handle->priv_num; i++)
537 netif_device_attach(handle->priv[i]->netdev);
538
539 /* Disable Host Sleep */
540 woal_cancel_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), MOAL_NO_WAIT);
541 PRINTM(MCMND, "<--- Leave woal_sdio_resume --->\n");
542 LEAVE();
543 return MLAN_STATUS_SUCCESS;
544 }
545 #endif
546 #endif /* SDIO_SUSPEND_RESUME */
547
548 /**
549 * @brief This function writes data into card register
550 *
551 * @param handle A Pointer to the moal_handle structure
552 * @param reg Register offset
553 * @param data Value
554 *
555 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
556 */
557 mlan_status
woal_write_reg(moal_handle * handle,t_u32 reg,t_u32 data)558 woal_write_reg(moal_handle *handle, t_u32 reg, t_u32 data)
559 {
560 mlan_status ret = MLAN_STATUS_FAILURE;
561 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
562 sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
563 #endif
564 sdio_writeb(((struct sdio_mmc_card *)handle->card)->func, (t_u8)data,
565 reg, (int *)&ret);
566 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
567 sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
568 #endif
569 return ret;
570 }
571
572 /**
573 * @brief This function reads data from card register
574 *
575 * @param handle A Pointer to the moal_handle structure
576 * @param reg Register offset
577 * @param data Value
578 *
579 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
580 */
581 mlan_status
woal_read_reg(moal_handle * handle,t_u32 reg,t_u32 * data)582 woal_read_reg(moal_handle *handle, t_u32 reg, t_u32 *data)
583 {
584 mlan_status ret = MLAN_STATUS_FAILURE;
585 t_u8 val;
586 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
587 sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
588 #endif
589 val = sdio_readb(((struct sdio_mmc_card *)handle->card)->func, reg,
590 (int *)&ret);
591 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
592 sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
593 #endif
594 *data = val;
595
596 return ret;
597 }
598
599 /**
600 * @brief This function use SG mode to read/write data into card memory
601 *
602 * @param handle A Pointer to the moal_handle structure
603 * @param pmbuf_list Pointer to a linked list of mlan_buffer structure
604 * @param port Port
605 * @param write write flag
606 *
607 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
608 */
609 mlan_status
woal_sdio_rw_mb(moal_handle * handle,pmlan_buffer pmbuf_list,t_u32 port,t_u8 write)610 woal_sdio_rw_mb(moal_handle *handle, pmlan_buffer pmbuf_list, t_u32 port,
611 t_u8 write)
612 {
613 struct scatterlist sg_list[SDIO_MP_AGGR_DEF_PKT_LIMIT];
614 int num_sg = pmbuf_list->use_count;
615 int i = 0;
616 mlan_buffer *pmbuf = NULL;
617 struct mmc_request mmc_req;
618 struct mmc_command mmc_cmd;
619 struct mmc_data mmc_dat;
620 struct sdio_func *func = ((struct sdio_mmc_card *)handle->card)->func;
621 t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK);
622 t_u32 blkcnt = pmbuf_list->data_len / MLAN_SDIO_BLOCK_SIZE;
623 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
624 int status;
625 #endif
626
627 if (num_sg > SDIO_MP_AGGR_DEF_PKT_LIMIT) {
628 PRINTM(MERROR, "ERROR: num_sg=%d", num_sg);
629 return MLAN_STATUS_FAILURE;
630 }
631 sg_init_table(sg_list, num_sg);
632 pmbuf = pmbuf_list->pnext;
633 for (i = 0; i < num_sg; i++) {
634 if (pmbuf == pmbuf_list)
635 break;
636 sg_set_buf(&sg_list[i], pmbuf->pbuf + pmbuf->data_offset,
637 pmbuf->data_len);
638 pmbuf = pmbuf->pnext;
639 }
640 memset(&mmc_req, 0, sizeof(struct mmc_request));
641 memset(&mmc_cmd, 0, sizeof(struct mmc_command));
642 memset(&mmc_dat, 0, sizeof(struct mmc_data));
643
644 mmc_dat.sg = sg_list;
645 mmc_dat.sg_len = num_sg;
646 mmc_dat.blksz = MLAN_SDIO_BLOCK_SIZE;
647 mmc_dat.blocks = blkcnt;
648 mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
649
650 mmc_cmd.opcode = SD_IO_RW_EXTENDED;
651 mmc_cmd.arg = write ? 1 << 31 : 0;
652 mmc_cmd.arg |= (func->num & 0x7) << 28;
653 mmc_cmd.arg |= 1 << 27; /* block basic */
654 mmc_cmd.arg |= 0; /* fix address */
655 mmc_cmd.arg |= (ioport & 0x1FFFF) << 9;
656 mmc_cmd.arg |= blkcnt & 0x1FF;
657 mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
658
659 mmc_req.cmd = &mmc_cmd;
660 mmc_req.data = &mmc_dat;
661
662 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
663 sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
664 #endif
665 mmc_set_data_timeout(&mmc_dat,
666 ((struct sdio_mmc_card *)handle->card)->func->
667 card);
668 mmc_wait_for_req(((struct sdio_mmc_card *)handle->card)->func->card->
669 host, &mmc_req);
670
671 if (mmc_cmd.error || mmc_dat.error) {
672 PRINTM(MERROR, "CMD53 %s cmd_error = %d data_error=%d\n",
673 write ? "write" : "read", mmc_cmd.error, mmc_dat.error);
674 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
675 /* issue abort cmd52 command through F0 */
676 sdio_f0_writeb(((struct sdio_mmc_card *)handle->card)->func,
677 0x01, SDIO_CCCR_ABORT, &status);
678 #endif
679 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
680 sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
681 #endif
682 return MLAN_STATUS_FAILURE;
683 }
684 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
685 sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
686 #endif
687 return MLAN_STATUS_SUCCESS;
688 }
689
690 /**
691 * @brief This function writes multiple bytes into card memory
692 *
693 * @param handle A Pointer to the moal_handle structure
694 * @param pmbuf Pointer to mlan_buffer structure
695 * @param port Port
696 * @param timeout Time out value
697 *
698 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
699 */
700 mlan_status
woal_write_data_sync(moal_handle * handle,mlan_buffer * pmbuf,t_u32 port,t_u32 timeout)701 woal_write_data_sync(moal_handle *handle, mlan_buffer *pmbuf, t_u32 port,
702 t_u32 timeout)
703 {
704 mlan_status ret = MLAN_STATUS_FAILURE;
705 t_u8 *buffer = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset);
706 t_u8 blkmode =
707 (port & MLAN_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
708 t_u32 blksz = (blkmode == BLOCK_MODE) ? MLAN_SDIO_BLOCK_SIZE : 1;
709 t_u32 blkcnt =
710 (blkmode ==
711 BLOCK_MODE) ? (pmbuf->data_len /
712 MLAN_SDIO_BLOCK_SIZE) : pmbuf->data_len;
713 t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK);
714 int status = 0;
715 if (pmbuf->use_count > 1)
716 return woal_sdio_rw_mb(handle, pmbuf, port, MTRUE);
717 #ifdef SDIO_MMC_DEBUG
718 handle->cmd53w = 1;
719 #endif
720 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
721 sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
722 #endif
723 status = sdio_writesb(((struct sdio_mmc_card *)handle->card)->func,
724 ioport, buffer, blkcnt * blksz);
725 if (!status)
726 ret = MLAN_STATUS_SUCCESS;
727 else {
728 PRINTM(MERROR, "cmd53 write error=%d\n", status);
729 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
730 /* issue abort cmd52 command through F0 */
731 sdio_f0_writeb(((struct sdio_mmc_card *)handle->card)->func,
732 0x01, SDIO_CCCR_ABORT, &status);
733 #endif
734 }
735 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
736 sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
737 #endif
738 #ifdef SDIO_MMC_DEBUG
739 handle->cmd53w = 2;
740 #endif
741 return ret;
742 }
743
744 /**
745 * @brief This function reads multiple bytes from card memory
746 *
747 * @param handle A Pointer to the moal_handle structure
748 * @param pmbuf Pointer to mlan_buffer structure
749 * @param port Port
750 * @param timeout Time out value
751 *
752 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
753 */
754 mlan_status
woal_read_data_sync(moal_handle * handle,mlan_buffer * pmbuf,t_u32 port,t_u32 timeout)755 woal_read_data_sync(moal_handle *handle, mlan_buffer *pmbuf, t_u32 port,
756 t_u32 timeout)
757 {
758 mlan_status ret = MLAN_STATUS_FAILURE;
759 t_u8 *buffer = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset);
760 t_u8 blkmode =
761 (port & MLAN_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
762 t_u32 blksz = (blkmode == BLOCK_MODE) ? MLAN_SDIO_BLOCK_SIZE : 1;
763 t_u32 blkcnt =
764 (blkmode ==
765 BLOCK_MODE) ? (pmbuf->data_len /
766 MLAN_SDIO_BLOCK_SIZE) : pmbuf->data_len;
767 t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK);
768 int status = 0;
769 if (pmbuf->use_count > 1)
770 return woal_sdio_rw_mb(handle, pmbuf, port, MFALSE);
771 #ifdef SDIO_MMC_DEBUG
772 handle->cmd53r = 1;
773 #endif
774 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
775 sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
776 #endif
777 status = sdio_readsb(((struct sdio_mmc_card *)handle->card)->func,
778 buffer, ioport, blkcnt * blksz);
779 if (!status) {
780 ret = MLAN_STATUS_SUCCESS;
781 } else {
782 PRINTM(MERROR, "cmd53 read error=%d\n", status);
783 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
784 /* issue abort cmd52 command through F0 */
785 sdio_f0_writeb(((struct sdio_mmc_card *)handle->card)->func,
786 0x01, SDIO_CCCR_ABORT, &status);
787 #endif
788 }
789 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
790 sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
791 #endif
792 #ifdef SDIO_MMC_DEBUG
793 handle->cmd53r = 2;
794 #endif
795 return ret;
796 }
797
798 /**
799 * @brief This function registers the IF module in bus driver
800 *
801 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
802 */
803 mlan_status
woal_bus_register(void)804 woal_bus_register(void)
805 {
806 mlan_status ret = MLAN_STATUS_SUCCESS;
807
808 ENTER();
809
810 /* SDIO Driver Registration */
811 if (sdio_register_driver(&wlan_sdio)) {
812 PRINTM(MFATAL, "SDIO Driver Registration Failed \n");
813 LEAVE();
814 return MLAN_STATUS_FAILURE;
815 }
816
817 /* init GPIO PORT for wakeup purpose */
818 GPIO_PORT_INIT();
819 /* set default value */
820 GPIO_PORT_TO_HIGH();
821
822 LEAVE();
823 return ret;
824 }
825
826 /**
827 * @brief This function de-registers the IF module in bus driver
828 *
829 * @return N/A
830 */
831 void
woal_bus_unregister(void)832 woal_bus_unregister(void)
833 {
834 ENTER();
835
836 /* SDIO Driver Unregistration */
837 sdio_unregister_driver(&wlan_sdio);
838
839 LEAVE();
840 }
841
842 /**
843 * @brief This function de-registers the device
844 *
845 * @param handle A pointer to moal_handle structure
846 * @return N/A
847 */
848 void
woal_unregister_dev(moal_handle * handle)849 woal_unregister_dev(moal_handle *handle)
850 {
851 ENTER();
852 if (handle->card) {
853 /* Release the SDIO IRQ */
854 sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func);
855 sdio_release_irq(((struct sdio_mmc_card *)handle->card)->func);
856 sdio_disable_func(((struct sdio_mmc_card *)handle->card)->func);
857 sdio_release_host(((struct sdio_mmc_card *)handle->card)->func);
858
859 sdio_set_drvdata(((struct sdio_mmc_card *)handle->card)->func,
860 NULL);
861
862 GPIO_PORT_TO_LOW();
863 PRINTM(MWARN, "Making the sdio dev card as NULL\n");
864 }
865
866 LEAVE();
867 }
868
869 /**
870 * @brief This function registers the device
871 *
872 * @param handle A pointer to moal_handle structure
873 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
874 */
875 mlan_status
woal_register_dev(moal_handle * handle)876 woal_register_dev(moal_handle *handle)
877 {
878 int ret = MLAN_STATUS_SUCCESS;
879 struct sdio_mmc_card *card = handle->card;
880 struct sdio_func *func;
881
882 ENTER();
883
884 GPIO_PORT_INIT();
885 GPIO_PORT_TO_HIGH();
886
887 func = card->func;
888 sdio_claim_host(func);
889 /* Request the SDIO IRQ */
890 ret = sdio_claim_irq(func, woal_sdio_interrupt);
891 if (ret) {
892 PRINTM(MFATAL, "sdio_claim_irq failed: ret=%d\n", ret);
893 goto release_host;
894 }
895
896 /* Set block size */
897 ret = sdio_set_block_size(card->func, MLAN_SDIO_BLOCK_SIZE);
898 if (ret) {
899 PRINTM(MERROR,
900 "sdio_set_block_seize(): cannot set SDIO block size\n");
901 ret = MLAN_STATUS_FAILURE;
902 goto release_irq;
903 }
904
905 sdio_release_host(func);
906 sdio_set_drvdata(func, card);
907
908 handle->hotplug_device = &func->dev;
909
910 LEAVE();
911 return MLAN_STATUS_SUCCESS;
912
913 release_irq:
914 sdio_release_irq(func);
915 release_host:
916 sdio_release_host(func);
917 handle->card = NULL;
918
919 LEAVE();
920 return MLAN_STATUS_FAILURE;
921 }
922
923 /**
924 * @brief This function set bus clock on/off
925 *
926 * @param handle A pointer to moal_handle structure
927 * @param option TRUE--on , FALSE--off
928 * @return MLAN_STATUS_SUCCESS
929 */
930 int
woal_sdio_set_bus_clock(moal_handle * handle,t_u8 option)931 woal_sdio_set_bus_clock(moal_handle *handle, t_u8 option)
932 {
933 struct sdio_mmc_card *cardp = (struct sdio_mmc_card *)handle->card;
934 struct mmc_host *host = cardp->func->card->host;
935
936 ENTER();
937 if (option == MTRUE) {
938 /* restore value if non-zero */
939 if (cardp->host_clock)
940 host->ios.clock = cardp->host_clock;
941 } else {
942 /* backup value if non-zero, then clear */
943 if (host->ios.clock)
944 cardp->host_clock = host->ios.clock;
945 host->ios.clock = 0;
946 }
947
948 host->ops->set_ios(host, &host->ios);
949 LEAVE();
950 return MLAN_STATUS_SUCCESS;
951 }
952
953 /**
954 * @brief This function updates card reg based on the Cmd52 value in dev structure
955 *
956 * @param handle A pointer to moal_handle structure
957 * @param func A pointer to store func variable
958 * @param reg A pointer to store reg variable
959 * @param val A pointer to store val variable
960 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
961 */
962 int
woal_sdio_read_write_cmd52(moal_handle * handle,int func,int reg,int val)963 woal_sdio_read_write_cmd52(moal_handle *handle, int func, int reg, int val)
964 {
965 int ret = MLAN_STATUS_SUCCESS;
966 struct sdio_mmc_card *card = (struct sdio_mmc_card *)handle->card;
967
968 ENTER();
969 /* Save current func and reg for read */
970 handle->cmd52_func = func;
971 handle->cmd52_reg = reg;
972 sdio_claim_host(card->func);
973 if (val >= 0) {
974 /* Perform actual write only if val is provided */
975 if (func)
976 sdio_writeb(card->func, val, reg, &ret);
977 else
978 sdio_f0_writeb(card->func, val, reg, &ret);
979 if (ret) {
980 PRINTM(MERROR,
981 "Cannot write value (0x%x) to func %d reg 0x%x\n",
982 val, func, reg);
983 } else {
984 PRINTM(MMSG, "write value (0x%x) to func %d reg 0x%x\n",
985 (u8)val, func, reg);
986 handle->cmd52_val = val;
987 }
988 } else {
989 if (func)
990 val = sdio_readb(card->func, reg, &ret);
991 else
992 val = sdio_f0_readb(card->func, reg, &ret);
993 if (ret) {
994 PRINTM(MERROR,
995 "Cannot read value from func %d reg 0x%x\n",
996 func, reg);
997 } else {
998 PRINTM(MMSG,
999 "read value (0x%x) from func %d reg 0x%x\n",
1000 (u8)val, func, reg);
1001 handle->cmd52_val = val;
1002 }
1003 }
1004 sdio_release_host(card->func);
1005 LEAVE();
1006 return ret;
1007 }
1008