Skip to content

Commit 4b8a43e

Browse files
ChaotianJingstorulf
authored andcommitted
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 <[email protected]> Signed-off-by: Ulf Hansson <[email protected]>
1 parent 2084890 commit 4b8a43e

File tree

1 file changed

+86
-3
lines changed

1 file changed

+86
-3
lines changed

drivers/mmc/host/mtk-sd.c

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include <linux/of_gpio.h>
2424
#include <linux/pinctrl/consumer.h>
2525
#include <linux/platform_device.h>
26+
#include <linux/pm.h>
27+
#include <linux/pm_runtime.h>
2628
#include <linux/regulator/consumer.h>
2729
#include <linux/spinlock.h>
2830

@@ -213,6 +215,7 @@
213215
#define MSDC_ASYNC_FLAG (0x1 << 1)
214216
#define MSDC_MMAP_FLAG (0x1 << 2)
215217

218+
#define MTK_MMC_AUTOSUSPEND_DELAY 50
216219
#define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */
217220
#define DAT_TIMEOUT (HZ * 5) /* 1000ms x5 */
218221

@@ -255,6 +258,15 @@ struct msdc_dma {
255258
dma_addr_t bd_addr; /* the physical address of bd array */
256259
};
257260

261+
struct 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+
258270
struct msdc_host {
259271
struct device *dev;
260272
struct mmc_host *mmc; /* mmc structure */
@@ -287,6 +299,7 @@ struct msdc_host {
287299
u32 sclk; /* SD/MS bus clock frequency */
288300
bool ddr;
289301
bool vqmmc_enabled;
302+
struct msdc_save_para save_para; /* used when gate HCLK */
290303
};
291304

292305
static 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)
678691
if (mrq->data)
679692
msdc_unprepare_data(host, mrq);
680693
mmc_request_done(host->mmc, mrq);
694+
695+
pm_runtime_mark_last_busy(host->dev);
696+
pm_runtime_put_autosuspend(host->dev);
681697
}
682698

683699
/* 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)
832848
WARN_ON(host->mrq);
833849
host->mrq = mrq;
834850

851+
pm_runtime_get_sync(host->dev);
852+
835853
if (mrq->data)
836854
msdc_prepare_data(host, mrq);
837855

@@ -1146,6 +1164,8 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
11461164
int ret;
11471165
u32 ddr = 0;
11481166

1167+
pm_runtime_get_sync(host->dev);
1168+
11491169
if (ios->timing == MMC_TIMING_UHS_DDR50 ||
11501170
ios->timing == MMC_TIMING_MMC_DDR52)
11511171
ddr = 1;
@@ -1160,7 +1180,7 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
11601180
ios->vdd);
11611181
if (ret) {
11621182
dev_err(host->dev, "Failed to set vmmc power!\n");
1163-
return;
1183+
goto end;
11641184
}
11651185
}
11661186
break;
@@ -1188,6 +1208,10 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
11881208

11891209
if (host->mclk != ios->clock || host->ddr != ddr)
11901210
msdc_set_mclk(host, ddr, ios->clock);
1211+
1212+
end:
1213+
pm_runtime_mark_last_busy(host->dev);
1214+
pm_runtime_put_autosuspend(host->dev);
11911215
}
11921216

11931217
static struct mmc_host_ops mt_msdc_ops = {
@@ -1311,12 +1335,18 @@ static int msdc_drv_probe(struct platform_device *pdev)
13111335
if (ret)
13121336
goto release;
13131337

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);
13141342
ret = mmc_add_host(mmc);
1343+
13151344
if (ret)
1316-
goto release;
1345+
goto end;
13171346

13181347
return 0;
1319-
1348+
end:
1349+
pm_runtime_disable(host->dev);
13201350
release:
13211351
platform_set_drvdata(pdev, NULL);
13221352
msdc_deinit_hw(host);
@@ -1344,11 +1374,15 @@ static int msdc_drv_remove(struct platform_device *pdev)
13441374
mmc = platform_get_drvdata(pdev);
13451375
host = mmc_priv(mmc);
13461376

1377+
pm_runtime_get_sync(host->dev);
1378+
13471379
platform_set_drvdata(pdev, NULL);
13481380
mmc_remove_host(host->mmc);
13491381
msdc_deinit_hw(host);
13501382
msdc_gate_clock(host);
13511383

1384+
pm_runtime_disable(host->dev);
1385+
pm_runtime_put_noidle(host->dev);
13521386
dma_free_coherent(&pdev->dev,
13531387
sizeof(struct mt_gpdma_desc),
13541388
host->dma.gpd, host->dma.gpd_addr);
@@ -1360,6 +1394,54 @@ static int msdc_drv_remove(struct platform_device *pdev)
13601394
return 0;
13611395
}
13621396

1397+
#ifdef CONFIG_PM
1398+
static 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+
1408+
static 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+
1418+
static 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+
1428+
static 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+
1439+
static 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+
13631445
static const struct of_device_id msdc_of_ids[] = {
13641446
{ .compatible = "mediatek,mt8135-mmc", },
13651447
{}
@@ -1371,6 +1453,7 @@ static struct platform_driver mt_msdc_driver = {
13711453
.driver = {
13721454
.name = "mtk-msdc",
13731455
.of_match_table = msdc_of_ids,
1456+
.pm = &msdc_dev_pm_ops,
13741457
},
13751458
};
13761459

0 commit comments

Comments
 (0)