diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 113 |
1 files changed, 111 insertions, 2 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index 4688904908e..dd07d33a927 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -27,6 +27,7 @@ #include <linux/errno.h> #include <linux/sched.h> /* request_irq() */ #include <linux/module.h> +#include <linux/platform_device.h> #include <net/cfg80211.h> #include <defs.h> @@ -55,6 +56,15 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { }; MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); +#ifdef CONFIG_BRCMFMAC_SDIO_OOB +static struct list_head oobirq_lh; +struct brcmf_sdio_oobirq { + unsigned int irq; + unsigned long flags; + struct list_head list; +}; +#endif /* CONFIG_BRCMFMAC_SDIO_OOB */ + static bool brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev) { @@ -107,10 +117,17 @@ static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev, } sdio_release_host(sdfunc); } - } else if (regaddr == SDIO_CCCR_ABORT) { + } else if ((regaddr == SDIO_CCCR_ABORT) || + (regaddr == SDIO_CCCR_IENx)) { + sdfunc = kmemdup(sdiodev->func[0], sizeof(struct sdio_func), + GFP_KERNEL); + if (!sdfunc) + return -ENOMEM; + sdfunc->num = 0; sdio_claim_host(sdfunc); sdio_writeb(sdfunc, *byte, regaddr, &err_ret); sdio_release_host(sdfunc); + kfree(sdfunc); } else if (regaddr < 0xF0) { brcmf_dbg(ERROR, "F0 Wr:0x%02x: write disallowed\n", regaddr); err_ret = -EPERM; @@ -461,12 +478,40 @@ void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev) } +#ifdef CONFIG_BRCMFMAC_SDIO_OOB +static int brcmf_sdio_getintrcfg(struct brcmf_sdio_dev *sdiodev) +{ + struct brcmf_sdio_oobirq *oobirq_entry; + + if (list_empty(&oobirq_lh)) { + brcmf_dbg(ERROR, "no valid oob irq resource\n"); + return -ENXIO; + } + + oobirq_entry = list_first_entry(&oobirq_lh, struct brcmf_sdio_oobirq, + list); + + sdiodev->irq = oobirq_entry->irq; + sdiodev->irq_flags = oobirq_entry->flags; + list_del(&oobirq_entry->list); + kfree(oobirq_entry); + + return 0; +} +#else +static inline int brcmf_sdio_getintrcfg(struct brcmf_sdio_dev *sdiodev) +{ + return 0; +} +#endif /* CONFIG_BRCMFMAC_SDIO_OOB */ + static int brcmf_ops_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) { int ret = 0; struct brcmf_sdio_dev *sdiodev; struct brcmf_bus *bus_if; + brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "func->class=%x\n", func->class); brcmf_dbg(TRACE, "sdio_vendor: 0x%04x\n", func->vendor); @@ -486,7 +531,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, kfree(bus_if); return -ENOMEM; } - sdiodev->func[0] = func->card->sdio_func[0]; + sdiodev->func[0] = func; sdiodev->func[1] = func; sdiodev->bus_if = bus_if; bus_if->bus_priv.sdio = sdiodev; @@ -505,6 +550,10 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, sdiodev = dev_get_drvdata(&func->card->dev); if ((!sdiodev) || (sdiodev->func[1]->card != func->card)) return -ENODEV; + + ret = brcmf_sdio_getintrcfg(sdiodev); + if (ret) + return ret; sdiodev->func[2] = func; bus_if = sdiodev->bus_if; @@ -597,6 +646,65 @@ static struct sdio_driver brcmf_sdmmc_driver = { #endif /* CONFIG_PM_SLEEP */ }; +#ifdef CONFIG_BRCMFMAC_SDIO_OOB +static int brcmf_sdio_pd_probe(struct platform_device *pdev) +{ + struct resource *res; + struct brcmf_sdio_oobirq *oobirq_entry; + int i, ret; + + INIT_LIST_HEAD(&oobirq_lh); + + for (i = 0; ; i++) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, i); + if (!res) + break; + + oobirq_entry = kzalloc(sizeof(struct brcmf_sdio_oobirq), + GFP_KERNEL); + oobirq_entry->irq = res->start; + oobirq_entry->flags = res->flags & IRQF_TRIGGER_MASK; + list_add_tail(&oobirq_entry->list, &oobirq_lh); + } + if (i == 0) + return -ENXIO; + + ret = sdio_register_driver(&brcmf_sdmmc_driver); + + if (ret) + brcmf_dbg(ERROR, "sdio_register_driver failed: %d\n", ret); + + return ret; +} + +static struct platform_driver brcmf_sdio_pd = { + .probe = brcmf_sdio_pd_probe, + .driver = { + .name = "brcmf_sdio_pd" + } +}; + +void brcmf_sdio_exit(void) +{ + brcmf_dbg(TRACE, "Enter\n"); + + sdio_unregister_driver(&brcmf_sdmmc_driver); + + platform_driver_unregister(&brcmf_sdio_pd); +} + +void brcmf_sdio_init(void) +{ + int ret; + + brcmf_dbg(TRACE, "Enter\n"); + + ret = platform_driver_register(&brcmf_sdio_pd); + + if (ret) + brcmf_dbg(ERROR, "platform_driver_register failed: %d\n", ret); +} +#else void brcmf_sdio_exit(void) { brcmf_dbg(TRACE, "Enter\n"); @@ -615,3 +723,4 @@ void brcmf_sdio_init(void) if (ret) brcmf_dbg(ERROR, "sdio_register_driver failed: %d\n", ret); } +#endif /* CONFIG_BRCMFMAC_SDIO_OOB */ |