Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
bcmsdh.c
Go to the documentation of this file.
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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19 
20 #include <linux/types.h>
21 #include <linux/netdevice.h>
22 #include <linux/export.h>
23 #include <linux/pci.h>
24 #include <linux/pci_ids.h>
25 #include <linux/sched.h>
26 #include <linux/completion.h>
27 #include <linux/mmc/sdio.h>
28 #include <linux/mmc/sdio_func.h>
29 #include <linux/mmc/card.h>
30 
31 #include <defs.h>
32 #include <brcm_hw_ids.h>
33 #include <brcmu_utils.h>
34 #include <brcmu_wifi.h>
35 #include <soc.h>
36 #include "dhd_bus.h"
37 #include "dhd_dbg.h"
38 #include "sdio_host.h"
39 
40 #define SDIOH_API_ACCESS_RETRY_LIMIT 2
41 
42 #ifdef CONFIG_BRCMFMAC_SDIO_OOB
43 static irqreturn_t brcmf_sdio_irqhandler(int irq, void *dev_id)
44 {
45  struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(dev_id);
46 
47  brcmf_dbg(INTR, "oob intr triggered\n");
48 
49  /*
50  * out-of-band interrupt is level-triggered which won't
51  * be cleared until dpc
52  */
53  if (sdiodev->irq_en) {
54  disable_irq_nosync(irq);
55  sdiodev->irq_en = false;
56  }
57 
58  brcmf_sdbrcm_isr(sdiodev->bus);
59 
60  return IRQ_HANDLED;
61 }
62 
63 int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
64 {
65  int ret = 0;
66  u8 data;
67  unsigned long flags;
68 
69  brcmf_dbg(TRACE, "Entering\n");
70 
71  brcmf_dbg(ERROR, "requesting irq %d\n", sdiodev->irq);
72  ret = request_irq(sdiodev->irq, brcmf_sdio_irqhandler,
73  sdiodev->irq_flags, "brcmf_oob_intr",
74  &sdiodev->func[1]->card->dev);
75  if (ret != 0)
76  return ret;
77  spin_lock_init(&sdiodev->irq_en_lock);
78  spin_lock_irqsave(&sdiodev->irq_en_lock, flags);
79  sdiodev->irq_en = true;
80  spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
81 
82  ret = enable_irq_wake(sdiodev->irq);
83  if (ret != 0)
84  return ret;
85  sdiodev->irq_wake = true;
86 
87  /* must configure SDIO_CCCR_IENx to enable irq */
88  data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
89  data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
90  brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
91 
92  /* redirect, configure and enable io for interrupt signal */
94  if (sdiodev->irq_flags & IRQF_TRIGGER_HIGH)
95  data |= SDIO_SEPINT_ACT_HI;
96  brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
97 
98  return 0;
99 }
100 
101 int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
102 {
103  brcmf_dbg(TRACE, "Entering\n");
104 
106  brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
107 
108  if (sdiodev->irq_wake) {
109  disable_irq_wake(sdiodev->irq);
110  sdiodev->irq_wake = false;
111  }
112  free_irq(sdiodev->irq, &sdiodev->func[1]->card->dev);
113  sdiodev->irq_en = false;
114 
115  return 0;
116 }
117 #else /* CONFIG_BRCMFMAC_SDIO_OOB */
118 static void brcmf_sdio_irqhandler(struct sdio_func *func)
119 {
120  struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
121 
122  brcmf_dbg(INTR, "ib intr triggered\n");
123 
124  brcmf_sdbrcm_isr(sdiodev->bus);
125 }
126 
127 /* dummy handler for SDIO function 2 interrupt */
128 static void brcmf_sdio_dummy_irqhandler(struct sdio_func *func)
129 {
130 }
131 
133 {
134  brcmf_dbg(TRACE, "Entering\n");
135 
136  sdio_claim_host(sdiodev->func[1]);
137  sdio_claim_irq(sdiodev->func[1], brcmf_sdio_irqhandler);
138  sdio_claim_irq(sdiodev->func[2], brcmf_sdio_dummy_irqhandler);
139  sdio_release_host(sdiodev->func[1]);
140 
141  return 0;
142 }
143 
145 {
146  brcmf_dbg(TRACE, "Entering\n");
147 
148  sdio_claim_host(sdiodev->func[1]);
149  sdio_release_irq(sdiodev->func[2]);
150  sdio_release_irq(sdiodev->func[1]);
151  sdio_release_host(sdiodev->func[1]);
152 
153  return 0;
154 }
155 #endif /* CONFIG_BRCMFMAC_SDIO_OOB */
156 
157 int
159 {
160  int err = 0, i;
161  u8 addr[3];
162  s32 retry;
163 
164  addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
165  addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK;
166  addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK;
167 
168  for (i = 0; i < 3; i++) {
169  retry = 0;
170  do {
171  if (retry)
172  usleep_range(1000, 2000);
173  err = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE,
175  &addr[i]);
176  } while (err != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
177 
178  if (err) {
179  brcmf_dbg(ERROR, "failed at addr:0x%0x\n",
181  break;
182  }
183  }
184 
185  return err;
186 }
187 
188 int
190  void *data, bool write)
191 {
192  u8 func_num, reg_size;
193  u32 bar;
194  s32 retry = 0;
195  int ret;
196 
197  /*
198  * figure out how to read the register based on address range
199  * 0x00 ~ 0x7FF: function 0 CCCR and FBR
200  * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
201  * The rest: function 1 silicon backplane core registers
202  */
203  if ((addr & ~REG_F0_REG_MASK) == 0) {
204  func_num = SDIO_FUNC_0;
205  reg_size = 1;
206  } else if ((addr & ~REG_F1_MISC_MASK) == 0) {
207  func_num = SDIO_FUNC_1;
208  reg_size = 1;
209  } else {
210  func_num = SDIO_FUNC_1;
211  reg_size = 4;
212 
213  /* Set the window for SB core register */
214  bar = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
215  if (bar != sdiodev->sbwad) {
216  ret = brcmf_sdcard_set_sbaddr_window(sdiodev, bar);
217  if (ret != 0) {
218  memset(data, 0xFF, reg_size);
219  return ret;
220  }
221  sdiodev->sbwad = bar;
222  }
223  addr &= SBSDIO_SB_OFT_ADDR_MASK;
225  }
226 
227  do {
228  if (!write)
229  memset(data, 0, reg_size);
230  if (retry) /* wait for 1 ms till bus get settled down */
231  usleep_range(1000, 2000);
232  if (reg_size == 1)
233  ret = brcmf_sdioh_request_byte(sdiodev, write,
234  func_num, addr, data);
235  else
236  ret = brcmf_sdioh_request_word(sdiodev, write,
237  func_num, addr, data, 4);
238  } while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
239 
240  if (ret != 0)
241  brcmf_dbg(ERROR, "failed with %d\n", ret);
242 
243  return ret;
244 }
245 
246 u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
247 {
248  u8 data;
249  int retval;
250 
251  brcmf_dbg(INFO, "addr:0x%08x\n", addr);
252  sdio_claim_host(sdiodev->func[1]);
253  retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
254  sdio_release_host(sdiodev->func[1]);
255  brcmf_dbg(INFO, "data:0x%02x\n", data);
256 
257  if (ret)
258  *ret = retval;
259 
260  return data;
261 }
262 
263 u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
264 {
265  u32 data;
266  int retval;
267 
268  brcmf_dbg(INFO, "addr:0x%08x\n", addr);
269  sdio_claim_host(sdiodev->func[1]);
270  retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
271  sdio_release_host(sdiodev->func[1]);
272  brcmf_dbg(INFO, "data:0x%08x\n", data);
273 
274  if (ret)
275  *ret = retval;
276 
277  return data;
278 }
279 
280 void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
281  u8 data, int *ret)
282 {
283  int retval;
284 
285  brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data);
286  sdio_claim_host(sdiodev->func[1]);
287  retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
288  sdio_release_host(sdiodev->func[1]);
289 
290  if (ret)
291  *ret = retval;
292 }
293 
294 void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
295  u32 data, int *ret)
296 {
297  int retval;
298 
299  brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data);
300  sdio_claim_host(sdiodev->func[1]);
301  retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
302  sdio_release_host(sdiodev->func[1]);
303 
304  if (ret)
305  *ret = retval;
306 }
307 
308 static int brcmf_sdcard_recv_prepare(struct brcmf_sdio_dev *sdiodev, uint fn,
309  uint flags, uint width, u32 *addr)
310 {
311  uint bar0 = *addr & ~SBSDIO_SB_OFT_ADDR_MASK;
312  int err = 0;
313 
314  /* Async not implemented yet */
315  if (flags & SDIO_REQ_ASYNC)
316  return -ENOTSUPP;
317 
318  if (bar0 != sdiodev->sbwad) {
319  err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
320  if (err)
321  return err;
322 
323  sdiodev->sbwad = bar0;
324  }
325 
326  *addr &= SBSDIO_SB_OFT_ADDR_MASK;
327 
328  if (width == 4)
330 
331  return 0;
332 }
333 
334 int
335 brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
336  uint flags, u8 *buf, uint nbytes)
337 {
338  struct sk_buff *mypkt;
339  int err;
340 
341  mypkt = brcmu_pkt_buf_get_skb(nbytes);
342  if (!mypkt) {
343  brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
344  nbytes);
345  return -EIO;
346  }
347 
348  err = brcmf_sdcard_recv_pkt(sdiodev, addr, fn, flags, mypkt);
349  if (!err)
350  memcpy(buf, mypkt->data, nbytes);
351 
352  brcmu_pkt_buf_free_skb(mypkt);
353  return err;
354 }
355 
356 int
357 brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
358  uint flags, struct sk_buff *pkt)
359 {
360  uint incr_fix;
361  uint width;
362  int err = 0;
363 
364  brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
365  fn, addr, pkt->len);
366 
367  sdio_claim_host(sdiodev->func[1]);
368 
369  width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
370  err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
371  if (err)
372  goto done;
373 
374  incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
375  err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ,
376  fn, addr, pkt);
377 
378 done:
379  sdio_release_host(sdiodev->func[1]);
380 
381  return err;
382 }
383 
384 int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
385  uint flags, struct sk_buff_head *pktq)
386 {
387  uint incr_fix;
388  uint width;
389  int err = 0;
390 
391  brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
392  fn, addr, pktq->qlen);
393 
394  sdio_claim_host(sdiodev->func[1]);
395 
396  width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
397  err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
398  if (err)
399  goto done;
400 
401  incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
402  err = brcmf_sdioh_request_chain(sdiodev, incr_fix, SDIOH_READ, fn, addr,
403  pktq);
404 
405 done:
406  sdio_release_host(sdiodev->func[1]);
407 
408  return err;
409 }
410 
411 int
412 brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
413  uint flags, u8 *buf, uint nbytes)
414 {
415  struct sk_buff *mypkt;
416  int err;
417 
418  mypkt = brcmu_pkt_buf_get_skb(nbytes);
419  if (!mypkt) {
420  brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
421  nbytes);
422  return -EIO;
423  }
424 
425  memcpy(mypkt->data, buf, nbytes);
426  err = brcmf_sdcard_send_pkt(sdiodev, addr, fn, flags, mypkt);
427 
428  brcmu_pkt_buf_free_skb(mypkt);
429  return err;
430 
431 }
432 
433 int
434 brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
435  uint flags, struct sk_buff *pkt)
436 {
437  uint incr_fix;
438  uint width;
439  uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
440  int err = 0;
441 
442  brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
443  fn, addr, pkt->len);
444 
445  /* Async not implemented yet */
446  if (flags & SDIO_REQ_ASYNC)
447  return -ENOTSUPP;
448 
449  sdio_claim_host(sdiodev->func[1]);
450 
451  if (bar0 != sdiodev->sbwad) {
452  err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
453  if (err)
454  goto done;
455 
456  sdiodev->sbwad = bar0;
457  }
458 
459  addr &= SBSDIO_SB_OFT_ADDR_MASK;
460 
461  incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
462  width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
463  if (width == 4)
465 
466  err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn,
467  addr, pkt);
468 
469 done:
470  sdio_release_host(sdiodev->func[1]);
471 
472  return err;
473 }
474 
475 int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr,
476  u8 *buf, uint nbytes)
477 {
478  struct sk_buff *mypkt;
479  bool write = rw ? SDIOH_WRITE : SDIOH_READ;
480  int err;
481 
482  addr &= SBSDIO_SB_OFT_ADDR_MASK;
484 
485  mypkt = brcmu_pkt_buf_get_skb(nbytes);
486  if (!mypkt) {
487  brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
488  nbytes);
489  return -EIO;
490  }
491 
492  /* For a write, copy the buffer data into the packet. */
493  if (write)
494  memcpy(mypkt->data, buf, nbytes);
495 
496  err = brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC, write,
497  SDIO_FUNC_1, addr, mypkt);
498 
499  /* For a read, copy the packet data back to the buffer. */
500  if (!err && !write)
501  memcpy(buf, mypkt->data, nbytes);
502 
503  brcmu_pkt_buf_free_skb(mypkt);
504  return err;
505 }
506 
507 int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
508 {
509  char t_func = (char)fn;
510  brcmf_dbg(TRACE, "Enter\n");
511 
512  /* issue abort cmd52 command through F0 */
513  sdio_claim_host(sdiodev->func[1]);
515  SDIO_CCCR_ABORT, &t_func);
516  sdio_release_host(sdiodev->func[1]);
517 
518  brcmf_dbg(TRACE, "Exit\n");
519  return 0;
520 }
521 
522 int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
523 {
524  u32 regs = 0;
525  int ret = 0;
526 
527  ret = brcmf_sdioh_attach(sdiodev);
528  if (ret)
529  goto out;
530 
531  regs = SI_ENUM_BASE;
532 
533  /* Report the BAR, to fix if needed */
534  sdiodev->sbwad = SI_ENUM_BASE;
535 
536  /* try to attach to the target device */
537  sdiodev->bus = brcmf_sdbrcm_probe(regs, sdiodev);
538  if (!sdiodev->bus) {
539  brcmf_dbg(ERROR, "device attach failed\n");
540  ret = -ENODEV;
541  goto out;
542  }
543 
544 out:
545  if (ret)
546  brcmf_sdio_remove(sdiodev);
547 
548  return ret;
549 }
551 
552 int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
553 {
554  if (sdiodev->bus) {
555  brcmf_sdbrcm_disconnect(sdiodev->bus);
556  sdiodev->bus = NULL;
557  }
558 
559  brcmf_sdioh_detach(sdiodev);
560 
561  sdiodev->sbwad = 0;
562 
563  return 0;
564 }
566 
567 void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable)
568 {
569  if (enable)
571  else
572  brcmf_sdbrcm_wd_timer(sdiodev->bus, 0);
573 }