static int bcmsdh_sdmmc_suspend(struct device *pdev) { struct sdio_func *func = dev_to_sdio_func(pdev); mmc_pm_flag_t sdio_flags; int ret = 0; if (func->num != 2) return 0; sd_trace(("%s Enter\n", __FUNCTION__)); if (dhd_os_check_wakelock(bcmsdh_get_drvdata())) return -EBUSY; sdio_flags = sdio_get_host_pm_caps(func); if (!(sdio_flags & MMC_PM_KEEP_POWER)) { sd_err(("%s: can't keep power while host is suspended\n", __FUNCTION__)); return -EINVAL; } /* keep power while host suspended */ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); if (ret) { sd_err(("%s: error while trying to keep power\n", __FUNCTION__)); return ret; } #if defined(OOB_INTR_ONLY) bcmsdh_oob_intr_set(0); #endif /* defined(OOB_INTR_ONLY) */ sdio_flags = sdio_get_host_pm_caps(func); if (!(sdio_flags & MMC_PM_KEEP_POWER)) { sd_err(("can't keep power while host " "is suspended\n", __FUNCTION__)); ret = -EINVAL; goto out; } /* keep power while host suspended */ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); if (ret) { sd_err(("error while trying to keep power\n", __FUNCTION__)); goto out; } dhd_mmc_suspend = TRUE; smp_mb(); out: return ret; }
static int brcmf_sdio_suspend(struct device *dev) { mmc_pm_flag_t sdio_flags; struct brcmf_sdio_dev *sdiodev; struct sdio_func *func = dev_to_sdio_func(dev); int ret = 0; brcmf_dbg(TRACE, "\n"); sdiodev = dev_get_drvdata(&func->card->dev); atomic_set(&sdiodev->suspend, true); sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]); if (!(sdio_flags & MMC_PM_KEEP_POWER)) { brcmf_dbg(ERROR, "Host can't keep power while suspended\n"); return -EINVAL; } ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER); if (ret) { brcmf_dbg(ERROR, "Failed to set pm_flags\n"); return ret; } brcmf_sdio_wdtmr_enable(sdiodev, false); return ret; }
/* * SDIO resume. * * Kernel needs to suspend all functions separately. Therefore all * registered functions must have drivers with suspend and resume * methods. Failing that the kernel simply removes the whole card. * * If already not resumed, this function turns on the traffic and * sends a host sleep cancel request to the firmware. */ static int mwifiex_sdio_resume(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; mmc_pm_flag_t pm_flag = 0; if (func) { pm_flag = sdio_get_host_pm_caps(func); card = sdio_get_drvdata(func); if (!card || !card->adapter) { pr_err("resume: invalid card or adapter\n"); return 0; } } else { pr_err("resume: sdio_func is not specified\n"); return 0; } adapter = card->adapter; if (!adapter->is_suspended) { dev_warn(adapter->dev, "device already resumed\n"); return 0; } adapter->is_suspended = false; /* Disable Host Sleep */ mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), MWIFIEX_ASYNC_CMD); return 0; }
static int brcmf_sdio_suspend(struct device *dev) { mmc_pm_flag_t sdio_flags; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; int ret = 0; brcmf_dbg(SDIO, "\n"); atomic_set(&sdiodev->suspend, true); 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; } ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER); if (ret) { brcmf_err("Failed to set pm_flags\n"); return ret; } brcmf_sdio_wdtmr_enable(sdiodev, false); return ret; }
/** @brief This function handles client driver resume * * @param dev A pointer to device structure * @return BT_STATUS_SUCCESS */ int bt_sdio_resume(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); mmc_pm_flag_t pm_flags = 0; bt_private *priv = NULL; struct sdio_mmc_card *cardp; struct m_dev *m_dev = NULL; ENTER(); pm_flags = sdio_get_host_pm_caps(func); PRINTM(CMD, "BT: %s: resume: PM flags = 0x%x\n", sdio_func_id(func), pm_flags); cardp = sdio_get_drvdata(func); if (!cardp || !cardp->priv) { PRINTM(ERROR, "BT: Card or priv structure is not valid\n"); LEAVE(); return BT_STATUS_SUCCESS; } priv = cardp->priv; priv->adapter->is_suspended = FALSE; m_dev = &(priv->bt_dev.m_dev[BT_SEQ]); PRINTM(CMD, "BT %s: SDIO resume\n", m_dev->name); mbt_hci_resume_dev(m_dev); sbi_wakeup_firmware(priv); /* enable FM event mask */ if ((priv->bt_dev.m_dev[FM_SEQ].dev_type == FM_TYPE) && test_bit(HCI_RUNNING, &(priv->bt_dev.m_dev[FM_SEQ].flags))) fm_set_intr_mask(priv, FM_DEFAULT_INTR_MASK); priv->adapter->hs_state = HS_DEACTIVATED; PRINTM(CMD, "BT:%s: HS DEACTIVATED in Resume!\n", m_dev->name); LEAVE(); return BT_STATUS_SUCCESS; }
static void wl1271_sdio_enable_irq_wake(struct wl1271 *wl) { int ret; mmc_pm_flag_t mmcflags; struct ieee80211_hw *hw = wl->hw; struct sdio_func *func = wl_to_func(wl); ret = enable_irq_wake(wl->irq); if (!ret) { wl->irq_wake_enabled = true; device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1); /* if sdio can keep power while host is suspended, enable wow */ mmcflags = sdio_get_host_pm_caps(func); wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags); if (mmcflags & MMC_PM_KEEP_POWER) { hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; hw->wiphy->wowlan.n_patterns = WL1271_MAX_RX_DATA_FILTERS; hw->wiphy->wowlan.pattern_min_len = 1; hw->wiphy->wowlan.pattern_max_len = WL1271_RX_DATA_FILTER_MAX_PATTERN_SIZE; } } }
static int wl1271_suspend(struct device *dev) { /* Tell MMC/SDIO core it's OK to power down the card * (if it isn't already), but not to remove it completely */ struct sdio_func *func = dev_to_sdio_func(dev); struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); struct wl1271 *wl = platform_get_drvdata(glue->core); mmc_pm_flag_t sdio_flags; int ret = 0; dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n", wl->wow_enabled); /* check whether sdio should keep power */ if (wl->wow_enabled) { sdio_flags = sdio_get_host_pm_caps(func); if (!(sdio_flags & MMC_PM_KEEP_POWER)) { dev_err(dev, "can't keep power while host " "is suspended\n"); ret = -EINVAL; goto out; } /* keep power while host suspended */ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); if (ret) { dev_err(dev, "error while trying to keep power\n"); goto out; } } out: return ret; }
/** @brief This function handles client driver suspend * * @param dev A pointer to device structure * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ int woal_sdio_suspend(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); mmc_pm_flag_t pm_flags = 0; moal_handle *handle = NULL; struct sdio_mmc_card *cardp; int i; int ret = MLAN_STATUS_SUCCESS; int hs_actived = 0; ENTER(); if (func) { pm_flags = sdio_get_host_pm_caps(func); PRINTM(MCMND, "%s: suspend: PM flags = 0x%x\n", sdio_func_id(func), pm_flags); if (!(pm_flags & MMC_PM_KEEP_POWER)) { PRINTM(MERROR, "%s: cannot remain alive while host is suspended\n", sdio_func_id(func)); LEAVE(); return -ENOSYS; } cardp = sdio_get_drvdata(func); if (!cardp || !cardp->handle) { PRINTM(MERROR, "Card or moal_handle structure is not valid\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } } else { PRINTM(MERROR, "sdio_func is not specified\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } handle = cardp->handle; if (pm_keep_power) { /* Enable the Host Sleep */ hs_actived = woal_enable_hs(woal_get_priv(handle, MLAN_BSS_TYPE_ANY)); if (hs_actived) { PRINTM(MCMND, "suspend with MMC_PM_KEEP_POWER\n"); ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); } } /* Indicate device suspended */ handle->is_suspended = MTRUE; for (i = 0; i < handle->priv_num; i++) netif_carrier_off(handle->priv[i]->netdev); LEAVE(); return ret; }
static int wl1271_suspend(struct device *dev) { /* Tell MMC/SDIO core it's OK to power down the card * (if it isn't already), but not to remove it completely */ struct sdio_func *func = dev_to_sdio_func(dev); struct wl1271 *wl = sdio_get_drvdata(func); mmc_pm_flag_t sdio_flags; unsigned long flags; bool abort; int ret = 0; /* * if there is a pending irq work, we should abort the suspension. * (irq might come between mac80211 suspension and our suspension) * TODO: maybe remove it, since system will wake up anyway? */ spin_lock_irqsave(&wl->wl_lock, flags); abort = !!test_bit(WL1271_FLAG_PENDING_WORK, &wl->flags); spin_unlock_irqrestore(&wl->wl_lock, flags); if (abort) { wl1271_info("pending irq work - aborting suspend"); return -EBUSY; } /* * we need to look into wl to tell which suspend method to use. * we will have full power, ps mode, elp, and power off */ wl1271_info("%s: wow_enabled: %d", __func__, wl->wow_enabled); if (wl->wow_enabled) { sdio_flags = sdio_get_host_pm_caps(func); wl1271_info("suspend PM flags = 0x%x", sdio_flags); if (!(sdio_flags & MMC_PM_KEEP_POWER)) { wl1271_error("can't keep power while host " "is suspended"); goto power_off; } /* keep power while host suspended */ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); if (ret) { wl1271_error("error while trying to keep power"); goto power_off; } /* release host */ sdio_release_host(func); } power_off: return 0; }
/** @brief This function handles client driver suspend * * @param dev A pointer to device structure * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE */ int bt_sdio_suspend(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); mmc_pm_flag_t pm_flags = 0; bt_private *priv = NULL; struct sdio_mmc_card *cardp; struct hci_dev *hcidev; ENTER(); if (func) { pm_flags = sdio_get_host_pm_caps(func); PRINTM(CMD, "%s: suspend: PM flags = 0x%x\n", sdio_func_id(func), pm_flags); if (!(pm_flags & MMC_PM_KEEP_POWER)) { PRINTM(ERROR, "%s: cannot remain alive while host is suspended\n", sdio_func_id(func)); return -ENOSYS; } cardp = sdio_get_drvdata(func); if (!cardp || !cardp->priv) { PRINTM(ERROR, "Card or priv structure is not valid\n"); LEAVE(); return BT_STATUS_SUCCESS; } } else { PRINTM(ERROR, "sdio_func is not specified\n"); LEAVE(); return BT_STATUS_SUCCESS; } PRINTM(CMD, "SDIO suspend\n"); priv = cardp->priv; if ((pm_keep_power) && (priv->adapter->hs_state != HS_ACTIVATED)) bt_enable_hs(priv); hcidev = priv->bt_dev.hcidev; hci_suspend_dev(hcidev); skb_queue_purge(&priv->adapter->tx_queue); LEAVE(); /* We will keep the power when hs enabled successfully */ if ((pm_keep_power) && (priv->adapter->hs_state == HS_ACTIVATED)) #ifdef MMC_PM_SKIP_RESUME_PROBE return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER | MMC_PM_SKIP_RESUME_PROBE); #else return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); #endif else return BT_STATUS_SUCCESS;
/* * SDIO suspend. * * Kernel needs to suspend all functions separately. Therefore all * registered functions must have drivers with suspend and resume * methods. Failing that the kernel simply removes the whole card. * * If already not suspended, this function allocates and sends a host * sleep activate request to the firmware and turns off the traffic. */ static int mwifiex_sdio_suspend(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; mmc_pm_flag_t pm_flag = 0; int i; int ret = 0; if (func) { pm_flag = sdio_get_host_pm_caps(func); pr_debug("cmd: %s: suspend: PM flag = 0x%x\n", sdio_func_id(func), pm_flag); if (!(pm_flag & MMC_PM_KEEP_POWER)) { pr_err("%s: cannot remain alive while host is" " suspended\n", sdio_func_id(func)); return -ENOSYS; } card = sdio_get_drvdata(func); if (!card || !card->adapter) { pr_err("suspend: invalid card or adapter\n"); return 0; } } else { pr_err("suspend: sdio_func is not specified\n"); return 0; } adapter = card->adapter; /* Enable the Host Sleep */ if (!mwifiex_enable_hs(adapter)) { dev_err(adapter->dev, "cmd: failed to suspend\n"); return -EFAULT; } dev_dbg(adapter->dev, "cmd: suspend with MMC_PM_KEEP_POWER\n"); ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); /* Indicate device suspended */ adapter->is_suspended = true; for (i = 0; i < adapter->priv_num; i++) netif_carrier_off(adapter->priv[i]->netdev); return ret; }
static int bcmsdh_sdmmc_suspend(struct device *pdev) { int err; sdioh_info_t *sdioh; struct sdio_func *func = dev_to_sdio_func(pdev); mmc_pm_flag_t sdio_flags; sd_err(("%s +\n", __FUNCTION__)); if (func->num != 2) return 0; sdioh = sdio_get_drvdata(func); err = bcmsdh_suspend(sdioh->bcmsdh); if (err){ sd_err(("%s -\n", __FUNCTION__)); return err; } sdio_flags = sdio_get_host_pm_caps(func); if (!(sdio_flags & MMC_PM_KEEP_POWER)) { sd_err(("%s: can't keep power while host is suspended\n", __FUNCTION__)); sd_err(("%s -\n", __FUNCTION__)); return -EINVAL; } /* keep power while host suspended */ err = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); if (err) { sd_err(("%s: error while trying to keep power\n", __FUNCTION__)); sd_err(("%s -\n", __FUNCTION__)); return err; } #if defined(OOB_INTR_ONLY) #ifndef HW_WIFI_OOB_INT_SET bcmsdh_oob_intr_set(sdioh->bcmsdh, FALSE); #endif #endif dhd_mmc_suspend = TRUE; #ifdef HW_WIFI_WAKEUP_SRC_PARSE g_wifi_firstwake = TRUE; #endif smp_mb(); sd_err(("%s -\n", __FUNCTION__)); return 0; }
/** @brief This function handles client driver resume * * @param dev A pointer to device structure * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ int woal_sdio_resume(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); mmc_pm_flag_t pm_flags = 0; moal_handle *handle = NULL; struct sdio_mmc_card *cardp; int i; ENTER(); if (func) { pm_flags = sdio_get_host_pm_caps(func); PRINTM(MCMND, "%s: resume: PM flags = 0x%x\n", sdio_func_id(func), pm_flags); cardp = sdio_get_drvdata(func); if (!cardp || !cardp->handle) { PRINTM(MERROR, "Card or moal_handle structure is not valid\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } } else { PRINTM(MERROR, "sdio_func is not specified\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } handle = cardp->handle; if (handle->is_suspended == MFALSE) { PRINTM(MWARN, "Device already resumed\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } handle->is_suspended = MFALSE; for (i = 0; i < handle->priv_num; i++) netif_carrier_on(handle->priv[i]->netdev); /* Disable Host Sleep */ woal_hs_cfg_cancel(woal_get_priv(handle, MLAN_BSS_TYPE_ANY), MOAL_NO_WAIT); LEAVE(); return MLAN_STATUS_SUCCESS; }
/** @brief This function handles client driver resume * * @param dev A pointer to device structure * @return MLAN_STATUS_SUCCESS */ int woal_sdio_resume(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); mmc_pm_flag_t pm_flags = 0; moal_handle *handle = NULL; struct sdio_mmc_card *cardp; int i; ENTER(); PRINTM(MCMND, "<--- Enter woal_sdio_resume --->\n"); wifi_enable_hostwake_irq(MFALSE); pm_flags = sdio_get_host_pm_caps(func); PRINTM(MCMND, "%s: resume: PM flags = 0x%x\n", sdio_func_id(func), pm_flags); cardp = sdio_get_drvdata(func); if (!cardp || !cardp->handle) { PRINTM(MERROR, "Card or moal_handle structure is not valid\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } handle = cardp->handle; if (handle->is_suspended == MFALSE) { PRINTM(MWARN, "Device already resumed\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } handle->is_suspended = MFALSE; if (woal_check_driver_status(handle)) { PRINTM(MERROR, "Resuem, device is in hang state\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } for (i = 0; i < handle->priv_num; i++) netif_device_attach(handle->priv[i]->netdev); /* Disable Host Sleep */ woal_cancel_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), MOAL_NO_WAIT); PRINTM(MCMND, "<--- Leave woal_sdio_resume --->\n"); LEAVE(); return MLAN_STATUS_SUCCESS; }
static int wl1271_suspend(struct device *dev) { /* Tell MMC/SDIO core it's OK to power down the card * (if it isn't already), but not to remove it completely */ struct sdio_func *func = dev_to_sdio_func(dev); struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); struct wl1271 *wl = platform_get_drvdata(glue->core); mmc_pm_flag_t sdio_flags; int ret = 0; dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n", wl->wow_enabled); /* * check whether sdio should keep power. * due to some mmc layer issues, the system automatically * powers us up on resume, which later cause issues when * we try to restore_power again explicitly. * workaround it by always asking to keep power. this is * fine as the driver controls the chip power anyway. * TODO: remove it when mmc issue is fixed. */ if (true || wl->wow_enabled) { sdio_flags = sdio_get_host_pm_caps(func); if (!(sdio_flags & MMC_PM_KEEP_POWER)) { dev_err(dev, "can't keep power while host " "is suspended\n"); ret = -EINVAL; goto out; } /* keep power while host suspended */ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); if (ret) { dev_err(dev, "error while trying to keep power\n"); goto out; } } out: return ret; }
static int bcmsdh_sdmmc_suspend(struct device *pdev) { int err; sdioh_info_t *sdioh; struct sdio_func *func = dev_to_sdio_func(pdev); mmc_pm_flag_t sdio_flags; sd_err(("%s Enter\n", __FUNCTION__)); if (func->num != 2) return 0; dhd_mmc_suspend = TRUE; sdioh = sdio_get_drvdata(func); err = bcmsdh_suspend(sdioh->bcmsdh); if (err) { dhd_mmc_suspend = FALSE; return err; } sdio_flags = sdio_get_host_pm_caps(func); if (!(sdio_flags & MMC_PM_KEEP_POWER)) { sd_err(("%s: can't keep power while host is suspended\n", __FUNCTION__)); dhd_mmc_suspend = FALSE; return -EINVAL; } /* keep power while host suspended */ err = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); if (err) { sd_err(("%s: error while trying to keep power\n", __FUNCTION__)); dhd_mmc_suspend = FALSE; return err; } #if defined(OOB_INTR_ONLY) && !defined(CUSTOMER_HW4) bcmsdh_oob_intr_set(sdioh->bcmsdh, FALSE); #endif /* OOB_INTR_ONLY && !CUSTOMER_HW4 */ smp_mb(); return 0; }
static int mwifiex_sdio_resume(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; mmc_pm_flag_t pm_flag = 0; int i; if (func) { pm_flag = sdio_get_host_pm_caps(func); card = sdio_get_drvdata(func); if (!card || !card->adapter) { pr_err("resume: invalid card or adapter\n"); return 0; } } else { pr_err("resume: sdio_func is not specified\n"); return 0; } adapter = card->adapter; if (!adapter->is_suspended) { dev_warn(adapter->dev, "device already resumed\n"); return 0; } adapter->is_suspended = false; for (i = 0; i < adapter->priv_num; i++) if (adapter->priv[i]->media_connected) netif_carrier_on(adapter->priv[i]->netdev); mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), MWIFIEX_ASYNC_CMD); return 0; }
static int esp_sdio_suspend(struct device *dev) { //#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)) struct sdio_func *func = dev_to_sdio_func(dev); #else struct sdio_func *func = container_of(dev, struct sdio_func, dev); #endif struct esp_sdio_ctrl *sctrl = sdio_get_drvdata(func); struct esp_pub *epub = sctrl->epub; printk("%s", __func__); #if 0 sip_send_suspend_config(epub, 1); #endif atomic_set(&epub->ps.state, ESP_PM_ON); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)) do{ u32 sdio_flags = 0; int ret = 0; sdio_flags = sdio_get_host_pm_caps(func); if (!(sdio_flags & MMC_PM_KEEP_POWER)) { printk("%s can't keep power while host is suspended\n", __func__); } /* keep power while host suspended */ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); if (ret) { printk("%s error while trying to keep power\n", __func__); } }while(0); #endif return 0; }
static int wl1271_suspend(struct device *dev) { /* Tell MMC/SDIO core it's OK to power down the card * (if it isn't already), but not to remove it completely */ struct sdio_func *func = dev_to_sdio_func(dev); struct wl1271 *wl = sdio_get_drvdata(func); mmc_pm_flag_t sdio_flags; int ret = 0; wl1271_debug(DEBUG_MAC80211, "wl1271 suspend. wow_enabled: %d", wl->wow_enabled); /* check whether sdio should keep power */ if (wl->wow_enabled) { sdio_flags = sdio_get_host_pm_caps(func); if (!(sdio_flags & MMC_PM_KEEP_POWER)) { wl1271_error("can't keep power while host " "is suspended"); ret = -EINVAL; goto out; } printk("\n\nSetting MMC_PM_KEEP_POWER\n"); /* keep power while host suspended */ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); if (ret) { wl1271_error("error while trying to keep power"); goto out; } /* release host */ sdio_release_host(func); } out: return ret; }
/** @brief This function handles client driver resume * * @param dev A pointer to device structure * @return BT_STATUS_SUCCESS */ int bt_sdio_resume(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); mmc_pm_flag_t pm_flags = 0; bt_private *priv = NULL; struct sdio_mmc_card *cardp; struct hci_dev *hcidev; ENTER(); if (func) { pm_flags = sdio_get_host_pm_caps(func); PRINTM(CMD, "BT: %s: resume: PM flags = 0x%x\n", sdio_func_id(func), pm_flags); cardp = sdio_get_drvdata(func); if (!cardp || !cardp->priv) { PRINTM(ERROR, "BT: Card or priv structure is not valid\n"); LEAVE(); return BT_STATUS_SUCCESS; } } else { PRINTM(ERROR, "BT: sdio_func is not specified\n"); LEAVE(); return BT_STATUS_SUCCESS; } priv = cardp->priv; priv->adapter->is_suspended = FALSE; hcidev = priv->bt_dev.hcidev; PRINTM(CMD, "BT %s: SDIO resume\n", hcidev->name); hci_resume_dev(hcidev); sbi_wakeup_firmware(priv); priv->adapter->hs_state = HS_DEACTIVATED; PRINTM(CMD, "BT:%s: HS DEACTIVATED in Resume!\n", hcidev->name); LEAVE(); return BT_STATUS_SUCCESS; }
static int wl1271_probe(struct sdio_func *func, const struct sdio_device_id *id) { struct wlcore_platdev_data pdev_data; struct wl12xx_sdio_glue *glue; struct resource res[1]; mmc_pm_flag_t mmcflags; int ret = -ENOMEM; const char *chip_family; /* We are only able to handle the wlan function */ if (func->num != 0x02) return -ENODEV; memset(&pdev_data, 0x00, sizeof(pdev_data)); pdev_data.if_ops = &sdio_ops; glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { dev_err(&func->dev, "can't allocate glue\n"); goto out; } glue->dev = &func->dev; /* Grab access to FN0 for ELP reg. */ func->card->quirks |= MMC_QUIRK_LENIENT_FN0; /* Use block mode for transferring over one block size of data */ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; pdev_data.pdata = wl12xx_get_platform_data(); if (IS_ERR(pdev_data.pdata)) { ret = PTR_ERR(pdev_data.pdata); dev_err(glue->dev, "missing wlan platform data: %d\n", ret); goto out_free_glue; } /* if sdio can keep power while host is suspended, enable wow */ mmcflags = sdio_get_host_pm_caps(func); dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags); if (mmcflags & MMC_PM_KEEP_POWER) pdev_data.pdata->pwr_in_suspend = true; sdio_set_drvdata(func, glue); /* Tell PM core that we don't need the card to be powered now */ pm_runtime_put_noidle(&func->dev); /* * Due to a hardware bug, we can't differentiate wl18xx from * wl12xx, because both report the same device ID. The only * way to differentiate is by checking the SDIO revision, * which is 3.00 on the wl18xx chips. */ if (func->card->cccr.sdio_vsn == SDIO_SDIO_REV_3_00) chip_family = "wl18xx"; else chip_family = "wl12xx"; glue->core = platform_device_alloc(chip_family, PLATFORM_DEVID_AUTO); if (!glue->core) { dev_err(glue->dev, "can't allocate platform_device"); ret = -ENOMEM; goto out_free_glue; } glue->core->dev.parent = &func->dev; memset(res, 0x00, sizeof(res)); res[0].start = pdev_data.pdata->irq; res[0].flags = IORESOURCE_IRQ; res[0].name = "irq"; ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res)); if (ret) { dev_err(glue->dev, "can't add resources\n"); goto out_dev_put; } ret = platform_device_add_data(glue->core, &pdev_data, sizeof(pdev_data)); if (ret) { dev_err(glue->dev, "can't add platform data\n"); goto out_dev_put; } ret = platform_device_add(glue->core); if (ret) { dev_err(glue->dev, "can't add platform device\n"); goto out_dev_put; } return 0; out_dev_put: platform_device_put(glue->core); out_free_glue: kfree(glue); out: return ret; }
/** @brief This function handles client driver suspend * * @param dev A pointer to device structure * @return MLAN_STATUS_SUCCESS or error code */ int woal_sdio_suspend(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); mmc_pm_flag_t pm_flags = 0; moal_handle *handle = NULL; struct sdio_mmc_card *cardp; int i, retry_num = 8; int ret = MLAN_STATUS_SUCCESS; int hs_actived = 0; mlan_ds_ps_info pm_info; ENTER(); PRINTM(MCMND, "<--- Enter woal_sdio_suspend --->\n"); pm_flags = sdio_get_host_pm_caps(func); PRINTM(MCMND, "%s: suspend: PM flags = 0x%x\n", sdio_func_id(func), pm_flags); if (!(pm_flags & MMC_PM_KEEP_POWER)) { PRINTM(MERROR, "%s: cannot remain alive while host is suspended\n", sdio_func_id(func)); LEAVE(); return -ENOSYS; } cardp = sdio_get_drvdata(func); if (!cardp || !cardp->handle) { PRINTM(MERROR, "Card or moal_handle structure is not valid\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } handle = cardp->handle; if (handle->is_suspended == MTRUE) { PRINTM(MWARN, "Device already suspended\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } if (handle->fw_dump) { PRINTM(MMSG, "suspend not allowed while FW dump!"); ret = -EBUSY; goto done; } handle->suspend_fail = MFALSE; memset(&pm_info, 0, sizeof(pm_info)); for (i = 0; i < retry_num; i++) { if (MLAN_STATUS_SUCCESS == woal_get_pm_info(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), &pm_info)) { if (pm_info.is_suspend_allowed == MTRUE) break; else PRINTM(MMSG, "Suspend not allowed and retry again\n"); } woal_sched_timeout(100); } if (pm_info.is_suspend_allowed == MFALSE) { PRINTM(MMSG, "Suspend not allowed\n"); ret = -EBUSY; goto done; } for (i = 0; i < handle->priv_num; i++) netif_device_detach(handle->priv[i]->netdev); if (pm_keep_power) { /* Enable the Host Sleep */ #ifdef MMC_PM_FUNC_SUSPENDED handle->suspend_notify_req = MTRUE; #endif hs_actived = woal_enable_hs(woal_get_priv (handle, MLAN_BSS_ROLE_ANY)); #ifdef MMC_PM_FUNC_SUSPENDED handle->suspend_notify_req = MFALSE; #endif if (hs_actived) { #ifdef MMC_PM_SKIP_RESUME_PROBE PRINTM(MCMND, "suspend with MMC_PM_KEEP_POWER and MMC_PM_SKIP_RESUME_PROBE\n"); ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER | MMC_PM_SKIP_RESUME_PROBE); #else PRINTM(MCMND, "suspend with MMC_PM_KEEP_POWER\n"); ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); #endif } else { PRINTM(MMSG, "HS not actived, suspend fail!"); handle->suspend_fail = MTRUE; for (i = 0; i < handle->priv_num; i++) netif_device_attach(handle->priv[i]->netdev); ret = -EBUSY; goto done; } } /* Indicate device suspended */ handle->is_suspended = MTRUE; done: PRINTM(MCMND, "<--- Leave woal_sdio_suspend --->\n"); LEAVE(); return ret; }
/** @brief This function handles client driver suspend * * @param dev A pointer to device structure * @return BT_STATUS_SUCCESS or other error no. */ int bt_sdio_suspend(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); mmc_pm_flag_t pm_flags = 0; bt_private *priv = NULL; struct sdio_mmc_card *cardp; struct m_dev *m_dev = NULL; ENTER(); pm_flags = sdio_get_host_pm_caps(func); PRINTM(CMD, "BT: %s: suspend: PM flags = 0x%x\n", sdio_func_id(func), pm_flags); if (!(pm_flags & MMC_PM_KEEP_POWER)) { PRINTM(ERROR, "BT: %s: cannot remain alive while host is suspended\n", sdio_func_id(func)); return -ENOSYS; } cardp = sdio_get_drvdata(func); if (!cardp || !cardp->priv) { PRINTM(ERROR, "BT: Card or priv structure is not valid\n"); LEAVE(); return BT_STATUS_SUCCESS; } priv = cardp->priv; if ((mbt_pm_keep_power) && (priv->adapter->hs_state != HS_ACTIVATED)) { /* disable FM event mask */ if ((priv->bt_dev.m_dev[FM_SEQ].dev_type == FM_TYPE) && test_bit(HCI_RUNNING, &(priv->bt_dev.m_dev[FM_SEQ].flags))) fm_set_intr_mask(priv, FM_DISABLE_INTR_MASK); if (BT_STATUS_SUCCESS != bt_enable_hs(priv)) { PRINTM(CMD, "BT: HS not actived, suspend fail!\n"); if (BT_STATUS_SUCCESS != bt_enable_hs(priv)) { PRINTM(CMD, "BT: HS not actived the second time, force to suspend!\n"); } } } m_dev = &(priv->bt_dev.m_dev[BT_SEQ]); PRINTM(CMD, "BT %s: SDIO suspend\n", m_dev->name); mbt_hci_suspend_dev(m_dev); skb_queue_purge(&priv->adapter->tx_queue); priv->adapter->is_suspended = TRUE; LEAVE(); /* We will keep the power when hs enabled successfully */ if ((mbt_pm_keep_power) && (priv->adapter->hs_state == HS_ACTIVATED)) { #ifdef MMC_PM_SKIP_RESUME_PROBE PRINTM(CMD, "BT: suspend with MMC_PM_KEEP_POWER and " "MMC_PM_SKIP_RESUME_PROBE\n"); return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER | MMC_PM_SKIP_RESUME_PROBE); #else PRINTM(CMD, "BT: suspend with MMC_PM_KEEP_POWER\n"); return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); #endif } else { PRINTM(CMD, "BT: suspend without MMC_PM_KEEP_POWER\n"); return BT_STATUS_SUCCESS; } }
static int __devinit wl1271_probe(struct sdio_func *func, const struct sdio_device_id *id) { struct ieee80211_hw *hw; const struct wl12xx_platform_data *wlan_data; struct wl1271 *wl; unsigned long irqflags; mmc_pm_flag_t mmcflags; int ret; /* We are only able to handle the wlan function */ if (func->num != 0x02) return -ENODEV; hw = wl1271_alloc_hw(); if (IS_ERR(hw)) return PTR_ERR(hw); wl = hw->priv; wl->if_priv = func; wl->if_ops = &sdio_ops; /* Grab access to FN0 for ELP reg. */ func->card->quirks |= MMC_QUIRK_LENIENT_FN0; /* Use block mode for transferring over one block size of data */ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; wlan_data = wl12xx_get_platform_data(); if (IS_ERR(wlan_data)) { ret = PTR_ERR(wlan_data); wl1271_error("missing wlan platform data: %d", ret); goto out_free; } wl->irq = wlan_data->irq; wl->ref_clock = wlan_data->board_ref_clock; wl->tcxo_clock = wlan_data->board_tcxo_clock; wl->platform_quirks = wlan_data->platform_quirks; if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) irqflags = IRQF_TRIGGER_RISING; else irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, irqflags, DRIVER_NAME, wl); if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); goto out_free; } ret = enable_irq_wake(wl->irq); if (!ret) { wl->irq_wake_enabled = true; device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1); /* if sdio can keep power while host is suspended, enable wow */ mmcflags = sdio_get_host_pm_caps(func); wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags); if (mmcflags & MMC_PM_KEEP_POWER) hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; } disable_irq(wl->irq); ret = wl1271_init_ieee80211(wl); if (ret) goto out_irq; ret = wl1271_register_hw(wl); if (ret) goto out_irq; sdio_set_drvdata(func, wl); /* Tell PM core that we don't need the card to be powered now */ pm_runtime_put_noidle(&func->dev); return 0; out_irq: free_irq(wl->irq, wl); out_free: wl1271_free_hw(wl); return ret; }