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