mmc: msm_sdcc: Added hardware reset functionality for SD cards
In error situations, sometimes the card doesn't respond to commands. To recover from such situations, a power-cycle is issued to the card and it is reinitialized. msmsdcc_hw_reset: Defined in mmc host operations 'hw_reset'. This function power-cycles the card. CRs-fixed: 375869 Change-Id: I2b02649ae3befe700a7a2401b93eb69c8014a4ce Signed-off-by: Asutosh Das <asutoshd@codeaurora.org>
This commit is contained in:
committed by
Stephen Boyd
parent
b9100e4b65
commit
3b1258a65e
@@ -2385,8 +2385,10 @@ static int msmsdcc_setup_vreg(struct msmsdcc_host *host, bool enable,
|
||||
struct msm_mmc_reg_data *vreg_table[2];
|
||||
|
||||
curr_slot = host->plat->vreg_data;
|
||||
if (!curr_slot)
|
||||
if (!curr_slot) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
vreg_table[0] = curr_slot->vdd_data;
|
||||
vreg_table[1] = curr_slot->vdd_io_data;
|
||||
@@ -3988,6 +3990,51 @@ exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Work around of the unavailability of a power_reset functionality in SD cards
|
||||
* by turning the OFF & back ON the regulators supplying the SD card.
|
||||
*/
|
||||
void msmsdcc_hw_reset(struct mmc_host *mmc)
|
||||
{
|
||||
struct mmc_card *card = mmc->card;
|
||||
struct msmsdcc_host *host = mmc_priv(mmc);
|
||||
int rc;
|
||||
|
||||
/* Write-protection bits would be lost on a hardware reset in emmc */
|
||||
if (!card || !mmc_card_sd(card))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Continuing on failing to disable regulator would lead to a panic
|
||||
* anyway, since the commands would fail and console would be flooded
|
||||
* with prints, eventually leading to a watchdog bark
|
||||
*/
|
||||
rc = msmsdcc_setup_vreg(host, false, false);
|
||||
if (rc) {
|
||||
pr_err("%s: %s disable regulator: failed: %d\n",
|
||||
mmc_hostname(mmc), __func__, rc);
|
||||
BUG_ON(rc);
|
||||
}
|
||||
|
||||
/* 10ms delay for the supply to reach the desired voltage level */
|
||||
usleep_range(10000, 12000);
|
||||
|
||||
/*
|
||||
* Continuing on failing to enable regulator would lead to a panic
|
||||
* anyway, since the commands would fail and console would be flooded
|
||||
* with prints, eventually leading to a watchdog bark
|
||||
*/
|
||||
rc = msmsdcc_setup_vreg(host, true, false);
|
||||
if (rc) {
|
||||
pr_err("%s: %s enable regulator: failed: %d\n",
|
||||
mmc_hostname(mmc), __func__, rc);
|
||||
BUG_ON(rc);
|
||||
}
|
||||
|
||||
/* 10ms delay for the supply to reach the desired voltage level */
|
||||
usleep_range(10000, 12000);
|
||||
}
|
||||
|
||||
static const struct mmc_host_ops msmsdcc_ops = {
|
||||
.enable = msmsdcc_enable,
|
||||
.disable = msmsdcc_disable,
|
||||
@@ -3998,7 +4045,8 @@ static const struct mmc_host_ops msmsdcc_ops = {
|
||||
.get_ro = msmsdcc_get_ro,
|
||||
.enable_sdio_irq = msmsdcc_enable_sdio_irq,
|
||||
.start_signal_voltage_switch = msmsdcc_switch_io_voltage,
|
||||
.execute_tuning = msmsdcc_execute_tuning
|
||||
.execute_tuning = msmsdcc_execute_tuning,
|
||||
.hw_reset = msmsdcc_hw_reset,
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
@@ -5595,7 +5643,7 @@ msmsdcc_probe(struct platform_device *pdev)
|
||||
mmc->caps |= plat->mmc_bus_width;
|
||||
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
|
||||
mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
|
||||
|
||||
mmc->caps |= MMC_CAP_HW_RESET;
|
||||
/*
|
||||
* If we send the CMD23 before multi block write/read command
|
||||
* then we need not to send CMD12 at the end of the transfer.
|
||||
|
||||
Reference in New Issue
Block a user