diff mbox

[V2] mmc: core: Add host capability check for power class

Message ID 1323921517-31241-1-git-send-email-girish.shivananjappa@linaro.org
State New
Headers show

Commit Message

Girish K S Dec. 15, 2011, 3:58 a.m. UTC
This patch adds a check whether the host supports maximum current value
obtained from the device's extended csd register for a selected interface
voltage and frequency.

cc: Chris Ball <cjb@laptop.org>
Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
---
Changes in v2:
	deleted a unnecessary if else condition identified by subhash J
Changes in v1:
       reduced the number of comparisons as per Hein's suggestion

 drivers/mmc/core/mmc.c   |   19 +++++++++++++++++++
 include/linux/mmc/card.h |    4 ++++
 2 files changed, 23 insertions(+), 0 deletions(-)

Comments

Amit Daniel Kachhap Dec. 15, 2011, 6:03 a.m. UTC | #1
On Thu, Dec 15, 2011 at 9:28 AM, Girish K S
<girish.shivananjappa@linaro.org> wrote:
> This patch adds a check whether the host supports maximum current value
> obtained from the device's extended csd register for a selected interface
> voltage and frequency.
>
> cc: Chris Ball <cjb@laptop.org>
> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
> ---
> Changes in v2:
>        deleted a unnecessary if else condition identified by subhash J
> Changes in v1:
>       reduced the number of comparisons as per Hein's suggestion
>
>  drivers/mmc/core/mmc.c   |   19 +++++++++++++++++++
>  include/linux/mmc/card.h |    4 ++++
>  2 files changed, 23 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 006e932..b9ef777 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -688,6 +688,25 @@ static int mmc_select_powerclass(struct mmc_card *card,
>                pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >>
>                                EXT_CSD_PWR_CL_4BIT_SHIFT;
>
> +       if (pwrclass_val >= MMC_MAX_CURRENT_800)
Hi girish,

These checks can be made like ,
if (pwrclass_val > MMC_MAX_CURRENT_800)
        pwrclass_val = MMC_MAX_CURRENT_800;
Applicable in all below conditional checks.

Thanks,
Amit D

> +               pwrclass_val = MMC_MAX_CURRENT_800;
> +       else if (pwrclass_val >= MMC_MAX_CURRENT_600)
> +               pwrclass_val = MMC_MAX_CURRENT_600;
> +       else if (pwrclass_val >= MMC_MAX_CURRENT_400)
> +               pwrclass_val = MMC_MAX_CURRENT_400;
> +       else
> +               pwrclass_val = MMC_MAX_CURRENT_200;
> +
> +       if ((pwrclass_val == MMC_MAX_CURRENT_800) &&
> +           !(card->host->caps & MMC_CAP_MAX_CURRENT_800))
> +               pwrclass_val = MMC_MAX_CURRENT_600;
> +       if ((pwrclass_val == MMC_MAX_CURRENT_600) &&
> +           !(card->host->caps & MMC_CAP_MAX_CURRENT_600))
> +               pwrclass_val = MMC_MAX_CURRENT_400;
> +       if ((pwrclass_val == MMC_MAX_CURRENT_400) &&
> +           !(card->host->caps & MMC_CAP_MAX_CURRENT_400))
> +               pwrclass_val = MMC_MAX_CURRENT_200;
> +
>        /* If the power class is different from the default value */
>        if (pwrclass_val > 0) {
>                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index 9478a6b..c5e031a 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -195,6 +195,10 @@ struct mmc_part {
>  #define MMC_BLK_DATA_AREA_GP   (1<<2)
>  };
>
> +#define MMC_MAX_CURRENT_200    (0)
> +#define MMC_MAX_CURRENT_400    (7)
> +#define MMC_MAX_CURRENT_600    (11)
> +#define MMC_MAX_CURRENT_800    (13)
>  /*
>  * MMC device
>  */
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Girish K S Dec. 15, 2011, 6:16 a.m. UTC | #2
On 15 December 2011 11:33, amit kachhap <amit.kachhap@linaro.org> wrote:
> On Thu, Dec 15, 2011 at 9:28 AM, Girish K S
> <girish.shivananjappa@linaro.org> wrote:
>> This patch adds a check whether the host supports maximum current value
>> obtained from the device's extended csd register for a selected interface
>> voltage and frequency.
>>
>> cc: Chris Ball <cjb@laptop.org>
>> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
>> ---
>> Changes in v2:
>>        deleted a unnecessary if else condition identified by subhash J
>> Changes in v1:
>>       reduced the number of comparisons as per Hein's suggestion
>>
>>  drivers/mmc/core/mmc.c   |   19 +++++++++++++++++++
>>  include/linux/mmc/card.h |    4 ++++
>>  2 files changed, 23 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index 006e932..b9ef777 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -688,6 +688,25 @@ static int mmc_select_powerclass(struct mmc_card *card,
>>                pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >>
>>                                EXT_CSD_PWR_CL_4BIT_SHIFT;
>>
>> +       if (pwrclass_val >= MMC_MAX_CURRENT_800)
> Hi girish,
>
> These checks can be made like ,
> if (pwrclass_val > MMC_MAX_CURRENT_800)
>        pwrclass_val = MMC_MAX_CURRENT_800;
> Applicable in all below conditional checks.

I feel that should be OK. Since there will be no significant
improvement or side effects with the current implementation.

>
> Thanks,
> Amit D
>
>> +               pwrclass_val = MMC_MAX_CURRENT_800;
>> +       else if (pwrclass_val >= MMC_MAX_CURRENT_600)
>> +               pwrclass_val = MMC_MAX_CURRENT_600;
>> +       else if (pwrclass_val >= MMC_MAX_CURRENT_400)
>> +               pwrclass_val = MMC_MAX_CURRENT_400;
>> +       else
>> +               pwrclass_val = MMC_MAX_CURRENT_200;
>> +
>> +       if ((pwrclass_val == MMC_MAX_CURRENT_800) &&
>> +           !(card->host->caps & MMC_CAP_MAX_CURRENT_800))
>> +               pwrclass_val = MMC_MAX_CURRENT_600;
>> +       if ((pwrclass_val == MMC_MAX_CURRENT_600) &&
>> +           !(card->host->caps & MMC_CAP_MAX_CURRENT_600))
>> +               pwrclass_val = MMC_MAX_CURRENT_400;
>> +       if ((pwrclass_val == MMC_MAX_CURRENT_400) &&
>> +           !(card->host->caps & MMC_CAP_MAX_CURRENT_400))
>> +               pwrclass_val = MMC_MAX_CURRENT_200;
>> +
>>        /* If the power class is different from the default value */
>>        if (pwrclass_val > 0) {
>>                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> index 9478a6b..c5e031a 100644
>> --- a/include/linux/mmc/card.h
>> +++ b/include/linux/mmc/card.h
>> @@ -195,6 +195,10 @@ struct mmc_part {
>>  #define MMC_BLK_DATA_AREA_GP   (1<<2)
>>  };
>>
>> +#define MMC_MAX_CURRENT_200    (0)
>> +#define MMC_MAX_CURRENT_400    (7)
>> +#define MMC_MAX_CURRENT_600    (11)
>> +#define MMC_MAX_CURRENT_800    (13)
>>  /*
>>  * MMC device
>>  */
>> --
>> 1.7.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Hein_Tibosch Dec. 15, 2011, 9:57 a.m. UTC | #3
On 12/15/2011 2:03 PM, amit kachhap wrote:

> On Thu, Dec 15, 2011 at 9:28 AM, Girish K S
> <girish.shivananjappa@linaro.org> wrote:
>> This patch adds a check whether the host supports maximum current value
>> obtained from the device's extended csd register for a selected interface
>> voltage and frequency.
>>
>> cc: Chris Ball <cjb@laptop.org>
>> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
>> ---
>> Changes in v2:
>>        deleted a unnecessary if else condition identified by subhash J
>> Changes in v1:
>>       reduced the number of comparisons as per Hein's suggestion
>>
>>  drivers/mmc/core/mmc.c   |   19 +++++++++++++++++++
>>  include/linux/mmc/card.h |    4 ++++
>>  2 files changed, 23 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index 006e932..b9ef777 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -688,6 +688,25 @@ static int mmc_select_powerclass(struct mmc_card *card,
>>                pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >>
>>                                EXT_CSD_PWR_CL_4BIT_SHIFT;
>>
>> +       if (pwrclass_val >= MMC_MAX_CURRENT_800)
> Hi girish,
>
> These checks can be made like ,
> if (pwrclass_val > MMC_MAX_CURRENT_800)
>         pwrclass_val = MMC_MAX_CURRENT_800;
> Applicable in all below conditional checks.
Hi both,

Suppose pwrclass_val == MMC_MAX_CURRENT_800 (13),
then with

+       if (pwrclass_val > MMC_MAX_CURRENT_800)
+               pwrclass_val = MMC_MAX_CURRENT_800;
+       else if (pwrclass_val > MMC_MAX_CURRENT_600)
+               pwrclass_val = MMC_MAX_CURRENT_600;

it would get a value of MMC_MAX_CURRENT_600, which is too low

Hein
Saugata Das Dec. 15, 2011, 10:04 a.m. UTC | #4
On 15 December 2011 09:28, Girish K S <girish.shivananjappa@linaro.org> wrote:
> This patch adds a check whether the host supports maximum current value
> obtained from the device's extended csd register for a selected interface
> voltage and frequency.
>
> cc: Chris Ball <cjb@laptop.org>
> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
> ---
> Changes in v2:
>        deleted a unnecessary if else condition identified by subhash J
> Changes in v1:
>       reduced the number of comparisons as per Hein's suggestion
>
>  drivers/mmc/core/mmc.c   |   19 +++++++++++++++++++
>  include/linux/mmc/card.h |    4 ++++
>  2 files changed, 23 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 006e932..b9ef777 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -688,6 +688,25 @@ static int mmc_select_powerclass(struct mmc_card *card,
>                pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >>
>                                EXT_CSD_PWR_CL_4BIT_SHIFT;
>
> +       if (pwrclass_val >= MMC_MAX_CURRENT_800)
> +               pwrclass_val = MMC_MAX_CURRENT_800;
> +       else if (pwrclass_val >= MMC_MAX_CURRENT_600)
> +               pwrclass_val = MMC_MAX_CURRENT_600;
> +       else if (pwrclass_val >= MMC_MAX_CURRENT_400)
> +               pwrclass_val = MMC_MAX_CURRENT_400;
> +       else
> +               pwrclass_val = MMC_MAX_CURRENT_200;
> +
> +       if ((pwrclass_val == MMC_MAX_CURRENT_800) &&
> +           !(card->host->caps & MMC_CAP_MAX_CURRENT_800))
> +               pwrclass_val = MMC_MAX_CURRENT_600;
> +       if ((pwrclass_val == MMC_MAX_CURRENT_600) &&
> +           !(card->host->caps & MMC_CAP_MAX_CURRENT_600))
> +               pwrclass_val = MMC_MAX_CURRENT_400;
> +       if ((pwrclass_val == MMC_MAX_CURRENT_400) &&
> +           !(card->host->caps & MMC_CAP_MAX_CURRENT_400))
> +               pwrclass_val = MMC_MAX_CURRENT_200;
> +
>        /* If the power class is different from the default value */
>        if (pwrclass_val > 0) {
>                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,

It is not allowed to set the POWER_CLASS with any value other than
what is mentioned in the PWR_CL_ff_vvv or PWR_CL_DDR_ff_vvv  for the
corresponding frequency, voltage. That is, if PWR_CL_200_195 is 14 and
we want to operate at HS200 then the only value allowed for
POWER_CLASS is 14. So, we need to check the PWR_CL numbers and choose
the operating mode (HS200/DDR50/..) based on the platform capability
to support the current consumption and set the corresponding
POWER_CLASS value.

Please refer to section 6.6.5 of the 4.5 spec.


> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index 9478a6b..c5e031a 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -195,6 +195,10 @@ struct mmc_part {
>  #define MMC_BLK_DATA_AREA_GP   (1<<2)
>  };
>
> +#define MMC_MAX_CURRENT_200    (0)
> +#define MMC_MAX_CURRENT_400    (7)
> +#define MMC_MAX_CURRENT_600    (11)
> +#define MMC_MAX_CURRENT_800    (13)
>  /*
>  * MMC device
>  */
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Girish K S Dec. 15, 2011, 10:52 a.m. UTC | #5
On 15 December 2011 15:34, Saugata Das <saugata.das@linaro.org> wrote:
> On 15 December 2011 09:28, Girish K S <girish.shivananjappa@linaro.org> wrote:
>> This patch adds a check whether the host supports maximum current value
>> obtained from the device's extended csd register for a selected interface
>> voltage and frequency.
>>
>> cc: Chris Ball <cjb@laptop.org>
>> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
>> ---
>> Changes in v2:
>>        deleted a unnecessary if else condition identified by subhash J
>> Changes in v1:
>>       reduced the number of comparisons as per Hein's suggestion
>>
>>  drivers/mmc/core/mmc.c   |   19 +++++++++++++++++++
>>  include/linux/mmc/card.h |    4 ++++
>>  2 files changed, 23 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index 006e932..b9ef777 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -688,6 +688,25 @@ static int mmc_select_powerclass(struct mmc_card *card,
>>                pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >>
>>                                EXT_CSD_PWR_CL_4BIT_SHIFT;
>>
>> +       if (pwrclass_val >= MMC_MAX_CURRENT_800)
>> +               pwrclass_val = MMC_MAX_CURRENT_800;
>> +       else if (pwrclass_val >= MMC_MAX_CURRENT_600)
>> +               pwrclass_val = MMC_MAX_CURRENT_600;
>> +       else if (pwrclass_val >= MMC_MAX_CURRENT_400)
>> +               pwrclass_val = MMC_MAX_CURRENT_400;
>> +       else
>> +               pwrclass_val = MMC_MAX_CURRENT_200;
>> +
>> +       if ((pwrclass_val == MMC_MAX_CURRENT_800) &&
>> +           !(card->host->caps & MMC_CAP_MAX_CURRENT_800))
>> +               pwrclass_val = MMC_MAX_CURRENT_600;
>> +       if ((pwrclass_val == MMC_MAX_CURRENT_600) &&
>> +           !(card->host->caps & MMC_CAP_MAX_CURRENT_600))
>> +               pwrclass_val = MMC_MAX_CURRENT_400;
>> +       if ((pwrclass_val == MMC_MAX_CURRENT_400) &&
>> +           !(card->host->caps & MMC_CAP_MAX_CURRENT_400))
>> +               pwrclass_val = MMC_MAX_CURRENT_200;
>> +
>>        /* If the power class is different from the default value */
>>        if (pwrclass_val > 0) {
>>                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>
> It is not allowed to set the POWER_CLASS with any value other than
> what is mentioned in the PWR_CL_ff_vvv or PWR_CL_DDR_ff_vvv  for the
> corresponding frequency, voltage. That is, if PWR_CL_200_195 is 14 and
> we want to operate at HS200 then the only value allowed for
> POWER_CLASS is 14. So, we need to check the PWR_CL numbers and choose
> the operating mode (HS200/DDR50/..) based on the platform capability
> to support the current consumption and set the corresponding
> POWER_CLASS value.
>
> Please refer to section 6.6.5 of the 4.5 spec.

The upstreamed code reads the extended csd value based on the already
set voltage level and frequency of host. So it will get the required
power class value which can be set directly. Is my understanding
correct?

>
>
>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> index 9478a6b..c5e031a 100644
>> --- a/include/linux/mmc/card.h
>> +++ b/include/linux/mmc/card.h
>> @@ -195,6 +195,10 @@ struct mmc_part {
>>  #define MMC_BLK_DATA_AREA_GP   (1<<2)
>>  };
>>
>> +#define MMC_MAX_CURRENT_200    (0)
>> +#define MMC_MAX_CURRENT_400    (7)
>> +#define MMC_MAX_CURRENT_600    (11)
>> +#define MMC_MAX_CURRENT_800    (13)
>>  /*
>>  * MMC device
>>  */
>> --
>> 1.7.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Saugata Das Dec. 15, 2011, 1:05 p.m. UTC | #6
On 15 December 2011 16:22, Girish K S <girish.shivananjappa@linaro.org> wrote:
> On 15 December 2011 15:34, Saugata Das <saugata.das@linaro.org> wrote:
>> On 15 December 2011 09:28, Girish K S <girish.shivananjappa@linaro.org> wrote:
>>> This patch adds a check whether the host supports maximum current value
>>> obtained from the device's extended csd register for a selected interface
>>> voltage and frequency.
>>>
>>> cc: Chris Ball <cjb@laptop.org>
>>> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
>>> ---
>>> Changes in v2:
>>>        deleted a unnecessary if else condition identified by subhash J
>>> Changes in v1:
>>>       reduced the number of comparisons as per Hein's suggestion
>>>
>>>  drivers/mmc/core/mmc.c   |   19 +++++++++++++++++++
>>>  include/linux/mmc/card.h |    4 ++++
>>>  2 files changed, 23 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>>> index 006e932..b9ef777 100644
>>> --- a/drivers/mmc/core/mmc.c
>>> +++ b/drivers/mmc/core/mmc.c
>>> @@ -688,6 +688,25 @@ static int mmc_select_powerclass(struct mmc_card *card,
>>>                pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >>
>>>                                EXT_CSD_PWR_CL_4BIT_SHIFT;
>>>
>>> +       if (pwrclass_val >= MMC_MAX_CURRENT_800)
>>> +               pwrclass_val = MMC_MAX_CURRENT_800;
>>> +       else if (pwrclass_val >= MMC_MAX_CURRENT_600)
>>> +               pwrclass_val = MMC_MAX_CURRENT_600;
>>> +       else if (pwrclass_val >= MMC_MAX_CURRENT_400)
>>> +               pwrclass_val = MMC_MAX_CURRENT_400;
>>> +       else
>>> +               pwrclass_val = MMC_MAX_CURRENT_200;
>>> +
>>> +       if ((pwrclass_val == MMC_MAX_CURRENT_800) &&
>>> +           !(card->host->caps & MMC_CAP_MAX_CURRENT_800))
>>> +               pwrclass_val = MMC_MAX_CURRENT_600;
>>> +       if ((pwrclass_val == MMC_MAX_CURRENT_600) &&
>>> +           !(card->host->caps & MMC_CAP_MAX_CURRENT_600))
>>> +               pwrclass_val = MMC_MAX_CURRENT_400;
>>> +       if ((pwrclass_val == MMC_MAX_CURRENT_400) &&
>>> +           !(card->host->caps & MMC_CAP_MAX_CURRENT_400))
>>> +               pwrclass_val = MMC_MAX_CURRENT_200;
>>> +
>>>        /* If the power class is different from the default value */
>>>        if (pwrclass_val > 0) {
>>>                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>
>> It is not allowed to set the POWER_CLASS with any value other than
>> what is mentioned in the PWR_CL_ff_vvv or PWR_CL_DDR_ff_vvv  for the
>> corresponding frequency, voltage. That is, if PWR_CL_200_195 is 14 and
>> we want to operate at HS200 then the only value allowed for
>> POWER_CLASS is 14. So, we need to check the PWR_CL numbers and choose
>> the operating mode (HS200/DDR50/..) based on the platform capability
>> to support the current consumption and set the corresponding
>> POWER_CLASS value.
>>
>> Please refer to section 6.6.5 of the 4.5 spec.
>
> The upstreamed code reads the extended csd value based on the already
> set voltage level and frequency of host. So it will get the required
> power class value which can be set directly. Is my understanding
> correct?
>

It is not enough to just check the voltage level and frequency.
Consider this example, host has capability to support
MMC_CAP_MAX_CURRENT_400, the PWR_CL_DDR_52_360 has the value 9 (400mA)
and PWR_CL_200_360 has the value 14 (800mA). Then even though the host
might be capable to run 200MHz clock and 3.6V, it can only enable DDR
at 52MHz and set 9 in POWER_CLASS.

I think, in mmc_select_powerclass, we need to loop through the power
classes of all supported modes of transfer (HS200, DDR52, ... ) and
choose the mode which gives maximum bandwidth but falls within host
capability of current consumption. Then set this to POWER_CLASS byte
and also use the same information when setting HS_TIMING in
mmc_init_card.

>>
>>
>>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>>> index 9478a6b..c5e031a 100644
>>> --- a/include/linux/mmc/card.h
>>> +++ b/include/linux/mmc/card.h
>>> @@ -195,6 +195,10 @@ struct mmc_part {
>>>  #define MMC_BLK_DATA_AREA_GP   (1<<2)
>>>  };
>>>
>>> +#define MMC_MAX_CURRENT_200    (0)
>>> +#define MMC_MAX_CURRENT_400    (7)
>>> +#define MMC_MAX_CURRENT_600    (11)
>>> +#define MMC_MAX_CURRENT_800    (13)
>>>  /*
>>>  * MMC device
>>>  */
>>> --
>>> 1.7.1
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 006e932..b9ef777 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -688,6 +688,25 @@  static int mmc_select_powerclass(struct mmc_card *card,
 		pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >>
 				EXT_CSD_PWR_CL_4BIT_SHIFT;
 
+	if (pwrclass_val >= MMC_MAX_CURRENT_800)
+		pwrclass_val = MMC_MAX_CURRENT_800;
+	else if (pwrclass_val >= MMC_MAX_CURRENT_600)
+		pwrclass_val = MMC_MAX_CURRENT_600;
+	else if (pwrclass_val >= MMC_MAX_CURRENT_400)
+		pwrclass_val = MMC_MAX_CURRENT_400;
+	else
+		pwrclass_val = MMC_MAX_CURRENT_200;
+
+	if ((pwrclass_val == MMC_MAX_CURRENT_800) &&
+	    !(card->host->caps & MMC_CAP_MAX_CURRENT_800))
+		pwrclass_val = MMC_MAX_CURRENT_600;
+	if ((pwrclass_val == MMC_MAX_CURRENT_600) &&
+	    !(card->host->caps & MMC_CAP_MAX_CURRENT_600))
+		pwrclass_val = MMC_MAX_CURRENT_400;
+	if ((pwrclass_val == MMC_MAX_CURRENT_400) &&
+	    !(card->host->caps & MMC_CAP_MAX_CURRENT_400))
+		pwrclass_val = MMC_MAX_CURRENT_200;
+
 	/* If the power class is different from the default value */
 	if (pwrclass_val > 0) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 9478a6b..c5e031a 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -195,6 +195,10 @@  struct mmc_part {
 #define MMC_BLK_DATA_AREA_GP	(1<<2)
 };
 
+#define MMC_MAX_CURRENT_200	(0)
+#define MMC_MAX_CURRENT_400	(7)
+#define MMC_MAX_CURRENT_600	(11)
+#define MMC_MAX_CURRENT_800	(13)
 /*
  * MMC device
  */