wifi: wfx: allow SDIO device to wake up the host

If the device is connected with SDIO bus, it can wake up the host using
either the SDIO controller (that requires MMC_PM_WAKE_SDIO_IRQ
capability) or the out-of-bound IRQ. This patch allows both.

Obviously, the SDIO controller must be able to keep the SDIO device
powered on.

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
Link: https://patch.msgid.link/20250304153224.39083-5-jerome.pouiller@silabs.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Jérôme Pouiller 2025-03-04 16:32:23 +01:00 committed by Johannes Berg
parent 32bd7f4b39
commit 75516809af

View File

@ -14,6 +14,7 @@
#include <linux/of_irq.h>
#include <linux/irq.h>
#include <linux/align.h>
#include <linux/pm.h>
#include "bus.h"
#include "wfx.h"
@ -191,9 +192,48 @@ static const struct of_device_id wfx_sdio_of_match[] = {
};
MODULE_DEVICE_TABLE(of, wfx_sdio_of_match);
static int wfx_sdio_suspend(struct device *dev)
{
struct sdio_func *func = dev_to_sdio_func(dev);
struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
int ret;
if (!device_may_wakeup(dev))
return 0;
flush_work(&bus->core->hif.bh);
/* Either "wakeup-source" attribute or out-of-band IRQ is required for
* WoWLAN
*/
if (bus->of_irq) {
ret = enable_irq_wake(bus->of_irq);
if (ret)
return ret;
} else {
ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
if (ret)
return ret;
}
return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
}
static int wfx_sdio_resume(struct device *dev)
{
struct sdio_func *func = dev_to_sdio_func(dev);
struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
if (!device_may_wakeup(dev))
return 0;
if (bus->of_irq)
return disable_irq_wake(bus->of_irq);
else
return 0;
}
static int wfx_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
{
const struct wfx_platform_data *pdata = of_device_get_match_data(&func->dev);
mmc_pm_flag_t pm_flag = sdio_get_host_pm_caps(func);
struct device_node *np = func->dev.of_node;
struct wfx_sdio_priv *bus;
int ret;
@ -235,6 +275,9 @@ static int wfx_sdio_probe(struct sdio_func *func, const struct sdio_device_id *i
if (ret)
goto sdio_release;
if (pm_flag & MMC_PM_KEEP_POWER)
device_set_wakeup_capable(&func->dev, true);
return 0;
sdio_release:
@ -261,6 +304,8 @@ static const struct sdio_device_id wfx_sdio_ids[] = {
};
MODULE_DEVICE_TABLE(sdio, wfx_sdio_ids);
static DEFINE_SIMPLE_DEV_PM_OPS(wfx_sdio_pm_ops, wfx_sdio_suspend, wfx_sdio_resume);
struct sdio_driver wfx_sdio_driver = {
.name = "wfx-sdio",
.id_table = wfx_sdio_ids,
@ -268,5 +313,6 @@ struct sdio_driver wfx_sdio_driver = {
.remove = wfx_sdio_remove,
.drv = {
.of_match_table = wfx_sdio_of_match,
.pm = &wfx_sdio_pm_ops,
}
};