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