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>
46extern volatile bool dhd_mmc_suspend;
47#endif
48#include "bcmsdh_sdmmc.h"
49
50#ifndef BCMSDH_MODULE
51extern int sdio_function_init(void);
52extern void sdio_function_cleanup(void);
53#endif /* BCMSDH_MODULE */
54
55#if !defined(OOB_INTR_ONLY)
56static void IRQHandler(struct sdio_func *func);
57static void IRQHandlerF2(struct sdio_func *func);
58#endif /* !defined(OOB_INTR_ONLY) */
59static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr);
60extern int sdio_reset_comm(struct mmc_card *card);
61
62extern PBCMSDH_SDMMC_INSTANCE gInstance;
63
64uint sd_sdmode = SDIOH_MODE_SD4;	/* Use SD4 mode by default */
65uint sd_f2_blocksize = 512;		/* Default blocksize */
66
67uint sd_divisor = 2;			/* Default 48MHz/2 = 24MHz */
68
69uint sd_power = 1;		/* Default to SD Slot powered ON */
70uint sd_clock = 1;		/* Default to SD Clock turned ON */
71uint sd_hiok = FALSE;	/* Don't use hi-speed mode by default */
72uint sd_msglevel = 0x01;
73uint sd_use_dma = TRUE;
74DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait);
75DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait);
76DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait);
77DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait);
78
79#define DMA_ALIGN_MASK	0x03
80
81int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data);
82
83static int
84sdioh_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 */
122extern sdioh_info_t *
123sdioh_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
188extern SDIOH_API_RC
189sdioh_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
215extern SDIOH_API_RC
216sdioh_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
246extern SDIOH_API_RC
247sdioh_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 */
278extern SDIOH_API_RC
279sdioh_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
309extern SDIOH_API_RC
310sdioh_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
339extern SDIOH_API_RC
340sdioh_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)
348extern bool
349sdioh_interrupt_pending(sdioh_info_t *sd)
350{
351	return (0);
352}
353#endif
354
355uint
356sdioh_query_iofnum(sdioh_info_t *sd)
357{
358	return sd->num_funcs;
359}
360
361/* IOVar table */
362enum {
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
381const 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
400int
401sdioh_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	}
661exit:
662
663	return bcmerror;
664}
665
666#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
667
668SDIOH_API_RC
669sdioh_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
686extern SDIOH_API_RC
687sdioh_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
695extern SDIOH_API_RC
696sdioh_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
704static int
705sdioh_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
725extern SDIOH_API_RC
726sdioh_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
757extern SDIOH_API_RC
758sdioh_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
840extern SDIOH_API_RC
841sdioh_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
888static SDIOH_API_RC
889sdioh_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 */
981extern SDIOH_API_RC
982sdioh_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 */
1070extern int
1071sdioh_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 */
1088int 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 */
1096void
1097sdioh_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 */
1104void
1105sdioh_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 */
1112int
1113sdioh_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 */
1138static 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) */
1164static 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 */
1178static int
1179sdioh_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
1203int
1204sdioh_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
1280int
1281sdioh_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