aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChaotian Jing <chaotian.jing@mediatek.com>2015-06-15 07:20:49 -0400
committerUlf Hansson <ulf.hansson@linaro.org>2015-06-18 03:21:04 -0400
commit4b8a43e90ccf88c91475b802d1388c0779be2bda (patch)
tree14769199867583dde3bfd25d6b290903a773a222
parent208489032bdd8d4a7de50f3057c175058f271956 (diff)
mmc: mediatek: Add PM support for MMC driver
Add PM support for Mediatek MMC driver Save/restore registers when PM Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
-rw-r--r--drivers/mmc/host/mtk-sd.c89
1 files changed, 86 insertions, 3 deletions
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index fd965cb81133..7153500dd007 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -23,6 +23,8 @@
23#include <linux/of_gpio.h> 23#include <linux/of_gpio.h>
24#include <linux/pinctrl/consumer.h> 24#include <linux/pinctrl/consumer.h>
25#include <linux/platform_device.h> 25#include <linux/platform_device.h>
26#include <linux/pm.h>
27#include <linux/pm_runtime.h>
26#include <linux/regulator/consumer.h> 28#include <linux/regulator/consumer.h>
27#include <linux/spinlock.h> 29#include <linux/spinlock.h>
28 30
@@ -213,6 +215,7 @@
213#define MSDC_ASYNC_FLAG (0x1 << 1) 215#define MSDC_ASYNC_FLAG (0x1 << 1)
214#define MSDC_MMAP_FLAG (0x1 << 2) 216#define MSDC_MMAP_FLAG (0x1 << 2)
215 217
218#define MTK_MMC_AUTOSUSPEND_DELAY 50
216#define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */ 219#define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */
217#define DAT_TIMEOUT (HZ * 5) /* 1000ms x5 */ 220#define DAT_TIMEOUT (HZ * 5) /* 1000ms x5 */
218 221
@@ -255,6 +258,15 @@ struct msdc_dma {
255 dma_addr_t bd_addr; /* the physical address of bd array */ 258 dma_addr_t bd_addr; /* the physical address of bd array */
256}; 259};
257 260
261struct msdc_save_para {
262 u32 msdc_cfg;
263 u32 iocon;
264 u32 sdc_cfg;
265 u32 pad_tune;
266 u32 patch_bit0;
267 u32 patch_bit1;
268};
269
258struct msdc_host { 270struct msdc_host {
259 struct device *dev; 271 struct device *dev;
260 struct mmc_host *mmc; /* mmc structure */ 272 struct mmc_host *mmc; /* mmc structure */
@@ -287,6 +299,7 @@ struct msdc_host {
287 u32 sclk; /* SD/MS bus clock frequency */ 299 u32 sclk; /* SD/MS bus clock frequency */
288 bool ddr; 300 bool ddr;
289 bool vqmmc_enabled; 301 bool vqmmc_enabled;
302 struct msdc_save_para save_para; /* used when gate HCLK */
290}; 303};
291 304
292static void sdr_set_bits(void __iomem *reg, u32 bs) 305static void sdr_set_bits(void __iomem *reg, u32 bs)
@@ -678,6 +691,9 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
678 if (mrq->data) 691 if (mrq->data)
679 msdc_unprepare_data(host, mrq); 692 msdc_unprepare_data(host, mrq);
680 mmc_request_done(host->mmc, mrq); 693 mmc_request_done(host->mmc, mrq);
694
695 pm_runtime_mark_last_busy(host->dev);
696 pm_runtime_put_autosuspend(host->dev);
681} 697}
682 698
683/* returns true if command is fully handled; returns false otherwise */ 699/* returns true if command is fully handled; returns false otherwise */
@@ -832,6 +848,8 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq)
832 WARN_ON(host->mrq); 848 WARN_ON(host->mrq);
833 host->mrq = mrq; 849 host->mrq = mrq;
834 850
851 pm_runtime_get_sync(host->dev);
852
835 if (mrq->data) 853 if (mrq->data)
836 msdc_prepare_data(host, mrq); 854 msdc_prepare_data(host, mrq);
837 855
@@ -1146,6 +1164,8 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1146 int ret; 1164 int ret;
1147 u32 ddr = 0; 1165 u32 ddr = 0;
1148 1166
1167 pm_runtime_get_sync(host->dev);
1168
1149 if (ios->timing == MMC_TIMING_UHS_DDR50 || 1169 if (ios->timing == MMC_TIMING_UHS_DDR50 ||
1150 ios->timing == MMC_TIMING_MMC_DDR52) 1170 ios->timing == MMC_TIMING_MMC_DDR52)
1151 ddr = 1; 1171 ddr = 1;
@@ -1160,7 +1180,7 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1160 ios->vdd); 1180 ios->vdd);
1161 if (ret) { 1181 if (ret) {
1162 dev_err(host->dev, "Failed to set vmmc power!\n"); 1182 dev_err(host->dev, "Failed to set vmmc power!\n");
1163 return; 1183 goto end;
1164 } 1184 }
1165 } 1185 }
1166 break; 1186 break;
@@ -1188,6 +1208,10 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1188 1208
1189 if (host->mclk != ios->clock || host->ddr != ddr) 1209 if (host->mclk != ios->clock || host->ddr != ddr)
1190 msdc_set_mclk(host, ddr, ios->clock); 1210 msdc_set_mclk(host, ddr, ios->clock);
1211
1212end:
1213 pm_runtime_mark_last_busy(host->dev);
1214 pm_runtime_put_autosuspend(host->dev);
1191} 1215}
1192 1216
1193static struct mmc_host_ops mt_msdc_ops = { 1217static struct mmc_host_ops mt_msdc_ops = {
@@ -1311,12 +1335,18 @@ static int msdc_drv_probe(struct platform_device *pdev)
1311 if (ret) 1335 if (ret)
1312 goto release; 1336 goto release;
1313 1337
1338 pm_runtime_set_active(host->dev);
1339 pm_runtime_set_autosuspend_delay(host->dev, MTK_MMC_AUTOSUSPEND_DELAY);
1340 pm_runtime_use_autosuspend(host->dev);
1341 pm_runtime_enable(host->dev);
1314 ret = mmc_add_host(mmc); 1342 ret = mmc_add_host(mmc);
1343
1315 if (ret) 1344 if (ret)
1316 goto release; 1345 goto end;
1317 1346
1318 return 0; 1347 return 0;
1319 1348end:
1349 pm_runtime_disable(host->dev);
1320release: 1350release:
1321 platform_set_drvdata(pdev, NULL); 1351 platform_set_drvdata(pdev, NULL);
1322 msdc_deinit_hw(host); 1352 msdc_deinit_hw(host);
@@ -1344,11 +1374,15 @@ static int msdc_drv_remove(struct platform_device *pdev)
1344 mmc = platform_get_drvdata(pdev); 1374 mmc = platform_get_drvdata(pdev);
1345 host = mmc_priv(mmc); 1375 host = mmc_priv(mmc);
1346 1376
1377 pm_runtime_get_sync(host->dev);
1378
1347 platform_set_drvdata(pdev, NULL); 1379 platform_set_drvdata(pdev, NULL);
1348 mmc_remove_host(host->mmc); 1380 mmc_remove_host(host->mmc);
1349 msdc_deinit_hw(host); 1381 msdc_deinit_hw(host);
1350 msdc_gate_clock(host); 1382 msdc_gate_clock(host);
1351 1383
1384 pm_runtime_disable(host->dev);
1385 pm_runtime_put_noidle(host->dev);
1352 dma_free_coherent(&pdev->dev, 1386 dma_free_coherent(&pdev->dev,
1353 sizeof(struct mt_gpdma_desc), 1387 sizeof(struct mt_gpdma_desc),
1354 host->dma.gpd, host->dma.gpd_addr); 1388 host->dma.gpd, host->dma.gpd_addr);
@@ -1360,6 +1394,54 @@ static int msdc_drv_remove(struct platform_device *pdev)
1360 return 0; 1394 return 0;
1361} 1395}
1362 1396
1397#ifdef CONFIG_PM
1398static void msdc_save_reg(struct msdc_host *host)
1399{
1400 host->save_para.msdc_cfg = readl(host->base + MSDC_CFG);
1401 host->save_para.iocon = readl(host->base + MSDC_IOCON);
1402 host->save_para.sdc_cfg = readl(host->base + SDC_CFG);
1403 host->save_para.pad_tune = readl(host->base + MSDC_PAD_TUNE);
1404 host->save_para.patch_bit0 = readl(host->base + MSDC_PATCH_BIT);
1405 host->save_para.patch_bit1 = readl(host->base + MSDC_PATCH_BIT1);
1406}
1407
1408static void msdc_restore_reg(struct msdc_host *host)
1409{
1410 writel(host->save_para.msdc_cfg, host->base + MSDC_CFG);
1411 writel(host->save_para.iocon, host->base + MSDC_IOCON);
1412 writel(host->save_para.sdc_cfg, host->base + SDC_CFG);
1413 writel(host->save_para.pad_tune, host->base + MSDC_PAD_TUNE);
1414 writel(host->save_para.patch_bit0, host->base + MSDC_PATCH_BIT);
1415 writel(host->save_para.patch_bit1, host->base + MSDC_PATCH_BIT1);
1416}
1417
1418static int msdc_runtime_suspend(struct device *dev)
1419{
1420 struct mmc_host *mmc = dev_get_drvdata(dev);
1421 struct msdc_host *host = mmc_priv(mmc);
1422
1423 msdc_save_reg(host);
1424 msdc_gate_clock(host);
1425 return 0;
1426}
1427
1428static int msdc_runtime_resume(struct device *dev)
1429{
1430 struct mmc_host *mmc = dev_get_drvdata(dev);
1431 struct msdc_host *host = mmc_priv(mmc);
1432
1433 msdc_ungate_clock(host);
1434 msdc_restore_reg(host);
1435 return 0;
1436}
1437#endif
1438
1439static const struct dev_pm_ops msdc_dev_pm_ops = {
1440 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
1441 pm_runtime_force_resume)
1442 SET_RUNTIME_PM_OPS(msdc_runtime_suspend, msdc_runtime_resume, NULL)
1443};
1444
1363static const struct of_device_id msdc_of_ids[] = { 1445static const struct of_device_id msdc_of_ids[] = {
1364 { .compatible = "mediatek,mt8135-mmc", }, 1446 { .compatible = "mediatek,mt8135-mmc", },
1365 {} 1447 {}
@@ -1371,6 +1453,7 @@ static struct platform_driver mt_msdc_driver = {
1371 .driver = { 1453 .driver = {
1372 .name = "mtk-msdc", 1454 .name = "mtk-msdc",
1373 .of_match_table = msdc_of_ids, 1455 .of_match_table = msdc_of_ids,
1456 .pm = &msdc_dev_pm_ops,
1374 }, 1457 },
1375}; 1458};
1376 1459