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