1 /*
2  * Copyright (c) 2010 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 #include <linux/types.h>
17 #include <linux/netdevice.h>
18 #include <bcmdefs.h>
19 #include <bcmdevs.h>
20 #include <bcmutils.h>
21 #include <sdio.h>		/* SDIO Device and Protocol Specs */
22 #include <sdioh.h>		/* SDIO Host Controller Specification */
23 #include <bcmsdbus.h>		/* bcmsdh to/from specific controller APIs */
24 #include <sdiovar.h>		/* ioctl/iovars */
25 
26 #include <linux/mmc/core.h>
27 #include <linux/mmc/sdio_func.h>
28 #include <linux/mmc/sdio_ids.h>
29 
30 #include <dngl_stats.h>
31 #include <dhd.h>
32 
33 #if defined(CONFIG_PM_SLEEP)
34 #include <linux/suspend.h>
35 extern volatile bool dhd_mmc_suspend;
36 #endif
37 #include "bcmsdh_sdmmc.h"
38 
39 extern int sdio_function_init(void);
40 extern void sdio_function_cleanup(void);
41 
42 #if !defined(OOB_INTR_ONLY)
43 static void IRQHandler(struct sdio_func *func);
44 static void IRQHandlerF2(struct sdio_func *func);
45 #endif				/* !defined(OOB_INTR_ONLY) */
46 static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, u32 regaddr);
47 extern int sdio_reset_comm(struct mmc_card *card);
48 
49 extern PBCMSDH_SDMMC_INSTANCE gInstance;
50 
51 uint sd_sdmode = SDIOH_MODE_SD4;	/* Use SD4 mode by default */
52 uint sd_f2_blocksize = 512;	/* Default blocksize */
53 
54 uint sd_divisor = 2;		/* Default 48MHz/2 = 24MHz */
55 
56 uint sd_power = 1;		/* Default to SD Slot powered ON */
57 uint sd_clock = 1;		/* Default to SD Clock turned ON */
58 uint sd_hiok = false;		/* Don't use hi-speed mode by default */
59 uint sd_msglevel = 0x01;
60 uint sd_use_dma = true;
61 DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait);
62 DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait);
63 DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait);
64 DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait);
65 
66 #define DMA_ALIGN_MASK	0x03
67 
68 int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, u32 regaddr,
69 			     int regsize, u32 *data);
70 
sdioh_sdmmc_card_enablefuncs(sdioh_info_t * sd)71 static int sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd)
72 {
73 	int err_ret;
74 	u32 fbraddr;
75 	u8 func;
76 
77 	sd_trace(("%s\n", __func__));
78 
79 	/* Get the Card's common CIS address */
80 	sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0);
81 	sd->func_cis_ptr[0] = sd->com_cis_ptr;
82 	sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __func__,
83 		 sd->com_cis_ptr));
84 
85 	/* Get the Card's function CIS (for each function) */
86 	for (fbraddr = SDIOD_FBR_STARTADDR, func = 1;
87 	     func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
88 		sd->func_cis_ptr[func] =
89 		    sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr);
90 		sd_info(("%s: Function %d CIS Ptr = 0x%x\n", __func__, func,
91 			 sd->func_cis_ptr[func]));
92 	}
93 
94 	sd->func_cis_ptr[0] = sd->com_cis_ptr;
95 	sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __func__,
96 		 sd->com_cis_ptr));
97 
98 	/* Enable Function 1 */
99 	sdio_claim_host(gInstance->func[1]);
100 	err_ret = sdio_enable_func(gInstance->func[1]);
101 	sdio_release_host(gInstance->func[1]);
102 	if (err_ret) {
103 		sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x",
104 			err_ret));
105 	}
106 
107 	return false;
108 }
109 
110 /*
111  *	Public entry points & extern's
112  */
sdioh_attach(void * bar0,uint irq)113 sdioh_info_t *sdioh_attach(void *bar0, uint irq)
114 {
115 	sdioh_info_t *sd;
116 	int err_ret;
117 
118 	sd_trace(("%s\n", __func__));
119 
120 	if (gInstance == NULL) {
121 		sd_err(("%s: SDIO Device not present\n", __func__));
122 		return NULL;
123 	}
124 
125 	sd = kzalloc(sizeof(sdioh_info_t), GFP_ATOMIC);
126 	if (sd == NULL) {
127 		sd_err(("sdioh_attach: out of memory\n"));
128 		return NULL;
129 	}
130 	if (sdioh_sdmmc_osinit(sd) != 0) {
131 		sd_err(("%s:sdioh_sdmmc_osinit() failed\n", __func__));
132 		kfree(sd);
133 		return NULL;
134 	}
135 
136 	sd->num_funcs = 2;
137 	sd->sd_blockmode = true;
138 	sd->use_client_ints = true;
139 	sd->client_block_size[0] = 64;
140 
141 	gInstance->sd = sd;
142 
143 	/* Claim host controller */
144 	sdio_claim_host(gInstance->func[1]);
145 
146 	sd->client_block_size[1] = 64;
147 	err_ret = sdio_set_block_size(gInstance->func[1], 64);
148 	if (err_ret)
149 		sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
150 
151 	/* Release host controller F1 */
152 	sdio_release_host(gInstance->func[1]);
153 
154 	if (gInstance->func[2]) {
155 		/* Claim host controller F2 */
156 		sdio_claim_host(gInstance->func[2]);
157 
158 		sd->client_block_size[2] = sd_f2_blocksize;
159 		err_ret =
160 		    sdio_set_block_size(gInstance->func[2], sd_f2_blocksize);
161 		if (err_ret)
162 			sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize "
163 				"to %d\n", sd_f2_blocksize));
164 
165 		/* Release host controller F2 */
166 		sdio_release_host(gInstance->func[2]);
167 	}
168 
169 	sdioh_sdmmc_card_enablefuncs(sd);
170 
171 	sd_trace(("%s: Done\n", __func__));
172 	return sd;
173 }
174 
sdioh_detach(sdioh_info_t * sd)175 extern SDIOH_API_RC sdioh_detach(sdioh_info_t *sd)
176 {
177 	sd_trace(("%s\n", __func__));
178 
179 	if (sd) {
180 
181 		/* Disable Function 2 */
182 		sdio_claim_host(gInstance->func[2]);
183 		sdio_disable_func(gInstance->func[2]);
184 		sdio_release_host(gInstance->func[2]);
185 
186 		/* Disable Function 1 */
187 		sdio_claim_host(gInstance->func[1]);
188 		sdio_disable_func(gInstance->func[1]);
189 		sdio_release_host(gInstance->func[1]);
190 
191 		/* deregister irq */
192 		sdioh_sdmmc_osfree(sd);
193 
194 		kfree(sd);
195 	}
196 	return SDIOH_API_RC_SUCCESS;
197 }
198 
199 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
200 
sdioh_enable_func_intr(void)201 extern SDIOH_API_RC sdioh_enable_func_intr(void)
202 {
203 	u8 reg;
204 	int err;
205 
206 	if (gInstance->func[0]) {
207 		sdio_claim_host(gInstance->func[0]);
208 
209 		reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err);
210 		if (err) {
211 			sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n",
212 				__func__, err));
213 			sdio_release_host(gInstance->func[0]);
214 			return SDIOH_API_RC_FAIL;
215 		}
216 
217 		/* Enable F1 and F2 interrupts, set master enable */
218 		reg |=
219 		    (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN |
220 		     INTR_CTL_MASTER_EN);
221 
222 		sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err);
223 		sdio_release_host(gInstance->func[0]);
224 
225 		if (err) {
226 			sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n",
227 				__func__, err));
228 			return SDIOH_API_RC_FAIL;
229 		}
230 	}
231 
232 	return SDIOH_API_RC_SUCCESS;
233 }
234 
sdioh_disable_func_intr(void)235 extern SDIOH_API_RC sdioh_disable_func_intr(void)
236 {
237 	u8 reg;
238 	int err;
239 
240 	if (gInstance->func[0]) {
241 		sdio_claim_host(gInstance->func[0]);
242 		reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err);
243 		if (err) {
244 			sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n",
245 				__func__, err));
246 			sdio_release_host(gInstance->func[0]);
247 			return SDIOH_API_RC_FAIL;
248 		}
249 
250 		reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN);
251 		/* Disable master interrupt with the last function interrupt */
252 		if (!(reg & 0xFE))
253 			reg = 0;
254 		sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err);
255 
256 		sdio_release_host(gInstance->func[0]);
257 		if (err) {
258 			sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n",
259 				__func__, err));
260 			return SDIOH_API_RC_FAIL;
261 		}
262 	}
263 	return SDIOH_API_RC_SUCCESS;
264 }
265 #endif				/* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
266 
267 /* Configure callback to client when we receive client interrupt */
268 extern SDIOH_API_RC
sdioh_interrupt_register(sdioh_info_t * sd,sdioh_cb_fn_t fn,void * argh)269 sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
270 {
271 	sd_trace(("%s: Entering\n", __func__));
272 	if (fn == NULL) {
273 		sd_err(("%s: interrupt handler is NULL, not registering\n",
274 			__func__));
275 		return SDIOH_API_RC_FAIL;
276 	}
277 #if !defined(OOB_INTR_ONLY)
278 	sd->intr_handler = fn;
279 	sd->intr_handler_arg = argh;
280 	sd->intr_handler_valid = true;
281 
282 	/* register and unmask irq */
283 	if (gInstance->func[2]) {
284 		sdio_claim_host(gInstance->func[2]);
285 		sdio_claim_irq(gInstance->func[2], IRQHandlerF2);
286 		sdio_release_host(gInstance->func[2]);
287 	}
288 
289 	if (gInstance->func[1]) {
290 		sdio_claim_host(gInstance->func[1]);
291 		sdio_claim_irq(gInstance->func[1], IRQHandler);
292 		sdio_release_host(gInstance->func[1]);
293 	}
294 #elif defined(HW_OOB)
295 	sdioh_enable_func_intr();
296 #endif				/* defined(OOB_INTR_ONLY) */
297 	return SDIOH_API_RC_SUCCESS;
298 }
299 
sdioh_interrupt_deregister(sdioh_info_t * sd)300 extern SDIOH_API_RC sdioh_interrupt_deregister(sdioh_info_t *sd)
301 {
302 	sd_trace(("%s: Entering\n", __func__));
303 
304 #if !defined(OOB_INTR_ONLY)
305 	if (gInstance->func[1]) {
306 		/* register and unmask irq */
307 		sdio_claim_host(gInstance->func[1]);
308 		sdio_release_irq(gInstance->func[1]);
309 		sdio_release_host(gInstance->func[1]);
310 	}
311 
312 	if (gInstance->func[2]) {
313 		/* Claim host controller F2 */
314 		sdio_claim_host(gInstance->func[2]);
315 		sdio_release_irq(gInstance->func[2]);
316 		/* Release host controller F2 */
317 		sdio_release_host(gInstance->func[2]);
318 	}
319 
320 	sd->intr_handler_valid = false;
321 	sd->intr_handler = NULL;
322 	sd->intr_handler_arg = NULL;
323 #elif defined(HW_OOB)
324 	sdioh_disable_func_intr();
325 #endif				/*  !defined(OOB_INTR_ONLY) */
326 	return SDIOH_API_RC_SUCCESS;
327 }
328 
sdioh_interrupt_query(sdioh_info_t * sd,bool * onoff)329 extern SDIOH_API_RC sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
330 {
331 	sd_trace(("%s: Entering\n", __func__));
332 	*onoff = sd->client_intr_enabled;
333 	return SDIOH_API_RC_SUCCESS;
334 }
335 
336 #if defined(DHD_DEBUG)
sdioh_interrupt_pending(sdioh_info_t * sd)337 extern bool sdioh_interrupt_pending(sdioh_info_t *sd)
338 {
339 	return 0;
340 }
341 #endif
342 
sdioh_query_iofnum(sdioh_info_t * sd)343 uint sdioh_query_iofnum(sdioh_info_t *sd)
344 {
345 	return sd->num_funcs;
346 }
347 
348 /* IOVar table */
349 enum {
350 	IOV_MSGLEVEL = 1,
351 	IOV_BLOCKMODE,
352 	IOV_BLOCKSIZE,
353 	IOV_DMA,
354 	IOV_USEINTS,
355 	IOV_NUMINTS,
356 	IOV_NUMLOCALINTS,
357 	IOV_HOSTREG,
358 	IOV_DEVREG,
359 	IOV_DIVISOR,
360 	IOV_SDMODE,
361 	IOV_HISPEED,
362 	IOV_HCIREGS,
363 	IOV_POWER,
364 	IOV_CLOCK,
365 	IOV_RXCHAIN
366 };
367 
368 const bcm_iovar_t sdioh_iovars[] = {
369 	{"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0},
370 	{"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0},
371 	{"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0},/* ((fn << 16) |
372 								 size) */
373 	{"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0},
374 	{"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0},
375 	{"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0},
376 	{"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0},
377 	{"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t)}
378 	,
379 	{"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t)}
380 	,
381 	{"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0}
382 	,
383 	{"sd_power", IOV_POWER, 0, IOVT_UINT32, 0}
384 	,
385 	{"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0}
386 	,
387 	{"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}
388 	,
389 	{"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0}
390 	,
391 	{"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0}
392 	,
393 	{NULL, 0, 0, 0, 0}
394 };
395 
396 int
sdioh_iovar_op(sdioh_info_t * si,const char * name,void * params,int plen,void * arg,int len,bool set)397 sdioh_iovar_op(sdioh_info_t *si, const char *name,
398 	       void *params, int plen, void *arg, int len, bool set)
399 {
400 	const bcm_iovar_t *vi = NULL;
401 	int bcmerror = 0;
402 	int val_size;
403 	s32 int_val = 0;
404 	bool bool_val;
405 	u32 actionid;
406 
407 	ASSERT(name);
408 	ASSERT(len >= 0);
409 
410 	/* Get must have return space; Set does not take qualifiers */
411 	ASSERT(set || (arg && len));
412 	ASSERT(!set || (!params && !plen));
413 
414 	sd_trace(("%s: Enter (%s %s)\n", __func__, (set ? "set" : "get"),
415 		  name));
416 
417 	vi = bcm_iovar_lookup(sdioh_iovars, name);
418 	if (vi == NULL) {
419 		bcmerror = BCME_UNSUPPORTED;
420 		goto exit;
421 	}
422 
423 	bcmerror = bcm_iovar_lencheck(vi, arg, len, set);
424 	if (bcmerror != 0)
425 		goto exit;
426 
427 	/* Set up params so get and set can share the convenience variables */
428 	if (params == NULL) {
429 		params = arg;
430 		plen = len;
431 	}
432 
433 	if (vi->type == IOVT_VOID)
434 		val_size = 0;
435 	else if (vi->type == IOVT_BUFFER)
436 		val_size = len;
437 	else
438 		val_size = sizeof(int);
439 
440 	if (plen >= (int)sizeof(int_val))
441 		memcpy(&int_val, params, sizeof(int_val));
442 
443 	bool_val = (int_val != 0) ? true : false;
444 
445 	actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
446 	switch (actionid) {
447 	case IOV_GVAL(IOV_MSGLEVEL):
448 		int_val = (s32) sd_msglevel;
449 		memcpy(arg, &int_val, val_size);
450 		break;
451 
452 	case IOV_SVAL(IOV_MSGLEVEL):
453 		sd_msglevel = int_val;
454 		break;
455 
456 	case IOV_GVAL(IOV_BLOCKMODE):
457 		int_val = (s32) si->sd_blockmode;
458 		memcpy(arg, &int_val, val_size);
459 		break;
460 
461 	case IOV_SVAL(IOV_BLOCKMODE):
462 		si->sd_blockmode = (bool) int_val;
463 		/* Haven't figured out how to make non-block mode with DMA */
464 		break;
465 
466 	case IOV_GVAL(IOV_BLOCKSIZE):
467 		if ((u32) int_val > si->num_funcs) {
468 			bcmerror = BCME_BADARG;
469 			break;
470 		}
471 		int_val = (s32) si->client_block_size[int_val];
472 		memcpy(arg, &int_val, val_size);
473 		break;
474 
475 	case IOV_SVAL(IOV_BLOCKSIZE):
476 		{
477 			uint func = ((u32) int_val >> 16);
478 			uint blksize = (u16) int_val;
479 			uint maxsize;
480 
481 			if (func > si->num_funcs) {
482 				bcmerror = BCME_BADARG;
483 				break;
484 			}
485 
486 			switch (func) {
487 			case 0:
488 				maxsize = 32;
489 				break;
490 			case 1:
491 				maxsize = BLOCK_SIZE_4318;
492 				break;
493 			case 2:
494 				maxsize = BLOCK_SIZE_4328;
495 				break;
496 			default:
497 				maxsize = 0;
498 			}
499 			if (blksize > maxsize) {
500 				bcmerror = BCME_BADARG;
501 				break;
502 			}
503 			if (!blksize)
504 				blksize = maxsize;
505 
506 			/* Now set it */
507 			si->client_block_size[func] = blksize;
508 
509 			break;
510 		}
511 
512 	case IOV_GVAL(IOV_RXCHAIN):
513 		int_val = false;
514 		memcpy(arg, &int_val, val_size);
515 		break;
516 
517 	case IOV_GVAL(IOV_DMA):
518 		int_val = (s32) si->sd_use_dma;
519 		memcpy(arg, &int_val, val_size);
520 		break;
521 
522 	case IOV_SVAL(IOV_DMA):
523 		si->sd_use_dma = (bool) int_val;
524 		break;
525 
526 	case IOV_GVAL(IOV_USEINTS):
527 		int_val = (s32) si->use_client_ints;
528 		memcpy(arg, &int_val, val_size);
529 		break;
530 
531 	case IOV_SVAL(IOV_USEINTS):
532 		si->use_client_ints = (bool) int_val;
533 		if (si->use_client_ints)
534 			si->intmask |= CLIENT_INTR;
535 		else
536 			si->intmask &= ~CLIENT_INTR;
537 
538 		break;
539 
540 	case IOV_GVAL(IOV_DIVISOR):
541 		int_val = (u32) sd_divisor;
542 		memcpy(arg, &int_val, val_size);
543 		break;
544 
545 	case IOV_SVAL(IOV_DIVISOR):
546 		sd_divisor = int_val;
547 		break;
548 
549 	case IOV_GVAL(IOV_POWER):
550 		int_val = (u32) sd_power;
551 		memcpy(arg, &int_val, val_size);
552 		break;
553 
554 	case IOV_SVAL(IOV_POWER):
555 		sd_power = int_val;
556 		break;
557 
558 	case IOV_GVAL(IOV_CLOCK):
559 		int_val = (u32) sd_clock;
560 		memcpy(arg, &int_val, val_size);
561 		break;
562 
563 	case IOV_SVAL(IOV_CLOCK):
564 		sd_clock = int_val;
565 		break;
566 
567 	case IOV_GVAL(IOV_SDMODE):
568 		int_val = (u32) sd_sdmode;
569 		memcpy(arg, &int_val, val_size);
570 		break;
571 
572 	case IOV_SVAL(IOV_SDMODE):
573 		sd_sdmode = int_val;
574 		break;
575 
576 	case IOV_GVAL(IOV_HISPEED):
577 		int_val = (u32) sd_hiok;
578 		memcpy(arg, &int_val, val_size);
579 		break;
580 
581 	case IOV_SVAL(IOV_HISPEED):
582 		sd_hiok = int_val;
583 		break;
584 
585 	case IOV_GVAL(IOV_NUMINTS):
586 		int_val = (s32) si->intrcount;
587 		memcpy(arg, &int_val, val_size);
588 		break;
589 
590 	case IOV_GVAL(IOV_NUMLOCALINTS):
591 		int_val = (s32) 0;
592 		memcpy(arg, &int_val, val_size);
593 		break;
594 
595 	case IOV_GVAL(IOV_HOSTREG):
596 		{
597 			sdreg_t *sd_ptr = (sdreg_t *) params;
598 
599 			if (sd_ptr->offset < SD_SysAddr
600 			    || sd_ptr->offset > SD_MaxCurCap) {
601 				sd_err(("%s: bad offset 0x%x\n", __func__,
602 					sd_ptr->offset));
603 				bcmerror = BCME_BADARG;
604 				break;
605 			}
606 
607 			sd_trace(("%s: rreg%d at offset %d\n", __func__,
608 				  (sd_ptr->offset & 1) ? 8
609 				  : ((sd_ptr->offset & 2) ? 16 : 32),
610 				  sd_ptr->offset));
611 			if (sd_ptr->offset & 1)
612 				int_val = 8;	/* sdioh_sdmmc_rreg8(si,
613 						 sd_ptr->offset); */
614 			else if (sd_ptr->offset & 2)
615 				int_val = 16;	/* sdioh_sdmmc_rreg16(si,
616 						 sd_ptr->offset); */
617 			else
618 				int_val = 32;	/* sdioh_sdmmc_rreg(si,
619 						 sd_ptr->offset); */
620 
621 			memcpy(arg, &int_val, sizeof(int_val));
622 			break;
623 		}
624 
625 	case IOV_SVAL(IOV_HOSTREG):
626 		{
627 			sdreg_t *sd_ptr = (sdreg_t *) params;
628 
629 			if (sd_ptr->offset < SD_SysAddr
630 			    || sd_ptr->offset > SD_MaxCurCap) {
631 				sd_err(("%s: bad offset 0x%x\n", __func__,
632 					sd_ptr->offset));
633 				bcmerror = BCME_BADARG;
634 				break;
635 			}
636 
637 			sd_trace(("%s: wreg%d value 0x%08x at offset %d\n",
638 				  __func__, sd_ptr->value,
639 				  (sd_ptr->offset & 1) ? 8
640 				  : ((sd_ptr->offset & 2) ? 16 : 32),
641 				  sd_ptr->offset));
642 			break;
643 		}
644 
645 	case IOV_GVAL(IOV_DEVREG):
646 		{
647 			sdreg_t *sd_ptr = (sdreg_t *) params;
648 			u8 data = 0;
649 
650 			if (sdioh_cfg_read
651 			    (si, sd_ptr->func, sd_ptr->offset, &data)) {
652 				bcmerror = BCME_SDIO_ERROR;
653 				break;
654 			}
655 
656 			int_val = (int)data;
657 			memcpy(arg, &int_val, sizeof(int_val));
658 			break;
659 		}
660 
661 	case IOV_SVAL(IOV_DEVREG):
662 		{
663 			sdreg_t *sd_ptr = (sdreg_t *) params;
664 			u8 data = (u8) sd_ptr->value;
665 
666 			if (sdioh_cfg_write
667 			    (si, sd_ptr->func, sd_ptr->offset, &data)) {
668 				bcmerror = BCME_SDIO_ERROR;
669 				break;
670 			}
671 			break;
672 		}
673 
674 	default:
675 		bcmerror = BCME_UNSUPPORTED;
676 		break;
677 	}
678 exit:
679 
680 	return bcmerror;
681 }
682 
683 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
684 
sdioh_enable_hw_oob_intr(sdioh_info_t * sd,bool enable)685 SDIOH_API_RC sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
686 {
687 	SDIOH_API_RC status;
688 	u8 data;
689 
690 	if (enable)
691 		data = 3;	/* enable hw oob interrupt */
692 	else
693 		data = 4;	/* disable hw oob interrupt */
694 	data |= 4;		/* Active HIGH */
695 
696 	status = sdioh_request_byte(sd, SDIOH_WRITE, 0, 0xf2, &data);
697 	return status;
698 }
699 #endif				/* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
700 
701 extern SDIOH_API_RC
sdioh_cfg_read(sdioh_info_t * sd,uint fnc_num,u32 addr,u8 * data)702 sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, u32 addr, u8 *data)
703 {
704 	SDIOH_API_RC status;
705 	/* No lock needed since sdioh_request_byte does locking */
706 	status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
707 	return status;
708 }
709 
710 extern SDIOH_API_RC
sdioh_cfg_write(sdioh_info_t * sd,uint fnc_num,u32 addr,u8 * data)711 sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, u32 addr, u8 *data)
712 {
713 	/* No lock needed since sdioh_request_byte does locking */
714 	SDIOH_API_RC status;
715 	status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
716 	return status;
717 }
718 
sdioh_sdmmc_get_cisaddr(sdioh_info_t * sd,u32 regaddr)719 static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, u32 regaddr)
720 {
721 	/* read 24 bits and return valid 17 bit addr */
722 	int i;
723 	u32 scratch, regdata;
724 	u8 *ptr = (u8 *)&scratch;
725 	for (i = 0; i < 3; i++) {
726 		if ((sdioh_sdmmc_card_regread(sd, 0, regaddr, 1, &regdata)) !=
727 		    SUCCESS)
728 			sd_err(("%s: Can't read!\n", __func__));
729 
730 		*ptr++ = (u8) regdata;
731 		regaddr++;
732 	}
733 
734 	/* Only the lower 17-bits are valid */
735 	scratch = le32_to_cpu(scratch);
736 	scratch &= 0x0001FFFF;
737 	return scratch;
738 }
739 
740 extern SDIOH_API_RC
sdioh_cis_read(sdioh_info_t * sd,uint func,u8 * cisd,u32 length)741 sdioh_cis_read(sdioh_info_t *sd, uint func, u8 *cisd, u32 length)
742 {
743 	u32 count;
744 	int offset;
745 	u32 foo;
746 	u8 *cis = cisd;
747 
748 	sd_trace(("%s: Func = %d\n", __func__, func));
749 
750 	if (!sd->func_cis_ptr[func]) {
751 		memset(cis, 0, length);
752 		sd_err(("%s: no func_cis_ptr[%d]\n", __func__, func));
753 		return SDIOH_API_RC_FAIL;
754 	}
755 
756 	sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __func__, func,
757 		sd->func_cis_ptr[func]));
758 
759 	for (count = 0; count < length; count++) {
760 		offset = sd->func_cis_ptr[func] + count;
761 		if (sdioh_sdmmc_card_regread(sd, 0, offset, 1, &foo) < 0) {
762 			sd_err(("%s: regread failed: Can't read CIS\n",
763 				__func__));
764 			return SDIOH_API_RC_FAIL;
765 		}
766 
767 		*cis = (u8) (foo & 0xff);
768 		cis++;
769 	}
770 
771 	return SDIOH_API_RC_SUCCESS;
772 }
773 
774 extern SDIOH_API_RC
sdioh_request_byte(sdioh_info_t * sd,uint rw,uint func,uint regaddr,u8 * byte)775 sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr,
776 		   u8 *byte)
777 {
778 	int err_ret;
779 
780 	sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __func__, rw, func,
781 		 regaddr));
782 
783 	DHD_PM_RESUME_WAIT(sdioh_request_byte_wait);
784 	DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
785 	if (rw) {		/* CMD52 Write */
786 		if (func == 0) {
787 			/* Can only directly write to some F0 registers.
788 			 * Handle F2 enable
789 			 * as a special case.
790 			 */
791 			if (regaddr == SDIOD_CCCR_IOEN) {
792 				if (gInstance->func[2]) {
793 					sdio_claim_host(gInstance->func[2]);
794 					if (*byte & SDIO_FUNC_ENABLE_2) {
795 						/* Enable Function 2 */
796 						err_ret =
797 						    sdio_enable_func
798 						    (gInstance->func[2]);
799 						if (err_ret)
800 							sd_err(("bcmsdh_sdmmc: enable F2 failed:%d",
801 								 err_ret));
802 					} else {
803 						/* Disable Function 2 */
804 						err_ret =
805 						    sdio_disable_func
806 						    (gInstance->func[2]);
807 						if (err_ret)
808 							sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d",
809 								 err_ret));
810 					}
811 					sdio_release_host(gInstance->func[2]);
812 				}
813 			}
814 #if defined(MMC_SDIO_ABORT)
815 			/* to allow abort command through F1 */
816 			else if (regaddr == SDIOD_CCCR_IOABORT) {
817 				sdio_claim_host(gInstance->func[func]);
818 				/*
819 				 * this sdio_f0_writeb() can be replaced
820 				 * with another api
821 				 * depending upon MMC driver change.
822 				 * As of this time, this is temporaray one
823 				 */
824 				sdio_writeb(gInstance->func[func], *byte,
825 					    regaddr, &err_ret);
826 				sdio_release_host(gInstance->func[func]);
827 			}
828 #endif				/* MMC_SDIO_ABORT */
829 			else if (regaddr < 0xF0) {
830 				sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write "
831 					"disallowed\n", regaddr));
832 			} else {
833 				/* Claim host controller, perform F0 write,
834 				 and release */
835 				sdio_claim_host(gInstance->func[func]);
836 				sdio_f0_writeb(gInstance->func[func], *byte,
837 					       regaddr, &err_ret);
838 				sdio_release_host(gInstance->func[func]);
839 			}
840 		} else {
841 			/* Claim host controller, perform Fn write,
842 			 and release */
843 			sdio_claim_host(gInstance->func[func]);
844 			sdio_writeb(gInstance->func[func], *byte, regaddr,
845 				    &err_ret);
846 			sdio_release_host(gInstance->func[func]);
847 		}
848 	} else {		/* CMD52 Read */
849 		/* Claim host controller, perform Fn read, and release */
850 		sdio_claim_host(gInstance->func[func]);
851 
852 		if (func == 0) {
853 			*byte =
854 			    sdio_f0_readb(gInstance->func[func], regaddr,
855 					  &err_ret);
856 		} else {
857 			*byte =
858 			    sdio_readb(gInstance->func[func], regaddr,
859 				       &err_ret);
860 		}
861 
862 		sdio_release_host(gInstance->func[func]);
863 	}
864 
865 	if (err_ret)
866 		sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, "
867 			"Err: %d\n", rw ? "Write" : "Read", func, regaddr,
868 			*byte, err_ret));
869 
870 	return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
871 }
872 
873 extern SDIOH_API_RC
sdioh_request_word(sdioh_info_t * sd,uint cmd_type,uint rw,uint func,uint addr,u32 * word,uint nbytes)874 sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func,
875 		   uint addr, u32 *word, uint nbytes)
876 {
877 	int err_ret = SDIOH_API_RC_FAIL;
878 
879 	if (func == 0) {
880 		sd_err(("%s: Only CMD52 allowed to F0.\n", __func__));
881 		return SDIOH_API_RC_FAIL;
882 	}
883 
884 	sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
885 		 __func__, cmd_type, rw, func, addr, nbytes));
886 
887 	DHD_PM_RESUME_WAIT(sdioh_request_word_wait);
888 	DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
889 	/* Claim host controller */
890 	sdio_claim_host(gInstance->func[func]);
891 
892 	if (rw) {		/* CMD52 Write */
893 		if (nbytes == 4) {
894 			sdio_writel(gInstance->func[func], *word, addr,
895 				    &err_ret);
896 		} else if (nbytes == 2) {
897 			sdio_writew(gInstance->func[func], (*word & 0xFFFF),
898 				    addr, &err_ret);
899 		} else {
900 			sd_err(("%s: Invalid nbytes: %d\n", __func__, nbytes));
901 		}
902 	} else {		/* CMD52 Read */
903 		if (nbytes == 4) {
904 			*word =
905 			    sdio_readl(gInstance->func[func], addr, &err_ret);
906 		} else if (nbytes == 2) {
907 			*word =
908 			    sdio_readw(gInstance->func[func], addr,
909 				       &err_ret) & 0xFFFF;
910 		} else {
911 			sd_err(("%s: Invalid nbytes: %d\n", __func__, nbytes));
912 		}
913 	}
914 
915 	/* Release host controller */
916 	sdio_release_host(gInstance->func[func]);
917 
918 	if (err_ret) {
919 		sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x",
920 			rw ? "Write" : "Read", err_ret));
921 	}
922 
923 	return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
924 }
925 
926 static SDIOH_API_RC
sdioh_request_packet(sdioh_info_t * sd,uint fix_inc,uint write,uint func,uint addr,struct sk_buff * pkt)927 sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
928 		     uint addr, struct sk_buff *pkt)
929 {
930 	bool fifo = (fix_inc == SDIOH_DATA_FIX);
931 	u32 SGCount = 0;
932 	int err_ret = 0;
933 
934 	struct sk_buff *pnext;
935 
936 	sd_trace(("%s: Enter\n", __func__));
937 
938 	ASSERT(pkt);
939 	DHD_PM_RESUME_WAIT(sdioh_request_packet_wait);
940 	DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
941 
942 	/* Claim host controller */
943 	sdio_claim_host(gInstance->func[func]);
944 	for (pnext = pkt; pnext; pnext = pnext->next) {
945 		uint pkt_len = pnext->len;
946 		pkt_len += 3;
947 		pkt_len &= 0xFFFFFFFC;
948 
949 #ifdef CONFIG_MMC_MSM7X00A
950 		if ((pkt_len % 64) == 32) {
951 			sd_trace(("%s: Rounding up TX packet +=32\n",
952 				  __func__));
953 			pkt_len += 32;
954 		}
955 #endif				/* CONFIG_MMC_MSM7X00A */
956 		/* Make sure the packet is aligned properly.
957 		 * If it isn't, then this
958 		 * is the fault of sdioh_request_buffer() which
959 		 * is supposed to give
960 		 * us something we can work with.
961 		 */
962 		ASSERT(((u32) (pkt->data) & DMA_ALIGN_MASK) == 0);
963 
964 		if ((write) && (!fifo)) {
965 			err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
966 						   ((u8 *) (pnext->data)),
967 						   pkt_len);
968 		} else if (write) {
969 			err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
970 						   ((u8 *) (pnext->data)),
971 						   pkt_len);
972 		} else if (fifo) {
973 			err_ret = sdio_readsb(gInstance->func[func],
974 					      ((u8 *) (pnext->data)),
975 					      addr, pkt_len);
976 		} else {
977 			err_ret = sdio_memcpy_fromio(gInstance->func[func],
978 						     ((u8 *) (pnext->data)),
979 						     addr, pkt_len);
980 		}
981 
982 		if (err_ret) {
983 			sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d,"
984 				 "ERR=0x%08x\n", __func__,
985 				 (write) ? "TX" : "RX",
986 				 pnext, SGCount, addr, pkt_len, err_ret));
987 		} else {
988 			sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
989 				  __func__,
990 				  (write) ? "TX" : "RX",
991 				  pnext, SGCount, addr, pkt_len));
992 		}
993 
994 		if (!fifo)
995 			addr += pkt_len;
996 		SGCount++;
997 
998 	}
999 
1000 	/* Release host controller */
1001 	sdio_release_host(gInstance->func[func]);
1002 
1003 	sd_trace(("%s: Exit\n", __func__));
1004 	return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
1005 }
1006 
1007 /*
1008  * This function takes a buffer or packet, and fixes everything up
1009  * so that in the
1010  * end, a DMA-able packet is created.
1011  *
1012  * A buffer does not have an associated packet pointer,
1013  * and may or may not be aligned.
1014  * A packet may consist of a single packet, or a packet chain.
1015  * If it is a packet chain,
1016  * then all the packets in the chain must be properly aligned.
1017  * If the packet data is not
1018  * aligned, then there may only be one packet, and in this case,
1019  * it is copied to a new
1020  * aligned packet.
1021  *
1022  */
1023 extern SDIOH_API_RC
sdioh_request_buffer(sdioh_info_t * sd,uint pio_dma,uint fix_inc,uint write,uint func,uint addr,uint reg_width,uint buflen_u,u8 * buffer,struct sk_buff * pkt)1024 sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write,
1025 		     uint func, uint addr, uint reg_width, uint buflen_u,
1026 		     u8 *buffer, struct sk_buff *pkt)
1027 {
1028 	SDIOH_API_RC Status;
1029 	struct sk_buff *mypkt = NULL;
1030 
1031 	sd_trace(("%s: Enter\n", __func__));
1032 
1033 	DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait);
1034 	DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
1035 	/* Case 1: we don't have a packet. */
1036 	if (pkt == NULL) {
1037 		sd_data(("%s: Creating new %s Packet, len=%d\n",
1038 			 __func__, write ? "TX" : "RX", buflen_u));
1039 		mypkt = pkt_buf_get_skb(buflen_u);
1040 		if (!mypkt) {
1041 			sd_err(("%s: pkt_buf_get_skb failed: len %d\n",
1042 				__func__, buflen_u));
1043 			return SDIOH_API_RC_FAIL;
1044 		}
1045 
1046 		/* For a write, copy the buffer data into the packet. */
1047 		if (write)
1048 			memcpy(mypkt->data, buffer, buflen_u);
1049 
1050 		Status =
1051 		    sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
1052 
1053 		/* For a read, copy the packet data back to the buffer. */
1054 		if (!write)
1055 			memcpy(buffer, mypkt->data, buflen_u);
1056 
1057 		pkt_buf_free_skb(mypkt);
1058 	} else if (((u32) (pkt->data) & DMA_ALIGN_MASK) != 0) {
1059 		/* Case 2: We have a packet, but it is unaligned. */
1060 
1061 		/* In this case, we cannot have a chain. */
1062 		ASSERT(pkt->next == NULL);
1063 
1064 		sd_data(("%s: Creating aligned %s Packet, len=%d\n",
1065 			 __func__, write ? "TX" : "RX", pkt->len));
1066 		mypkt = pkt_buf_get_skb(pkt->len);
1067 		if (!mypkt) {
1068 			sd_err(("%s: pkt_buf_get_skb failed: len %d\n",
1069 				__func__, pkt->len));
1070 			return SDIOH_API_RC_FAIL;
1071 		}
1072 
1073 		/* For a write, copy the buffer data into the packet. */
1074 		if (write)
1075 			memcpy(mypkt->data, pkt->data, pkt->len);
1076 
1077 		Status =
1078 		    sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
1079 
1080 		/* For a read, copy the packet data back to the buffer. */
1081 		if (!write)
1082 			memcpy(pkt->data, mypkt->data, mypkt->len);
1083 
1084 		pkt_buf_free_skb(mypkt);
1085 	} else {		/* case 3: We have a packet and
1086 				 it is aligned. */
1087 		sd_data(("%s: Aligned %s Packet, direct DMA\n",
1088 			 __func__, write ? "Tx" : "Rx"));
1089 		Status =
1090 		    sdioh_request_packet(sd, fix_inc, write, func, addr, pkt);
1091 	}
1092 
1093 	return Status;
1094 }
1095 
1096 /* this function performs "abort" for both of host & device */
sdioh_abort(sdioh_info_t * sd,uint func)1097 extern int sdioh_abort(sdioh_info_t *sd, uint func)
1098 {
1099 #if defined(MMC_SDIO_ABORT)
1100 	char t_func = (char)func;
1101 #endif				/* defined(MMC_SDIO_ABORT) */
1102 	sd_trace(("%s: Enter\n", __func__));
1103 
1104 #if defined(MMC_SDIO_ABORT)
1105 	/* issue abort cmd52 command through F1 */
1106 	sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT,
1107 			   &t_func);
1108 #endif				/* defined(MMC_SDIO_ABORT) */
1109 
1110 	sd_trace(("%s: Exit\n", __func__));
1111 	return SDIOH_API_RC_SUCCESS;
1112 }
1113 
1114 /* Reset and re-initialize the device */
sdioh_sdio_reset(sdioh_info_t * si)1115 int sdioh_sdio_reset(sdioh_info_t *si)
1116 {
1117 	sd_trace(("%s: Enter\n", __func__));
1118 	sd_trace(("%s: Exit\n", __func__));
1119 	return SDIOH_API_RC_SUCCESS;
1120 }
1121 
1122 /* Disable device interrupt */
sdioh_sdmmc_devintr_off(sdioh_info_t * sd)1123 void sdioh_sdmmc_devintr_off(sdioh_info_t *sd)
1124 {
1125 	sd_trace(("%s: %d\n", __func__, sd->use_client_ints));
1126 	sd->intmask &= ~CLIENT_INTR;
1127 }
1128 
1129 /* Enable device interrupt */
sdioh_sdmmc_devintr_on(sdioh_info_t * sd)1130 void sdioh_sdmmc_devintr_on(sdioh_info_t *sd)
1131 {
1132 	sd_trace(("%s: %d\n", __func__, sd->use_client_ints));
1133 	sd->intmask |= CLIENT_INTR;
1134 }
1135 
1136 /* Read client card reg */
1137 int
sdioh_sdmmc_card_regread(sdioh_info_t * sd,int func,u32 regaddr,int regsize,u32 * data)1138 sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, u32 regaddr,
1139 			 int regsize, u32 *data)
1140 {
1141 
1142 	if ((func == 0) || (regsize == 1)) {
1143 		u8 temp = 0;
1144 
1145 		sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1146 		*data = temp;
1147 		*data &= 0xff;
1148 		sd_data(("%s: byte read data=0x%02x\n", __func__, *data));
1149 	} else {
1150 		sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data,
1151 				   regsize);
1152 		if (regsize == 2)
1153 			*data &= 0xffff;
1154 
1155 		sd_data(("%s: word read data=0x%08x\n", __func__, *data));
1156 	}
1157 
1158 	return SUCCESS;
1159 }
1160 
1161 #if !defined(OOB_INTR_ONLY)
1162 /* bcmsdh_sdmmc interrupt handler */
IRQHandler(struct sdio_func * func)1163 static void IRQHandler(struct sdio_func *func)
1164 {
1165 	sdioh_info_t *sd;
1166 
1167 	sd_trace(("bcmsdh_sdmmc: ***IRQHandler\n"));
1168 	sd = gInstance->sd;
1169 
1170 	ASSERT(sd != NULL);
1171 	sdio_release_host(gInstance->func[0]);
1172 
1173 	if (sd->use_client_ints) {
1174 		sd->intrcount++;
1175 		ASSERT(sd->intr_handler);
1176 		ASSERT(sd->intr_handler_arg);
1177 		(sd->intr_handler) (sd->intr_handler_arg);
1178 	} else {
1179 		sd_err(("bcmsdh_sdmmc: ***IRQHandler\n"));
1180 
1181 		sd_err(("%s: Not ready for intr: enabled %d, handler %p\n",
1182 			__func__, sd->client_intr_enabled, sd->intr_handler));
1183 	}
1184 
1185 	sdio_claim_host(gInstance->func[0]);
1186 }
1187 
1188 /* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */
IRQHandlerF2(struct sdio_func * func)1189 static void IRQHandlerF2(struct sdio_func *func)
1190 {
1191 	sdioh_info_t *sd;
1192 
1193 	sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n"));
1194 
1195 	sd = gInstance->sd;
1196 
1197 	ASSERT(sd != NULL);
1198 }
1199 #endif				/* !defined(OOB_INTR_ONLY) */
1200 
1201 #ifdef NOTUSED
1202 /* Write client card reg */
1203 static int
sdioh_sdmmc_card_regwrite(sdioh_info_t * sd,int func,u32 regaddr,int regsize,u32 data)1204 sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, u32 regaddr,
1205 			  int regsize, u32 data)
1206 {
1207 
1208 	if ((func == 0) || (regsize == 1)) {
1209 		u8 temp;
1210 
1211 		temp = data & 0xff;
1212 		sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1213 		sd_data(("%s: byte write data=0x%02x\n", __func__, data));
1214 	} else {
1215 		if (regsize == 2)
1216 			data &= 0xffff;
1217 
1218 		sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data,
1219 				   regsize);
1220 
1221 		sd_data(("%s: word write data=0x%08x\n", __func__, data));
1222 	}
1223 
1224 	return SUCCESS;
1225 }
1226 #endif				/* NOTUSED */
1227 
sdioh_start(sdioh_info_t * si,int stage)1228 int sdioh_start(sdioh_info_t *si, int stage)
1229 {
1230 	return 0;
1231 }
1232 
sdioh_stop(sdioh_info_t * si)1233 int sdioh_stop(sdioh_info_t *si)
1234 {
1235 	return 0;
1236 }
1237