From 408806f740497c5d71f9c305b3d6aad260ff186d Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Tue, 16 Jun 2015 16:07:17 +0530 Subject: mmc: omap_hsmmc: Fix DTO and DCRC handling DTO/DCRC errors were not being informed to the mmc core since commit ae4bf788ee9b ("mmc: omap_hsmmc: consolidate error report handling of HSMMC IRQ"). This commit made sure 'end_trans' is never set on DTO/DCRC errors. This is because after this commit 'host->data' is checked after it has been cleared to NULL by omap_hsmmc_dma_cleanup(). Because 'end_trans' is never set, omap_hsmmc_xfer_done() is never invoked making core layer not to be aware of DTO/DCRC errors. Because of this any command invoked after DTO/DCRC error leads to a hang. Fix this by checking for 'host->data' before it is actually cleared. Fixes: ae4bf788ee9b ("mmc: omap_hsmmc: consolidate error report handling of HSMMC IRQ") CC: stable@vger.kernel.org Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Vignesh R Tested-by: Andreas Fenkart Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index b2b411da297b..0132ba75a437 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1062,6 +1062,10 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) if (status & (CTO_EN | CCRC_EN)) end_cmd = 1; + if (host->data || host->response_busy) { + end_trans = !end_cmd; + host->response_busy = 0; + } if (status & (CTO_EN | DTO_EN)) hsmmc_command_incomplete(host, -ETIMEDOUT, end_cmd); else if (status & (CCRC_EN | DCRC_EN)) @@ -1081,10 +1085,6 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) } dev_dbg(mmc_dev(host->mmc), "AC12 err: 0x%x\n", ac12); } - if (host->data || host->response_busy) { - end_trans = !end_cmd; - host->response_busy = 0; - } } OMAP_HSMMC_WRITE(host->base, STAT, status); -- cgit v1.2.3-70-g09d2 From 5027cd1e323d2f8136abb32ac7c8e1e1a94eac05 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Tue, 16 Jun 2015 16:07:18 +0530 Subject: mmc: omap_hsmmc: Handle BADA, DEB and CEB interrupts Sometimes BADA, DEB or CEB error interrupts occur when sd card is unplugged during data transfer. These interrupts are currently ignored by the interrupt handler. But, this results in card not being recognised on subsequent insertion. This is because mmcqd is waiting forever for the data transfer(for which error occurred) to complete. Fix this, by reporting BADA, DEB, CEB errors to mmc-core as -EILSEQ, so that the core can do appropriate handling. Signed-off-by: Vignesh R Tested-by: Andreas Fenkart Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 0132ba75a437..4d1203236890 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1068,7 +1068,8 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) } if (status & (CTO_EN | DTO_EN)) hsmmc_command_incomplete(host, -ETIMEDOUT, end_cmd); - else if (status & (CCRC_EN | DCRC_EN)) + else if (status & (CCRC_EN | DCRC_EN | DEB_EN | CEB_EN | + BADA_EN)) hsmmc_command_incomplete(host, -EILSEQ, end_cmd); if (status & ACE_EN) { -- cgit v1.2.3-70-g09d2 From f7f0f03506d00fc2939a8625ed141c2dda568fad Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Tue, 7 Jul 2015 20:38:43 +0200 Subject: mmc: omap_hsmmc: call omap_hsmmc_set_power directly If no pdata.set_power was set by the platform code, the driver was updating pdata with its own fallback function. This is a no-no since pdata shall be read-only. This patch pushes the check 'pdata->set_power != NULL' down into the fallback functions. If pdata.set_power is really set, it calls them and exits, otherwise the fallback code is used. Signed-off-by: Andreas Fenkart Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 4d1203236890..1fad7c746bc3 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -213,7 +213,6 @@ struct omap_hsmmc_host { int context_loss; int protect_card; int reqs_blocked; - int use_reg; int req_in_progress; unsigned long clk_rate; unsigned int flags; @@ -262,6 +261,9 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) platform_get_drvdata(to_platform_device(dev)); int ret = 0; + if (mmc_pdata(host)->set_power) + return mmc_pdata(host)->set_power(dev, power_on, vdd); + /* * If we don't see a Vcc regulator, assume it's a fixed * voltage always-on regulator. @@ -344,6 +346,9 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) struct regulator *reg; int ocr_value = 0; + if (mmc_pdata(host)->set_power) + return 0; + reg = devm_regulator_get(host->dev, "vmmc"); if (IS_ERR(reg)) { dev_err(host->dev, "unable to get vmmc regulator %ld\n", @@ -363,7 +368,6 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) } } } - mmc_pdata(host)->set_power = omap_hsmmc_set_power; /* Allow an aux regulator */ reg = devm_regulator_get_optional(host->dev, "vmmc_aux"); @@ -383,8 +387,8 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) { int vdd = ffs(mmc_pdata(host)->ocr_mask) - 1; - mmc_pdata(host)->set_power(host->dev, 1, vdd); - mmc_pdata(host)->set_power(host->dev, 0, 0); + omap_hsmmc_set_power(host->dev, 1, vdd); + omap_hsmmc_set_power(host->dev, 0, 0); } return 0; @@ -392,7 +396,8 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host) { - mmc_pdata(host)->set_power = NULL; + if (mmc_pdata(host)->set_power) + return; } static inline int omap_hsmmc_have_reg(void) @@ -402,6 +407,11 @@ static inline int omap_hsmmc_have_reg(void) #else +static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) +{ + return 0; +} + static inline int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) { return -EINVAL; @@ -1149,11 +1159,11 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) clk_disable_unprepare(host->dbclk); /* Turn the power off */ - ret = mmc_pdata(host)->set_power(host->dev, 0, 0); + ret = omap_hsmmc_set_power(host->dev, 0, 0); /* Turn the power ON with given VDD 1.8 or 3.0v */ if (!ret) - ret = mmc_pdata(host)->set_power(host->dev, 1, vdd); + ret = omap_hsmmc_set_power(host->dev, 1, vdd); pm_runtime_get_sync(host->dev); if (host->dbclk) clk_prepare_enable(host->dbclk); @@ -1552,10 +1562,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (ios->power_mode != host->power_mode) { switch (ios->power_mode) { case MMC_POWER_OFF: - mmc_pdata(host)->set_power(host->dev, 0, 0); + omap_hsmmc_set_power(host->dev, 0, 0); break; case MMC_POWER_UP: - mmc_pdata(host)->set_power(host->dev, 1, ios->vdd); + omap_hsmmc_set_power(host->dev, 1, ios->vdd); break; case MMC_POWER_ON: do_send_init_stream = 1; @@ -2078,11 +2088,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev) goto err_irq; } - if (omap_hsmmc_have_reg() && !mmc_pdata(host)->set_power) { + if (omap_hsmmc_have_reg()) { ret = omap_hsmmc_reg_get(host); if (ret) goto err_irq; - host->use_reg = 1; } mmc->ocr_avail = mmc_pdata(host)->ocr_mask; @@ -2125,8 +2134,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) err_slot_name: mmc_remove_host(mmc); - if (host->use_reg) - omap_hsmmc_reg_put(host); + omap_hsmmc_reg_put(host); err_irq: device_init_wakeup(&pdev->dev, false); if (host->tx_chan) @@ -2150,8 +2158,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev) pm_runtime_get_sync(host->dev); mmc_remove_host(host->mmc); - if (host->use_reg) - omap_hsmmc_reg_put(host); + omap_hsmmc_reg_put(host); if (host->tx_chan) dma_release_channel(host->tx_chan); -- cgit v1.2.3-70-g09d2 From 4c06654c47ee2ff5308b7e89994225ff81b48ef2 Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Tue, 7 Jul 2015 20:38:44 +0200 Subject: mmc: omap_hsmmc: regulator automatically released by devm Signed-off-by: Andreas Fenkart Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 1fad7c746bc3..19ae7e693526 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -394,12 +394,6 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) return 0; } -static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host) -{ - if (mmc_pdata(host)->set_power) - return; -} - static inline int omap_hsmmc_have_reg(void) { return 1; @@ -417,10 +411,6 @@ static inline int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) return -EINVAL; } -static inline void omap_hsmmc_reg_put(struct omap_hsmmc_host *host) -{ -} - static inline int omap_hsmmc_have_reg(void) { return 0; @@ -2134,7 +2124,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) err_slot_name: mmc_remove_host(mmc); - omap_hsmmc_reg_put(host); err_irq: device_init_wakeup(&pdev->dev, false); if (host->tx_chan) @@ -2158,7 +2147,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev) pm_runtime_get_sync(host->dev); mmc_remove_host(host->mmc); - omap_hsmmc_reg_put(host); if (host->tx_chan) dma_release_channel(host->tx_chan); -- cgit v1.2.3-70-g09d2 From 7d607f917008218564ae44ca3ef47076a9b36e8f Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:43:53 +0530 Subject: mmc: host: omap_hsmmc: use devm_regulator_get_optional() for vmmc Since vmmc can be optional for some platforms, use devm_regulator_get_optional() for vmmc. Now return error only if the return value of devm_regulator_get_optional() is not the same as -ENODEV, since with -EPROBE_DEFER, the regulator can be obtained later and all other errors are fatal. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 19ae7e693526..9b335aff5882 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -345,15 +345,19 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) { struct regulator *reg; int ocr_value = 0; + int ret; if (mmc_pdata(host)->set_power) return 0; - reg = devm_regulator_get(host->dev, "vmmc"); + reg = devm_regulator_get_optional(host->dev, "vmmc"); if (IS_ERR(reg)) { - dev_err(host->dev, "unable to get vmmc regulator %ld\n", + ret = PTR_ERR(reg); + if (ret != -ENODEV) + return ret; + host->vcc = NULL; + dev_dbg(host->dev, "unable to get vmmc regulator %ld\n", PTR_ERR(reg)); - return PTR_ERR(reg); } else { host->vcc = reg; ocr_value = mmc_regulator_get_ocrmask(reg); -- cgit v1.2.3-70-g09d2 From 6a9b2ff07d0415ad19fb07b9a141863fb86c3497 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:43:54 +0530 Subject: mmc: host: omap_hsmmc: return on fatal errors from omap_hsmmc_reg_get Now return error only if the return value of devm_regulator_get_optional() is not the same as -ENODEV, since with -EPROBE_DEFER, the regulator can be obtained later and all other errors are fatal. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 9b335aff5882..2eafd6f64676 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -375,10 +375,28 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) /* Allow an aux regulator */ reg = devm_regulator_get_optional(host->dev, "vmmc_aux"); - host->vcc_aux = IS_ERR(reg) ? NULL : reg; + if (IS_ERR(reg)) { + ret = PTR_ERR(reg); + if (ret != -ENODEV) + return ret; + host->vcc_aux = NULL; + dev_dbg(host->dev, "unable to get vmmc_aux regulator %ld\n", + PTR_ERR(reg)); + } else { + host->vcc_aux = reg; + } reg = devm_regulator_get_optional(host->dev, "pbias"); - host->pbias = IS_ERR(reg) ? NULL : reg; + if (IS_ERR(reg)) { + ret = PTR_ERR(reg); + if (ret != -ENODEV) + return ret; + host->pbias = NULL; + dev_dbg(host->dev, "unable to get pbias regulator %ld\n", + PTR_ERR(reg)); + } else { + host->pbias = reg; + } /* For eMMC do not power off when not in sleep state */ if (mmc_pdata(host)->no_regulator_off_init) -- cgit v1.2.3-70-g09d2 From c299dc39883ca5596905507cc945332fa4bae8bd Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:43:55 +0530 Subject: mmc: host: omap_hsmmc: cleanup omap_hsmmc_reg_get() No functional change. Instead of using a local regulator variable in omap_hsmmc_reg_get() for holding the return value of devm_regulator_get_optional() and then assigning to omap_hsmmc_host regulator members: vcc, vcc_aux and pbias, directly use the omap_hsmmc_host regulator members. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Roger Quadros Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 2eafd6f64676..3fde2f9dfb25 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -343,24 +343,22 @@ error_set_power: static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) { - struct regulator *reg; int ocr_value = 0; int ret; if (mmc_pdata(host)->set_power) return 0; - reg = devm_regulator_get_optional(host->dev, "vmmc"); - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); + host->vcc = devm_regulator_get_optional(host->dev, "vmmc"); + if (IS_ERR(host->vcc)) { + ret = PTR_ERR(host->vcc); if (ret != -ENODEV) return ret; - host->vcc = NULL; dev_dbg(host->dev, "unable to get vmmc regulator %ld\n", - PTR_ERR(reg)); + PTR_ERR(host->vcc)); + host->vcc = NULL; } else { - host->vcc = reg; - ocr_value = mmc_regulator_get_ocrmask(reg); + ocr_value = mmc_regulator_get_ocrmask(host->vcc); if (!mmc_pdata(host)->ocr_mask) { mmc_pdata(host)->ocr_mask = ocr_value; } else { @@ -374,28 +372,24 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) } /* Allow an aux regulator */ - reg = devm_regulator_get_optional(host->dev, "vmmc_aux"); - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); + host->vcc_aux = devm_regulator_get_optional(host->dev, "vmmc_aux"); + if (IS_ERR(host->vcc_aux)) { + ret = PTR_ERR(host->vcc_aux); if (ret != -ENODEV) return ret; - host->vcc_aux = NULL; dev_dbg(host->dev, "unable to get vmmc_aux regulator %ld\n", - PTR_ERR(reg)); - } else { - host->vcc_aux = reg; + PTR_ERR(host->vcc_aux)); + host->vcc_aux = NULL; } - reg = devm_regulator_get_optional(host->dev, "pbias"); - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); + host->pbias = devm_regulator_get_optional(host->dev, "pbias"); + if (IS_ERR(host->pbias)) { + ret = PTR_ERR(host->pbias); if (ret != -ENODEV) return ret; - host->pbias = NULL; dev_dbg(host->dev, "unable to get pbias regulator %ld\n", - PTR_ERR(reg)); - } else { - host->pbias = reg; + PTR_ERR(host->pbias)); + host->pbias = NULL; } /* For eMMC do not power off when not in sleep state */ -- cgit v1.2.3-70-g09d2 From b49069fc0b96de5dd508ccba0a1417e524734712 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:43:56 +0530 Subject: mmc: host: omap_hsmmc: use the ocrmask provided by the vmmc regulator If the vmmc regulator provides a valid ocrmask, use it. By this even if the pdata has a valid ocrmask, it will be overwritten with the ocrmask of the vmmc regulator. Also remove the unnecessary compatibility check between the ocrmask in the pdata and the ocrmask from the vmmc regulator. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 3fde2f9dfb25..30f363da1987 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -359,16 +359,8 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) host->vcc = NULL; } else { ocr_value = mmc_regulator_get_ocrmask(host->vcc); - if (!mmc_pdata(host)->ocr_mask) { + if (ocr_value > 0) mmc_pdata(host)->ocr_mask = ocr_value; - } else { - if (!(mmc_pdata(host)->ocr_mask & ocr_value)) { - dev_err(host->dev, "ocrmask %x is not supported\n", - mmc_pdata(host)->ocr_mask); - mmc_pdata(host)->ocr_mask = 0; - return -EINVAL; - } - } } /* Allow an aux regulator */ -- cgit v1.2.3-70-g09d2 From aa9a68014bb6c6e1052d79561815885b797d15ea Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:43:57 +0530 Subject: mmc: host: omap_hsmmc: use mmc_host's vmmc and vqmmc No functional change. Instead of using omap_hsmmc_host's vcc and vcc_aux members, use vmmc and vqmmc present in mmc_host which is present for the same purpose. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Roger Quadros Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 63 +++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 35 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 30f363da1987..58e4ffd3c70e 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -181,15 +181,6 @@ struct omap_hsmmc_host { struct mmc_data *data; struct clk *fclk; struct clk *dbclk; - /* - * vcc == configured supply - * vcc_aux == optional - * - MMC1, supply for DAT4..DAT7 - * - MMC2/MMC2, external level shifter voltage supply, for - * chip (SDIO, eMMC, etc) or transceiver (MMC2 only) - */ - struct regulator *vcc; - struct regulator *vcc_aux; struct regulator *pbias; bool pbias_enabled; void __iomem *base; @@ -259,6 +250,7 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) { struct omap_hsmmc_host *host = platform_get_drvdata(to_platform_device(dev)); + struct mmc_host *mmc = host->mmc; int ret = 0; if (mmc_pdata(host)->set_power) @@ -268,7 +260,7 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) * If we don't see a Vcc regulator, assume it's a fixed * voltage always-on regulator. */ - if (!host->vcc) + if (!mmc->supply.vmmc) return 0; if (mmc_pdata(host)->before_set_reg) @@ -297,23 +289,23 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) * chips/cards need an interface voltage rail too. */ if (power_on) { - if (host->vcc) - ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); + if (mmc->supply.vmmc) + ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); /* Enable interface voltage rail, if needed */ - if (ret == 0 && host->vcc_aux) { - ret = regulator_enable(host->vcc_aux); - if (ret < 0 && host->vcc) - ret = mmc_regulator_set_ocr(host->mmc, - host->vcc, 0); + if (ret == 0 && mmc->supply.vqmmc) { + ret = regulator_enable(mmc->supply.vqmmc); + if (ret < 0 && mmc->supply.vmmc) + ret = mmc_regulator_set_ocr(mmc, + mmc->supply.vmmc, + 0); } } else { /* Shut down the rail */ - if (host->vcc_aux) - ret = regulator_disable(host->vcc_aux); - if (host->vcc) { + if (mmc->supply.vqmmc) + ret = regulator_disable(mmc->supply.vqmmc); + if (mmc->supply.vmmc) { /* Then proceed to shut down the local regulator */ - ret = mmc_regulator_set_ocr(host->mmc, - host->vcc, 0); + ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); } } @@ -345,33 +337,34 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) { int ocr_value = 0; int ret; + struct mmc_host *mmc = host->mmc; if (mmc_pdata(host)->set_power) return 0; - host->vcc = devm_regulator_get_optional(host->dev, "vmmc"); - if (IS_ERR(host->vcc)) { - ret = PTR_ERR(host->vcc); + mmc->supply.vmmc = devm_regulator_get_optional(host->dev, "vmmc"); + if (IS_ERR(mmc->supply.vmmc)) { + ret = PTR_ERR(mmc->supply.vmmc); if (ret != -ENODEV) return ret; dev_dbg(host->dev, "unable to get vmmc regulator %ld\n", - PTR_ERR(host->vcc)); - host->vcc = NULL; + PTR_ERR(mmc->supply.vmmc)); + mmc->supply.vmmc = NULL; } else { - ocr_value = mmc_regulator_get_ocrmask(host->vcc); + ocr_value = mmc_regulator_get_ocrmask(mmc->supply.vmmc); if (ocr_value > 0) mmc_pdata(host)->ocr_mask = ocr_value; } /* Allow an aux regulator */ - host->vcc_aux = devm_regulator_get_optional(host->dev, "vmmc_aux"); - if (IS_ERR(host->vcc_aux)) { - ret = PTR_ERR(host->vcc_aux); + mmc->supply.vqmmc = devm_regulator_get_optional(host->dev, "vmmc_aux"); + if (IS_ERR(mmc->supply.vqmmc)) { + ret = PTR_ERR(mmc->supply.vqmmc); if (ret != -ENODEV) return ret; dev_dbg(host->dev, "unable to get vmmc_aux regulator %ld\n", - PTR_ERR(host->vcc_aux)); - host->vcc_aux = NULL; + PTR_ERR(mmc->supply.vqmmc)); + mmc->supply.vqmmc = NULL; } host->pbias = devm_regulator_get_optional(host->dev, "pbias"); @@ -391,8 +384,8 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) * To disable boot_on regulator, enable regulator * to increase usecount and then disable it. */ - if ((host->vcc && regulator_is_enabled(host->vcc) > 0) || - (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) { + if ((mmc->supply.vmmc && regulator_is_enabled(mmc->supply.vmmc) > 0) || + (mmc->supply.vqmmc && regulator_is_enabled(mmc->supply.vqmmc))) { int vdd = ffs(mmc_pdata(host)->ocr_mask) - 1; omap_hsmmc_set_power(host->dev, 1, vdd); -- cgit v1.2.3-70-g09d2 From ef62b8bc2c740a7f72525a4797aa45056c833e3d Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:43:58 +0530 Subject: mmc: host: omap_hsmmc: remove unnecessary pbias set_voltage Remove the unnecessary pbias regulator_set_voltage done after pbias regulator_disable in omap_hsmmc_set_power. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Roger Quadros Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 58e4ffd3c70e..c4c284e0246a 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -272,7 +272,6 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) if (!ret) host->pbias_enabled = 0; } - regulator_set_voltage(host->pbias, VDD_3V0, VDD_3V0); } /* -- cgit v1.2.3-70-g09d2 From 229f329265d6d2a738fc861b7b9b6144980580f6 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:43:59 +0530 Subject: mmc: host: omap_hsmmc: return error if any of the regulator APIs fail Return error if any of the regulator APIs (regulator_enable, regulator_disable, regulator_set_voltage) fails in omap_hsmmc_set_power to avoid undefined behavior. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 52 +++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 12 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index c4c284e0246a..284ab0063156 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -269,8 +269,11 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) if (host->pbias) { if (host->pbias_enabled == 1) { ret = regulator_disable(host->pbias); - if (!ret) - host->pbias_enabled = 0; + if (ret) { + dev_err(dev, "pbias reg disable failed\n"); + return ret; + } + host->pbias_enabled = 0; } } @@ -288,23 +291,35 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) * chips/cards need an interface voltage rail too. */ if (power_on) { - if (mmc->supply.vmmc) + if (mmc->supply.vmmc) { ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); + if (ret) + return ret; + } + /* Enable interface voltage rail, if needed */ - if (ret == 0 && mmc->supply.vqmmc) { + if (mmc->supply.vqmmc) { ret = regulator_enable(mmc->supply.vqmmc); - if (ret < 0 && mmc->supply.vmmc) - ret = mmc_regulator_set_ocr(mmc, - mmc->supply.vmmc, - 0); + if (ret) { + dev_err(dev, "vmmc_aux reg enable failed\n"); + goto err_set_vqmmc; + } } } else { /* Shut down the rail */ - if (mmc->supply.vqmmc) + if (mmc->supply.vqmmc) { ret = regulator_disable(mmc->supply.vqmmc); + if (ret) { + dev_err(dev, "vmmc_aux reg disable failed\n"); + return ret; + } + } + if (mmc->supply.vmmc) { /* Then proceed to shut down the local regulator */ ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + if (ret) + return ret; } } @@ -316,19 +331,32 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) ret = regulator_set_voltage(host->pbias, VDD_3V0, VDD_3V0); if (ret < 0) - goto error_set_power; + goto err_set_voltage; if (host->pbias_enabled == 0) { ret = regulator_enable(host->pbias); - if (!ret) + if (ret) { + dev_err(dev, "pbias reg enable failed\n"); + goto err_set_voltage; + } else { host->pbias_enabled = 1; + } } } if (mmc_pdata(host)->after_set_reg) mmc_pdata(host)->after_set_reg(dev, power_on, vdd); -error_set_power: + return 0; + +err_set_voltage: + if (mmc->supply.vqmmc) + regulator_disable(mmc->supply.vqmmc); + +err_set_vqmmc: + if (mmc->supply.vmmc) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + return ret; } -- cgit v1.2.3-70-g09d2 From 2a17f84442e22cd1522400fcc0356c4a36b38361 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:44:00 +0530 Subject: mmc: host: omap_hsmmc: add separate functions for enable/disable supply No functional change. Cleanup omap_hsmmc_set_power by adding separate functions for enable/disable supply and invoke it from omap_hsmmc_set_power. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 101 +++++++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 35 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 284ab0063156..3fa78d477a41 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -246,6 +246,65 @@ static int omap_hsmmc_get_cover_state(struct device *dev) #ifdef CONFIG_REGULATOR +static int omap_hsmmc_enable_supply(struct mmc_host *mmc, int vdd) +{ + int ret; + + if (mmc->supply.vmmc) { + ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); + if (ret) + return ret; + } + + /* Enable interface voltage rail, if needed */ + if (mmc->supply.vqmmc) { + ret = regulator_enable(mmc->supply.vqmmc); + if (ret) { + dev_err(mmc_dev(mmc), "vmmc_aux reg enable failed\n"); + goto err_vqmmc; + } + } + + return 0; + +err_vqmmc: + if (mmc->supply.vmmc) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + + return ret; +} + +static int omap_hsmmc_disable_supply(struct mmc_host *mmc) +{ + int ret; + int status; + + if (mmc->supply.vqmmc) { + ret = regulator_disable(mmc->supply.vqmmc); + if (ret) { + dev_err(mmc_dev(mmc), "vmmc_aux reg disable failed\n"); + return ret; + } + } + + if (mmc->supply.vmmc) { + ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + if (ret) + goto err_set_ocr; + } + + return 0; + +err_set_ocr: + if (mmc->supply.vqmmc) { + status = regulator_enable(mmc->supply.vqmmc); + if (status) + dev_err(mmc_dev(mmc), "vmmc_aux re-enable failed\n"); + } + + return ret; +} + static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) { struct omap_hsmmc_host *host = @@ -291,36 +350,13 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) * chips/cards need an interface voltage rail too. */ if (power_on) { - if (mmc->supply.vmmc) { - ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); - if (ret) - return ret; - } - - /* Enable interface voltage rail, if needed */ - if (mmc->supply.vqmmc) { - ret = regulator_enable(mmc->supply.vqmmc); - if (ret) { - dev_err(dev, "vmmc_aux reg enable failed\n"); - goto err_set_vqmmc; - } - } + ret = omap_hsmmc_enable_supply(mmc, vdd); + if (ret) + return ret; } else { - /* Shut down the rail */ - if (mmc->supply.vqmmc) { - ret = regulator_disable(mmc->supply.vqmmc); - if (ret) { - dev_err(dev, "vmmc_aux reg disable failed\n"); - return ret; - } - } - - if (mmc->supply.vmmc) { - /* Then proceed to shut down the local regulator */ - ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); - if (ret) - return ret; - } + ret = omap_hsmmc_disable_supply(mmc); + if (ret) + return ret; } if (host->pbias) { @@ -350,12 +386,7 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) return 0; err_set_voltage: - if (mmc->supply.vqmmc) - regulator_disable(mmc->supply.vqmmc); - -err_set_vqmmc: - if (mmc->supply.vmmc) - mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + omap_hsmmc_disable_supply(mmc); return ret; } -- cgit v1.2.3-70-g09d2 From ec85c95e8ce5df18608ee9aa6a2626d903f548af Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:44:01 +0530 Subject: mmc: host: omap_hsmmc: add separate function to set pbias No functional change. Cleanup omap_hsmmc_set_power by adding separate functions to set pbias and invoke it from omap_hsmmc_set_power. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 78 ++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 30 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 3fa78d477a41..810d612f58a0 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -305,6 +305,48 @@ err_set_ocr: return ret; } +static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on, + int vdd) +{ + int ret; + + if (!host->pbias) + return 0; + + if (power_on) { + if (vdd <= VDD_165_195) + ret = regulator_set_voltage(host->pbias, VDD_1V8, + VDD_1V8); + else + ret = regulator_set_voltage(host->pbias, VDD_3V0, + VDD_3V0); + if (ret < 0) { + dev_err(host->dev, "pbias set voltage fail\n"); + return ret; + } + + if (host->pbias_enabled == 0) { + ret = regulator_enable(host->pbias); + if (ret) { + dev_err(host->dev, "pbias reg enable fail\n"); + return ret; + } + host->pbias_enabled = 1; + } + } else { + if (host->pbias_enabled == 1) { + ret = regulator_disable(host->pbias); + if (ret) { + dev_err(host->dev, "pbias reg disable fail\n"); + return ret; + } + host->pbias_enabled = 0; + } + } + + return 0; +} + static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) { struct omap_hsmmc_host *host = @@ -325,16 +367,9 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) if (mmc_pdata(host)->before_set_reg) mmc_pdata(host)->before_set_reg(dev, power_on, vdd); - if (host->pbias) { - if (host->pbias_enabled == 1) { - ret = regulator_disable(host->pbias); - if (ret) { - dev_err(dev, "pbias reg disable failed\n"); - return ret; - } - host->pbias_enabled = 0; - } - } + ret = omap_hsmmc_set_pbias(host, false, 0); + if (ret) + return ret; /* * Assume Vcc regulator is used only to power the card ... OMAP @@ -359,26 +394,9 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) return ret; } - if (host->pbias) { - if (vdd <= VDD_165_195) - ret = regulator_set_voltage(host->pbias, VDD_1V8, - VDD_1V8); - else - ret = regulator_set_voltage(host->pbias, VDD_3V0, - VDD_3V0); - if (ret < 0) - goto err_set_voltage; - - if (host->pbias_enabled == 0) { - ret = regulator_enable(host->pbias); - if (ret) { - dev_err(dev, "pbias reg enable failed\n"); - goto err_set_voltage; - } else { - host->pbias_enabled = 1; - } - } - } + ret = omap_hsmmc_set_pbias(host, true, vdd); + if (ret) + goto err_set_voltage; if (mmc_pdata(host)->after_set_reg) mmc_pdata(host)->after_set_reg(dev, power_on, vdd); -- cgit v1.2.3-70-g09d2 From 97fe7e5ab6318ea5716f86be3b4ca8776a9e609c Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:44:02 +0530 Subject: mmc: host: omap_hsmmc: avoid pbias regulator enable on power off Fix omap_hsmmc_set_power so that pbias regulator is not enabled during power off. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 810d612f58a0..eec69752a189 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -388,16 +388,16 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) ret = omap_hsmmc_enable_supply(mmc, vdd); if (ret) return ret; + + ret = omap_hsmmc_set_pbias(host, true, vdd); + if (ret) + goto err_set_voltage; } else { ret = omap_hsmmc_disable_supply(mmc); if (ret) return ret; } - ret = omap_hsmmc_set_pbias(host, true, vdd); - if (ret) - goto err_set_voltage; - if (mmc_pdata(host)->after_set_reg) mmc_pdata(host)->after_set_reg(dev, power_on, vdd); -- cgit v1.2.3-70-g09d2 From c8518efa6de999bcbd638702c2a2d72fe83431e4 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:44:03 +0530 Subject: mmc: host: omap_hsmmc: don't use ->set_power to set initial regulator state If the regulator is enabled on boot (checked using regulator_is_enabled), invoke regulator_enable() so that the usecount reflects the correct state of the regulator and then disable the regulator so that the initial state of the regulator is disabled. Avoid using ->set_power, since set_power also takes care of setting the voltages which is not needed at this point. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 66 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 10 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index eec69752a189..cd4bd6d4c71e 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -409,6 +409,59 @@ err_set_voltage: return ret; } +static int omap_hsmmc_disable_boot_regulator(struct regulator *reg) +{ + int ret; + + if (!reg) + return 0; + + if (regulator_is_enabled(reg)) { + ret = regulator_enable(reg); + if (ret) + return ret; + + ret = regulator_disable(reg); + if (ret) + return ret; + } + + return 0; +} + +static int omap_hsmmc_disable_boot_regulators(struct omap_hsmmc_host *host) +{ + struct mmc_host *mmc = host->mmc; + int ret; + + /* + * disable regulators enabled during boot and get the usecount + * right so that regulators can be enabled/disabled by checking + * the return value of regulator_is_enabled + */ + ret = omap_hsmmc_disable_boot_regulator(mmc->supply.vmmc); + if (ret) { + dev_err(host->dev, "fail to disable boot enabled vmmc reg\n"); + return ret; + } + + ret = omap_hsmmc_disable_boot_regulator(mmc->supply.vqmmc); + if (ret) { + dev_err(host->dev, + "fail to disable boot enabled vmmc_aux reg\n"); + return ret; + } + + ret = omap_hsmmc_disable_boot_regulator(host->pbias); + if (ret) { + dev_err(host->dev, + "failed to disable boot enabled pbias reg\n"); + return ret; + } + + return 0; +} + static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) { int ocr_value = 0; @@ -456,17 +509,10 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) /* For eMMC do not power off when not in sleep state */ if (mmc_pdata(host)->no_regulator_off_init) return 0; - /* - * To disable boot_on regulator, enable regulator - * to increase usecount and then disable it. - */ - if ((mmc->supply.vmmc && regulator_is_enabled(mmc->supply.vmmc) > 0) || - (mmc->supply.vqmmc && regulator_is_enabled(mmc->supply.vqmmc))) { - int vdd = ffs(mmc_pdata(host)->ocr_mask) - 1; - omap_hsmmc_set_power(host->dev, 1, vdd); - omap_hsmmc_set_power(host->dev, 0, 0); - } + ret = omap_hsmmc_disable_boot_regulators(host); + if (ret) + return ret; return 0; } -- cgit v1.2.3-70-g09d2 From 3f77f702389b7fbc955ec95721ce3861e40697fc Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:44:04 +0530 Subject: mmc: host: omap_hsmmc: enable/disable vmmc_aux regulator based on previous state enable vmmc_aux regulator only if it is in disabled state and disable vmmc_aux regulator only if it is in enabled state. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index cd4bd6d4c71e..5a5946a7f2df 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -184,6 +184,7 @@ struct omap_hsmmc_host { struct regulator *pbias; bool pbias_enabled; void __iomem *base; + int vqmmc_enabled; resource_size_t mapbase; spinlock_t irq_lock; /* Prevent races with irq handler */ unsigned int dma_len; @@ -249,6 +250,7 @@ static int omap_hsmmc_get_cover_state(struct device *dev) static int omap_hsmmc_enable_supply(struct mmc_host *mmc, int vdd) { int ret; + struct omap_hsmmc_host *host = mmc_priv(mmc); if (mmc->supply.vmmc) { ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); @@ -257,12 +259,13 @@ static int omap_hsmmc_enable_supply(struct mmc_host *mmc, int vdd) } /* Enable interface voltage rail, if needed */ - if (mmc->supply.vqmmc) { + if (mmc->supply.vqmmc && !host->vqmmc_enabled) { ret = regulator_enable(mmc->supply.vqmmc); if (ret) { dev_err(mmc_dev(mmc), "vmmc_aux reg enable failed\n"); goto err_vqmmc; } + host->vqmmc_enabled = 1; } return 0; @@ -278,13 +281,15 @@ static int omap_hsmmc_disable_supply(struct mmc_host *mmc) { int ret; int status; + struct omap_hsmmc_host *host = mmc_priv(mmc); - if (mmc->supply.vqmmc) { + if (mmc->supply.vqmmc && host->vqmmc_enabled) { ret = regulator_disable(mmc->supply.vqmmc); if (ret) { dev_err(mmc_dev(mmc), "vmmc_aux reg disable failed\n"); return ret; } + host->vqmmc_enabled = 0; } if (mmc->supply.vmmc) { @@ -2077,6 +2082,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) host->power_mode = MMC_POWER_OFF; host->next_data.cookie = 1; host->pbias_enabled = 0; + host->vqmmc_enabled = 0; ret = omap_hsmmc_gpio_init(mmc, host, pdata); if (ret) -- cgit v1.2.3-70-g09d2 From c55d7a0553643a7e8f120688b82b594471084d3c Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:44:05 +0530 Subject: mmc: host: omap_hsmmc: use regulator_is_enabled to find pbias status Use regulator_is_enabled of pbias regulator to find pbias regulator status instead of maintaining a custom bookkeeping pbias_enabled variable. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 5a5946a7f2df..4cd7a5805de8 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -182,7 +182,6 @@ struct omap_hsmmc_host { struct clk *fclk; struct clk *dbclk; struct regulator *pbias; - bool pbias_enabled; void __iomem *base; int vqmmc_enabled; resource_size_t mapbase; @@ -330,22 +329,20 @@ static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on, return ret; } - if (host->pbias_enabled == 0) { + if (!regulator_is_enabled(host->pbias)) { ret = regulator_enable(host->pbias); if (ret) { dev_err(host->dev, "pbias reg enable fail\n"); return ret; } - host->pbias_enabled = 1; } } else { - if (host->pbias_enabled == 1) { + if (regulator_is_enabled(host->pbias)) { ret = regulator_disable(host->pbias); if (ret) { dev_err(host->dev, "pbias reg disable fail\n"); return ret; } - host->pbias_enabled = 0; } } @@ -2081,7 +2078,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) host->base = base + pdata->reg_offset; host->power_mode = MMC_POWER_OFF; host->next_data.cookie = 1; - host->pbias_enabled = 0; host->vqmmc_enabled = 0; ret = omap_hsmmc_gpio_init(mmc, host, pdata); -- cgit v1.2.3-70-g09d2 From 1d17f30bd87bf4857478b2a68dadf0096ca1cb40 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:44:06 +0530 Subject: mmc: host: omap_hsmmc: use ios->vdd for setting vmmc voltage vdd voltage is set in mmc core to ios->vdd and vmmc should actually be set to this voltage. Modify omap_hsmmc_enable_supply to not take vdd as argument since now it's directly set to the voltage in ios->vdd. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 4cd7a5805de8..58683b3c55b6 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -246,13 +246,14 @@ static int omap_hsmmc_get_cover_state(struct device *dev) #ifdef CONFIG_REGULATOR -static int omap_hsmmc_enable_supply(struct mmc_host *mmc, int vdd) +static int omap_hsmmc_enable_supply(struct mmc_host *mmc) { int ret; struct omap_hsmmc_host *host = mmc_priv(mmc); + struct mmc_ios *ios = &mmc->ios; if (mmc->supply.vmmc) { - ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); + ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); if (ret) return ret; } @@ -387,7 +388,7 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) * chips/cards need an interface voltage rail too. */ if (power_on) { - ret = omap_hsmmc_enable_supply(mmc, vdd); + ret = omap_hsmmc_enable_supply(mmc); if (ret) return ret; -- cgit v1.2.3-70-g09d2 From 987e05c9c3fbffba81104b8ae9a0dde9c73758e9 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:44:07 +0530 Subject: mmc: host: omap_hsmmc: remove CONFIG_REGULATOR check Now that support for platforms which have optional regulator is added, remove CONFIG_REGULATOR check in omap_hsmmc. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) (limited to 'drivers/mmc/host/omap_hsmmc.c') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 58683b3c55b6..781e4db31767 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -244,8 +244,6 @@ static int omap_hsmmc_get_cover_state(struct device *dev) return mmc_gpio_get_cd(host->mmc); } -#ifdef CONFIG_REGULATOR - static int omap_hsmmc_enable_supply(struct mmc_host *mmc) { int ret; @@ -520,30 +518,6 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) return 0; } -static inline int omap_hsmmc_have_reg(void) -{ - return 1; -} - -#else - -static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) -{ - return 0; -} - -static inline int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) -{ - return -EINVAL; -} - -static inline int omap_hsmmc_have_reg(void) -{ - return 0; -} - -#endif - static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id); static int omap_hsmmc_gpio_init(struct mmc_host *mmc, @@ -2204,11 +2178,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev) goto err_irq; } - if (omap_hsmmc_have_reg()) { - ret = omap_hsmmc_reg_get(host); - if (ret) - goto err_irq; - } + ret = omap_hsmmc_reg_get(host); + if (ret) + goto err_irq; mmc->ocr_avail = mmc_pdata(host)->ocr_mask; -- cgit v1.2.3-70-g09d2