static int sdhci_pltfm_suspend(struct device *device)
{
	struct sdio_dev *dev =
		platform_get_drvdata(to_platform_device(device));
	struct sdhci_host *host = dev->host;
	int ret = 0;

	if (!sdhci_pltfm_rpm_enabled(dev)) {
		ret = sdhci_pltfm_clk_enable(dev, 1);
		if (ret) {
			dev_err(dev->dev,
				"Failed to enable clock during suspend\n");
			return -EAGAIN;
		}
	}

	host->mmc->pm_flags |= host->mmc->pm_caps;

	ret = sdhci_suspend_host(host);
	if (ret) {
		dev_err(dev->dev, "Unable to suspend sdhci host err=%d\n",
			ret);
		return ret;
	}

	if (sdhci_pltfm_rpm_enabled(dev)) {
		/*
		 * Note that we havent done a get_sync. The
		 * pm core takes care of that.
		 */
		pm_runtime_put_sync_suspend(dev->dev);
	} else {
		ret = sdhci_pltfm_clk_enable(dev, 0);
		if (ret) {
			dev_err(dev->dev,
				"Failed to disable clock during suspend\n");
			/* Not really a big error to cry and return */
		}
	}

	if(dev->devtype == SDIO_DEV_TYPE_SDMMC)
	{
		printk(KERN_ERR "mmc regulator off.. delay 50ms added\n");
		mdelay(50);// this is Samsung internal specification.
	}

	dev->suspended = 1;
	return 0;
}
static int sdhci_pltfm_runtime_resume(struct device *device)
{
	int ret = 0;
	unsigned long flags;
	struct sdio_dev *dev =
		platform_get_drvdata(to_platform_device(device));
	struct sdhci_host *host = dev->host;

	/* This is never going to happen, but still */
	if (!sdhci_pltfm_rpm_enabled(dev)) {
		dev_err(dev->dev, "Spurious rpm resume call\n");
		/* But no menaing in returning error */
		return 0;
	}

	spin_lock_irqsave(&host->lock, flags);
	host->runtime_suspended = false;
	spin_unlock_irqrestore(&host->lock, flags);

	ret = sdhci_pltfm_clk_enable(dev, 1);
	if (ret) {
		dev_err(dev->dev,
			"Failed to enable clock during run time resume\n");
		return -EAGAIN;
	}

	return 0;
}
static int sdhci_pltfm_resume(struct device *device)
{
	struct sdio_dev *dev =
		platform_get_drvdata(to_platform_device(device));
	struct sdhci_host *host = dev->host;
	int ret = 0;

	if (sdhci_pltfm_rpm_enabled(dev)) {
		/*
		 * Note that we havent done a put_sync. The
		 * pm core takes care of that.
		 */
		pm_runtime_get_sync(dev->dev);
	} else {
		ret = sdhci_pltfm_clk_enable(dev, 1);
		if (ret) {
			dev_err(dev->dev,
				"Failed to enable clock during resume\n");
			return -EAGAIN;
		}
	}

	ret = sdhci_resume_host(host);
	if (ret) {
		dev_err(dev->dev,
		 "Unable to resume sdhci host err=%d\n", ret);
		return ret;
	}

	if (!sdhci_pltfm_rpm_enabled(dev)) {
		ret = sdhci_pltfm_clk_enable(dev, 0);
		if (ret) {
			dev_err(dev->dev,
				"Failed to disable clock during resume\n");
			/* Not really a big error to cry and return*/
		}
	}

	dev->suspended = 0;

	if (dev->devtype == SDIO_DEV_TYPE_EMMC)
		host->mmc->pm_flags |= MMC_PM_KEEP_POWER;

	return 0;
}
static void __devexit sdhci_pltfm_runtime_pm_forbid(struct device *device)
{
	struct sdio_dev *dev =
		platform_get_drvdata(to_platform_device(device));

	if (!sdhci_pltfm_rpm_enabled(dev))
		return;

	pm_runtime_forbid(device);
	pm_runtime_get_noresume(device);
	pm_runtime_disable(device);
}
static void sdhci_pltfm_shutdown(struct platform_device *pdev)
{
	u16 clk;
	int ret;
	struct sdio_dev *dev = platform_get_drvdata(pdev);
	struct sdhci_host *host = dev->host;

	if (sdhci_pltfm_rpm_enabled(dev)) {
		pm_runtime_get_sync(dev->dev);
	} else {
		ret = sdhci_pltfm_clk_enable(dev, 1);
		if (ret)
			dev_err(dev->dev,
			"enable clock during shutdown failed\n");
	}

	/* Certain cards don't like abrupt clock
	 * shutdown, and they go insane if we do so.
	 * When PM runtime autosuspend is enabled,
	 * it takes time for the clock to be cut,
	 * but during this time, the system reboot
	 * can abruptly cut it off. Avoid that by
	 * disabling the clock to the card.
	 */
	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
	clk &= ~SDHCI_CLOCK_CARD_EN;
	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);

	if (sdhci_pltfm_rpm_enabled(dev)) {
		pm_runtime_put_sync_suspend(dev->dev);
	} else {
		ret = sdhci_pltfm_clk_enable(dev, 0);
		if (ret)
			dev_err(dev->dev,
			"disable clock during shutdown failed\n");
	}
}
static void __devinit sdhci_pltfm_runtime_pm_init(struct device *device)
{
	struct sdio_dev *dev =
		platform_get_drvdata(to_platform_device(device));

	if (!sdhci_pltfm_rpm_enabled(dev))
		return;

	pm_runtime_irq_safe(device);
	pm_runtime_enable(device);

	if (dev->devtype == SDIO_DEV_TYPE_WIFI)
		pm_runtime_set_autosuspend_delay(device,
				KONA_MMC_WIFI_AUTOSUSPEND_DELAY);
	else
		pm_runtime_set_autosuspend_delay(device,
				KONA_MMC_AUTOSUSPEND_DELAY);

	pm_runtime_use_autosuspend(device);
}
/*
 * Software emulation of the SD card insertion/removal. Set insert=1 for insert
 * and insert=0 for removal
 */
