drivers: wireless: bcm4329: set MMC_PM_KEEP_POWER on suspend
Rakesh Kumar [Mon, 5 Mar 2012 09:18:07 +0000 (14:18 +0530)]
MMC_PM_KEEP_POWER should be set before each suspend/resume cycle as
mmc drivers clears MMC_PM_KEEP_POWER from pm_flags on resume.

Bug 942826

Change-Id: Ie11c661bdc3450cc4e75fa7700b96aedc69d628a
Signed-off-by: Rakesh Kumar <krakesh@nvidia.com>
Reviewed-on: http://git-master/r/87703
Reviewed-by: Rakesh Goyal <rgoyal@nvidia.com>
Tested-by: Rakesh Goyal <rgoyal@nvidia.com>
Reviewed-by: Sachin Nikam <snikam@nvidia.com>

drivers/net/wireless/bcm4329/bcmsdh_sdmmc_linux.c

index 5a1a46c..b1fc35b 100644 (file)
@@ -141,11 +141,58 @@ static const struct sdio_device_id bcmsdh_sdmmc_ids[] = {
 
 MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids);
 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
+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;
+
+       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;
+       }
+
+out:
+       return ret;
+}
+
+static int bcmsdh_sdmmc_resume(struct device *pdev)
+{
+       /* nothing to do since MMC_PM_KEEP_POWER is cleared by MMC stack */
+       return 0;
+}
+
+static const struct dev_pm_ops bcmsdh_sdmmc_pm_ops = {
+       .suspend        = bcmsdh_sdmmc_suspend,
+       .resume         = bcmsdh_sdmmc_resume,
+};
+#endif
+
 static struct sdio_driver bcmsdh_sdmmc_driver = {
        .probe          = bcmsdh_sdmmc_probe,
        .remove         = bcmsdh_sdmmc_remove,
        .name           = "bcmsdh_sdmmc",
        .id_table       = bcmsdh_sdmmc_ids,
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
+       .drv = {
+               .pm     = &bcmsdh_sdmmc_pm_ops,
+       },
+#endif
        };
 
 struct sdos_info {