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