forked from Minki/linux
brcmfmac: define and use platform specific data for SDIO.
This patch adds support for platform specific data for SDIO fullmac devices. Currently OOB interrupts are configured by Kconfig BRCMFMAC_SDIO_OOB but that is now determined dynamically by checking availibility of platform data. Cc: Hauke Mehrtens <hauke@hauke-m.de> Reviewed-by: Arend Van Spriel <arend@broadcom.com> Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Reviewed-by: Piotr Haber <phaber@broadcom.com> Signed-off-by: Hante Meuleman <meuleman@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
979c29205f
commit
668761ac01
@ -37,15 +37,6 @@ config BRCMFMAC_SDIO
|
||||
IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to
|
||||
use the driver for a SDIO wireless card.
|
||||
|
||||
config BRCMFMAC_SDIO_OOB
|
||||
bool "Out of band interrupt support for SDIO interface chipset"
|
||||
depends on BRCMFMAC_SDIO
|
||||
---help---
|
||||
This option enables out-of-band interrupt support for Broadcom
|
||||
SDIO Wifi chipset using fullmac in order to gain better
|
||||
performance and deep sleep wake up capability on certain
|
||||
platforms. Say N if you are unsure.
|
||||
|
||||
config BRCMFMAC_USB
|
||||
bool "USB bus interface support for FullMAC driver"
|
||||
depends on USB
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/mmc/sdio.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/platform_data/brcmfmac-sdio.h>
|
||||
|
||||
#include <defs.h>
|
||||
#include <brcm_hw_ids.h>
|
||||
@ -37,16 +38,15 @@
|
||||
|
||||
#define SDIOH_API_ACCESS_RETRY_LIMIT 2
|
||||
|
||||
#ifdef CONFIG_BRCMFMAC_SDIO_OOB
|
||||
static irqreturn_t brcmf_sdio_irqhandler(int irq, void *dev_id)
|
||||
|
||||
static irqreturn_t brcmf_sdio_oob_irqhandler(int irq, void *dev_id)
|
||||
{
|
||||
struct brcmf_bus *bus_if = dev_get_drvdata(dev_id);
|
||||
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
|
||||
|
||||
brcmf_dbg(INTR, "oob intr triggered\n");
|
||||
brcmf_dbg(INTR, "OOB intr triggered\n");
|
||||
|
||||
/*
|
||||
* out-of-band interrupt is level-triggered which won't
|
||||
/* out-of-band interrupt is level-triggered which won't
|
||||
* be cleared until dpc
|
||||
*/
|
||||
if (sdiodev->irq_en) {
|
||||
@ -59,72 +59,12 @@ static irqreturn_t brcmf_sdio_irqhandler(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 data;
|
||||
unsigned long flags;
|
||||
|
||||
brcmf_dbg(SDIO, "Entering: irq %d\n", sdiodev->irq);
|
||||
|
||||
ret = request_irq(sdiodev->irq, brcmf_sdio_irqhandler,
|
||||
sdiodev->irq_flags, "brcmf_oob_intr",
|
||||
&sdiodev->func[1]->dev);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
spin_lock_init(&sdiodev->irq_en_lock);
|
||||
spin_lock_irqsave(&sdiodev->irq_en_lock, flags);
|
||||
sdiodev->irq_en = true;
|
||||
spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
|
||||
|
||||
ret = enable_irq_wake(sdiodev->irq);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
sdiodev->irq_wake = true;
|
||||
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
|
||||
/* must configure SDIO_CCCR_IENx to enable irq */
|
||||
data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
|
||||
data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
|
||||
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
|
||||
|
||||
/* redirect, configure and enable io for interrupt signal */
|
||||
data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
|
||||
if (sdiodev->irq_flags & IRQF_TRIGGER_HIGH)
|
||||
data |= SDIO_SEPINT_ACT_HI;
|
||||
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
|
||||
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
brcmf_dbg(SDIO, "Entering\n");
|
||||
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
|
||||
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
|
||||
if (sdiodev->irq_wake) {
|
||||
disable_irq_wake(sdiodev->irq);
|
||||
sdiodev->irq_wake = false;
|
||||
}
|
||||
free_irq(sdiodev->irq, &sdiodev->func[1]->dev);
|
||||
sdiodev->irq_en = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* CONFIG_BRCMFMAC_SDIO_OOB */
|
||||
static void brcmf_sdio_irqhandler(struct sdio_func *func)
|
||||
static void brcmf_sdio_ib_irqhandler(struct sdio_func *func)
|
||||
{
|
||||
struct brcmf_bus *bus_if = dev_get_drvdata(&func->dev);
|
||||
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
|
||||
|
||||
brcmf_dbg(INTR, "ib intr triggered\n");
|
||||
brcmf_dbg(INTR, "IB intr triggered\n");
|
||||
|
||||
brcmf_sdbrcm_isr(sdiodev->bus);
|
||||
}
|
||||
@ -136,12 +76,56 @@ static void brcmf_sdio_dummy_irqhandler(struct sdio_func *func)
|
||||
|
||||
int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
brcmf_dbg(SDIO, "Entering\n");
|
||||
int ret = 0;
|
||||
u8 data;
|
||||
unsigned long flags;
|
||||
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
sdio_claim_irq(sdiodev->func[1], brcmf_sdio_irqhandler);
|
||||
sdio_claim_irq(sdiodev->func[2], brcmf_sdio_dummy_irqhandler);
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
|
||||
brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n",
|
||||
sdiodev->pdata->oob_irq_nr);
|
||||
ret = request_irq(sdiodev->pdata->oob_irq_nr,
|
||||
brcmf_sdio_oob_irqhandler,
|
||||
sdiodev->pdata->oob_irq_flags,
|
||||
"brcmf_oob_intr",
|
||||
&sdiodev->func[1]->dev);
|
||||
if (ret != 0) {
|
||||
brcmf_err("request_irq failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
sdiodev->oob_irq_requested = true;
|
||||
spin_lock_init(&sdiodev->irq_en_lock);
|
||||
spin_lock_irqsave(&sdiodev->irq_en_lock, flags);
|
||||
sdiodev->irq_en = true;
|
||||
spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
|
||||
|
||||
ret = enable_irq_wake(sdiodev->pdata->oob_irq_nr);
|
||||
if (ret != 0) {
|
||||
brcmf_err("enable_irq_wake failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
sdiodev->irq_wake = true;
|
||||
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
|
||||
/* must configure SDIO_CCCR_IENx to enable irq */
|
||||
data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
|
||||
data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
|
||||
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
|
||||
|
||||
/* redirect, configure and enable io for interrupt signal */
|
||||
data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
|
||||
if (sdiodev->pdata->oob_irq_flags & IRQF_TRIGGER_HIGH)
|
||||
data |= SDIO_SEPINT_ACT_HI;
|
||||
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
|
||||
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
} else {
|
||||
brcmf_dbg(SDIO, "Entering\n");
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
sdio_claim_irq(sdiodev->func[1], brcmf_sdio_ib_irqhandler);
|
||||
sdio_claim_irq(sdiodev->func[2], brcmf_sdio_dummy_irqhandler);
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -150,14 +134,31 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
brcmf_dbg(SDIO, "Entering\n");
|
||||
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
sdio_release_irq(sdiodev->func[2]);
|
||||
sdio_release_irq(sdiodev->func[1]);
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
|
||||
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
|
||||
if (sdiodev->oob_irq_requested) {
|
||||
sdiodev->oob_irq_requested = false;
|
||||
if (sdiodev->irq_wake) {
|
||||
disable_irq_wake(sdiodev->pdata->oob_irq_nr);
|
||||
sdiodev->irq_wake = false;
|
||||
}
|
||||
free_irq(sdiodev->pdata->oob_irq_nr,
|
||||
&sdiodev->func[1]->dev);
|
||||
sdiodev->irq_en = false;
|
||||
}
|
||||
} else {
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
sdio_release_irq(sdiodev->func[2]);
|
||||
sdio_release_irq(sdiodev->func[1]);
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
|
||||
|
||||
int
|
||||
brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/sched.h> /* request_irq() */
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/brcmfmac-sdio.h>
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
#include <defs.h>
|
||||
@ -62,14 +63,8 @@ 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 struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata;
|
||||
|
||||
|
||||
static bool
|
||||
brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev)
|
||||
@ -428,33 +423,6 @@ 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_err("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)
|
||||
{
|
||||
@ -495,15 +463,13 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
|
||||
dev_set_drvdata(&func->dev, bus_if);
|
||||
dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
|
||||
sdiodev->dev = &sdiodev->func[1]->dev;
|
||||
sdiodev->pdata = brcmfmac_sdio_pdata;
|
||||
|
||||
atomic_set(&sdiodev->suspend, false);
|
||||
init_waitqueue_head(&sdiodev->request_byte_wait);
|
||||
init_waitqueue_head(&sdiodev->request_word_wait);
|
||||
init_waitqueue_head(&sdiodev->request_chain_wait);
|
||||
init_waitqueue_head(&sdiodev->request_buffer_wait);
|
||||
err = brcmf_sdio_getintrcfg(sdiodev);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
brcmf_dbg(SDIO, "F2 found, calling brcmf_sdio_probe...\n");
|
||||
err = brcmf_sdio_probe(sdiodev);
|
||||
@ -598,7 +564,7 @@ static const struct dev_pm_ops brcmf_sdio_pm_ops = {
|
||||
static struct sdio_driver brcmf_sdmmc_driver = {
|
||||
.probe = brcmf_ops_sdio_probe,
|
||||
.remove = brcmf_ops_sdio_remove,
|
||||
.name = "brcmfmac",
|
||||
.name = BRCMFMAC_SDIO_PDATA_NAME,
|
||||
.id_table = brcmf_sdmmc_ids,
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.drv = {
|
||||
@ -607,43 +573,40 @@ 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;
|
||||
int ret;
|
||||
|
||||
INIT_LIST_HEAD(&oobirq_lh);
|
||||
brcmf_dbg(SDIO, "Enter\n");
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
|
||||
if (!res)
|
||||
break;
|
||||
brcmfmac_sdio_pdata = pdev->dev.platform_data;
|
||||
|
||||
oobirq_entry = kzalloc(sizeof(struct brcmf_sdio_oobirq),
|
||||
GFP_KERNEL);
|
||||
if (!oobirq_entry)
|
||||
return -ENOMEM;
|
||||
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;
|
||||
if (brcmfmac_sdio_pdata->power_on)
|
||||
brcmfmac_sdio_pdata->power_on();
|
||||
|
||||
ret = sdio_register_driver(&brcmf_sdmmc_driver);
|
||||
|
||||
if (ret)
|
||||
brcmf_err("sdio_register_driver failed: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int brcmf_sdio_pd_remove(struct platform_device *pdev)
|
||||
{
|
||||
brcmf_dbg(SDIO, "Enter\n");
|
||||
|
||||
if (brcmfmac_sdio_pdata->power_off)
|
||||
brcmfmac_sdio_pdata->power_off();
|
||||
|
||||
sdio_unregister_driver(&brcmf_sdmmc_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver brcmf_sdio_pd = {
|
||||
.probe = brcmf_sdio_pd_probe,
|
||||
.remove = brcmf_sdio_pd_remove,
|
||||
.driver = {
|
||||
.name = "brcmf_sdio_pd"
|
||||
.name = BRCMFMAC_SDIO_PDATA_NAME
|
||||
}
|
||||
};
|
||||
|
||||
@ -651,9 +614,10 @@ void brcmf_sdio_exit(void)
|
||||
{
|
||||
brcmf_dbg(SDIO, "Enter\n");
|
||||
|
||||
sdio_unregister_driver(&brcmf_sdmmc_driver);
|
||||
|
||||
platform_driver_unregister(&brcmf_sdio_pd);
|
||||
if (brcmfmac_sdio_pdata)
|
||||
platform_driver_unregister(&brcmf_sdio_pd);
|
||||
else
|
||||
sdio_unregister_driver(&brcmf_sdmmc_driver);
|
||||
}
|
||||
|
||||
void brcmf_sdio_init(void)
|
||||
@ -662,28 +626,12 @@ void brcmf_sdio_init(void)
|
||||
|
||||
brcmf_dbg(SDIO, "Enter\n");
|
||||
|
||||
ret = platform_driver_register(&brcmf_sdio_pd);
|
||||
ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe);
|
||||
if (ret == -ENODEV) {
|
||||
brcmf_dbg(SDIO, "No platform data available, registering without.\n");
|
||||
ret = sdio_register_driver(&brcmf_sdmmc_driver);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
brcmf_err("platform_driver_register failed: %d\n", ret);
|
||||
brcmf_err("driver registration failed: %d\n", ret);
|
||||
}
|
||||
#else
|
||||
void brcmf_sdio_exit(void)
|
||||
{
|
||||
brcmf_dbg(SDIO, "Enter\n");
|
||||
|
||||
sdio_unregister_driver(&brcmf_sdmmc_driver);
|
||||
}
|
||||
|
||||
void brcmf_sdio_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
brcmf_dbg(SDIO, "Enter\n");
|
||||
|
||||
ret = sdio_register_driver(&brcmf_sdmmc_driver);
|
||||
|
||||
if (ret)
|
||||
brcmf_err("sdio_register_driver failed: %d\n", ret);
|
||||
}
|
||||
#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/platform_data/brcmfmac-sdio.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <defs.h>
|
||||
#include <brcmu_wifi.h>
|
||||
@ -517,7 +518,7 @@ static int qcount[NUMPRIO];
|
||||
static int tx_packets[NUMPRIO];
|
||||
#endif /* DEBUG */
|
||||
|
||||
#define SDIO_DRIVE_STRENGTH 6 /* in milliamps */
|
||||
#define DEFAULT_SDIO_DRIVE_STRENGTH 6 /* in milliamps */
|
||||
|
||||
#define RETRYCHAN(chan) ((chan) == SDPCM_EVENT_CHANNEL)
|
||||
|
||||
@ -2046,23 +2047,19 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
|
||||
bus->tx_seq = bus->rx_seq = 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BRCMFMAC_SDIO_OOB
|
||||
static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags);
|
||||
if (!bus->sdiodev->irq_en && !atomic_read(&bus->ipend)) {
|
||||
enable_irq(bus->sdiodev->irq);
|
||||
bus->sdiodev->irq_en = true;
|
||||
if (bus->sdiodev->oob_irq_requested) {
|
||||
spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags);
|
||||
if (!bus->sdiodev->irq_en && !atomic_read(&bus->ipend)) {
|
||||
enable_irq(bus->sdiodev->pdata->oob_irq_nr);
|
||||
bus->sdiodev->irq_en = true;
|
||||
}
|
||||
spin_unlock_irqrestore(&bus->sdiodev->irq_en_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&bus->sdiodev->irq_en_lock, flags);
|
||||
}
|
||||
#else
|
||||
static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
|
||||
|
||||
static inline void brcmf_sdbrcm_adddpctsk(struct brcmf_sdio *bus)
|
||||
{
|
||||
@ -3639,6 +3636,7 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
|
||||
int err = 0;
|
||||
int reg_addr;
|
||||
u32 reg_val;
|
||||
u32 drivestrength;
|
||||
|
||||
bus->alp_only = true;
|
||||
|
||||
@ -3679,8 +3677,11 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
brcmf_sdio_chip_drivestrengthinit(bus->sdiodev, bus->ci,
|
||||
SDIO_DRIVE_STRENGTH);
|
||||
if ((bus->sdiodev->pdata) && (bus->sdiodev->pdata->drive_strength))
|
||||
drivestrength = bus->sdiodev->pdata->drive_strength;
|
||||
else
|
||||
drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH;
|
||||
brcmf_sdio_chip_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength);
|
||||
|
||||
/* Get info on the SOCRAM cores... */
|
||||
bus->ramsize = bus->ci->ramsize;
|
||||
|
@ -174,13 +174,11 @@ struct brcmf_sdio_dev {
|
||||
wait_queue_head_t request_buffer_wait;
|
||||
struct device *dev;
|
||||
struct brcmf_bus *bus_if;
|
||||
#ifdef CONFIG_BRCMFMAC_SDIO_OOB
|
||||
unsigned int irq; /* oob interrupt number */
|
||||
unsigned long irq_flags; /* board specific oob flags */
|
||||
struct brcmfmac_sdio_platform_data *pdata;
|
||||
bool oob_irq_requested;
|
||||
bool irq_en; /* irq enable flags */
|
||||
spinlock_t irq_en_lock;
|
||||
bool irq_wake; /* irq wake enable flags */
|
||||
#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
|
||||
};
|
||||
|
||||
/* Register/deregister interrupt handler. */
|
||||
|
124
include/linux/platform_data/brcmfmac-sdio.h
Normal file
124
include/linux/platform_data/brcmfmac-sdio.h
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2013 Broadcom Corporation
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_BRCMFMAC_PLATFORM_H
|
||||
#define _LINUX_BRCMFMAC_PLATFORM_H
|
||||
|
||||
/*
|
||||
* Platform specific driver functions and data. Through the platform specific
|
||||
* device data functions can be provided to help the brcmfmac driver to
|
||||
* operate with the device in combination with the used platform.
|
||||
*
|
||||
* Use the platform data in the following (similar) way:
|
||||
*
|
||||
*
|
||||
#include <brcmfmac_platform.h>
|
||||
|
||||
|
||||
static void brcmfmac_power_on(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void brcmfmac_power_off(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void brcmfmac_reset(void)
|
||||
{
|
||||
}
|
||||
|
||||
static struct brcmfmac_sdio_platform_data brcmfmac_sdio_pdata = {
|
||||
.power_on = brcmfmac_power_on,
|
||||
.power_off = brcmfmac_power_off,
|
||||
.reset = brcmfmac_reset
|
||||
};
|
||||
|
||||
static struct platform_device brcmfmac_device = {
|
||||
.name = BRCMFMAC_SDIO_PDATA_NAME,
|
||||
.id = PLATFORM_DEVID_NONE,
|
||||
.dev.platform_data = &brcmfmac_sdio_pdata
|
||||
};
|
||||
|
||||
void __init brcmfmac_init_pdata(void)
|
||||
{
|
||||
brcmfmac_sdio_pdata.oob_irq_supported = true;
|
||||
brcmfmac_sdio_pdata.oob_irq_nr = gpio_to_irq(GPIO_BRCMF_SDIO_OOB);
|
||||
brcmfmac_sdio_pdata.oob_irq_flags = IORESOURCE_IRQ |
|
||||
IORESOURCE_IRQ_HIGHLEVEL;
|
||||
platform_device_register(&brcmfmac_device);
|
||||
}
|
||||
*
|
||||
*
|
||||
* Note: the brcmfmac can be loaded as module or be statically built-in into
|
||||
* the kernel. If built-in then do note that it uses module_init (and
|
||||
* module_exit) routines which equal device_initcall. So if you intend to
|
||||
* create a module with the platform specific data for the brcmfmac and have
|
||||
* it built-in to the kernel then use a higher initcall then device_initcall
|
||||
* (see init.h). If this is not done then brcmfmac will load without problems
|
||||
* but will not pickup the platform data.
|
||||
*
|
||||
* When the driver does not "detect" platform driver data then it will continue
|
||||
* without reporting anything and just assume there is no data needed. Which is
|
||||
* probably true for most platforms.
|
||||
*
|
||||
* Explanation of the platform_data fields:
|
||||
*
|
||||
* drive_strength: is the preferred drive_strength to be used for the SDIO
|
||||
* pins. If 0 then a default value will be used. This is the target drive
|
||||
* strength, the exact drive strength which will be used depends on the
|
||||
* capabilities of the device.
|
||||
*
|
||||
* oob_irq_supported: does the board have support for OOB interrupts. SDIO
|
||||
* in-band interrupts are relatively slow and for having less overhead on
|
||||
* interrupt processing an out of band interrupt can be used. If the HW
|
||||
* supports this then enable this by setting this field to true and configure
|
||||
* the oob related fields.
|
||||
*
|
||||
* oob_irq_nr, oob_irq_flags: the OOB interrupt information. The values are
|
||||
* used for registering the irq using request_irq function.
|
||||
*
|
||||
* power_on: This function is called by the brcmfmac when the module gets
|
||||
* loaded. This can be particularly useful for low power devices. The platform
|
||||
* spcific routine may for example decide to power up the complete device.
|
||||
* If there is no use-case for this function then provide NULL.
|
||||
*
|
||||
* power_off: This function is called by the brcmfmac when the module gets
|
||||
* unloaded. At this point the device can be powered down or otherwise be reset.
|
||||
* So if an actual power_off is not supported but reset is then reset the device
|
||||
* when this function gets called. This can be particularly useful for low power
|
||||
* devices. If there is no use-case for this function (either power-down or
|
||||
* reset) then provide NULL.
|
||||
*
|
||||
* reset: This function can get called if the device communication broke down.
|
||||
* This functionality is particularly useful in case of SDIO type devices. It is
|
||||
* possible to reset a dongle via sdio data interface, but it requires that
|
||||
* this is fully functional. This function is chip/module specific and this
|
||||
* function should return only after the complete reset has completed.
|
||||
*/
|
||||
|
||||
#define BRCMFMAC_SDIO_PDATA_NAME "brcmfmac_sdio"
|
||||
|
||||
struct brcmfmac_sdio_platform_data {
|
||||
unsigned int drive_strength;
|
||||
bool oob_irq_supported;
|
||||
unsigned int oob_irq_nr;
|
||||
unsigned long oob_irq_flags;
|
||||
void (*power_on)(void);
|
||||
void (*power_off)(void);
|
||||
void (*reset)(void);
|
||||
};
|
||||
|
||||
#endif /* _LINUX_BRCMFMAC_PLATFORM_H */
|
Loading…
Reference in New Issue
Block a user