dmaengine: fix cyclic dma usage
[linux-flexiantxendom0-3.2.10.git] / drivers / net / wireless / brcm80211 / brcmfmac / bcmsdh_sdmmc.c
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
17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18
19 #include <linux/types.h>
20 #include <linux/netdevice.h>
21 #include <linux/mmc/sdio.h>
22 #include <linux/mmc/core.h>
23 #include <linux/mmc/sdio_func.h>
24 #include <linux/mmc/sdio_ids.h>
25 #include <linux/mmc/card.h>
26 #include <linux/suspend.h>
27 #include <linux/errno.h>
28 #include <linux/sched.h>        /* request_irq() */
29 #include <linux/module.h>
30 #include <net/cfg80211.h>
31
32 #include <defs.h>
33 #include <brcm_hw_ids.h>
34 #include <brcmu_utils.h>
35 #include <brcmu_wifi.h>
36 #include "sdio_host.h"
37 #include "dhd_dbg.h"
38 #include "dhd_bus.h"
39
40 #define SDIO_VENDOR_ID_BROADCOM         0x02d0
41
42 #define DMA_ALIGN_MASK  0x03
43
44 #define SDIO_DEVICE_ID_BROADCOM_4329    0x4329
45 #define SDIO_DEVICE_ID_BROADCOM_4330    0x4330
46
47 #define SDIO_FUNC1_BLOCKSIZE            64
48 #define SDIO_FUNC2_BLOCKSIZE            512
49
50 /* devices we support, null terminated */
51 static const struct sdio_device_id brcmf_sdmmc_ids[] = {
52         {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
53         {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)},
54         { /* end: all zeroes */ },
55 };
56 MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
57
58 static bool
59 brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev)
60 {
61         bool is_err = false;
62 #ifdef CONFIG_PM_SLEEP
63         is_err = atomic_read(&sdiodev->suspend);
64 #endif
65         return is_err;
66 }
67
68 static void
69 brcmf_pm_resume_wait(struct brcmf_sdio_dev *sdiodev, wait_queue_head_t *wq)
70 {
71 #ifdef CONFIG_PM_SLEEP
72         int retry = 0;
73         while (atomic_read(&sdiodev->suspend) && retry++ != 30)
74                 wait_event_timeout(*wq, false, HZ/100);
75 #endif
76 }
77
78 static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev,
79                                             uint regaddr, u8 *byte)
80 {
81         struct sdio_func *sdfunc = sdiodev->func[0];
82         int err_ret;
83
84         /*
85          * Can only directly write to some F0 registers.
86          * Handle F2 enable/disable and Abort command
87          * as a special case.
88          */
89         if (regaddr == SDIO_CCCR_IOEx) {
90                 sdfunc = sdiodev->func[2];
91                 if (sdfunc) {
92                         sdio_claim_host(sdfunc);
93                         if (*byte & SDIO_FUNC_ENABLE_2) {
94                                 /* Enable Function 2 */
95                                 err_ret = sdio_enable_func(sdfunc);
96                                 if (err_ret)
97                                         brcmf_dbg(ERROR,
98                                                   "enable F2 failed:%d\n",
99                                                   err_ret);
100                         } else {
101                                 /* Disable Function 2 */
102                                 err_ret = sdio_disable_func(sdfunc);
103                                 if (err_ret)
104                                         brcmf_dbg(ERROR,
105                                                   "Disable F2 failed:%d\n",
106                                                   err_ret);
107                         }
108                         sdio_release_host(sdfunc);
109                 }
110         } else if (regaddr == SDIO_CCCR_ABORT) {
111                 sdio_claim_host(sdfunc);
112                 sdio_writeb(sdfunc, *byte, regaddr, &err_ret);
113                 sdio_release_host(sdfunc);
114         } else if (regaddr < 0xF0) {
115                 brcmf_dbg(ERROR, "F0 Wr:0x%02x: write disallowed\n", regaddr);
116                 err_ret = -EPERM;
117         } else {
118                 sdio_claim_host(sdfunc);
119                 sdio_f0_writeb(sdfunc, *byte, regaddr, &err_ret);
120                 sdio_release_host(sdfunc);
121         }
122
123         return err_ret;
124 }
125
126 int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func,
127                              uint regaddr, u8 *byte)
128 {
129         int err_ret;
130
131         brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr);
132
133         brcmf_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait);
134         if (brcmf_pm_resume_error(sdiodev))
135                 return -EIO;
136
137         if (rw && func == 0) {
138                 /* handle F0 separately */
139                 err_ret = brcmf_sdioh_f0_write_byte(sdiodev, regaddr, byte);
140         } else {
141                 sdio_claim_host(sdiodev->func[func]);
142                 if (rw) /* CMD52 Write */
143                         sdio_writeb(sdiodev->func[func], *byte, regaddr,
144                                     &err_ret);
145                 else if (func == 0) {
146                         *byte = sdio_f0_readb(sdiodev->func[func], regaddr,
147                                               &err_ret);
148                 } else {
149                         *byte = sdio_readb(sdiodev->func[func], regaddr,
150                                            &err_ret);
151                 }
152                 sdio_release_host(sdiodev->func[func]);
153         }
154
155         if (err_ret)
156                 brcmf_dbg(ERROR, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
157                           rw ? "write" : "read", func, regaddr, *byte, err_ret);
158
159         return err_ret;
160 }
161
162 int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
163                              uint rw, uint func, uint addr, u32 *word,
164                              uint nbytes)
165 {
166         int err_ret = -EIO;
167
168         if (func == 0) {
169                 brcmf_dbg(ERROR, "Only CMD52 allowed to F0\n");
170                 return -EINVAL;
171         }
172
173         brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
174                   rw, func, addr, nbytes);
175
176         brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
177         if (brcmf_pm_resume_error(sdiodev))
178                 return -EIO;
179         /* Claim host controller */
180         sdio_claim_host(sdiodev->func[func]);
181
182         if (rw) {               /* CMD52 Write */
183                 if (nbytes == 4)
184                         sdio_writel(sdiodev->func[func], *word, addr,
185                                     &err_ret);
186                 else if (nbytes == 2)
187                         sdio_writew(sdiodev->func[func], (*word & 0xFFFF),
188                                     addr, &err_ret);
189                 else
190                         brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes);
191         } else {                /* CMD52 Read */
192                 if (nbytes == 4)
193                         *word = sdio_readl(sdiodev->func[func], addr, &err_ret);
194                 else if (nbytes == 2)
195                         *word = sdio_readw(sdiodev->func[func], addr,
196                                            &err_ret) & 0xFFFF;
197                 else
198                         brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes);
199         }
200
201         /* Release host controller */
202         sdio_release_host(sdiodev->func[func]);
203
204         if (err_ret)
205                 brcmf_dbg(ERROR, "Failed to %s word, Err: 0x%08x\n",
206                           rw ? "write" : "read", err_ret);
207
208         return err_ret;
209 }
210
211 /* precondition: host controller is claimed */
212 static int
213 brcmf_sdioh_request_data(struct brcmf_sdio_dev *sdiodev, uint write, bool fifo,
214                          uint func, uint addr, struct sk_buff *pkt, uint pktlen)
215 {
216         int err_ret = 0;
217
218         if ((write) && (!fifo)) {
219                 err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
220                                            ((u8 *) (pkt->data)), pktlen);
221         } else if (write) {
222                 err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
223                                            ((u8 *) (pkt->data)), pktlen);
224         } else if (fifo) {
225                 err_ret = sdio_readsb(sdiodev->func[func],
226                                       ((u8 *) (pkt->data)), addr, pktlen);
227         } else {
228                 err_ret = sdio_memcpy_fromio(sdiodev->func[func],
229                                              ((u8 *) (pkt->data)),
230                                              addr, pktlen);
231         }
232
233         return err_ret;
234 }
235
236 /*
237  * This function takes a queue of packets. The packets on the queue
238  * are assumed to be properly aligned by the caller.
239  */
240 int
241 brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
242                           uint write, uint func, uint addr,
243                           struct sk_buff_head *pktq)
244 {
245         bool fifo = (fix_inc == SDIOH_DATA_FIX);
246         u32 SGCount = 0;
247         int err_ret = 0;
248
249         struct sk_buff *pkt;
250
251         brcmf_dbg(TRACE, "Enter\n");
252
253         brcmf_pm_resume_wait(sdiodev, &sdiodev->request_chain_wait);
254         if (brcmf_pm_resume_error(sdiodev))
255                 return -EIO;
256
257         /* Claim host controller */
258         sdio_claim_host(sdiodev->func[func]);
259
260         skb_queue_walk(pktq, pkt) {
261                 uint pkt_len = pkt->len;
262                 pkt_len += 3;
263                 pkt_len &= 0xFFFFFFFC;
264
265                 err_ret = brcmf_sdioh_request_data(sdiodev, write, fifo, func,
266                                                    addr, pkt, pkt_len);
267                 if (err_ret) {
268                         brcmf_dbg(ERROR, "%s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
269                                   write ? "TX" : "RX", pkt, SGCount, addr,
270                                   pkt_len, err_ret);
271                 } else {
272                         brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n",
273                                   write ? "TX" : "RX", pkt, SGCount, addr,
274                                   pkt_len);
275                 }
276                 if (!fifo)
277                         addr += pkt_len;
278
279                 SGCount++;
280         }
281
282         /* Release host controller */
283         sdio_release_host(sdiodev->func[func]);
284
285         brcmf_dbg(TRACE, "Exit\n");
286         return err_ret;
287 }
288
289 /*
290  * This function takes a single DMA-able packet.
291  */
292 int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
293                                uint fix_inc, uint write, uint func, uint addr,
294                                struct sk_buff *pkt)
295 {
296         int status;
297         uint pkt_len;
298         bool fifo = (fix_inc == SDIOH_DATA_FIX);
299
300         brcmf_dbg(TRACE, "Enter\n");
301
302         if (pkt == NULL)
303                 return -EINVAL;
304         pkt_len = pkt->len;
305
306         brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
307         if (brcmf_pm_resume_error(sdiodev))
308                 return -EIO;
309
310         /* Claim host controller */
311         sdio_claim_host(sdiodev->func[func]);
312
313         pkt_len += 3;
314         pkt_len &= (uint)~3;
315
316         status = brcmf_sdioh_request_data(sdiodev, write, fifo, func,
317                                            addr, pkt, pkt_len);
318         if (status) {
319                 brcmf_dbg(ERROR, "%s FAILED %p, addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
320                           write ? "TX" : "RX", pkt, addr, pkt_len, status);
321         } else {
322                 brcmf_dbg(TRACE, "%s xfr'd %p, addr=0x%05x, len=%d\n",
323                           write ? "TX" : "RX", pkt, addr, pkt_len);
324         }
325
326         /* Release host controller */
327         sdio_release_host(sdiodev->func[func]);
328
329         return status;
330 }
331
332 /* Read client card reg */
333 static int
334 brcmf_sdioh_card_regread(struct brcmf_sdio_dev *sdiodev, int func, u32 regaddr,
335                          int regsize, u32 *data)
336 {
337
338         if ((func == 0) || (regsize == 1)) {
339                 u8 temp = 0;
340
341                 brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, func, regaddr,
342                                          &temp);
343                 *data = temp;
344                 *data &= 0xff;
345                 brcmf_dbg(DATA, "byte read data=0x%02x\n", *data);
346         } else {
347                 brcmf_sdioh_request_word(sdiodev, SDIOH_READ, func, regaddr,
348                                          data, regsize);
349                 if (regsize == 2)
350                         *data &= 0xffff;
351
352                 brcmf_dbg(DATA, "word read data=0x%08x\n", *data);
353         }
354
355         return SUCCESS;
356 }
357
358 static int brcmf_sdioh_get_cisaddr(struct brcmf_sdio_dev *sdiodev, u32 regaddr)
359 {
360         /* read 24 bits and return valid 17 bit addr */
361         int i;
362         u32 scratch, regdata;
363         __le32 scratch_le;
364         u8 *ptr = (u8 *)&scratch_le;
365
366         for (i = 0; i < 3; i++) {
367                 if ((brcmf_sdioh_card_regread(sdiodev, 0, regaddr, 1,
368                                 &regdata)) != SUCCESS)
369                         brcmf_dbg(ERROR, "Can't read!\n");
370
371                 *ptr++ = (u8) regdata;
372                 regaddr++;
373         }
374
375         /* Only the lower 17-bits are valid */
376         scratch = le32_to_cpu(scratch_le);
377         scratch &= 0x0001FFFF;
378         return scratch;
379 }
380
381 static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev)
382 {
383         int err_ret;
384         u32 fbraddr;
385         u8 func;
386
387         brcmf_dbg(TRACE, "\n");
388
389         /* Get the Card's common CIS address */
390         sdiodev->func_cis_ptr[0] = brcmf_sdioh_get_cisaddr(sdiodev,
391                                                            SDIO_CCCR_CIS);
392         brcmf_dbg(INFO, "Card's Common CIS Ptr = 0x%x\n",
393                   sdiodev->func_cis_ptr[0]);
394
395         /* Get the Card's function CIS (for each function) */
396         for (fbraddr = SDIO_FBR_BASE(1), func = 1;
397              func <= sdiodev->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
398                 sdiodev->func_cis_ptr[func] =
399                     brcmf_sdioh_get_cisaddr(sdiodev, SDIO_FBR_CIS + fbraddr);
400                 brcmf_dbg(INFO, "Function %d CIS Ptr = 0x%x\n",
401                           func, sdiodev->func_cis_ptr[func]);
402         }
403
404         /* Enable Function 1 */
405         sdio_claim_host(sdiodev->func[1]);
406         err_ret = sdio_enable_func(sdiodev->func[1]);
407         sdio_release_host(sdiodev->func[1]);
408         if (err_ret)
409                 brcmf_dbg(ERROR, "Failed to enable F1 Err: 0x%08x\n", err_ret);
410
411         return false;
412 }
413
414 /*
415  *      Public entry points & extern's
416  */
417 int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
418 {
419         int err_ret = 0;
420
421         brcmf_dbg(TRACE, "\n");
422
423         sdiodev->num_funcs = 2;
424
425         sdio_claim_host(sdiodev->func[1]);
426         err_ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE);
427         sdio_release_host(sdiodev->func[1]);
428         if (err_ret) {
429                 brcmf_dbg(ERROR, "Failed to set F1 blocksize\n");
430                 goto out;
431         }
432
433         sdio_claim_host(sdiodev->func[2]);
434         err_ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE);
435         sdio_release_host(sdiodev->func[2]);
436         if (err_ret) {
437                 brcmf_dbg(ERROR, "Failed to set F2 blocksize\n");
438                 goto out;
439         }
440
441         brcmf_sdioh_enablefuncs(sdiodev);
442
443 out:
444         brcmf_dbg(TRACE, "Done\n");
445         return err_ret;
446 }
447
448 void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev)
449 {
450         brcmf_dbg(TRACE, "\n");
451
452         /* Disable Function 2 */
453         sdio_claim_host(sdiodev->func[2]);
454         sdio_disable_func(sdiodev->func[2]);
455         sdio_release_host(sdiodev->func[2]);
456
457         /* Disable Function 1 */
458         sdio_claim_host(sdiodev->func[1]);
459         sdio_disable_func(sdiodev->func[1]);
460         sdio_release_host(sdiodev->func[1]);
461
462 }
463
464 static int brcmf_ops_sdio_probe(struct sdio_func *func,
465                               const struct sdio_device_id *id)
466 {
467         int ret = 0;
468         struct brcmf_sdio_dev *sdiodev;
469         struct brcmf_bus *bus_if;
470         brcmf_dbg(TRACE, "Enter\n");
471         brcmf_dbg(TRACE, "func->class=%x\n", func->class);
472         brcmf_dbg(TRACE, "sdio_vendor: 0x%04x\n", func->vendor);
473         brcmf_dbg(TRACE, "sdio_device: 0x%04x\n", func->device);
474         brcmf_dbg(TRACE, "Function#: 0x%04x\n", func->num);
475
476         if (func->num == 1) {
477                 if (dev_get_drvdata(&func->card->dev)) {
478                         brcmf_dbg(ERROR, "card private drvdata occupied\n");
479                         return -ENXIO;
480                 }
481                 bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
482                 if (!bus_if)
483                         return -ENOMEM;
484                 sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
485                 if (!sdiodev) {
486                         kfree(bus_if);
487                         return -ENOMEM;
488                 }
489                 sdiodev->func[0] = func->card->sdio_func[0];
490                 sdiodev->func[1] = func;
491                 sdiodev->bus_if = bus_if;
492                 bus_if->bus_priv.sdio = sdiodev;
493                 bus_if->type = SDIO_BUS;
494                 bus_if->align = BRCMF_SDALIGN;
495                 dev_set_drvdata(&func->card->dev, sdiodev);
496
497                 atomic_set(&sdiodev->suspend, false);
498                 init_waitqueue_head(&sdiodev->request_byte_wait);
499                 init_waitqueue_head(&sdiodev->request_word_wait);
500                 init_waitqueue_head(&sdiodev->request_chain_wait);
501                 init_waitqueue_head(&sdiodev->request_buffer_wait);
502         }
503
504         if (func->num == 2) {
505                 sdiodev = dev_get_drvdata(&func->card->dev);
506                 if ((!sdiodev) || (sdiodev->func[1]->card != func->card))
507                         return -ENODEV;
508                 sdiodev->func[2] = func;
509
510                 bus_if = sdiodev->bus_if;
511                 sdiodev->dev = &func->dev;
512                 dev_set_drvdata(&func->dev, bus_if);
513
514                 brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n");
515                 ret = brcmf_sdio_probe(sdiodev);
516         }
517
518         return ret;
519 }
520
521 static void brcmf_ops_sdio_remove(struct sdio_func *func)
522 {
523         struct brcmf_bus *bus_if;
524         struct brcmf_sdio_dev *sdiodev;
525         brcmf_dbg(TRACE, "Enter\n");
526         brcmf_dbg(INFO, "func->class=%x\n", func->class);
527         brcmf_dbg(INFO, "sdio_vendor: 0x%04x\n", func->vendor);
528         brcmf_dbg(INFO, "sdio_device: 0x%04x\n", func->device);
529         brcmf_dbg(INFO, "Function#: 0x%04x\n", func->num);
530
531         if (func->num == 2) {
532                 bus_if = dev_get_drvdata(&func->dev);
533                 sdiodev = bus_if->bus_priv.sdio;
534                 brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n");
535                 brcmf_sdio_remove(sdiodev);
536                 dev_set_drvdata(&func->card->dev, NULL);
537                 dev_set_drvdata(&func->dev, NULL);
538                 kfree(bus_if);
539                 kfree(sdiodev);
540         }
541 }
542
543 #ifdef CONFIG_PM_SLEEP
544 static int brcmf_sdio_suspend(struct device *dev)
545 {
546         mmc_pm_flag_t sdio_flags;
547         struct sdio_func *func = dev_to_sdio_func(dev);
548         struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
549         int ret = 0;
550
551         brcmf_dbg(TRACE, "\n");
552
553         atomic_set(&sdiodev->suspend, true);
554
555         sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
556         if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
557                 brcmf_dbg(ERROR, "Host can't keep power while suspended\n");
558                 return -EINVAL;
559         }
560
561         ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
562         if (ret) {
563                 brcmf_dbg(ERROR, "Failed to set pm_flags\n");
564                 return ret;
565         }
566
567         brcmf_sdio_wdtmr_enable(sdiodev, false);
568
569         return ret;
570 }
571
572 static int brcmf_sdio_resume(struct device *dev)
573 {
574         struct sdio_func *func = dev_to_sdio_func(dev);
575         struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
576
577         brcmf_sdio_wdtmr_enable(sdiodev, true);
578         atomic_set(&sdiodev->suspend, false);
579         return 0;
580 }
581
582 static const struct dev_pm_ops brcmf_sdio_pm_ops = {
583         .suspend        = brcmf_sdio_suspend,
584         .resume         = brcmf_sdio_resume,
585 };
586 #endif  /* CONFIG_PM_SLEEP */
587
588 static struct sdio_driver brcmf_sdmmc_driver = {
589         .probe = brcmf_ops_sdio_probe,
590         .remove = brcmf_ops_sdio_remove,
591         .name = "brcmfmac",
592         .id_table = brcmf_sdmmc_ids,
593 #ifdef CONFIG_PM_SLEEP
594         .drv = {
595                 .pm = &brcmf_sdio_pm_ops,
596         },
597 #endif  /* CONFIG_PM_SLEEP */
598 };
599
600 void brcmf_sdio_exit(void)
601 {
602         brcmf_dbg(TRACE, "Enter\n");
603
604         sdio_unregister_driver(&brcmf_sdmmc_driver);
605 }
606
607 void brcmf_sdio_init(void)
608 {
609         int ret;
610
611         brcmf_dbg(TRACE, "Enter\n");
612
613         ret = sdio_register_driver(&brcmf_sdmmc_driver);
614
615         if (ret)
616                 brcmf_dbg(ERROR, "sdio_register_driver failed: %d\n", ret);
617 }