From 6af9e96e052a6d1a760c60cb340c5a6584cb92db Mon Sep 17 00:00:00 2001 From: Venkatraman S Date: Fri, 22 Jun 2012 11:42:36 +0530 Subject: mmc: core: Fix the HPI execution sequence mmc_execute_hpi should send the HPI command only once, and only if the card is in PRG state. According to eMMC spec, the command's completion time is not dependent on OUT_OF_INTERRUPT_TIME. Only the transition out of PRG STATE is guarded by OUT_OF_INTERRUPT_TIME - which is defined to begin at the end of sending the command itself. Specify the default timeout for the actual sending of HPI command, and then use OUT_OF_INTERRUPT_TIME to wait for the transition out of PRG state. Reported-by: Alex Lemberg Signed-off-by: Venkatraman S Reviewed-by: Namjae Jeon Reviewed-by: Subhash Jadavani Acked-by: Jaehoon Chung Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 55 ++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 23 deletions(-) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 0b6141d29dbd..a7e2c4b2f18c 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -404,6 +404,7 @@ int mmc_interrupt_hpi(struct mmc_card *card) { int err; u32 status; + unsigned long prg_wait; BUG_ON(!card); @@ -419,30 +420,38 @@ int mmc_interrupt_hpi(struct mmc_card *card) goto out; } - /* - * If the card status is in PRG-state, we can send the HPI command. - */ - if (R1_CURRENT_STATE(status) == R1_STATE_PRG) { - do { - /* - * We don't know when the HPI command will finish - * processing, so we need to resend HPI until out - * of prg-state, and keep checking the card status - * with SEND_STATUS. If a timeout error occurs when - * sending the HPI command, we are already out of - * prg-state. - */ - err = mmc_send_hpi_cmd(card, &status); - if (err) - pr_debug("%s: abort HPI (%d error)\n", - mmc_hostname(card->host), err); + switch (R1_CURRENT_STATE(status)) { + case R1_STATE_IDLE: + case R1_STATE_READY: + case R1_STATE_STBY: + /* + * In idle states, HPI is not needed and the caller + * can issue the next intended command immediately + */ + goto out; + case R1_STATE_PRG: + break; + default: + /* In all other states, it's illegal to issue HPI */ + pr_debug("%s: HPI cannot be sent. Card state=%d\n", + mmc_hostname(card->host), R1_CURRENT_STATE(status)); + err = -EINVAL; + goto out; + } - err = mmc_send_status(card, &status); - if (err) - break; - } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); - } else - pr_debug("%s: Left prg-state\n", mmc_hostname(card->host)); + err = mmc_send_hpi_cmd(card, &status); + if (err) + goto out; + + prg_wait = jiffies + msecs_to_jiffies(card->ext_csd.out_of_int_time); + do { + err = mmc_send_status(card, &status); + + if (!err && R1_CURRENT_STATE(status) == R1_STATE_TRAN) + break; + if (time_after(jiffies, prg_wait)) + err = -ETIMEDOUT; + } while (!err); out: mmc_release_host(card->host); -- cgit v1.2.3 From 45a6b32e24003d9749d8c6d1c83dfb64d6994ca7 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Mon, 11 Jun 2012 09:39:12 -0400 Subject: mmc: core: Export regulator_* functions as GPL The regulator API functions we're wrapping are exported as GPL, so our wrappers for the same functions should be too. Reported-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index a7e2c4b2f18c..28b1ffaf0bd1 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -950,7 +950,7 @@ int mmc_regulator_get_ocrmask(struct regulator *supply) return result; } -EXPORT_SYMBOL(mmc_regulator_get_ocrmask); +EXPORT_SYMBOL_GPL(mmc_regulator_get_ocrmask); /** * mmc_regulator_set_ocr - set regulator to match host->ios voltage @@ -1020,7 +1020,7 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc, "could not set regulator OCR (%d)\n", result); return result; } -EXPORT_SYMBOL(mmc_regulator_set_ocr); +EXPORT_SYMBOL_GPL(mmc_regulator_set_ocr); #endif /* CONFIG_REGULATOR */ -- cgit v1.2.3 From e137788dd115dd9d21759a768dba5fff9685e587 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 20 Jun 2012 02:28:43 -0400 Subject: mmc: add a function to get regulators, supplying card's power Add a function to get regulators, supplying card's Vdd and Vccq on a specific host. If a Vdd supplying regulator is found, the function checks, whether a valid OCR mask can be obtained from it. The Vccq regulator is optional. A failure to get it is not fatal. Signed-off-by: Guennadi Liakhovetski Reviwed-by: Mark Brown Acked-by: Ulf Hansson Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 23 +++++++++++++++++++++++ include/linux/mmc/host.h | 16 ++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 28b1ffaf0bd1..8d00aef9523e 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1022,6 +1022,29 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc, } EXPORT_SYMBOL_GPL(mmc_regulator_set_ocr); +int mmc_regulator_get_supply(struct mmc_host *mmc) +{ + struct device *dev = mmc_dev(mmc); + struct regulator *supply; + int ret; + + supply = devm_regulator_get(dev, "vmmc"); + mmc->supply.vmmc = supply; + mmc->supply.vqmmc = devm_regulator_get(dev, "vqmmc"); + + if (IS_ERR(supply)) + return PTR_ERR(supply); + + ret = mmc_regulator_get_ocrmask(supply); + if (ret > 0) + mmc->ocr_avail = ret; + else + dev_warn(mmc_dev(mmc), "Failed getting OCR mask: %d\n", ret); + + return 0; +} +EXPORT_SYMBOL_GPL(mmc_regulator_get_supply); + #endif /* CONFIG_REGULATOR */ /* diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 0707d228d7f1..9deb725799e7 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -155,6 +155,13 @@ struct mmc_hotplug { void *handler_priv; }; +struct regulator; + +struct mmc_supply { + struct regulator *vmmc; /* Card power supply */ + struct regulator *vqmmc; /* Optional Vccq supply */ +}; + struct mmc_host { struct device *parent; struct device class_dev; @@ -309,6 +316,7 @@ struct mmc_host { #ifdef CONFIG_REGULATOR bool regulator_enabled; /* regulator state */ #endif + struct mmc_supply supply; struct dentry *debugfs_root; @@ -357,13 +365,12 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host) wake_up_process(host->sdio_irq_thread); } -struct regulator; - #ifdef CONFIG_REGULATOR int mmc_regulator_get_ocrmask(struct regulator *supply); int mmc_regulator_set_ocr(struct mmc_host *mmc, struct regulator *supply, unsigned short vdd_bit); +int mmc_regulator_get_supply(struct mmc_host *mmc); #else static inline int mmc_regulator_get_ocrmask(struct regulator *supply) { @@ -376,6 +383,11 @@ static inline int mmc_regulator_set_ocr(struct mmc_host *mmc, { return 0; } + +static inline int mmc_regulator_get_supply(struct mmc_host *mmc) +{ + return 0; +} #endif int mmc_card_awake(struct mmc_host *host); -- cgit v1.2.3 From d9adcc12860d76cf3401c6ab7c0406b15b356b7a Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 14 Jun 2012 10:17:39 +0200 Subject: mmc: prohibit card detection when host is not ready Currently mmc host drivers have to decide whether to enable card detection before calling mmc_add_host() -- in which case a card insertion event can arrive before the host has been completely initialised -- or after mmc_add_host(), in which case the initial card detection can be problematic. This patch adds an explicit indication of when card detection should not be carried out. With it in place enabling card detection before calling mmc_add_host() should be safe. Similarly, disabling it again after calling mmc_remove_host() will avoid any races. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 2 ++ drivers/mmc/core/host.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 8d00aef9523e..9503cabc96f1 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2107,6 +2107,7 @@ void mmc_rescan(struct work_struct *work) void mmc_start_host(struct mmc_host *host) { host->f_init = max(freqs[0], host->f_min); + host->rescan_disable = 0; mmc_power_up(host); mmc_detect_change(host, 0); } @@ -2120,6 +2121,7 @@ void mmc_stop_host(struct mmc_host *host) spin_unlock_irqrestore(&host->lock, flags); #endif + host->rescan_disable = 1; cancel_delayed_work_sync(&host->detect); mmc_flush_scheduled_work(); diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 74cf29a504f4..597f189b4427 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -313,6 +313,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) if (!host) return NULL; + /* scanning will be enabled when we're ready */ + host->rescan_disable = 1; spin_lock(&mmc_host_lock); err = idr_get_new(&mmc_host_idr, host, &host->index); spin_unlock(&mmc_host_lock); -- cgit v1.2.3 From 108ecc4cf9c46a4caabaf18efc42d19818c95b70 Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Tue, 10 Jul 2012 16:55:37 +0800 Subject: mmc: core: reset signal voltage on power up Add a call to mmc_set_signal_voltage() to set signal voltage to 3.3v in mmc_power_up so that we do not need to touch signal voltage setting in mmc/sd/sdio init functions and rescan function. For mmc/sd cards, when doing a suspend/resume cycle, consider the unsafe resume case, the card will lose its power and when powered on again, we will set signal voltage to 3.3v in mmc_power_up before its resume function gets called, which will re-init the card. And for sdio cards, when doing a suspend/resume cycle, consider the unsafe resume case, the card will either lose its power or not depending on if it wants to wakeup the host. If power is not maintained, it is the same case as mmc/sd cards. If power is maintained, mmc_power_up will not be called and the card's signal voltage will remain at the last setting. Signed-off-by: Aaron Lu Tested-by: Venkatraman S Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 6 +++--- drivers/mmc/core/mmc.c | 3 --- drivers/mmc/core/sd.c | 3 --- drivers/mmc/core/sdio.c | 7 ------- 4 files changed, 3 insertions(+), 16 deletions(-) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 9503cabc96f1..8ac5246e2ab2 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1212,6 +1212,9 @@ static void mmc_power_up(struct mmc_host *host) host->ios.timing = MMC_TIMING_LEGACY; mmc_set_ios(host); + /* Set signal voltage to 3.3V */ + mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false); + /* * This delay should be sufficient to allow the power supply * to reach the minimum voltage. @@ -1963,9 +1966,6 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) */ mmc_hw_reset_for_init(host); - /* Initialization should be done at 3.3 V I/O voltage. */ - mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0); - /* * sdio_reset sends CMD52 to reset card. Since we do not know * if the card is being re-initialized, just send it. CMD52 diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 4f4489aa6bae..396b25891bb9 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -818,9 +818,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (!mmc_host_is_spi(host)) mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN); - /* Initialization should be done at 3.3 V I/O voltage. */ - mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0); - /* * Since we're changing the OCR value, we seem to * need to tell some cards to go back to the idle diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 441bdf472c99..74972c241dff 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -901,9 +901,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, BUG_ON(!host); WARN_ON(!host->claimed); - /* The initialization should be done at 3.3 V I/O voltage. */ - mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0); - err = mmc_sd_get_cid(host, ocr, cid, &rocr); if (err) return err; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 41c5fd8848f4..d4619e2ec030 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -591,9 +591,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, * Inform the card of the voltage */ if (!powered_resume) { - /* The initialization should be done at 3.3 V I/O voltage. */ - mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0); - err = mmc_send_io_op_cond(host, host->ocr, &ocr); if (err) goto err; @@ -1006,10 +1003,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host) * restore the correct voltage setting of the card. */ - /* The initialization should be done at 3.3 V I/O voltage. */ - if (!mmc_card_keep_power(host)) - mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0); - sdio_reset(host); mmc_go_idle(host); mmc_send_if_cond(host, host->ocr_avail); -- cgit v1.2.3