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_dbg(TRACE
, "Enter (%s %s)\n", set
? "set" : "get", name
);
91 vi
= brcmu_iovar_lookup(sdioh_iovars
, name
);
97 bcmerror
= brcmu_iovar_lencheck(vi
, arg
, len
, set
);
101 /* Set up params so get and set can share the convenience variables */
102 if (params
== NULL
) {
107 if (vi
->type
== IOVT_VOID
)
109 else if (vi
->type
== IOVT_BUFFER
)
112 val_size
= sizeof(int);
114 if (plen
>= (int)sizeof(int_val
))
115 memcpy(&int_val
, params
, sizeof(int_val
));
117 bool_val
= (int_val
!= 0) ? true : false;
119 actionid
= set
? IOV_SVAL(vi
->varid
) : IOV_GVAL(vi
->varid
);
121 case IOV_GVAL(IOV_RXCHAIN
):
123 memcpy(arg
, &int_val
, val_size
);
126 case IOV_GVAL(IOV_DEVREG
):
128 struct brcmf_sdreg
*sd_ptr
=
129 (struct brcmf_sdreg
*) params
;
132 if (brcmf_sdioh_request_byte(sdiodev
, SDIOH_READ
,
133 sd_ptr
->func
, sd_ptr
->offset
, &data
)) {
139 memcpy(arg
, &int_val
, sizeof(int_val
));
143 case IOV_SVAL(IOV_DEVREG
):
145 struct brcmf_sdreg
*sd_ptr
=
146 (struct brcmf_sdreg
*) params
;
147 u8 data
= (u8
) sd_ptr
->value
;
149 if (brcmf_sdioh_request_byte(sdiodev
, SDIOH_WRITE
,
150 sd_ptr
->func
, sd_ptr
->offset
, &data
)) {
158 bcmerror
= -ENOTSUPP
;
166 static void brcmf_sdioh_irqhandler(struct sdio_func
*func
)
168 struct brcmf_sdio_dev
*sdiodev
= dev_get_drvdata(&func
->card
->dev
);
170 brcmf_dbg(TRACE
, "***IRQHandler\n");
172 sdio_release_host(func
);
174 brcmf_sdbrcm_isr(sdiodev
->bus
);
176 sdio_claim_host(func
);
179 int brcmf_sdcard_intr_reg(struct brcmf_sdio_dev
*sdiodev
)
181 brcmf_dbg(TRACE
, "Entering\n");
183 sdio_claim_host(sdiodev
->func
[1]);
184 sdio_claim_irq(sdiodev
->func
[1], brcmf_sdioh_irqhandler
);
185 sdio_release_host(sdiodev
->func
[1]);
190 int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev
*sdiodev
)
192 brcmf_dbg(TRACE
, "Entering\n");
194 sdio_claim_host(sdiodev
->func
[1]);
195 sdio_release_irq(sdiodev
->func
[1]);
196 sdio_release_host(sdiodev
->func
[1]);
201 u8
brcmf_sdcard_cfg_read(struct brcmf_sdio_dev
*sdiodev
, uint fnc_num
, u32 addr
,
209 if (retry
) /* wait for 1 ms till bus get settled down */
211 status
= brcmf_sdioh_request_byte(sdiodev
, SDIOH_READ
, fnc_num
,
214 && (retry
++ < SDIOH_API_ACCESS_RETRY_LIMIT
));
218 brcmf_dbg(INFO
, "fun = %d, addr = 0x%x, u8data = 0x%x\n",
219 fnc_num
, addr
, data
);
225 brcmf_sdcard_cfg_write(struct brcmf_sdio_dev
*sdiodev
, uint fnc_num
, u32 addr
,
232 if (retry
) /* wait for 1 ms till bus get settled down */
234 status
= brcmf_sdioh_request_byte(sdiodev
, SDIOH_WRITE
, fnc_num
,
237 && (retry
++ < SDIOH_API_ACCESS_RETRY_LIMIT
));
241 brcmf_dbg(INFO
, "fun = %d, addr = 0x%x, u8data = 0x%x\n",
242 fnc_num
, addr
, data
);
245 int brcmf_sdcard_cis_read(struct brcmf_sdio_dev
*sdiodev
, uint func
, u8
* cis
,
250 u8
*tmp_buf
, *tmp_ptr
;
252 bool ascii
= func
& ~0xf;
255 status
= brcmf_sdioh_cis_read(sdiodev
, func
, cis
, length
);
258 /* Move binary bits to tmp and format them
259 into the provided buffer. */
260 tmp_buf
= kmalloc(length
, GFP_ATOMIC
);
261 if (tmp_buf
== NULL
) {
262 brcmf_dbg(ERROR
, "out of memory\n");
265 memcpy(tmp_buf
, cis
, length
);
266 for (tmp_ptr
= tmp_buf
, ptr
= cis
; ptr
< (cis
+ length
- 4);
268 ptr
+= sprintf((char *)ptr
, "%.2x ", *tmp_ptr
& 0xff);
269 if ((((tmp_ptr
- tmp_buf
) + 1) & 0xf) == 0)
270 ptr
+= sprintf((char *)ptr
, "\n");
279 brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev
*sdiodev
, u32 address
)
282 brcmf_sdcard_cfg_write(sdiodev
, SDIO_FUNC_1
, SBSDIO_FUNC1_SBADDRLOW
,
283 (address
>> 8) & SBSDIO_SBADDRLOW_MASK
, &err
);
285 brcmf_sdcard_cfg_write(sdiodev
, SDIO_FUNC_1
,
286 SBSDIO_FUNC1_SBADDRMID
,
287 (address
>> 16) & SBSDIO_SBADDRMID_MASK
,
290 brcmf_sdcard_cfg_write(sdiodev
, SDIO_FUNC_1
,
291 SBSDIO_FUNC1_SBADDRHIGH
,
292 (address
>> 24) & SBSDIO_SBADDRHIGH_MASK
,
298 u32
brcmf_sdcard_reg_read(struct brcmf_sdio_dev
*sdiodev
, u32 addr
, uint size
)
302 uint bar0
= addr
& ~SBSDIO_SB_OFT_ADDR_MASK
;
304 brcmf_dbg(INFO
, "fun = 1, addr = 0x%x\n", addr
);
306 if (bar0
!= sdiodev
->sbwad
) {
307 if (brcmf_sdcard_set_sbaddr_window(sdiodev
, bar0
))
310 sdiodev
->sbwad
= bar0
;
313 addr
&= SBSDIO_SB_OFT_ADDR_MASK
;
315 addr
|= SBSDIO_SB_ACCESS_2_4B_FLAG
;
317 status
= brcmf_sdioh_request_word(sdiodev
, SDIOH_CMD_TYPE_NORMAL
,
318 SDIOH_READ
, SDIO_FUNC_1
, addr
, &word
, size
);
320 sdiodev
->regfail
= (status
!= 0);
322 brcmf_dbg(INFO
, "u32data = 0x%x\n", word
);
324 /* if ok, return appropriately masked word */
330 return word
& 0xffff;
334 sdiodev
->regfail
= true;
339 /* otherwise, bad sdio access or invalid size */
340 brcmf_dbg(ERROR
, "error reading addr 0x%04x size %d\n", addr
, size
);
344 u32
brcmf_sdcard_reg_write(struct brcmf_sdio_dev
*sdiodev
, u32 addr
, uint size
,
348 uint bar0
= addr
& ~SBSDIO_SB_OFT_ADDR_MASK
;
351 brcmf_dbg(INFO
, "fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
352 addr
, size
* 8, data
);
354 if (bar0
!= sdiodev
->sbwad
) {
355 err
= brcmf_sdcard_set_sbaddr_window(sdiodev
, bar0
);
359 sdiodev
->sbwad
= bar0
;
362 addr
&= SBSDIO_SB_OFT_ADDR_MASK
;
364 addr
|= SBSDIO_SB_ACCESS_2_4B_FLAG
;
366 brcmf_sdioh_request_word(sdiodev
, SDIOH_CMD_TYPE_NORMAL
,
367 SDIOH_WRITE
, SDIO_FUNC_1
, addr
, &data
, size
);
368 sdiodev
->regfail
= (status
!= 0);
373 brcmf_dbg(ERROR
, "error writing 0x%08x to addr 0x%04x size %d\n",
378 bool brcmf_sdcard_regfail(struct brcmf_sdio_dev
*sdiodev
)
380 return sdiodev
->regfail
;
384 brcmf_sdcard_recv_buf(struct brcmf_sdio_dev
*sdiodev
, u32 addr
, uint fn
,
386 u8
*buf
, uint nbytes
, struct sk_buff
*pkt
)
391 uint bar0
= addr
& ~SBSDIO_SB_OFT_ADDR_MASK
;
394 brcmf_dbg(INFO
, "fun = %d, addr = 0x%x, size = %d\n", fn
, addr
, nbytes
);
396 /* Async not implemented yet */
397 if (flags
& SDIO_REQ_ASYNC
)
400 if (bar0
!= sdiodev
->sbwad
) {
401 err
= brcmf_sdcard_set_sbaddr_window(sdiodev
, bar0
);
405 sdiodev
->sbwad
= bar0
;
408 addr
&= SBSDIO_SB_OFT_ADDR_MASK
;
410 incr_fix
= (flags
& SDIO_REQ_FIXED
) ? SDIOH_DATA_FIX
: SDIOH_DATA_INC
;
411 width
= (flags
& SDIO_REQ_4BYTE
) ? 4 : 2;
413 addr
|= SBSDIO_SB_ACCESS_2_4B_FLAG
;
415 status
= brcmf_sdioh_request_buffer(sdiodev
, SDIOH_DATA_PIO
,
416 incr_fix
, SDIOH_READ
, fn
, addr
, width
, nbytes
, buf
, pkt
);
422 brcmf_sdcard_send_buf(struct brcmf_sdio_dev
*sdiodev
, u32 addr
, uint fn
,
423 uint flags
, u8
*buf
, uint nbytes
, struct sk_buff
*pkt
)
427 uint bar0
= addr
& ~SBSDIO_SB_OFT_ADDR_MASK
;
430 brcmf_dbg(INFO
, "fun = %d, addr = 0x%x, size = %d\n", fn
, addr
, nbytes
);
432 /* Async not implemented yet */
433 if (flags
& SDIO_REQ_ASYNC
)
436 if (bar0
!= sdiodev
->sbwad
) {
437 err
= brcmf_sdcard_set_sbaddr_window(sdiodev
, bar0
);
441 sdiodev
->sbwad
= bar0
;
444 addr
&= SBSDIO_SB_OFT_ADDR_MASK
;
446 incr_fix
= (flags
& SDIO_REQ_FIXED
) ? SDIOH_DATA_FIX
: SDIOH_DATA_INC
;
447 width
= (flags
& SDIO_REQ_4BYTE
) ? 4 : 2;
449 addr
|= SBSDIO_SB_ACCESS_2_4B_FLAG
;
451 return brcmf_sdioh_request_buffer(sdiodev
, SDIOH_DATA_PIO
,
452 incr_fix
, SDIOH_WRITE
, fn
, addr
, width
, nbytes
, buf
, pkt
);
455 int brcmf_sdcard_rwdata(struct brcmf_sdio_dev
*sdiodev
, uint rw
, u32 addr
,
456 u8
*buf
, uint nbytes
)
458 addr
&= SBSDIO_SB_OFT_ADDR_MASK
;
459 addr
|= SBSDIO_SB_ACCESS_2_4B_FLAG
;
461 return brcmf_sdioh_request_buffer(sdiodev
, SDIOH_DATA_PIO
,
462 SDIOH_DATA_INC
, (rw
? SDIOH_WRITE
: SDIOH_READ
), SDIO_FUNC_1
,
463 addr
, 4, nbytes
, buf
, NULL
);
466 int brcmf_sdcard_abort(struct brcmf_sdio_dev
*sdiodev
, uint fn
)
468 char t_func
= (char)fn
;
469 brcmf_dbg(TRACE
, "Enter\n");
471 /* issue abort cmd52 command through F0 */
472 brcmf_sdioh_request_byte(sdiodev
, SDIOH_WRITE
, SDIO_FUNC_0
,
473 SDIO_CCCR_ABORT
, &t_func
);
475 brcmf_dbg(TRACE
, "Exit\n");
479 u32
brcmf_sdcard_cur_sbwad(struct brcmf_sdio_dev
*sdiodev
)
481 return sdiodev
->sbwad
;
484 int brcmf_sdio_probe(struct brcmf_sdio_dev
*sdiodev
)
489 ret
= brcmf_sdioh_attach(sdiodev
);
495 /* Report the BAR, to fix if needed */
496 sdiodev
->sbwad
= SI_ENUM_BASE
;
498 /* try to attach to the target device */
499 sdiodev
->bus
= brcmf_sdbrcm_probe(0, 0, 0, 0, regs
, sdiodev
);
501 brcmf_dbg(ERROR
, "device attach failed\n");
508 brcmf_sdio_remove(sdiodev
);
512 EXPORT_SYMBOL(brcmf_sdio_probe
);
514 int brcmf_sdio_remove(struct brcmf_sdio_dev
*sdiodev
)
517 brcmf_sdbrcm_disconnect(sdiodev
->bus
);
521 brcmf_sdioh_detach(sdiodev
);
527 EXPORT_SYMBOL(brcmf_sdio_remove
);
529 int brcmf_sdio_register(void)
531 return brcmf_sdio_function_init();
534 void brcmf_sdio_unregister(void)
536 brcmf_sdio_function_cleanup();
539 void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev
*sdiodev
, bool enable
)
542 brcmf_sdbrcm_wd_timer(sdiodev
->bus
, brcmf_watchdog_ms
);
544 brcmf_sdbrcm_wd_timer(sdiodev
->bus
, 0);