From ebc5a1bf4f2afc2f2b348320dcfb45a8c0ac3de5 Mon Sep 17 00:00:00 2001 From: "harish_kandiga@mentor.com" Date: Tue, 10 Apr 2018 12:30:31 +0530 Subject: mmc: core: Add a new quirk for limiting clock rate This patch adds a quirk to limit clock rate which can be used to reduce the SDIO clock rate for some chips with broken UHS. Signed-off-by: Harish Jenny K N Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/sdio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/core/sdio.c') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index c599a628a387..24b510b743da 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -444,6 +444,7 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card) unsigned int bus_speed, timing; int err; unsigned char speed; + unsigned int max_rate; /* * If the host doesn't support any of the UHS-I modes, fallback on @@ -500,9 +501,12 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card) if (err) return err; + max_rate = min_not_zero(card->quirk_max_rate, + card->sw_caps.uhs_max_dtr); + if (bus_speed) { mmc_set_timing(card->host, timing); - mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr); + mmc_set_clock(card->host, max_rate); } return 0; -- cgit v1.2.3 From 247cfe53557524a94dd1001d19e5aa50bd5aca81 Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Fri, 13 Apr 2018 16:54:57 -0500 Subject: mmc: core: Add capability to avoid 3.3V signaling Some SD host controllers cannot handle extended use of 3.3V signaling. To accommodate these controllers, add a capability that requires us to negotiate the voltage down from 3.3V during card initialization. Signed-off-by: Kyle Roeschley Signed-off-by: Jennifer Dahm Signed-off-by: Ulf Hansson --- drivers/mmc/core/sdio.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/mmc/core/sdio.c') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 24b510b743da..87e53a721a10 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -792,6 +792,14 @@ try_again: if (err) goto remove; } + + if (host->caps2 & MMC_CAP2_AVOID_3_3V && + host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) { + pr_err("%s: Host failed to negotiate down from 3.3V\n", + mmc_hostname(host)); + err = -EINVAL; + goto remove; + } finish: if (!oldcard) host->card = card; -- cgit v1.2.3 From fb09f44e290b1775fbeadb4289dbcfc2f954b0d2 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 11 May 2015 16:46:47 +0200 Subject: mmc: core: Re-factor some code for SDIO re-initialization The mmc_sdio_init_card() function has a couple of callers. In the re-initialization cases, some additional reset commands are issued before mmc_sdio_init_card() is called. As these additional reset commands are the same, let's move these into a new static function, mmc_sdio_reinit_card() and call mmc_sdio_init_card() from there. In this way we avoid the open coding. Signed-off-by: Ulf Hansson Tested-by: Quentin Schulz Reviewed-by: Shawn Lin --- drivers/mmc/core/sdio.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'drivers/mmc/core/sdio.c') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 87e53a721a10..34d69d0b5bf8 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -813,6 +813,22 @@ err: return err; } +static int mmc_sdio_reinit_card(struct mmc_host *host, bool powered_resume) +{ + int ret; + + sdio_reset(host); + mmc_go_idle(host); + mmc_send_if_cond(host, host->card->ocr); + + ret = mmc_send_io_op_cond(host, 0, NULL); + if (ret) + return ret; + + return mmc_sdio_init_card(host, host->card->ocr, host->card, + powered_resume); +} + /* * Host is being removed. Free up the current card. */ @@ -960,14 +976,7 @@ static int mmc_sdio_resume(struct mmc_host *host) /* No need to reinitialize powered-resumed nonremovable cards */ if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) { - sdio_reset(host); - mmc_go_idle(host); - mmc_send_if_cond(host, host->card->ocr); - err = mmc_send_io_op_cond(host, 0, NULL); - if (!err) - err = mmc_sdio_init_card(host, host->card->ocr, - host->card, - mmc_card_keep_power(host)); + err = mmc_sdio_reinit_card(host, mmc_card_keep_power(host)); } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) { /* We may have switched to 1-bit mode during suspend */ err = sdio_enable_4bit_bus(host->card); @@ -990,8 +999,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host) { int ret; - mmc_claim_host(host); - /* * Reset the card by performing the same steps that are taken by * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe. @@ -1009,20 +1016,12 @@ static int mmc_sdio_power_restore(struct mmc_host *host) * */ - sdio_reset(host); - mmc_go_idle(host); - mmc_send_if_cond(host, host->card->ocr); - - ret = mmc_send_io_op_cond(host, 0, NULL); - if (ret) - goto out; + mmc_claim_host(host); - ret = mmc_sdio_init_card(host, host->card->ocr, host->card, - mmc_card_keep_power(host)); + ret = mmc_sdio_reinit_card(host, mmc_card_keep_power(host)); if (!ret && host->sdio_irqs) mmc_signal_sdio_irq(host); -out: mmc_release_host(host); return ret; -- cgit v1.2.3 From 3a3db6030b64ceb4b4e41a6811168c5d90a9f7f8 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 5 Apr 2018 13:24:43 +0200 Subject: mmc: core: Rename ->reset() bus ops to ->hw_reset() The bus ops ->reset() executes a full HW reset of the card, as the calling function mmc_hw_reset() also indicates by its name. Let's convert to follow the similar names, for both the bus ops callback and for the corresponding bus ops functions, as to clarify the purpose of code. Signed-off-by: Ulf Hansson Tested-by: Quentin Schulz Reviewed-by: Shawn Lin --- drivers/mmc/core/sdio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/core/sdio.c') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 34d69d0b5bf8..362737052f84 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -1050,7 +1050,7 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host) return ret; } -static int mmc_sdio_reset(struct mmc_host *host) +static int mmc_sdio_hw_reset(struct mmc_host *host) { mmc_power_cycle(host, host->card->ocr); return mmc_sdio_power_restore(host); @@ -1066,7 +1066,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = { .runtime_resume = mmc_sdio_runtime_resume, .power_restore = mmc_sdio_power_restore, .alive = mmc_sdio_alive, - .reset = mmc_sdio_reset, + .hw_reset = mmc_sdio_hw_reset, }; -- cgit v1.2.3 From 7405df4c79cd7b4204c5b4b5af2b1ad362ea85ad Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 5 Apr 2018 16:31:25 +0200 Subject: mmc: core: Implement ->sw_reset bus ops for SDIO Let's implement the ->sw_reset() bus ops to allow SDIO func drivers, in particular, to make a SW reset without doing a full power cycle of the SDIO card. Signed-off-by: Ulf Hansson Tested-by: Quentin Schulz Reviewed-by: Shawn Lin --- drivers/mmc/core/sdio.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/mmc/core/sdio.c') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 362737052f84..a86490dbca70 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -1056,6 +1056,18 @@ static int mmc_sdio_hw_reset(struct mmc_host *host) return mmc_sdio_power_restore(host); } +static int mmc_sdio_sw_reset(struct mmc_host *host) +{ + mmc_set_clock(host, host->f_init); + sdio_reset(host); + mmc_go_idle(host); + + mmc_set_initial_state(host); + mmc_set_initial_signal_voltage(host); + + return mmc_sdio_reinit_card(host, 0); +} + static const struct mmc_bus_ops mmc_sdio_ops = { .remove = mmc_sdio_remove, .detect = mmc_sdio_detect, @@ -1067,6 +1079,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = { .power_restore = mmc_sdio_power_restore, .alive = mmc_sdio_alive, .hw_reset = mmc_sdio_hw_reset, + .sw_reset = mmc_sdio_sw_reset, }; -- cgit v1.2.3