2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 /* ****************** SDIO CARD Interface Functions **************************/
18 #include <linux/types.h>
19 #include <linux/netdevice.h>
20 #include <linux/pci.h>
21 #include <linux/pci_ids.h>
22 #include <linux/sched.h>
23 #include <linux/completion.h>
24 #include <linux/mmc/sdio.h>
25 #include <linux/mmc/sdio_func.h>
26 #include <linux/mmc/card.h>
29 #include <brcm_hw_ids.h>
30 #include <brcmu_utils.h>
31 #include <brcmu_wifi.h>
36 #include "sdio_host.h"
38 #define SDIOH_API_ACCESS_RETRY_LIMIT 2
40 #define SDIOH_CMD_TYPE_NORMAL 0 /* Normal command */
41 #define SDIOH_CMD_TYPE_APPEND 1 /* Append command */
42 #define SDIOH_CMD_TYPE_CUTTHRU 2 /* Cut-through command */
44 #define SDIOH_DATA_PIO 0 /* PIO mode */
45 #define SDIOH_DATA_DMA 1 /* DMA mode */
47 /* Module parameters specific to each host-controller driver */
49 module_param(sd_f2_blocksize
, int, 0);
59 const struct brcmu_iovar sdioh_iovars
[] = {
60 {"sd_devreg", IOV_DEVREG
, 0, IOVT_BUFFER
, sizeof(struct brcmf_sdreg
)}
62 {"sd_rxchain", IOV_RXCHAIN
, 0, IOVT_BOOL
, 0}
68 brcmf_sdcard_iovar_op(struct brcmf_sdio_dev
*sdiodev
, const char *name
,
69 void *params
, int plen
, void *arg
, int len
, bool set
)
71 const struct brcmu_iovar
*vi
= NULL
;
78 if (name
== NULL
|| len
< 0)
81 /* Set does not take qualifiers */
82 if (set
&& (params
|| plen
))
85 /* Get must have return space;*/
86 if (!set
&& !(arg
&& len
))
89 BRCMF_TRACE(("%s: Enter (%s %s)\n", __func__
, (set
? "set" : "get"),
92 vi
= brcmu_iovar_lookup(sdioh_iovars
, name
);
98 bcmerror
= brcmu_iovar_lencheck(vi
, arg
, len
, set
);
102 /* Set up params so get and set can share the convenience variables */
103 if (params
== NULL
) {
108 if (vi
->type
== IOVT_VOID
)
110 else if (vi
->type
== IOVT_BUFFER
)
113 val_size
= sizeof(int);
115 if (plen
>= (int)sizeof(int_val
))
116 memcpy(&int_val
, params
, sizeof(int_val
));
118 bool_val
= (int_val
!= 0) ? true : false;
120 actionid
= set
? IOV_SVAL(vi
->varid
) : IOV_GVAL(vi
->varid
);
122 case IOV_GVAL(IOV_RXCHAIN
):
124 memcpy(arg
, &int_val
, val_size
);
127 case IOV_GVAL(IOV_DEVREG
):
129 struct brcmf_sdreg
*sd_ptr
=
130 (struct brcmf_sdreg
*) params
;
133 if (brcmf_sdioh_request_byte(sdiodev
, SDIOH_READ
,
134 sd_ptr
->func
, sd_ptr
->offset
, &data
)) {
140 memcpy(arg
, &int_val
, sizeof(int_val
));
144 case IOV_SVAL(IOV_DEVREG
):
146 struct brcmf_sdreg
*sd_ptr
=
147 (struct brcmf_sdreg
*) params
;
148 u8 data
= (u8
) sd_ptr
->value
;
150 if (brcmf_sdioh_request_byte(sdiodev
, SDIOH_WRITE
,
151 sd_ptr
->func
, sd_ptr
->offset
, &data
)) {
159 bcmerror
= -ENOTSUPP
;
167 static void brcmf_sdioh_irqhandler(struct sdio_func
*func
)
169 struct brcmf_sdio_dev
*sdiodev
= dev_get_drvdata(&func
->card
->dev
);
171 BRCMF_TRACE(("brcmf: ***IRQHandler\n"));
173 sdio_release_host(func
);
175 brcmf_sdbrcm_isr(sdiodev
->bus
);
177 sdio_claim_host(func
);
180 int brcmf_sdcard_intr_reg(struct brcmf_sdio_dev
*sdiodev
)
182 BRCMF_TRACE(("%s: Entering\n", __func__
));
184 sdio_claim_host(sdiodev
->func
[1]);
185 sdio_claim_irq(sdiodev
->func
[1], brcmf_sdioh_irqhandler
);
186 sdio_release_host(sdiodev
->func
[1]);
191 int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev
*sdiodev
)
193 BRCMF_TRACE(("%s: Entering\n", __func__
));
195 sdio_claim_host(sdiodev
->func
[1]);
196 sdio_release_irq(sdiodev
->func
[1]);
197 sdio_release_host(sdiodev
->func
[1]);
202 u8
brcmf_sdcard_cfg_read(struct brcmf_sdio_dev
*sdiodev
, uint fnc_num
, u32 addr
,
210 if (retry
) /* wait for 1 ms till bus get settled down */
212 status
= brcmf_sdioh_request_byte(sdiodev
, SDIOH_READ
, fnc_num
,
215 && (retry
++ < SDIOH_API_ACCESS_RETRY_LIMIT
));
219 BRCMF_INFO(("%s:fun = %d, addr = 0x%x, u8data = 0x%x\n",
220 __func__
, fnc_num
, addr
, data
));
226 brcmf_sdcard_cfg_write(struct brcmf_sdio_dev
*sdiodev
, uint fnc_num
, u32 addr
,
233 if (retry
) /* wait for 1 ms till bus get settled down */
235 status
= brcmf_sdioh_request_byte(sdiodev
, SDIOH_WRITE
, fnc_num
,
238 && (retry
++ < SDIOH_API_ACCESS_RETRY_LIMIT
));
242 BRCMF_INFO(("%s:fun = %d, addr = 0x%x, u8data = 0x%x\n",
243 __func__
, fnc_num
, addr
, data
));
246 int brcmf_sdcard_cis_read(struct brcmf_sdio_dev
*sdiodev
, uint func
, u8
* cis
,
251 u8
*tmp_buf
, *tmp_ptr
;
253 bool ascii
= func
& ~0xf;
256 status
= brcmf_sdioh_cis_read(sdiodev
, func
, cis
, length
);
259 /* Move binary bits to tmp and format them
260 into the provided buffer. */
261 tmp_buf
= kmalloc(length
, GFP_ATOMIC
);
262 if (tmp_buf
== NULL
) {
263 BRCMF_ERROR(("%s: out of memory\n", __func__
));
266 memcpy(tmp_buf
, cis
, length
);
267 for (tmp_ptr
= tmp_buf
, ptr
= cis
; ptr
< (cis
+ length
- 4);
269 ptr
+= sprintf((char *)ptr
, "%.2x ", *tmp_ptr
& 0xff);
270 if ((((tmp_ptr
- tmp_buf
) + 1) & 0xf) == 0)
271 ptr
+= sprintf((char *)ptr
, "\n");
280 brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev
*sdiodev
, u32 address
)
283 brcmf_sdcard_cfg_write(sdiodev
, SDIO_FUNC_1
, SBSDIO_FUNC1_SBADDRLOW
,
284 (address
>> 8) & SBSDIO_SBADDRLOW_MASK
, &err
);
286 brcmf_sdcard_cfg_write(sdiodev
, SDIO_FUNC_1
,
287 SBSDIO_FUNC1_SBADDRMID
,
288 (address
>> 16) & SBSDIO_SBADDRMID_MASK
,
291 brcmf_sdcard_cfg_write(sdiodev
, SDIO_FUNC_1
,
292 SBSDIO_FUNC1_SBADDRHIGH
,
293 (address
>> 24) & SBSDIO_SBADDRHIGH_MASK
,
299 u32
brcmf_sdcard_reg_read(struct brcmf_sdio_dev
*sdiodev
, u32 addr
, uint size
)
303 uint bar0
= addr
& ~SBSDIO_SB_OFT_ADDR_MASK
;
305 BRCMF_INFO(("%s:fun = 1, addr = 0x%x, ", __func__
, addr
));
307 if (bar0
!= sdiodev
->sbwad
) {
308 if (brcmf_sdcard_set_sbaddr_window(sdiodev
, bar0
))
311 sdiodev
->sbwad
= bar0
;
314 addr
&= SBSDIO_SB_OFT_ADDR_MASK
;
316 addr
|= SBSDIO_SB_ACCESS_2_4B_FLAG
;
318 status
= brcmf_sdioh_request_word(sdiodev
, SDIOH_CMD_TYPE_NORMAL
,
319 SDIOH_READ
, SDIO_FUNC_1
, addr
, &word
, size
);
321 sdiodev
->regfail
= (status
!= 0);
323 BRCMF_INFO(("u32data = 0x%x\n", word
));
325 /* if ok, return appropriately masked word */
331 return word
& 0xffff;
335 sdiodev
->regfail
= true;
340 /* otherwise, bad sdio access or invalid size */
341 BRCMF_ERROR(("%s: error reading addr 0x%04x size %d\n", __func__
,
346 u32
brcmf_sdcard_reg_write(struct brcmf_sdio_dev
*sdiodev
, u32 addr
, uint size
,
350 uint bar0
= addr
& ~SBSDIO_SB_OFT_ADDR_MASK
;
353 BRCMF_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
354 __func__
, addr
, size
* 8, data
));
356 if (bar0
!= sdiodev
->sbwad
) {
357 err
= brcmf_sdcard_set_sbaddr_window(sdiodev
, bar0
);
361 sdiodev
->sbwad
= bar0
;
364 addr
&= SBSDIO_SB_OFT_ADDR_MASK
;
366 addr
|= SBSDIO_SB_ACCESS_2_4B_FLAG
;
368 brcmf_sdioh_request_word(sdiodev
, SDIOH_CMD_TYPE_NORMAL
,
369 SDIOH_WRITE
, SDIO_FUNC_1
, addr
, &data
, size
);
370 sdiodev
->regfail
= (status
!= 0);
375 BRCMF_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n",
376 __func__
, data
, addr
, size
));
380 bool brcmf_sdcard_regfail(struct brcmf_sdio_dev
*sdiodev
)
382 return sdiodev
->regfail
;
386 brcmf_sdcard_recv_buf(struct brcmf_sdio_dev
*sdiodev
, u32 addr
, uint fn
,
388 u8
*buf
, uint nbytes
, struct sk_buff
*pkt
,
389 void (*complete
)(void *handle
, int status
,
396 uint bar0
= addr
& ~SBSDIO_SB_OFT_ADDR_MASK
;
399 BRCMF_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
400 __func__
, fn
, addr
, nbytes
));
402 /* Async not implemented yet */
403 if (flags
& SDIO_REQ_ASYNC
)
406 if (bar0
!= sdiodev
->sbwad
) {
407 err
= brcmf_sdcard_set_sbaddr_window(sdiodev
, bar0
);
411 sdiodev
->sbwad
= bar0
;
414 addr
&= SBSDIO_SB_OFT_ADDR_MASK
;
416 incr_fix
= (flags
& SDIO_REQ_FIXED
) ? SDIOH_DATA_FIX
: SDIOH_DATA_INC
;
417 width
= (flags
& SDIO_REQ_4BYTE
) ? 4 : 2;
419 addr
|= SBSDIO_SB_ACCESS_2_4B_FLAG
;
421 status
= brcmf_sdioh_request_buffer(sdiodev
, SDIOH_DATA_PIO
,
422 incr_fix
, SDIOH_READ
, fn
, addr
, width
, nbytes
, buf
, pkt
);
428 brcmf_sdcard_send_buf(struct brcmf_sdio_dev
*sdiodev
, u32 addr
, uint fn
,
429 uint flags
, u8
*buf
, uint nbytes
, void *pkt
,
430 void (*complete
)(void *handle
, int status
,
436 uint bar0
= addr
& ~SBSDIO_SB_OFT_ADDR_MASK
;
439 BRCMF_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
440 __func__
, fn
, addr
, nbytes
));
442 /* Async not implemented yet */
443 if (flags
& SDIO_REQ_ASYNC
)
446 if (bar0
!= sdiodev
->sbwad
) {
447 err
= brcmf_sdcard_set_sbaddr_window(sdiodev
, bar0
);
451 sdiodev
->sbwad
= bar0
;
454 addr
&= SBSDIO_SB_OFT_ADDR_MASK
;
456 incr_fix
= (flags
& SDIO_REQ_FIXED
) ? SDIOH_DATA_FIX
: SDIOH_DATA_INC
;
457 width
= (flags
& SDIO_REQ_4BYTE
) ? 4 : 2;
459 addr
|= SBSDIO_SB_ACCESS_2_4B_FLAG
;
461 return brcmf_sdioh_request_buffer(sdiodev
, SDIOH_DATA_PIO
,
462 incr_fix
, SDIOH_WRITE
, fn
, addr
, width
, nbytes
, buf
, pkt
);
465 int brcmf_sdcard_rwdata(struct brcmf_sdio_dev
*sdiodev
, uint rw
, u32 addr
,
466 u8
*buf
, uint nbytes
)
468 addr
&= SBSDIO_SB_OFT_ADDR_MASK
;
469 addr
|= SBSDIO_SB_ACCESS_2_4B_FLAG
;
471 return brcmf_sdioh_request_buffer(sdiodev
, SDIOH_DATA_PIO
,
472 SDIOH_DATA_INC
, (rw
? SDIOH_WRITE
: SDIOH_READ
), SDIO_FUNC_1
,
473 addr
, 4, nbytes
, buf
, NULL
);
476 int brcmf_sdcard_abort(struct brcmf_sdio_dev
*sdiodev
, uint fn
)
478 char t_func
= (char)fn
;
479 BRCMF_TRACE(("%s: Enter\n", __func__
));
481 /* issue abort cmd52 command through F0 */
482 brcmf_sdioh_request_byte(sdiodev
, SDIOH_WRITE
, SDIO_FUNC_0
,
483 SDIO_CCCR_ABORT
, &t_func
);
485 BRCMF_TRACE(("%s: Exit\n", __func__
));
489 u32
brcmf_sdcard_cur_sbwad(struct brcmf_sdio_dev
*sdiodev
)
491 return sdiodev
->sbwad
;
494 int brcmf_sdio_probe(struct brcmf_sdio_dev
*sdiodev
)
499 ret
= brcmf_sdioh_attach(sdiodev
);
505 /* Report the BAR, to fix if needed */
506 sdiodev
->sbwad
= SI_ENUM_BASE
;
508 /* try to attach to the target device */
509 sdiodev
->bus
= brcmf_sdbrcm_probe(0, 0, 0, 0, regs
, sdiodev
);
511 BRCMF_ERROR(("%s: device attach failed\n", __func__
));
518 brcmf_sdio_remove(sdiodev
);
522 EXPORT_SYMBOL(brcmf_sdio_probe
);
524 int brcmf_sdio_remove(struct brcmf_sdio_dev
*sdiodev
)
527 brcmf_sdbrcm_disconnect(sdiodev
->bus
);
531 brcmf_sdioh_detach(sdiodev
);
537 EXPORT_SYMBOL(brcmf_sdio_remove
);
539 int brcmf_sdio_register(void)
541 return brcmf_sdio_function_init();
544 void brcmf_sdio_unregister(void)
546 brcmf_sdio_function_cleanup();
549 void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev
*sdiodev
, bool enable
)
552 brcmf_sdbrcm_wd_timer(sdiodev
->bus
, brcmf_watchdog_ms
);
554 brcmf_sdbrcm_wd_timer(sdiodev
->bus
, 0);