static int bcm_kona_sd_card_emulate(struct sdio_dev *dev, int insert)
{
	struct sdhci_host *host = dev->host;
	uint32_t val;
	unsigned long flags;
	int ret = 0;

	if(strcmp("mmc2", mmc_hostname(host->mmc)) == 0)
		printk ("PNN: [%s]sd_card_emulate : %s\n",mmc_hostname(host->mmc), insert ? "insert" : "removal");
#ifndef CONFIG_ARCH_ISLAND
	/*
	 * The clock enabled here will be disabled in
	 * sdhci_tasklet_card
	 */
	if (sdhci_pltfm_rpm_enabled(dev)) {
		/*
		 * The code below can be executed just
		 * after a device resume. pm core
		 * enables the runtime pm for the device
		 * when the resume callback returns.
		 * It is possible that we reach here before
		 * that. One option is to wait for the RPM
		 * to be enabled, but this can create an
		 * obvious issue when we perform card
		 * insert/removal during the probe. We cant
		 * remove the pm_runtime_get_sync with a
		 * direct clock enable here, because the
		 * sdhci_irq will complain about "interrupt
		 * while runtime suspened". We cant even check
		 * for pm_runtime status and take an appropriate
		 * action, because if the status changes by the
		 * time the clcok disable is done in card tasklet,
		 * it will result in unbalanced RPM usage. Moreover
		 * why to wait for something in an ISR when we have
		 * an option.
		 * So a better option is to do both.
		 */
		pm_runtime_get_sync(dev->dev);
	}

	/* Enable clock once irrespective of RPM state */
	ret = sdhci_pltfm_clk_enable(dev, 1);
	if (ret) {
		dev_err(dev->dev,
			"enable clock during card emulate failed\n");
		return -EAGAIN;
	}
#endif
	/* this function can be called from various contexts including ISR */
	spin_lock_irqsave(&host->lock, flags);

	/* Ensure SD bus scanning to detect media change */
	host->mmc->rescan_disable = 0;

	/* Back-to-Back register write needs a delay of min 10uS.
	 * We keep 20uS
	 */
	udelay(20);
	val = sdhci_readl(host, KONA_SDHOST_CORESTAT);

	if (insert) {
		val |= KONA_SDHOST_CD_SW;
		sdhci_writel(host, val, KONA_SDHOST_CORESTAT);
	} else {
		val &= ~KONA_SDHOST_CD_SW;
		sdhci_writel(host, val, KONA_SDHOST_CORESTAT);
	}

	spin_unlock_irqrestore(&host->lock, flags);

	return 0;
}
static int sdhci_rpm_enabled(struct sdhci_host *host)
{
	struct sdio_dev *dev = sdhci_priv(host);

	return sdhci_pltfm_rpm_enabled(dev);
}
static int __devexit sdhci_pltfm_remove(struct platform_device *pdev)
{
	struct sdio_dev *dev = platform_get_drvdata(pdev);
	struct sdhci_host *host = dev->host;
	struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	int dead;
	u32 scratch;
	int ret = 0;

	atomic_set(&dev->initialized, 0);
	gDevs[dev->devtype] = NULL;
	printk("%s",__func__);
	if (dev->devtype == SDIO_DEV_TYPE_SDMMC && dev->cd_gpio >= 0) {
		free_irq(gpio_to_irq(dev->cd_gpio), dev);
		gpio_free(dev->cd_gpio);
	}

	if (dev->vdd_sdxc_regulator && dev->devtype == SDIO_DEV_TYPE_SDMMC) {
		/* Playing safe- if regulator is enabled, disable it first */
		if (regulator_is_enabled(dev->vdd_sdxc_regulator) > 0)
			regulator_disable(dev->vdd_sdxc_regulator);

		regulator_put(dev->vdd_sdxc_regulator);
	}

	proc_term(pdev);

	if (sdhci_pltfm_rpm_enabled(dev)) {
		pm_runtime_get_sync(dev->dev);
	} else {
		ret = sdhci_pltfm_clk_enable(dev, 1);
		if (ret)
			dev_err(dev->dev,
				"enable clock during pltfm remove failed\n");
	}

	dead = 0;
	scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
	if (scratch == (u32)-1)
		dead = 1;
	sdhci_remove_host(host, dead);

	if (sdhci_pltfm_rpm_enabled(dev)) {
		pm_runtime_put_sync_suspend(dev->dev);
	} else {
		ret = sdhci_pltfm_clk_enable(dev, 0);
		if (ret)
			dev_err(dev->dev,
				"disable clock during pltfm remove failed\n");
	}

#if !defined(CONFIG_MACH_BCM2850_FPGA) && !defined(CONFIG_MACH_BCM_FPGA)
	clk_disable(dev->sleep_clk);
	clk_put(dev->sleep_clk);
	clk_put(dev->peri_clk);
#endif

	sdhci_pltfm_runtime_pm_forbid(dev->dev);
	kfree(dev->cd_int_wake_lock_name);
	wake_lock_destroy(&dev->cd_int_wake_lock);
	platform_set_drvdata(pdev, NULL);
	if (dev->devtype == SDIO_DEV_TYPE_EMMC ||
		dev->devtype == SDIO_DEV_TYPE_SDMMC) {
		kfree(pdev->dev.platform_data);
		pdev->dev.platform_data = NULL;
	}
	kfree(dev);
	iounmap(host->ioaddr);
	release_mem_region(iomem->start, resource_size(iomem));
	sdhci_free_host(host);

	return 0;
}