Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+31 −14
Original line number Original line Diff line number Diff line
@@ -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)
	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)
	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;
+1 −0
Original line number Original line Diff line number Diff line
@@ -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,
+2 −0
Original line number Original line Diff line number Diff line
@@ -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);
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_ */