On Fri 22 May 06:27 PDT 2020, Veerabhadrarao Badiganti wrote:Thanks for the details Bjorn.
Hi Bjorn,You call regulator_enable(vqmmc) and regulator_disable() below, so you
On 5/22/2020 12:37 AM, Bjorn Andersson wrote:
On Thu 21 May 08:23 PDT 2020, Veerabhadrarao Badiganti wrote:<Merging your comment from V1 here>
On qcom SD host controllers voltage switching be done after the HWLooks better, thanks.
is ready for it. The HW informs its readiness through power irq.
The voltage switching should happen only then.
Use the internal voltage switching and then control the voltage
switching using power irq.
Set the regulator load as well so that regulator can be configured
in LPM mode when in is not being used.
Co-developed-by: Asutosh Das <asutoshd@xxxxxxxxxxxxxx>
Signed-off-by: Asutosh Das <asutoshd@xxxxxxxxxxxxxx>
Co-developed-by: Vijay Viswanath <vviswana@xxxxxxxxxxxxxx>
Signed-off-by: Vijay Viswanath <vviswana@xxxxxxxxxxxxxx>
Co-developed-by: Veerabhadrarao Badiganti <vbadigan@xxxxxxxxxxxxxx>
Signed-off-by: Veerabhadrarao Badiganti <vbadigan@xxxxxxxxxxxxxx>
---[..]
drivers/mmc/host/sdhci-msm.c | 207 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 198 insertions(+), 9 deletions(-)
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host)Missed this one on v1, in the event that mmc_regulator_set_ocr() return
@@ -1298,6 +1302,71 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
sdhci_msm_hs400(host, &mmc->ios);
}
+static int sdhci_msm_set_vmmc(struct mmc_host *mmc)
+{
+ int ret;
+
+ if (IS_ERR(mmc->supply.vmmc))
+ return 0;
+
+ ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, mmc->ios.vdd);
+ if (ret)
+ dev_err(mmc_dev(mmc), "%s: vmmc set ocr with vdd=%d failed: %d\n",
+ mmc_hostname(mmc), mmc->ios.vdd, ret);
a non-zero value it has already printed an error message. So please
replace the tail with just:
return mmc_regulator_set_ocr(...);
+Sorry for the late reply on v1, but please see my explanation regarding
+ return ret;
+}
+
+static int sdhci_msm_set_vqmmc(struct sdhci_msm_host *msm_host,
+ struct mmc_host *mmc, bool level)
+{
+ int load, ret;
+ struct mmc_ios ios;
+
+ if (IS_ERR(mmc->supply.vqmmc) ||
+ (mmc->ios.power_mode == MMC_POWER_UNDEFINED) ||
+ (msm_host->vqmmc_enabled == level))
+ return 0;
+
+ if (msm_host->vqmmc_load) {
+ load = level ? msm_host->vqmmc_load : 0;
+ ret = regulator_set_load(mmc->supply.vqmmc, load);
load and always-on regulators there.
Since I'm not turning off this regulator for eMMC, I wanted to keep it inYou should still call regulator_enable()/regulator_disable() on your
consumer regulator in this driver. When you do this the regulator core
will conclude that the regulator_dev (i.e. the part that represents the
hardware) is marked always_on and will not enable/disable the regulator.
But it will still invoke _regulator_handle_consumer_enable() and
_regulator_handle_consumer_disable(), which will aggregate the "load" of
all client regulators and update the regulator's load.
So this will apply the load as you expect regardless of it being
supplied by a regulator marked as always_on.
LPM mode
to save some power.
When the regulator configured in auto mode (RPMH_REGULATOR_MODE_AUTO) it
switches to LPM/HPM mode based on the active load.
So i have to minimize my driver load requirement so that I can let this
regulator
in LPM mode.
So i need to set load every-time I disable/enable the regulator.
are telling the regulator framework that your struct regulator should be
"on" or "off".
This will cause the sum of all struct regulator's for the underlying
struct regulator_dev to be recalculated. So after calling
regulator_disable() below your effective addition to the load
calculation is 0, regardless of which load you have specified.
Independent of this the property regulator-always-on (always_on in
struct regulator_dev) will determine if the enable/disable request will
actually be sent to the RPMh.
So, if you where to not call regulator_disable() for eMMC your argument
is correct, but as far as I can see you are and you're relying on the
regulator core to keep it always-on - and then the load logic is in
effect still.
Regards,
Bjorn
+ if (ret) {
+ dev_err(mmc_dev(mmc), "%s: vqmmc set load failed: %d\n",
+ mmc_hostname(mmc), ret);
+ goto out;
+ }
+ }
+
+ if (level) {
+ /* Set the IO voltage regulator to default voltage level */
+ if (msm_host->caps_0 & CORE_3_0V_SUPPORT)
+ ios.signal_voltage = MMC_SIGNAL_VOLTAGE_330;
+ else if (msm_host->caps_0 & CORE_1_8V_SUPPORT)
+ ios.signal_voltage = MMC_SIGNAL_VOLTAGE_180;
+
+ if (msm_host->caps_0 & CORE_VOLT_SUPPORT) {
+ ret = mmc_regulator_set_vqmmc(mmc, &ios);
+ if (ret < 0) {
+ dev_err(mmc_dev(mmc), "%s: vqmmc set volgate failed: %d\n",
+ mmc_hostname(mmc), ret);
+ goto out;
+ }
+ }
+ ret = regulator_enable(mmc->supply.vqmmc);
+ } else {
+ ret = regulator_disable(mmc->supply.vqmmc);
+ }
+
+ if (ret)
+ dev_err(mmc_dev(mmc), "%s: vqmm %sable failed: %d\n",
+ mmc_hostname(mmc), level ? "en":"dis", ret);
+ else
+ msm_host->vqmmc_enabled = level;
+out:
+ return ret;
+}