diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 63069dd8b8e8423ab8061281fbebfc87ab8d5b62..4c742a597cb00d822b797cbc619afa17298e5be1 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -37,6 +37,17 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "decl.h" #include "ioctl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index a0aec3e0045756c5bd7de515dfa98e02e74b15d1..cbd9dcd88b989d0e7ffcc824b9bcb3bf2e1daea7 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -73,6 +73,66 @@ static struct memory_type_mapping mem_type_mapping_tbl[] = { {"EXTLAST", NULL, 0, 0xFE}, }; +static const struct of_device_id mwifiex_sdio_of_match_table[] = { + { .compatible = "marvell,sd8897" }, + { .compatible = "marvell,sd8997" }, + { } +}; + +static irqreturn_t mwifiex_wake_irq_wifi(int irq, void *priv) +{ + struct mwifiex_plt_wake_cfg *cfg = priv; + + if (cfg->irq_wifi >= 0) { + pr_info("%s: wake by wifi", __func__); + cfg->wake_by_wifi = true; + disable_irq_nosync(irq); + } + + return IRQ_HANDLED; +} + +/* This function parse device tree node using mmc subnode devicetree API. + * The device node is saved in card->plt_of_node. + * if the device tree node exist and include interrupts attributes, this + * function will also request platform specific wakeup interrupt. + */ +static int mwifiex_sdio_probe_of(struct device *dev, struct sdio_mmc_card *card) +{ + struct mwifiex_plt_wake_cfg *cfg; + int ret; + + if (!dev->of_node || + !of_match_node(mwifiex_sdio_of_match_table, dev->of_node)) { + pr_err("sdio platform data not available"); + return -1; + } + + card->plt_of_node = dev->of_node; + card->plt_wake_cfg = devm_kzalloc(dev, sizeof(*card->plt_wake_cfg), + GFP_KERNEL); + cfg = card->plt_wake_cfg; + if (cfg && card->plt_of_node) { + cfg->irq_wifi = irq_of_parse_and_map(card->plt_of_node, 0); + if (!cfg->irq_wifi) { + dev_err(dev, "fail to parse irq_wifi from device tree"); + } else { + ret = devm_request_irq(dev, cfg->irq_wifi, + mwifiex_wake_irq_wifi, + IRQF_TRIGGER_LOW, + "wifi_wake", cfg); + if (ret) { + dev_err(dev, + "Failed to request irq_wifi %d (%d)\n", + cfg->irq_wifi, ret); + } + disable_irq(cfg->irq_wifi); + } + } + + return 0; +} + /* * SDIO probe. * @@ -127,6 +187,9 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) return -EIO; } + /* device tree node parsing and platform specific configuration*/ + mwifiex_sdio_probe_of(&func->dev, card); + if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops, MWIFIEX_SDIO)) { pr_err("%s: add card failed\n", __func__); @@ -183,6 +246,13 @@ static int mwifiex_sdio_resume(struct device *dev) mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), MWIFIEX_SYNC_CMD); + /* Disable platform specific wakeup interrupt */ + if (card->plt_wake_cfg && card->plt_wake_cfg->irq_wifi >= 0) { + disable_irq_wake(card->plt_wake_cfg->irq_wifi); + if (!card->plt_wake_cfg->wake_by_wifi) + disable_irq(card->plt_wake_cfg->irq_wifi); + } + return 0; } @@ -262,6 +332,13 @@ static int mwifiex_sdio_suspend(struct device *dev) adapter = card->adapter; + /* Enable platform specific wakeup interrupt */ + if (card->plt_wake_cfg && card->plt_wake_cfg->irq_wifi >= 0) { + card->plt_wake_cfg->wake_by_wifi = false; + enable_irq(card->plt_wake_cfg->irq_wifi); + enable_irq_wake(card->plt_wake_cfg->irq_wifi); + } + /* Enable the Host Sleep */ if (!mwifiex_enable_hs(adapter)) { mwifiex_dbg(adapter, ERROR, diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.h b/drivers/net/wireless/marvell/mwifiex/sdio.h index b9fbc5cf6262d8647d6064ddde51211acf749f72..db837f12c547946d1f76310e9b4c4377052eb904 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.h +++ b/drivers/net/wireless/marvell/mwifiex/sdio.h @@ -154,6 +154,11 @@ a->mpa_rx.start_port = 0; \ } while (0) +struct mwifiex_plt_wake_cfg { + int irq_wifi; + bool wake_by_wifi; +}; + /* data structure for SDIO MPA TX */ struct mwifiex_sdio_mpa_tx { /* multiport tx aggregation buffer pointer */ @@ -237,6 +242,8 @@ struct mwifiex_sdio_card_reg { struct sdio_mmc_card { struct sdio_func *func; struct mwifiex_adapter *adapter; + struct device_node *plt_of_node; + struct mwifiex_plt_wake_cfg *plt_wake_cfg; const char *firmware; const struct mwifiex_sdio_card_reg *reg; diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c index 8cb895b7f2ee49f623fa76c4a2c437d4ff01702e..e436574b169865344d39600cac714634b029f18d 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c @@ -2162,6 +2162,7 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) enum state_11d_t state_11d; struct mwifiex_ds_11n_tx_cfg tx_cfg; u8 sdio_sp_rx_aggr_enable; + int data; if (first_sta) { if (priv->adapter->iface_type == MWIFIEX_PCIE) { @@ -2182,9 +2183,16 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) * The cal-data can be read from device tree and/or * a configuration file and downloaded to firmware. */ - adapter->dt_node = - of_find_node_by_name(NULL, "marvell_cfgdata"); - if (adapter->dt_node) { + if (priv->adapter->iface_type == MWIFIEX_SDIO && + adapter->dev->of_node) { + adapter->dt_node = adapter->dev->of_node; + if (of_property_read_u32(adapter->dt_node, + "marvell,wakeup-pin", + &data) == 0) { + pr_debug("Wakeup pin = 0x%x\n", data); + adapter->hs_cfg.gpio = data; + } + ret = mwifiex_dnld_dt_cfgdata(priv, adapter->dt_node, "marvell,caldata"); if (ret)