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>
26 #include <brcm_hw_ids.h>
27 #include <brcmu_utils.h>
28 #include <brcmu_wifi.h>
33 #include "sdio_host.h"
35 #define SDIOH_API_ACCESS_RETRY_LIMIT 2
37 #define SDIOH_CMD_TYPE_NORMAL 0 /* Normal command */
38 #define SDIOH_CMD_TYPE_APPEND 1 /* Append command */
39 #define SDIOH_CMD_TYPE_CUTTHRU 2 /* Cut-through command */
41 #define SDIOH_DATA_PIO 0 /* PIO mode */
42 #define SDIOH_DATA_DMA 1 /* DMA mode */
44 /* Module parameters specific to each host-controller driver */
46 module_param(sd_f2_blocksize
, int, 0);
49 brcmf_sdcard_iovar_op(struct brcmf_sdio_dev
*sdiodev
, const char *name
,
50 void *params
, int plen
, void *arg
, int len
, bool set
)
52 return brcmf_sdioh_iovar_op(sdiodev
->sdioh
, name
, params
, plen
, arg
,
56 int brcmf_sdcard_intr_reg(struct brcmf_sdio_dev
*sdiodev
)
58 return brcmf_sdioh_interrupt_register(sdiodev
->sdioh
);
61 int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev
*sdiodev
)
63 return brcmf_sdioh_interrupt_deregister(sdiodev
->sdioh
);
66 u8
brcmf_sdcard_cfg_read(struct brcmf_sdio_dev
*sdiodev
, uint fnc_num
, u32 addr
,
74 if (retry
) /* wait for 1 ms till bus get settled down */
77 brcmf_sdioh_cfg_read(sdiodev
->sdioh
, fnc_num
, addr
,
80 && (retry
++ < SDIOH_API_ACCESS_RETRY_LIMIT
));
84 BRCMF_INFO(("%s:fun = %d, addr = 0x%x, u8data = 0x%x\n",
85 __func__
, fnc_num
, addr
, data
));
91 brcmf_sdcard_cfg_write(struct brcmf_sdio_dev
*sdiodev
, uint fnc_num
, u32 addr
,
98 if (retry
) /* wait for 1 ms till bus get settled down */
101 brcmf_sdioh_cfg_write(sdiodev
->sdioh
, fnc_num
, addr
,
104 && (retry
++ < SDIOH_API_ACCESS_RETRY_LIMIT
));
108 BRCMF_INFO(("%s:fun = %d, addr = 0x%x, u8data = 0x%x\n",
109 __func__
, fnc_num
, addr
, data
));
112 int brcmf_sdcard_cis_read(struct brcmf_sdio_dev
*sdiodev
, uint func
, u8
* cis
,
117 u8
*tmp_buf
, *tmp_ptr
;
119 bool ascii
= func
& ~0xf;
122 status
= brcmf_sdioh_cis_read(sdiodev
->sdioh
, func
, cis
, length
);
125 /* Move binary bits to tmp and format them
126 into the provided buffer. */
127 tmp_buf
= kmalloc(length
, GFP_ATOMIC
);
128 if (tmp_buf
== NULL
) {
129 BRCMF_ERROR(("%s: out of memory\n", __func__
));
132 memcpy(tmp_buf
, cis
, length
);
133 for (tmp_ptr
= tmp_buf
, ptr
= cis
; ptr
< (cis
+ length
- 4);
135 ptr
+= sprintf((char *)ptr
, "%.2x ", *tmp_ptr
& 0xff);
136 if ((((tmp_ptr
- tmp_buf
) + 1) & 0xf) == 0)
137 ptr
+= sprintf((char *)ptr
, "\n");
146 brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev
*sdiodev
, u32 address
)
149 brcmf_sdcard_cfg_write(sdiodev
, SDIO_FUNC_1
, SBSDIO_FUNC1_SBADDRLOW
,
150 (address
>> 8) & SBSDIO_SBADDRLOW_MASK
, &err
);
152 brcmf_sdcard_cfg_write(sdiodev
, SDIO_FUNC_1
,
153 SBSDIO_FUNC1_SBADDRMID
,
154 (address
>> 16) & SBSDIO_SBADDRMID_MASK
,
157 brcmf_sdcard_cfg_write(sdiodev
, SDIO_FUNC_1
,
158 SBSDIO_FUNC1_SBADDRHIGH
,
159 (address
>> 24) & SBSDIO_SBADDRHIGH_MASK
,
165 u32
brcmf_sdcard_reg_read(struct brcmf_sdio_dev
*sdiodev
, u32 addr
, uint size
)
169 uint bar0
= addr
& ~SBSDIO_SB_OFT_ADDR_MASK
;
171 BRCMF_INFO(("%s:fun = 1, addr = 0x%x, ", __func__
, addr
));
173 if (bar0
!= sdiodev
->sbwad
) {
174 if (brcmf_sdcard_set_sbaddr_window(sdiodev
, bar0
))
177 sdiodev
->sbwad
= bar0
;
180 addr
&= SBSDIO_SB_OFT_ADDR_MASK
;
182 addr
|= SBSDIO_SB_ACCESS_2_4B_FLAG
;
184 status
= brcmf_sdioh_request_word(sdiodev
->sdioh
, SDIOH_CMD_TYPE_NORMAL
,
185 SDIOH_READ
, SDIO_FUNC_1
, addr
, &word
, size
);
187 sdiodev
->regfail
= (status
!= 0);
189 BRCMF_INFO(("u32data = 0x%x\n", word
));
191 /* if ok, return appropriately masked word */
197 return word
& 0xffff;
201 sdiodev
->regfail
= true;
206 /* otherwise, bad sdio access or invalid size */
207 BRCMF_ERROR(("%s: error reading addr 0x%04x size %d\n", __func__
,
212 u32
brcmf_sdcard_reg_write(struct brcmf_sdio_dev
*sdiodev
, u32 addr
, uint size
,
216 uint bar0
= addr
& ~SBSDIO_SB_OFT_ADDR_MASK
;
219 BRCMF_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
220 __func__
, addr
, size
* 8, data
));
222 if (bar0
!= sdiodev
->sbwad
) {
223 err
= brcmf_sdcard_set_sbaddr_window(sdiodev
, bar0
);
227 sdiodev
->sbwad
= bar0
;
230 addr
&= SBSDIO_SB_OFT_ADDR_MASK
;
232 addr
|= SBSDIO_SB_ACCESS_2_4B_FLAG
;
234 brcmf_sdioh_request_word(sdiodev
->sdioh
, SDIOH_CMD_TYPE_NORMAL
,
235 SDIOH_WRITE
, SDIO_FUNC_1
, addr
, &data
, size
);
236 sdiodev
->regfail
= (status
!= 0);
241 BRCMF_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n",
242 __func__
, data
, addr
, size
));
246 bool brcmf_sdcard_regfail(struct brcmf_sdio_dev
*sdiodev
)
248 return sdiodev
->regfail
;
252 brcmf_sdcard_recv_buf(struct brcmf_sdio_dev
*sdiodev
, u32 addr
, uint fn
,
254 u8
*buf
, uint nbytes
, struct sk_buff
*pkt
,
255 void (*complete
)(void *handle
, int status
,
262 uint bar0
= addr
& ~SBSDIO_SB_OFT_ADDR_MASK
;
265 BRCMF_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
266 __func__
, fn
, addr
, nbytes
));
268 /* Async not implemented yet */
269 if (flags
& SDIO_REQ_ASYNC
)
272 if (bar0
!= sdiodev
->sbwad
) {
273 err
= brcmf_sdcard_set_sbaddr_window(sdiodev
, bar0
);
277 sdiodev
->sbwad
= bar0
;
280 addr
&= SBSDIO_SB_OFT_ADDR_MASK
;
282 incr_fix
= (flags
& SDIO_REQ_FIXED
) ? SDIOH_DATA_FIX
: SDIOH_DATA_INC
;
283 width
= (flags
& SDIO_REQ_4BYTE
) ? 4 : 2;
285 addr
|= SBSDIO_SB_ACCESS_2_4B_FLAG
;
287 status
= brcmf_sdioh_request_buffer(sdiodev
->sdioh
, SDIOH_DATA_PIO
,
288 incr_fix
, SDIOH_READ
, fn
, addr
, width
, nbytes
, buf
, pkt
);
294 brcmf_sdcard_send_buf(struct brcmf_sdio_dev
*sdiodev
, u32 addr
, uint fn
,
295 uint flags
, u8
*buf
, uint nbytes
, void *pkt
,
296 void (*complete
)(void *handle
, int status
,
302 uint bar0
= addr
& ~SBSDIO_SB_OFT_ADDR_MASK
;
305 BRCMF_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
306 __func__
, fn
, addr
, nbytes
));
308 /* Async not implemented yet */
309 if (flags
& SDIO_REQ_ASYNC
)
312 if (bar0
!= sdiodev
->sbwad
) {
313 err
= brcmf_sdcard_set_sbaddr_window(sdiodev
, bar0
);
317 sdiodev
->sbwad
= bar0
;
320 addr
&= SBSDIO_SB_OFT_ADDR_MASK
;
322 incr_fix
= (flags
& SDIO_REQ_FIXED
) ? SDIOH_DATA_FIX
: SDIOH_DATA_INC
;
323 width
= (flags
& SDIO_REQ_4BYTE
) ? 4 : 2;
325 addr
|= SBSDIO_SB_ACCESS_2_4B_FLAG
;
327 return brcmf_sdioh_request_buffer(sdiodev
->sdioh
, SDIOH_DATA_PIO
,
328 incr_fix
, SDIOH_WRITE
, fn
, addr
, width
, nbytes
, buf
, pkt
);
331 int brcmf_sdcard_rwdata(struct brcmf_sdio_dev
*sdiodev
, uint rw
, u32 addr
,
332 u8
*buf
, uint nbytes
)
334 addr
&= SBSDIO_SB_OFT_ADDR_MASK
;
335 addr
|= SBSDIO_SB_ACCESS_2_4B_FLAG
;
337 return brcmf_sdioh_request_buffer(sdiodev
->sdioh
, SDIOH_DATA_PIO
,
338 SDIOH_DATA_INC
, (rw
? SDIOH_WRITE
: SDIOH_READ
), SDIO_FUNC_1
,
339 addr
, 4, nbytes
, buf
, NULL
);
342 int brcmf_sdcard_abort(struct brcmf_sdio_dev
*sdiodev
, uint fn
)
344 return brcmf_sdioh_abort(sdiodev
->sdioh
, fn
);
347 u32
brcmf_sdcard_cur_sbwad(struct brcmf_sdio_dev
*sdiodev
)
349 return sdiodev
->sbwad
;
352 int brcmf_sdio_probe(struct brcmf_sdio_dev
*sdiodev
)
357 sdiodev
->sdioh
= brcmf_sdioh_attach((void *)0);
358 if (!sdiodev
->sdioh
) {
365 /* Report the BAR, to fix if needed */
366 sdiodev
->sbwad
= SI_ENUM_BASE
;
368 /* try to attach to the target device */
369 sdiodev
->bus
= brcmf_sdbrcm_probe(0, 0, 0, 0, regs
, sdiodev
);
371 BRCMF_ERROR(("%s: device attach failed\n", __func__
));
378 brcmf_sdio_remove(sdiodev
);
382 EXPORT_SYMBOL(brcmf_sdio_probe
);
384 int brcmf_sdio_remove(struct brcmf_sdio_dev
*sdiodev
)
387 brcmf_sdbrcm_disconnect(sdiodev
->bus
);
391 if (sdiodev
->sdioh
) {
392 brcmf_sdioh_detach(sdiodev
->sdioh
);
393 sdiodev
->sdioh
= NULL
;
400 EXPORT_SYMBOL(brcmf_sdio_remove
);
402 int brcmf_sdio_register(void)
404 return brcmf_sdio_function_init();
407 void brcmf_sdio_unregister(void)
409 brcmf_sdio_function_cleanup();
412 void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev
*sdiodev
, bool enable
)
415 brcmf_sdbrcm_wd_timer(sdiodev
->bus
, brcmf_watchdog_ms
);
417 brcmf_sdbrcm_wd_timer(sdiodev
->bus
, 0);