brcmfmac: replace brcmf_sdcard_cfg_read with brcmf_sdio_regrb
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / brcm80211 / brcmfmac / bcmsdh.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 /* ****************** 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_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_IENx,
91                                data, &ret);
92
93         /* redirect, configure ane enable io for interrupt signal */
94         data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
95         if (sdiodev->irq_flags | IRQF_TRIGGER_HIGH)
96                 data |= SDIO_SEPINT_ACT_HI;
97         brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_BRCM_SEPINT,
98                                data, &ret);
99
100         return 0;
101 }
102
103 int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
104 {
105         brcmf_dbg(TRACE, "Entering\n");
106
107         brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_BRCM_SEPINT,
108                                0, NULL);
109         brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_IENx, 0, NULL);
110
111         if (sdiodev->irq_wake) {
112                 disable_irq_wake(sdiodev->irq);
113                 sdiodev->irq_wake = false;
114         }
115         free_irq(sdiodev->irq, &sdiodev->func[1]->card->dev);
116         sdiodev->irq_en = false;
117
118         return 0;
119 }
120 #else           /* CONFIG_BRCMFMAC_SDIO_OOB */
121 static void brcmf_sdio_irqhandler(struct sdio_func *func)
122 {
123         struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
124
125         brcmf_dbg(INTR, "ib intr triggered\n");
126
127         brcmf_sdbrcm_isr(sdiodev->bus);
128 }
129
130 /* dummy handler for SDIO function 2 interrupt */
131 static void brcmf_sdio_dummy_irqhandler(struct sdio_func *func)
132 {
133 }
134
135 int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
136 {
137         brcmf_dbg(TRACE, "Entering\n");
138
139         sdio_claim_host(sdiodev->func[1]);
140         sdio_claim_irq(sdiodev->func[1], brcmf_sdio_irqhandler);
141         sdio_claim_irq(sdiodev->func[2], brcmf_sdio_dummy_irqhandler);
142         sdio_release_host(sdiodev->func[1]);
143
144         return 0;
145 }
146
147 int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
148 {
149         brcmf_dbg(TRACE, "Entering\n");
150
151         sdio_claim_host(sdiodev->func[1]);
152         sdio_release_irq(sdiodev->func[2]);
153         sdio_release_irq(sdiodev->func[1]);
154         sdio_release_host(sdiodev->func[1]);
155
156         return 0;
157 }
158 #endif          /* CONFIG_BRCMFMAC_SDIO_OOB */
159
160 void
161 brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr,
162                        u8 data, int *err)
163 {
164         int status;
165         s32 retry = 0;
166
167         do {
168                 if (retry)      /* wait for 1 ms till bus get settled down */
169                         udelay(1000);
170                 status = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, fnc_num,
171                                                   addr, (u8 *) &data);
172         } while (status != 0
173                  && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
174         if (err)
175                 *err = status;
176
177         brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n",
178                   fnc_num, addr, data);
179 }
180
181 int
182 brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
183 {
184         int err = 0, i;
185         u8 addr[3];
186         s32 retry;
187
188         addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
189         addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK;
190         addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK;
191
192         for (i = 0; i < 3; i++) {
193                 retry = 0;
194                 do {
195                         if (retry)
196                                 usleep_range(1000, 2000);
197                         err = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE,
198                                         SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW + i,
199                                         &addr[i]);
200                 } while (err != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
201
202                 if (err) {
203                         brcmf_dbg(ERROR, "failed at addr:0x%0x\n",
204                                   SBSDIO_FUNC1_SBADDRLOW + i);
205                         break;
206                 }
207         }
208
209         return err;
210 }
211
212 static int
213 brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
214                         void *data, bool write)
215 {
216         u8 func_num, reg_size;
217         u32 bar;
218         s32 retry = 0;
219         int ret;
220
221         /*
222          * figure out how to read the register based on address range
223          * 0x00 ~ 0xFF: function 0 CCCR
224          * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
225          * The rest: function 1 silicon backplane core registers
226          */
227         if ((addr & ~REG_F0_CCCR_MASK) == 0) {
228                 func_num = SDIO_FUNC_0;
229                 reg_size = 1;
230         } else if ((addr & ~REG_F1_MISC_MASK) == 0) {
231                 func_num = SDIO_FUNC_1;
232                 reg_size = 1;
233         } else {
234                 func_num = SDIO_FUNC_1;
235                 reg_size = 4;
236
237                 /* Set the window for SB core register */
238                 bar = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
239                 if (bar != sdiodev->sbwad) {
240                         ret = brcmf_sdcard_set_sbaddr_window(sdiodev, bar);
241                         if (ret != 0) {
242                                 memset(data, 0xFF, reg_size);
243                                 return ret;
244                         }
245                         sdiodev->sbwad = bar;
246                 }
247                 addr &= SBSDIO_SB_OFT_ADDR_MASK;
248                 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
249         }
250
251         do {
252                 if (!write)
253                         memset(data, 0, reg_size);
254                 if (retry)      /* wait for 1 ms till bus get settled down */
255                         usleep_range(1000, 2000);
256                 if (reg_size == 1)
257                         ret = brcmf_sdioh_request_byte(sdiodev, write,
258                                                        func_num, addr, data);
259                 else
260                         ret = brcmf_sdioh_request_word(sdiodev, write,
261                                                        func_num, addr, data, 4);
262         } while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
263
264         sdiodev->regfail = (ret != 0);
265         if (sdiodev->regfail)
266                 brcmf_dbg(ERROR, "failed with %d\n", ret);
267
268         return ret;
269 }
270
271 u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
272 {
273         u8 data;
274         int retval;
275
276         brcmf_dbg(INFO, "addr:0x%08x\n", addr);
277         retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
278         brcmf_dbg(INFO, "data:0x%02x\n", data);
279
280         if (ret)
281                 *ret = retval;
282
283         return data;
284 }
285
286 u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
287 {
288         u32 data;
289         int retval;
290
291         brcmf_dbg(INFO, "addr:0x%08x\n", addr);
292         retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
293         brcmf_dbg(INFO, "data:0x%08x\n", data);
294
295         if (ret)
296                 *ret = retval;
297
298         return data;
299 }
300
301 void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
302                       u8 data, int *ret)
303 {
304         int retval;
305
306         brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data);
307         retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
308
309         if (ret)
310                 *ret = retval;
311 }
312
313 void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
314                       u32 data, int *ret)
315 {
316         int retval;
317
318         brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data);
319         retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
320
321         if (ret)
322                 *ret = retval;
323 }
324
325 u32 brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr)
326 {
327         int status;
328         u32 word = 0;
329         uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
330
331         brcmf_dbg(INFO, "fun = 1, addr = 0x%x\n", addr);
332
333         if (bar0 != sdiodev->sbwad) {
334                 if (brcmf_sdcard_set_sbaddr_window(sdiodev, bar0))
335                         return 0xFFFFFFFF;
336
337                 sdiodev->sbwad = bar0;
338         }
339
340         addr &= SBSDIO_SB_OFT_ADDR_MASK;
341         addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
342
343         status = brcmf_sdioh_request_word(sdiodev, SDIOH_READ, SDIO_FUNC_1,
344                                           addr, &word, 4);
345
346         sdiodev->regfail = (status != 0);
347
348         if (status == 0) {
349                 brcmf_dbg(INFO, "data = 0x%x\n", word);
350                 return word;
351         } else {
352                 brcmf_dbg(ERROR, "failed %d at addr 0x%04x\n", status, addr);
353                 return 0xFFFFFFFF;
354         }
355 }
356
357 u32 brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, u32 data)
358 {
359         int status;
360         uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
361         int err = 0;
362
363         brcmf_dbg(INFO, "fun = 1, addr = 0x%x, uint32data = 0x%x\n",
364                   addr, data);
365
366         if (bar0 != sdiodev->sbwad) {
367                 err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
368                 if (err)
369                         return err;
370
371                 sdiodev->sbwad = bar0;
372         }
373
374         addr &= SBSDIO_SB_OFT_ADDR_MASK;
375         addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
376         status =
377             brcmf_sdioh_request_word(sdiodev, SDIOH_WRITE, SDIO_FUNC_1,
378                                      addr, &data, 4);
379         sdiodev->regfail = (status != 0);
380
381         if (status == 0)
382                 return 0;
383
384         brcmf_dbg(ERROR, "error writing 0x%08x to addr 0x%04x\n",
385                   data, addr);
386         return 0xFFFFFFFF;
387 }
388
389 bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev)
390 {
391         return sdiodev->regfail;
392 }
393
394 static int brcmf_sdcard_recv_prepare(struct brcmf_sdio_dev *sdiodev, uint fn,
395                                      uint flags, uint width, u32 *addr)
396 {
397         uint bar0 = *addr & ~SBSDIO_SB_OFT_ADDR_MASK;
398         int err = 0;
399
400         /* Async not implemented yet */
401         if (flags & SDIO_REQ_ASYNC)
402                 return -ENOTSUPP;
403
404         if (bar0 != sdiodev->sbwad) {
405                 err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
406                 if (err)
407                         return err;
408
409                 sdiodev->sbwad = bar0;
410         }
411
412         *addr &= SBSDIO_SB_OFT_ADDR_MASK;
413
414         if (width == 4)
415                 *addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
416
417         return 0;
418 }
419
420 int
421 brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
422                       uint flags, u8 *buf, uint nbytes)
423 {
424         struct sk_buff *mypkt;
425         int err;
426
427         mypkt = brcmu_pkt_buf_get_skb(nbytes);
428         if (!mypkt) {
429                 brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
430                           nbytes);
431                 return -EIO;
432         }
433
434         err = brcmf_sdcard_recv_pkt(sdiodev, addr, fn, flags, mypkt);
435         if (!err)
436                 memcpy(buf, mypkt->data, nbytes);
437
438         brcmu_pkt_buf_free_skb(mypkt);
439         return err;
440 }
441
442 int
443 brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
444                       uint flags, struct sk_buff *pkt)
445 {
446         uint incr_fix;
447         uint width;
448         int err = 0;
449
450         brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
451                   fn, addr, pkt->len);
452
453         width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
454         err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
455         if (err)
456                 return err;
457
458         incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
459         err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ,
460                                          fn, addr, pkt);
461
462         return err;
463 }
464
465 int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
466                             uint flags, struct sk_buff_head *pktq)
467 {
468         uint incr_fix;
469         uint width;
470         int err = 0;
471
472         brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
473                   fn, addr, pktq->qlen);
474
475         width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
476         err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
477         if (err)
478                 return err;
479
480         incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
481         err = brcmf_sdioh_request_chain(sdiodev, incr_fix, SDIOH_READ, fn, addr,
482                                         pktq);
483
484         return err;
485 }
486
487 int
488 brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
489                       uint flags, u8 *buf, uint nbytes)
490 {
491         struct sk_buff *mypkt;
492         int err;
493
494         mypkt = brcmu_pkt_buf_get_skb(nbytes);
495         if (!mypkt) {
496                 brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
497                           nbytes);
498                 return -EIO;
499         }
500
501         memcpy(mypkt->data, buf, nbytes);
502         err = brcmf_sdcard_send_pkt(sdiodev, addr, fn, flags, mypkt);
503
504         brcmu_pkt_buf_free_skb(mypkt);
505         return err;
506
507 }
508
509 int
510 brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
511                       uint flags, struct sk_buff *pkt)
512 {
513         uint incr_fix;
514         uint width;
515         uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
516         int err = 0;
517
518         brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
519                   fn, addr, pkt->len);
520
521         /* Async not implemented yet */
522         if (flags & SDIO_REQ_ASYNC)
523                 return -ENOTSUPP;
524
525         if (bar0 != sdiodev->sbwad) {
526                 err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
527                 if (err)
528                         return err;
529
530                 sdiodev->sbwad = bar0;
531         }
532
533         addr &= SBSDIO_SB_OFT_ADDR_MASK;
534
535         incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
536         width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
537         if (width == 4)
538                 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
539
540         return brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn,
541                                           addr, pkt);
542 }
543
544 int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr,
545                         u8 *buf, uint nbytes)
546 {
547         struct sk_buff *mypkt;
548         bool write = rw ? SDIOH_WRITE : SDIOH_READ;
549         int err;
550
551         addr &= SBSDIO_SB_OFT_ADDR_MASK;
552         addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
553
554         mypkt = brcmu_pkt_buf_get_skb(nbytes);
555         if (!mypkt) {
556                 brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
557                           nbytes);
558                 return -EIO;
559         }
560
561         /* For a write, copy the buffer data into the packet. */
562         if (write)
563                 memcpy(mypkt->data, buf, nbytes);
564
565         err = brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC, write,
566                                          SDIO_FUNC_1, addr, mypkt);
567
568         /* For a read, copy the packet data back to the buffer. */
569         if (!err && !write)
570                 memcpy(buf, mypkt->data, nbytes);
571
572         brcmu_pkt_buf_free_skb(mypkt);
573         return err;
574 }
575
576 int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
577 {
578         char t_func = (char)fn;
579         brcmf_dbg(TRACE, "Enter\n");
580
581         /* issue abort cmd52 command through F0 */
582         brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
583                                  SDIO_CCCR_ABORT, &t_func);
584
585         brcmf_dbg(TRACE, "Exit\n");
586         return 0;
587 }
588
589 int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
590 {
591         u32 regs = 0;
592         int ret = 0;
593
594         ret = brcmf_sdioh_attach(sdiodev);
595         if (ret)
596                 goto out;
597
598         regs = SI_ENUM_BASE;
599
600         /* Report the BAR, to fix if needed */
601         sdiodev->sbwad = SI_ENUM_BASE;
602
603         /* try to attach to the target device */
604         sdiodev->bus = brcmf_sdbrcm_probe(regs, sdiodev);
605         if (!sdiodev->bus) {
606                 brcmf_dbg(ERROR, "device attach failed\n");
607                 ret = -ENODEV;
608                 goto out;
609         }
610
611 out:
612         if (ret)
613                 brcmf_sdio_remove(sdiodev);
614
615         return ret;
616 }
617 EXPORT_SYMBOL(brcmf_sdio_probe);
618
619 int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
620 {
621         if (sdiodev->bus) {
622                 brcmf_sdbrcm_disconnect(sdiodev->bus);
623                 sdiodev->bus = NULL;
624         }
625
626         brcmf_sdioh_detach(sdiodev);
627
628         sdiodev->sbwad = 0;
629
630         return 0;
631 }
632 EXPORT_SYMBOL(brcmf_sdio_remove);
633
634 void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable)
635 {
636         if (enable)
637                 brcmf_sdbrcm_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
638         else
639                 brcmf_sdbrcm_wd_timer(sdiodev->bus, 0);
640 }