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