xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/mvl88w8977/mlinux/moal_sdio_mmc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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