Commit 330b4e4b authored by Hante Meuleman's avatar Hante Meuleman Committed by John W. Linville

brcmfmac: Add wowl support for SDIO devices.

This patch adds wowl support for SDIO bus devices. This feature
requires FW which has support for wowl built in.
Reviewed-by: default avatarArend Van Spriel <arend@broadcom.com>
Reviewed-by: default avatarFranky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: default avatarHante Meuleman <meuleman@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 244b124c
...@@ -1064,6 +1064,16 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, ...@@ -1064,6 +1064,16 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
if (!sdiodev->pdata) if (!sdiodev->pdata)
brcmf_of_probe(sdiodev); brcmf_of_probe(sdiodev);
#ifdef CONFIG_PM_SLEEP
/* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ
* is true or when platform data OOB irq is true).
*/
if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) &&
((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) ||
(sdiodev->pdata->oob_irq_supported)))
bus_if->wowl_supported = true;
#endif
atomic_set(&sdiodev->suspend, false); atomic_set(&sdiodev->suspend, false);
init_waitqueue_head(&sdiodev->request_word_wait); init_waitqueue_head(&sdiodev->request_word_wait);
init_waitqueue_head(&sdiodev->request_buffer_wait); init_waitqueue_head(&sdiodev->request_buffer_wait);
...@@ -1116,34 +1126,39 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func) ...@@ -1116,34 +1126,39 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
brcmf_dbg(SDIO, "Exit\n"); brcmf_dbg(SDIO, "Exit\n");
} }
void brcmf_sdio_wowl_config(struct device *dev, bool enabled)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
brcmf_dbg(SDIO, "Configuring WOWL, enabled=%d\n", enabled);
sdiodev->wowl_enabled = enabled;
}
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int brcmf_ops_sdio_suspend(struct device *dev) static int brcmf_ops_sdio_suspend(struct device *dev)
{ {
mmc_pm_flag_t sdio_flags;
struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
int ret = 0; mmc_pm_flag_t sdio_flags;
brcmf_dbg(SDIO, "Enter\n"); brcmf_dbg(SDIO, "Enter\n");
sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
brcmf_err("Host can't keep power while suspended\n");
return -EINVAL;
}
atomic_set(&sdiodev->suspend, true); atomic_set(&sdiodev->suspend, true);
ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER); if (sdiodev->wowl_enabled) {
if (ret) { sdio_flags = MMC_PM_KEEP_POWER;
brcmf_err("Failed to set pm_flags\n"); if (sdiodev->pdata->oob_irq_supported)
atomic_set(&sdiodev->suspend, false); enable_irq_wake(sdiodev->pdata->oob_irq_nr);
return ret; else
sdio_flags = MMC_PM_WAKE_SDIO_IRQ;
if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags))
brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
} }
brcmf_sdio_wd_timer(sdiodev->bus, 0); brcmf_sdio_wd_timer(sdiodev->bus, 0);
return ret; return 0;
} }
static int brcmf_ops_sdio_resume(struct device *dev) static int brcmf_ops_sdio_resume(struct device *dev)
...@@ -1152,6 +1167,8 @@ static int brcmf_ops_sdio_resume(struct device *dev) ...@@ -1152,6 +1167,8 @@ static int brcmf_ops_sdio_resume(struct device *dev)
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
brcmf_dbg(SDIO, "Enter\n"); brcmf_dbg(SDIO, "Enter\n");
if (sdiodev->pdata->oob_irq_supported)
disable_irq_wake(sdiodev->pdata->oob_irq_nr);
brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS); brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
atomic_set(&sdiodev->suspend, false); atomic_set(&sdiodev->suspend, false);
return 0; return 0;
......
...@@ -3949,6 +3949,7 @@ static struct brcmf_bus_ops brcmf_sdio_bus_ops = { ...@@ -3949,6 +3949,7 @@ static struct brcmf_bus_ops brcmf_sdio_bus_ops = {
.txctl = brcmf_sdio_bus_txctl, .txctl = brcmf_sdio_bus_txctl,
.rxctl = brcmf_sdio_bus_rxctl, .rxctl = brcmf_sdio_bus_rxctl,
.gettxq = brcmf_sdio_bus_gettxq, .gettxq = brcmf_sdio_bus_gettxq,
.wowl_config = brcmf_sdio_wowl_config
}; };
static void brcmf_sdio_firmware_callback(struct device *dev, static void brcmf_sdio_firmware_callback(struct device *dev,
......
...@@ -186,6 +186,7 @@ struct brcmf_sdio_dev { ...@@ -186,6 +186,7 @@ struct brcmf_sdio_dev {
struct sg_table sgtable; struct sg_table sgtable;
char fw_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN]; char fw_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
char nvram_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN]; char nvram_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
bool wowl_enabled;
}; };
/* sdio core registers */ /* sdio core registers */
...@@ -334,5 +335,6 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus); ...@@ -334,5 +335,6 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus);
void brcmf_sdio_isr(struct brcmf_sdio *bus); void brcmf_sdio_isr(struct brcmf_sdio *bus);
void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick); void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick);
void brcmf_sdio_wowl_config(struct device *dev, bool enabled);
#endif /* _BRCM_SDH_H_ */ #endif /* _BRCM_SDH_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment