Loading drivers/mmc/host/mtk-sd.c +86 −3 Original line number Original line Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include <linux/of_gpio.h> #include <linux/of_gpio.h> #include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h> #include <linux/spinlock.h> #include <linux/spinlock.h> Loading Loading @@ -213,6 +215,7 @@ #define MSDC_ASYNC_FLAG (0x1 << 1) #define MSDC_ASYNC_FLAG (0x1 << 1) #define MSDC_MMAP_FLAG (0x1 << 2) #define MSDC_MMAP_FLAG (0x1 << 2) #define MTK_MMC_AUTOSUSPEND_DELAY 50 #define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */ #define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */ #define DAT_TIMEOUT (HZ * 5) /* 1000ms x5 */ #define DAT_TIMEOUT (HZ * 5) /* 1000ms x5 */ Loading Loading @@ -255,6 +258,15 @@ struct msdc_dma { dma_addr_t bd_addr; /* the physical address of bd array */ dma_addr_t bd_addr; /* the physical address of bd array */ }; }; struct msdc_save_para { u32 msdc_cfg; u32 iocon; u32 sdc_cfg; u32 pad_tune; u32 patch_bit0; u32 patch_bit1; }; struct msdc_host { struct msdc_host { struct device *dev; struct device *dev; struct mmc_host *mmc; /* mmc structure */ struct mmc_host *mmc; /* mmc structure */ Loading Loading @@ -287,6 +299,7 @@ struct msdc_host { u32 sclk; /* SD/MS bus clock frequency */ u32 sclk; /* SD/MS bus clock frequency */ bool ddr; bool ddr; bool vqmmc_enabled; bool vqmmc_enabled; struct msdc_save_para save_para; /* used when gate HCLK */ }; }; static void sdr_set_bits(void __iomem *reg, u32 bs) static void sdr_set_bits(void __iomem *reg, u32 bs) Loading Loading @@ -678,6 +691,9 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq) if (mrq->data) if (mrq->data) msdc_unprepare_data(host, mrq); msdc_unprepare_data(host, mrq); mmc_request_done(host->mmc, mrq); mmc_request_done(host->mmc, mrq); pm_runtime_mark_last_busy(host->dev); pm_runtime_put_autosuspend(host->dev); } } /* returns true if command is fully handled; returns false otherwise */ /* returns true if command is fully handled; returns false otherwise */ Loading Loading @@ -832,6 +848,8 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(host->mrq); WARN_ON(host->mrq); host->mrq = mrq; host->mrq = mrq; pm_runtime_get_sync(host->dev); if (mrq->data) if (mrq->data) msdc_prepare_data(host, mrq); msdc_prepare_data(host, mrq); Loading Loading @@ -1146,6 +1164,8 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) int ret; int ret; u32 ddr = 0; u32 ddr = 0; pm_runtime_get_sync(host->dev); if (ios->timing == MMC_TIMING_UHS_DDR50 || if (ios->timing == MMC_TIMING_UHS_DDR50 || ios->timing == MMC_TIMING_MMC_DDR52) ios->timing == MMC_TIMING_MMC_DDR52) ddr = 1; ddr = 1; Loading @@ -1160,7 +1180,7 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ios->vdd); ios->vdd); if (ret) { if (ret) { dev_err(host->dev, "Failed to set vmmc power!\n"); dev_err(host->dev, "Failed to set vmmc power!\n"); return; goto end; } } } } break; break; Loading Loading @@ -1188,6 +1208,10 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (host->mclk != ios->clock || host->ddr != ddr) if (host->mclk != ios->clock || host->ddr != ddr) msdc_set_mclk(host, ddr, ios->clock); msdc_set_mclk(host, ddr, ios->clock); end: pm_runtime_mark_last_busy(host->dev); pm_runtime_put_autosuspend(host->dev); } } static struct mmc_host_ops mt_msdc_ops = { static struct mmc_host_ops mt_msdc_ops = { Loading Loading @@ -1311,12 +1335,18 @@ static int msdc_drv_probe(struct platform_device *pdev) if (ret) if (ret) goto release; goto release; pm_runtime_set_active(host->dev); pm_runtime_set_autosuspend_delay(host->dev, MTK_MMC_AUTOSUSPEND_DELAY); pm_runtime_use_autosuspend(host->dev); pm_runtime_enable(host->dev); ret = mmc_add_host(mmc); ret = mmc_add_host(mmc); if (ret) if (ret) goto release; goto end; return 0; return 0; end: pm_runtime_disable(host->dev); release: release: platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL); msdc_deinit_hw(host); msdc_deinit_hw(host); Loading Loading @@ -1344,11 +1374,15 @@ static int msdc_drv_remove(struct platform_device *pdev) mmc = platform_get_drvdata(pdev); mmc = platform_get_drvdata(pdev); host = mmc_priv(mmc); host = mmc_priv(mmc); pm_runtime_get_sync(host->dev); platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL); mmc_remove_host(host->mmc); mmc_remove_host(host->mmc); msdc_deinit_hw(host); msdc_deinit_hw(host); msdc_gate_clock(host); msdc_gate_clock(host); pm_runtime_disable(host->dev); pm_runtime_put_noidle(host->dev); dma_free_coherent(&pdev->dev, dma_free_coherent(&pdev->dev, sizeof(struct mt_gpdma_desc), sizeof(struct mt_gpdma_desc), host->dma.gpd, host->dma.gpd_addr); host->dma.gpd, host->dma.gpd_addr); Loading @@ -1360,6 +1394,54 @@ static int msdc_drv_remove(struct platform_device *pdev) return 0; return 0; } } #ifdef CONFIG_PM static void msdc_save_reg(struct msdc_host *host) { host->save_para.msdc_cfg = readl(host->base + MSDC_CFG); host->save_para.iocon = readl(host->base + MSDC_IOCON); host->save_para.sdc_cfg = readl(host->base + SDC_CFG); host->save_para.pad_tune = readl(host->base + MSDC_PAD_TUNE); host->save_para.patch_bit0 = readl(host->base + MSDC_PATCH_BIT); host->save_para.patch_bit1 = readl(host->base + MSDC_PATCH_BIT1); } static void msdc_restore_reg(struct msdc_host *host) { writel(host->save_para.msdc_cfg, host->base + MSDC_CFG); writel(host->save_para.iocon, host->base + MSDC_IOCON); writel(host->save_para.sdc_cfg, host->base + SDC_CFG); writel(host->save_para.pad_tune, host->base + MSDC_PAD_TUNE); writel(host->save_para.patch_bit0, host->base + MSDC_PATCH_BIT); writel(host->save_para.patch_bit1, host->base + MSDC_PATCH_BIT1); } static int msdc_runtime_suspend(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); struct msdc_host *host = mmc_priv(mmc); msdc_save_reg(host); msdc_gate_clock(host); return 0; } static int msdc_runtime_resume(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); struct msdc_host *host = mmc_priv(mmc); msdc_ungate_clock(host); msdc_restore_reg(host); return 0; } #endif static const struct dev_pm_ops msdc_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) SET_RUNTIME_PM_OPS(msdc_runtime_suspend, msdc_runtime_resume, NULL) }; static const struct of_device_id msdc_of_ids[] = { static const struct of_device_id msdc_of_ids[] = { { .compatible = "mediatek,mt8135-mmc", }, { .compatible = "mediatek,mt8135-mmc", }, {} {} Loading @@ -1371,6 +1453,7 @@ static struct platform_driver mt_msdc_driver = { .driver = { .driver = { .name = "mtk-msdc", .name = "mtk-msdc", .of_match_table = msdc_of_ids, .of_match_table = msdc_of_ids, .pm = &msdc_dev_pm_ops, }, }, }; }; Loading Loading
drivers/mmc/host/mtk-sd.c +86 −3 Original line number Original line Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include <linux/of_gpio.h> #include <linux/of_gpio.h> #include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h> #include <linux/spinlock.h> #include <linux/spinlock.h> Loading Loading @@ -213,6 +215,7 @@ #define MSDC_ASYNC_FLAG (0x1 << 1) #define MSDC_ASYNC_FLAG (0x1 << 1) #define MSDC_MMAP_FLAG (0x1 << 2) #define MSDC_MMAP_FLAG (0x1 << 2) #define MTK_MMC_AUTOSUSPEND_DELAY 50 #define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */ #define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */ #define DAT_TIMEOUT (HZ * 5) /* 1000ms x5 */ #define DAT_TIMEOUT (HZ * 5) /* 1000ms x5 */ Loading Loading @@ -255,6 +258,15 @@ struct msdc_dma { dma_addr_t bd_addr; /* the physical address of bd array */ dma_addr_t bd_addr; /* the physical address of bd array */ }; }; struct msdc_save_para { u32 msdc_cfg; u32 iocon; u32 sdc_cfg; u32 pad_tune; u32 patch_bit0; u32 patch_bit1; }; struct msdc_host { struct msdc_host { struct device *dev; struct device *dev; struct mmc_host *mmc; /* mmc structure */ struct mmc_host *mmc; /* mmc structure */ Loading Loading @@ -287,6 +299,7 @@ struct msdc_host { u32 sclk; /* SD/MS bus clock frequency */ u32 sclk; /* SD/MS bus clock frequency */ bool ddr; bool ddr; bool vqmmc_enabled; bool vqmmc_enabled; struct msdc_save_para save_para; /* used when gate HCLK */ }; }; static void sdr_set_bits(void __iomem *reg, u32 bs) static void sdr_set_bits(void __iomem *reg, u32 bs) Loading Loading @@ -678,6 +691,9 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq) if (mrq->data) if (mrq->data) msdc_unprepare_data(host, mrq); msdc_unprepare_data(host, mrq); mmc_request_done(host->mmc, mrq); mmc_request_done(host->mmc, mrq); pm_runtime_mark_last_busy(host->dev); pm_runtime_put_autosuspend(host->dev); } } /* returns true if command is fully handled; returns false otherwise */ /* returns true if command is fully handled; returns false otherwise */ Loading Loading @@ -832,6 +848,8 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(host->mrq); WARN_ON(host->mrq); host->mrq = mrq; host->mrq = mrq; pm_runtime_get_sync(host->dev); if (mrq->data) if (mrq->data) msdc_prepare_data(host, mrq); msdc_prepare_data(host, mrq); Loading Loading @@ -1146,6 +1164,8 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) int ret; int ret; u32 ddr = 0; u32 ddr = 0; pm_runtime_get_sync(host->dev); if (ios->timing == MMC_TIMING_UHS_DDR50 || if (ios->timing == MMC_TIMING_UHS_DDR50 || ios->timing == MMC_TIMING_MMC_DDR52) ios->timing == MMC_TIMING_MMC_DDR52) ddr = 1; ddr = 1; Loading @@ -1160,7 +1180,7 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ios->vdd); ios->vdd); if (ret) { if (ret) { dev_err(host->dev, "Failed to set vmmc power!\n"); dev_err(host->dev, "Failed to set vmmc power!\n"); return; goto end; } } } } break; break; Loading Loading @@ -1188,6 +1208,10 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (host->mclk != ios->clock || host->ddr != ddr) if (host->mclk != ios->clock || host->ddr != ddr) msdc_set_mclk(host, ddr, ios->clock); msdc_set_mclk(host, ddr, ios->clock); end: pm_runtime_mark_last_busy(host->dev); pm_runtime_put_autosuspend(host->dev); } } static struct mmc_host_ops mt_msdc_ops = { static struct mmc_host_ops mt_msdc_ops = { Loading Loading @@ -1311,12 +1335,18 @@ static int msdc_drv_probe(struct platform_device *pdev) if (ret) if (ret) goto release; goto release; pm_runtime_set_active(host->dev); pm_runtime_set_autosuspend_delay(host->dev, MTK_MMC_AUTOSUSPEND_DELAY); pm_runtime_use_autosuspend(host->dev); pm_runtime_enable(host->dev); ret = mmc_add_host(mmc); ret = mmc_add_host(mmc); if (ret) if (ret) goto release; goto end; return 0; return 0; end: pm_runtime_disable(host->dev); release: release: platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL); msdc_deinit_hw(host); msdc_deinit_hw(host); Loading Loading @@ -1344,11 +1374,15 @@ static int msdc_drv_remove(struct platform_device *pdev) mmc = platform_get_drvdata(pdev); mmc = platform_get_drvdata(pdev); host = mmc_priv(mmc); host = mmc_priv(mmc); pm_runtime_get_sync(host->dev); platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL); mmc_remove_host(host->mmc); mmc_remove_host(host->mmc); msdc_deinit_hw(host); msdc_deinit_hw(host); msdc_gate_clock(host); msdc_gate_clock(host); pm_runtime_disable(host->dev); pm_runtime_put_noidle(host->dev); dma_free_coherent(&pdev->dev, dma_free_coherent(&pdev->dev, sizeof(struct mt_gpdma_desc), sizeof(struct mt_gpdma_desc), host->dma.gpd, host->dma.gpd_addr); host->dma.gpd, host->dma.gpd_addr); Loading @@ -1360,6 +1394,54 @@ static int msdc_drv_remove(struct platform_device *pdev) return 0; return 0; } } #ifdef CONFIG_PM static void msdc_save_reg(struct msdc_host *host) { host->save_para.msdc_cfg = readl(host->base + MSDC_CFG); host->save_para.iocon = readl(host->base + MSDC_IOCON); host->save_para.sdc_cfg = readl(host->base + SDC_CFG); host->save_para.pad_tune = readl(host->base + MSDC_PAD_TUNE); host->save_para.patch_bit0 = readl(host->base + MSDC_PATCH_BIT); host->save_para.patch_bit1 = readl(host->base + MSDC_PATCH_BIT1); } static void msdc_restore_reg(struct msdc_host *host) { writel(host->save_para.msdc_cfg, host->base + MSDC_CFG); writel(host->save_para.iocon, host->base + MSDC_IOCON); writel(host->save_para.sdc_cfg, host->base + SDC_CFG); writel(host->save_para.pad_tune, host->base + MSDC_PAD_TUNE); writel(host->save_para.patch_bit0, host->base + MSDC_PATCH_BIT); writel(host->save_para.patch_bit1, host->base + MSDC_PATCH_BIT1); } static int msdc_runtime_suspend(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); struct msdc_host *host = mmc_priv(mmc); msdc_save_reg(host); msdc_gate_clock(host); return 0; } static int msdc_runtime_resume(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); struct msdc_host *host = mmc_priv(mmc); msdc_ungate_clock(host); msdc_restore_reg(host); return 0; } #endif static const struct dev_pm_ops msdc_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) SET_RUNTIME_PM_OPS(msdc_runtime_suspend, msdc_runtime_resume, NULL) }; static const struct of_device_id msdc_of_ids[] = { static const struct of_device_id msdc_of_ids[] = { { .compatible = "mediatek,mt8135-mmc", }, { .compatible = "mediatek,mt8135-mmc", }, {} {} Loading @@ -1371,6 +1453,7 @@ static struct platform_driver mt_msdc_driver = { .driver = { .driver = { .name = "mtk-msdc", .name = "mtk-msdc", .of_match_table = msdc_of_ids, .of_match_table = msdc_of_ids, .pm = &msdc_dev_pm_ops, }, }, }; }; Loading