On 14 December 2012 14:40, Ulf Hansson <[email protected]> wrote:
> On 14 December 2012 11:53, Kevin Liu <[email protected]> wrote:
>> 1. if host does NOT implement signal voltage setting function,
>> should return error.
>> 2. add the check for data signal before voltage change according
>> to the spec. If host does NOT detect a low signal level, the host
>> should abort the voltage switch sequence. (phisical layer spec 4.2.4.2(4))
>> 3. if voltage change failed then no need to restore the clock
>> before cycle power the card.
>> 4. call mmc_power_cycle here since it's a part of voltage switch.
>> besides -EAGAIN, any other error returned should also cycle power the card.
>>
>> Signed-off-by: Kevin Liu <[email protected]>
>> ---
>> drivers/mmc/core/core.c | 71
>> ++++++++++++++++++++++++++++------------------
>> 1 files changed, 43 insertions(+), 28 deletions(-)
>>
>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>> index d1aa8ab..da93186 100644
>> --- a/drivers/mmc/core/core.c
>> +++ b/drivers/mmc/core/core.c
>> @@ -1226,6 +1226,9 @@ int mmc_set_signal_voltage(struct mmc_host *host, int
>> signal_voltage, bool cmd11
>>
>> BUG_ON(!host);
>>
>> + if (!host->ops->start_signal_voltage_switch)
>> + return -EPERM;
>> +
>
> No, this is not OK.
> For example, eMMC might default use 1.8V as I/O voltage, you don't
> want to force host drivers implementing this function to make this
> work.
>
>> /*
>> * Send CMD11 only if the request is to switch the card to
>> * 1.8V signalling.
>> @@ -1245,47 +1248,59 @@ int mmc_set_signal_voltage(struct mmc_host *host,
>> int signal_voltage, bool cmd11
>>
>> host->ios.signal_voltage = signal_voltage;
>>
>> - if (host->ops->start_signal_voltage_switch) {
>> - u32 clock;
>> + u32 clock;
>> +
>> + mmc_host_clk_hold(host);
>> +
>> + if (cmd11) {
>> + if (!host->ops->card_busy)
>> + pr_warning("%s: cannot verify signal voltage
>> switch\n",
>> + mmc_hostname(host));
>>
>> - mmc_host_clk_hold(host);
>> /*
>> * During a signal voltage level switch, the clock must be
>> gated
>> * for a certain period of time according to the SD spec
>> */
>> - if (cmd11) {
>> - clock = host->ios.clock;
>> - host->ios.clock = 0;
>> - mmc_set_ios(host);
>> - }
>> + clock = host->ios.clock;
>> + host->ios.clock = 0;
>> + mmc_set_ios(host);
>>
>> - err = host->ops->start_signal_voltage_switch(host,
>> &host->ios);
>> + if (host->ops->card_busy && !host->ops->card_busy(host)) {
>> + err = -EAGAIN;
>> + } else {
>
> Great that you spotted this! We should check busy before we do the
> actual voltage switch.
>
> Although, I think it would make sense to do this before the clock is
> set to 0. Especially important for those host controllers that do
> support busy-detection, a qualified guess would be that those also
> could require the clock to be on to detect this. Or what do you think?
> From spec point of view it shall be safe to do it before setting clk
> to 0.
>
>>
>> - if (err && cmd11) {
>> - host->ios.clock = clock;
>> - mmc_set_ios(host);
>> - } else if (cmd11) {
>> - /* Keep clock gated for at least 5 ms */
>> - mmc_delay(5);
>> - host->ios.clock = clock;
>> - mmc_set_ios(host);
>> + err = host->ops->start_signal_voltage_switch(host,
>> &host->ios);
>>
>> - /* Wait for at least 1 ms according to spec */
>> - mmc_delay(1);
>> + if (!err) {
>> + /* Keep clock gated for at least 5 ms */
>> + mmc_delay(5);
>> + host->ios.clock = clock;
>> + mmc_set_ios(host);
>>
>> - /*
>> - * Failure to switch is indicated by the card holding
>> - * dat[0:3] low
>> - */
>> - if (!host->ops->card_busy)
>> - pr_warning("%s: cannot verify signal voltage
>> switch\n",
>> + /* Wait for at least 1 ms according to spec
>> */
>> + mmc_delay(1);
>> +
>> + /*
>> + * Failure to switch is indicated by the
>> card holding
>> + * dat[0:3] low
>> + */
>> + if (host->ops->card_busy &&
>> host->ops->card_busy(host))
>> + err = -EAGAIN;
>> + }
>> + }
>> + if (err) {
>> + /* Power cycle card */
>> + pr_debug("%s: Signal voltage switch failed, "
>> + "power cycling card \n",
>> mmc_hostname(host));
>> - else if (host->ops->card_busy(host))
>> - err = -EAGAIN;
>> + mmc_power_cycle(host);
I definitely agree, that this should be done here!
Although, this will break the SDIO case, so we need to fix that in the
sdio.c as well.
>> }
>> - mmc_host_clk_release(host);
>> + } else {
>> + err = host->ops->start_signal_voltage_switch(host,
>> &host->ios);
>> }
>>
>> + mmc_host_clk_release(host);
>> +
>> return err;
>> }
>>
>> --
>> 1.7.0.4
>>
>
> Kind regards
> Ulf Hansson
Kind regards
Ulf Hansson
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html