diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2012-04-20 12:27:13 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2012-07-21 00:02:15 -0400 |
commit | 7d17baa05da6a2e64ee15011cdf4319bd3e0ff61 (patch) | |
tree | 9fe6a2658adf59ce0d0564e9e5579329de6c82a8 | |
parent | e2ee996eaad64c149cb7cfd344789c7e0c1577dc (diff) |
mmc: sh_mmcif: add regulator support
Add regulator support to the sh_mmcif driver, but also preserve the current
power-callback.
Also note, that the card power is not switched off during clock gating
periods, hence there's no need to power it on every time the card is
re-activated.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Reviwed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Reviewed-by: Simon Horman <horms@verge.net.au>
Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r-- | drivers/mmc/host/sh_mmcif.c | 38 |
1 files changed, 31 insertions, 7 deletions
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 468027665ede..204bcedc2164 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c | |||
@@ -923,10 +923,22 @@ static int sh_mmcif_clk_update(struct sh_mmcif_host *host) | |||
923 | return ret; | 923 | return ret; |
924 | } | 924 | } |
925 | 925 | ||
926 | static void sh_mmcif_set_power(struct sh_mmcif_host *host, struct mmc_ios *ios) | ||
927 | { | ||
928 | struct sh_mmcif_plat_data *pd = host->pd->dev.platform_data; | ||
929 | struct mmc_host *mmc = host->mmc; | ||
930 | |||
931 | if (pd->set_pwr) | ||
932 | pd->set_pwr(host->pd, ios->power_mode != MMC_POWER_OFF); | ||
933 | if (!IS_ERR(mmc->supply.vmmc)) | ||
934 | /* Errors ignored... */ | ||
935 | mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, | ||
936 | ios->power_mode ? ios->vdd : 0); | ||
937 | } | ||
938 | |||
926 | static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | 939 | static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) |
927 | { | 940 | { |
928 | struct sh_mmcif_host *host = mmc_priv(mmc); | 941 | struct sh_mmcif_host *host = mmc_priv(mmc); |
929 | struct sh_mmcif_plat_data *p = host->pd->dev.platform_data; | ||
930 | unsigned long flags; | 942 | unsigned long flags; |
931 | 943 | ||
932 | spin_lock_irqsave(&host->lock, flags); | 944 | spin_lock_irqsave(&host->lock, flags); |
@@ -944,6 +956,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
944 | sh_mmcif_request_dma(host, host->pd->dev.platform_data); | 956 | sh_mmcif_request_dma(host, host->pd->dev.platform_data); |
945 | host->card_present = true; | 957 | host->card_present = true; |
946 | } | 958 | } |
959 | sh_mmcif_set_power(host, ios); | ||
947 | } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { | 960 | } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { |
948 | /* clock stop */ | 961 | /* clock stop */ |
949 | sh_mmcif_clock_control(host, 0); | 962 | sh_mmcif_clock_control(host, 0); |
@@ -957,8 +970,8 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
957 | pm_runtime_put(&host->pd->dev); | 970 | pm_runtime_put(&host->pd->dev); |
958 | clk_disable(host->hclk); | 971 | clk_disable(host->hclk); |
959 | host->power = false; | 972 | host->power = false; |
960 | if (p->set_pwr && ios->power_mode == MMC_POWER_OFF) | 973 | if (ios->power_mode == MMC_POWER_OFF) |
961 | p->set_pwr(host->pd, 0); | 974 | sh_mmcif_set_power(host, ios); |
962 | } | 975 | } |
963 | host->state = STATE_IDLE; | 976 | host->state = STATE_IDLE; |
964 | return; | 977 | return; |
@@ -966,8 +979,6 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
966 | 979 | ||
967 | if (ios->clock) { | 980 | if (ios->clock) { |
968 | if (!host->power) { | 981 | if (!host->power) { |
969 | if (p->set_pwr) | ||
970 | p->set_pwr(host->pd, ios->power_mode); | ||
971 | sh_mmcif_clk_update(host); | 982 | sh_mmcif_clk_update(host); |
972 | pm_runtime_get_sync(&host->pd->dev); | 983 | pm_runtime_get_sync(&host->pd->dev); |
973 | host->power = true; | 984 | host->power = true; |
@@ -1251,6 +1262,19 @@ static void mmcif_timeout_work(struct work_struct *work) | |||
1251 | mmc_request_done(host->mmc, mrq); | 1262 | mmc_request_done(host->mmc, mrq); |
1252 | } | 1263 | } |
1253 | 1264 | ||
1265 | static void sh_mmcif_init_ocr(struct sh_mmcif_host *host) | ||
1266 | { | ||
1267 | struct sh_mmcif_plat_data *pd = host->pd->dev.platform_data; | ||
1268 | struct mmc_host *mmc = host->mmc; | ||
1269 | |||
1270 | mmc_regulator_get_supply(mmc); | ||
1271 | |||
1272 | if (!mmc->ocr_avail) | ||
1273 | mmc->ocr_avail = pd->ocr; | ||
1274 | else if (pd->ocr) | ||
1275 | dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); | ||
1276 | } | ||
1277 | |||
1254 | static int __devinit sh_mmcif_probe(struct platform_device *pdev) | 1278 | static int __devinit sh_mmcif_probe(struct platform_device *pdev) |
1255 | { | 1279 | { |
1256 | int ret = 0, irq[2]; | 1280 | int ret = 0, irq[2]; |
@@ -1298,8 +1322,8 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) | |||
1298 | spin_lock_init(&host->lock); | 1322 | spin_lock_init(&host->lock); |
1299 | 1323 | ||
1300 | mmc->ops = &sh_mmcif_ops; | 1324 | mmc->ops = &sh_mmcif_ops; |
1301 | if (pd->ocr) | 1325 | sh_mmcif_init_ocr(host); |
1302 | mmc->ocr_avail = pd->ocr; | 1326 | |
1303 | mmc->caps = MMC_CAP_MMC_HIGHSPEED; | 1327 | mmc->caps = MMC_CAP_MMC_HIGHSPEED; |
1304 | if (pd->caps) | 1328 | if (pd->caps) |
1305 | mmc->caps |= pd->caps; | 1329 | mmc->caps |= pd->caps; |