mmc: msm_sdcc: reset sd card at boot time

As per sd spec, if a sd card initialized in UHS mode needs to be
reinitialized, then the card should be powered off and then powered
on before proceeding with initialization again. Otherwise the sd
card reports it does not support UHS mode and can't be initialized as
an UHS card.

Currently sd card could be left powered on either because its regulator
is marked as always on or because the sd card was not run-time suspended
at the time of reboot. As a result on reboot, the sd card is not detected
as an UHS card. In order to prevent this the sd card is powered off and
then powered on at boot time.

CRs-fixed: 369644
Change-Id: Ic44fa005a1ac2d59d174b320e5e80dd5323876c3
Signed-off-by: Krishna Konda <kkonda@codeaurora.org>
This commit is contained in:
Krishna Konda 2012-06-27 11:01:56 -07:00 committed by Stephen Boyd
parent c395e1b293
commit dc7422cd01
3 changed files with 39 additions and 12 deletions

View file

@ -51,6 +51,15 @@ struct msm_mmc_reg_data {
bool always_on;
/* is low power mode setting required for this regulator? */
bool lpm_sup;
/*
* Use to indicate if the regulator should be reset at boot time.
* Its needed only when sd card's vdd regulator is always on
* since always on regulators dont get reset at boot time.
*
* It is needed for sd 3.0 card to be detected as a sd 3.0 card
* on device reboot.
*/
bool reset_at_init;
};
/*

View file

@ -66,7 +66,8 @@ static struct msm_mmc_reg_data mmc_vdd_reg_data[MAX_SDCC_CONTROLLER] = {
.lpm_sup = 1,
.hpm_uA = 800000, /* 800mA */
.lpm_uA = 9000,
}
.reset_at_init = true,
},
};
/* All SDCC controllers may require voting for VDD PAD voltage */

View file

@ -2203,7 +2203,7 @@ out:
return rc;
}
static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg, bool is_init)
{
int rc = 0;
@ -2225,17 +2225,33 @@ static int msmsdcc_vreg_disable(struct msm_mmc_reg_data *vreg)
rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
if (rc)
goto out;
} else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
/* Put always_on regulator in LPM (low power mode) */
rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
if (rc < 0)
goto out;
} else if (vreg->is_enabled && vreg->always_on) {
if (!is_init && vreg->lpm_sup) {
/* Put always_on regulator in LPM (low power mode) */
rc = msmsdcc_vreg_set_optimum_mode(vreg, vreg->lpm_uA);
if (rc < 0)
goto out;
} else if (is_init && vreg->reset_at_init) {
/**
* The regulator might not actually be disabled if it
* is shared and in use by other drivers.
*/
rc = regulator_disable(vreg->reg);
if (rc) {
pr_err("%s: regulator_disable(%s) failed at " \
"bootup. rc=%d\n", __func__,
vreg->name, rc);
goto out;
}
vreg->is_enabled = false;
}
}
out:
return rc;
}
static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
bool is_init)
{
int rc = 0, i;
struct msm_mmc_slot_reg_data *curr_slot;
@ -2253,7 +2269,8 @@ static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable)
if (enable)
rc = msmsdcc_vreg_enable(vreg_table[i]);
else
rc = msmsdcc_vreg_disable(vreg_table[i]);
rc = msmsdcc_vreg_disable(vreg_table[i],
is_init);
if (rc)
goto out;
}
@ -2270,10 +2287,10 @@ static int msmsdcc_vreg_reset(struct msmsdcc_host *host)
{
int rc;
rc = msmsdcc_setup_vreg(host, 1);
rc = msmsdcc_setup_vreg(host, 1, true);
if (rc)
return rc;
rc = msmsdcc_setup_vreg(host, 0);
rc = msmsdcc_setup_vreg(host, 0, true);
return rc;
}
@ -2566,7 +2583,7 @@ static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
if (host->plat->translate_vdd && !host->sdio_gpio_lpm)
ret = host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
else if (!host->plat->translate_vdd && !host->sdio_gpio_lpm)
ret = msmsdcc_setup_vreg(host, !!ios->vdd);
ret = msmsdcc_setup_vreg(host, !!ios->vdd, false);
if (ret) {
pr_err("%s: Failed to setup voltage regulators\n",