cfg80211: notify core hints that helps to restore regd settings
[deliverable/linux.git] / drivers / net / wireless / brcm80211 / brcmfmac / bcmsdh.c
CommitLineData
5b435de0
AS
1/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
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.
7 *
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.
15 */
16/* ****************** SDIO CARD Interface Functions **************************/
17
18#include <linux/types.h>
19#include <linux/netdevice.h>
ee40fa06 20#include <linux/export.h>
5b435de0
AS
21#include <linux/pci.h>
22#include <linux/pci_ids.h>
23#include <linux/sched.h>
24#include <linux/completion.h>
25#include <linux/mmc/sdio.h>
26#include <linux/mmc/sdio_func.h>
27#include <linux/mmc/card.h>
28
29#include <defs.h>
30#include <brcm_hw_ids.h>
31#include <brcmu_utils.h>
32#include <brcmu_wifi.h>
33#include <soc.h>
34#include "dhd.h"
35#include "dhd_bus.h"
36#include "dhd_dbg.h"
37#include "sdio_host.h"
38
39#define SDIOH_API_ACCESS_RETRY_LIMIT 2
40
41static void brcmf_sdioh_irqhandler(struct sdio_func *func)
42{
655713be
FL
43 struct brcmf_bus *bus_if = dev_get_drvdata(&func->card->dev);
44 struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
5b435de0
AS
45
46 brcmf_dbg(TRACE, "***IRQHandler\n");
47
48 sdio_release_host(func);
49
50 brcmf_sdbrcm_isr(sdiodev->bus);
51
52 sdio_claim_host(func);
53}
54
55int brcmf_sdcard_intr_reg(struct brcmf_sdio_dev *sdiodev)
56{
57 brcmf_dbg(TRACE, "Entering\n");
58
59 sdio_claim_host(sdiodev->func[1]);
60 sdio_claim_irq(sdiodev->func[1], brcmf_sdioh_irqhandler);
61 sdio_release_host(sdiodev->func[1]);
62
63 return 0;
64}
65
66int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev)
67{
68 brcmf_dbg(TRACE, "Entering\n");
69
70 sdio_claim_host(sdiodev->func[1]);
71 sdio_release_irq(sdiodev->func[1]);
72 sdio_release_host(sdiodev->func[1]);
73
74 return 0;
75}
76
77u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr,
78 int *err)
79{
80 int status;
81 s32 retry = 0;
82 u8 data = 0;
83
84 do {
85 if (retry) /* wait for 1 ms till bus get settled down */
86 udelay(1000);
87 status = brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, fnc_num,
88 addr, (u8 *) &data);
89 } while (status != 0
90 && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
91 if (err)
92 *err = status;
93
94 brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n",
95 fnc_num, addr, data);
96
97 return data;
98}
99
100void
101brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr,
102 u8 data, int *err)
103{
104 int status;
105 s32 retry = 0;
106
107 do {
108 if (retry) /* wait for 1 ms till bus get settled down */
109 udelay(1000);
110 status = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, fnc_num,
111 addr, (u8 *) &data);
112 } while (status != 0
113 && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
114 if (err)
115 *err = status;
116
117 brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n",
118 fnc_num, addr, data);
119}
120
121int
122brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
123{
124 int err = 0;
125 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
126 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
127 if (!err)
128 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
129 SBSDIO_FUNC1_SBADDRMID,
130 (address >> 16) & SBSDIO_SBADDRMID_MASK,
131 &err);
132 if (!err)
133 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
134 SBSDIO_FUNC1_SBADDRHIGH,
135 (address >> 24) & SBSDIO_SBADDRHIGH_MASK,
136 &err);
137
138 return err;
139}
140
141u32 brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size)
142{
143 int status;
144 u32 word = 0;
145 uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
146
147 brcmf_dbg(INFO, "fun = 1, addr = 0x%x\n", addr);
148
149 if (bar0 != sdiodev->sbwad) {
150 if (brcmf_sdcard_set_sbaddr_window(sdiodev, bar0))
151 return 0xFFFFFFFF;
152
153 sdiodev->sbwad = bar0;
154 }
155
156 addr &= SBSDIO_SB_OFT_ADDR_MASK;
157 if (size == 4)
158 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
159
160 status = brcmf_sdioh_request_word(sdiodev, SDIOH_READ, SDIO_FUNC_1,
161 addr, &word, size);
162
163 sdiodev->regfail = (status != 0);
164
165 brcmf_dbg(INFO, "u32data = 0x%x\n", word);
166
167 /* if ok, return appropriately masked word */
168 if (status == 0) {
169 switch (size) {
170 case sizeof(u8):
171 return word & 0xff;
172 case sizeof(u16):
173 return word & 0xffff;
174 case sizeof(u32):
175 return word;
176 default:
177 sdiodev->regfail = true;
178
179 }
180 }
181
182 /* otherwise, bad sdio access or invalid size */
183 brcmf_dbg(ERROR, "error reading addr 0x%04x size %d\n", addr, size);
184 return 0xFFFFFFFF;
185}
186
187u32 brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size,
188 u32 data)
189{
190 int status;
191 uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
192 int err = 0;
193
194 brcmf_dbg(INFO, "fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
195 addr, size * 8, data);
196
197 if (bar0 != sdiodev->sbwad) {
198 err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
199 if (err)
200 return err;
201
202 sdiodev->sbwad = bar0;
203 }
204
205 addr &= SBSDIO_SB_OFT_ADDR_MASK;
206 if (size == 4)
207 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
208 status =
209 brcmf_sdioh_request_word(sdiodev, SDIOH_WRITE, SDIO_FUNC_1,
210 addr, &data, size);
211 sdiodev->regfail = (status != 0);
212
213 if (status == 0)
214 return 0;
215
216 brcmf_dbg(ERROR, "error writing 0x%08x to addr 0x%04x size %d\n",
217 data, addr, size);
218 return 0xFFFFFFFF;
219}
220
221bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev)
222{
223 return sdiodev->regfail;
224}
225
5adfeb63
AS
226static int brcmf_sdcard_recv_prepare(struct brcmf_sdio_dev *sdiodev, uint fn,
227 uint flags, uint width, u32 *addr)
5b435de0 228{
5adfeb63 229 uint bar0 = *addr & ~SBSDIO_SB_OFT_ADDR_MASK;
5b435de0
AS
230 int err = 0;
231
5b435de0
AS
232 /* Async not implemented yet */
233 if (flags & SDIO_REQ_ASYNC)
234 return -ENOTSUPP;
235
236 if (bar0 != sdiodev->sbwad) {
237 err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
238 if (err)
239 return err;
240
241 sdiodev->sbwad = bar0;
242 }
243
5adfeb63
AS
244 *addr &= SBSDIO_SB_OFT_ADDR_MASK;
245
246 if (width == 4)
247 *addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
248
249 return 0;
250}
251
252int
253brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
254 uint flags, u8 *buf, uint nbytes)
255{
256 struct sk_buff *mypkt;
257 int err;
258
259 mypkt = brcmu_pkt_buf_get_skb(nbytes);
260 if (!mypkt) {
261 brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
262 nbytes);
263 return -EIO;
264 }
265
266 err = brcmf_sdcard_recv_pkt(sdiodev, addr, fn, flags, mypkt);
267 if (!err)
268 memcpy(buf, mypkt->data, nbytes);
269
270 brcmu_pkt_buf_free_skb(mypkt);
271 return err;
272}
273
274int
275brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
276 uint flags, struct sk_buff *pkt)
277{
278 uint incr_fix;
279 uint width;
280 int err = 0;
281
282 brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
283 fn, addr, pkt->len);
284
285 width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
286 err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
287 if (err)
288 return err;
5b435de0
AS
289
290 incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
5adfeb63 291 err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ,
4c6e869d 292 fn, addr, pkt);
5adfeb63
AS
293
294 return err;
295}
296
297int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
298 uint flags, struct sk_buff_head *pktq)
299{
300 uint incr_fix;
301 uint width;
302 int err = 0;
303
304 brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
305 fn, addr, pktq->qlen);
306
5b435de0 307 width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
5adfeb63
AS
308 err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
309 if (err)
310 return err;
5b435de0 311
5adfeb63
AS
312 incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
313 err = brcmf_sdioh_request_chain(sdiodev, incr_fix, SDIOH_READ, fn, addr,
314 pktq);
5b435de0 315
5adfeb63 316 return err;
5b435de0
AS
317}
318
319int
320brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
5adfeb63
AS
321 uint flags, u8 *buf, uint nbytes)
322{
323 struct sk_buff *mypkt;
324 int err;
325
326 mypkt = brcmu_pkt_buf_get_skb(nbytes);
327 if (!mypkt) {
328 brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
329 nbytes);
330 return -EIO;
331 }
332
333 memcpy(mypkt->data, buf, nbytes);
334 err = brcmf_sdcard_send_pkt(sdiodev, addr, fn, flags, mypkt);
335
336 brcmu_pkt_buf_free_skb(mypkt);
337 return err;
338
339}
340
341int
342brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
343 uint flags, struct sk_buff *pkt)
5b435de0
AS
344{
345 uint incr_fix;
346 uint width;
347 uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
348 int err = 0;
349
5adfeb63
AS
350 brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
351 fn, addr, pkt->len);
5b435de0
AS
352
353 /* Async not implemented yet */
354 if (flags & SDIO_REQ_ASYNC)
355 return -ENOTSUPP;
356
357 if (bar0 != sdiodev->sbwad) {
358 err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
359 if (err)
360 return err;
361
362 sdiodev->sbwad = bar0;
363 }
364
365 addr &= SBSDIO_SB_OFT_ADDR_MASK;
366
367 incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
368 width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
369 if (width == 4)
370 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
371
372 return brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn,
4c6e869d 373 addr, pkt);
5b435de0
AS
374}
375
376int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr,
377 u8 *buf, uint nbytes)
378{
4c6e869d
AS
379 struct sk_buff *mypkt;
380 bool write = rw ? SDIOH_WRITE : SDIOH_READ;
381 int err;
382
5b435de0
AS
383 addr &= SBSDIO_SB_OFT_ADDR_MASK;
384 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
385
4c6e869d
AS
386 mypkt = brcmu_pkt_buf_get_skb(nbytes);
387 if (!mypkt) {
388 brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
389 nbytes);
390 return -EIO;
391 }
392
393 /* For a write, copy the buffer data into the packet. */
394 if (write)
395 memcpy(mypkt->data, buf, nbytes);
396
397 err = brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC, write,
398 SDIO_FUNC_1, addr, mypkt);
399
400 /* For a read, copy the packet data back to the buffer. */
401 if (!err && !write)
402 memcpy(buf, mypkt->data, nbytes);
403
404 brcmu_pkt_buf_free_skb(mypkt);
405 return err;
5b435de0
AS
406}
407
408int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
409{
410 char t_func = (char)fn;
411 brcmf_dbg(TRACE, "Enter\n");
412
413 /* issue abort cmd52 command through F0 */
414 brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
415 SDIO_CCCR_ABORT, &t_func);
416
417 brcmf_dbg(TRACE, "Exit\n");
418 return 0;
419}
420
421int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
422{
423 u32 regs = 0;
424 int ret = 0;
425
426 ret = brcmf_sdioh_attach(sdiodev);
427 if (ret)
428 goto out;
429
430 regs = SI_ENUM_BASE;
431
432 /* Report the BAR, to fix if needed */
433 sdiodev->sbwad = SI_ENUM_BASE;
434
435 /* try to attach to the target device */
4175b88b 436 sdiodev->bus = brcmf_sdbrcm_probe(regs, sdiodev);
5b435de0
AS
437 if (!sdiodev->bus) {
438 brcmf_dbg(ERROR, "device attach failed\n");
439 ret = -ENODEV;
440 goto out;
441 }
442
443out:
444 if (ret)
445 brcmf_sdio_remove(sdiodev);
446
447 return ret;
448}
449EXPORT_SYMBOL(brcmf_sdio_probe);
450
451int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
452{
453 if (sdiodev->bus) {
454 brcmf_sdbrcm_disconnect(sdiodev->bus);
455 sdiodev->bus = NULL;
456 }
457
458 brcmf_sdioh_detach(sdiodev);
459
460 sdiodev->sbwad = 0;
461
462 return 0;
463}
464EXPORT_SYMBOL(brcmf_sdio_remove);
465
466void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable)
467{
468 if (enable)
469 brcmf_sdbrcm_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
470 else
471 brcmf_sdbrcm_wd_timer(sdiodev->bus, 0);
472}
This page took 0.078472 seconds and 5 git commands to generate.