diff options
-rw-r--r-- | drivers/mmc/core/core.c | 75 | ||||
-rw-r--r-- | include/linux/mmc/core.h | 2 |
2 files changed, 77 insertions, 0 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index f7284b905eb3..5f288aeeb721 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/err.h> | 20 | #include <linux/err.h> |
21 | #include <linux/leds.h> | 21 | #include <linux/leds.h> |
22 | #include <linux/scatterlist.h> | 22 | #include <linux/scatterlist.h> |
23 | #include <linux/log2.h> | ||
23 | 24 | ||
24 | #include <linux/mmc/card.h> | 25 | #include <linux/mmc/card.h> |
25 | #include <linux/mmc/host.h> | 26 | #include <linux/mmc/host.h> |
@@ -448,6 +449,80 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width) | |||
448 | mmc_set_ios(host); | 449 | mmc_set_ios(host); |
449 | } | 450 | } |
450 | 451 | ||
452 | /** | ||
453 | * mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number | ||
454 | * @vdd: voltage (mV) | ||
455 | * @low_bits: prefer low bits in boundary cases | ||
456 | * | ||
457 | * This function returns the OCR bit number according to the provided @vdd | ||
458 | * value. If conversion is not possible a negative errno value returned. | ||
459 | * | ||
460 | * Depending on the @low_bits flag the function prefers low or high OCR bits | ||
461 | * on boundary voltages. For example, | ||
462 | * with @low_bits = true, 3300 mV translates to ilog2(MMC_VDD_32_33); | ||
463 | * with @low_bits = false, 3300 mV translates to ilog2(MMC_VDD_33_34); | ||
464 | * | ||
465 | * Any value in the [1951:1999] range translates to the ilog2(MMC_VDD_20_21). | ||
466 | */ | ||
467 | static int mmc_vdd_to_ocrbitnum(int vdd, bool low_bits) | ||
468 | { | ||
469 | const int max_bit = ilog2(MMC_VDD_35_36); | ||
470 | int bit; | ||
471 | |||
472 | if (vdd < 1650 || vdd > 3600) | ||
473 | return -EINVAL; | ||
474 | |||
475 | if (vdd >= 1650 && vdd <= 1950) | ||
476 | return ilog2(MMC_VDD_165_195); | ||
477 | |||
478 | if (low_bits) | ||
479 | vdd -= 1; | ||
480 | |||
481 | /* Base 2000 mV, step 100 mV, bit's base 8. */ | ||
482 | bit = (vdd - 2000) / 100 + 8; | ||
483 | if (bit > max_bit) | ||
484 | return max_bit; | ||
485 | return bit; | ||
486 | } | ||
487 | |||
488 | /** | ||
489 | * mmc_vddrange_to_ocrmask - Convert a voltage range to the OCR mask | ||
490 | * @vdd_min: minimum voltage value (mV) | ||
491 | * @vdd_max: maximum voltage value (mV) | ||
492 | * | ||
493 | * This function returns the OCR mask bits according to the provided @vdd_min | ||
494 | * and @vdd_max values. If conversion is not possible the function returns 0. | ||
495 | * | ||
496 | * Notes wrt boundary cases: | ||
497 | * This function sets the OCR bits for all boundary voltages, for example | ||
498 | * [3300:3400] range is translated to MMC_VDD_32_33 | MMC_VDD_33_34 | | ||
499 | * MMC_VDD_34_35 mask. | ||
500 | */ | ||
501 | u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max) | ||
502 | { | ||
503 | u32 mask = 0; | ||
504 | |||
505 | if (vdd_max < vdd_min) | ||
506 | return 0; | ||
507 | |||
508 | /* Prefer high bits for the boundary vdd_max values. */ | ||
509 | vdd_max = mmc_vdd_to_ocrbitnum(vdd_max, false); | ||
510 | if (vdd_max < 0) | ||
511 | return 0; | ||
512 | |||
513 | /* Prefer low bits for the boundary vdd_min values. */ | ||
514 | vdd_min = mmc_vdd_to_ocrbitnum(vdd_min, true); | ||
515 | if (vdd_min < 0) | ||
516 | return 0; | ||
517 | |||
518 | /* Fill the mask, from max bit to min bit. */ | ||
519 | while (vdd_max >= vdd_min) | ||
520 | mask |= 1 << vdd_max--; | ||
521 | |||
522 | return mask; | ||
523 | } | ||
524 | EXPORT_SYMBOL(mmc_vddrange_to_ocrmask); | ||
525 | |||
451 | /* | 526 | /* |
452 | * Mask off any voltages we don't support and select | 527 | * Mask off any voltages we don't support and select |
453 | * the lowest voltage | 528 | * the lowest voltage |
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 143cebf0586f..7ac8b500d55c 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h | |||
@@ -151,4 +151,6 @@ static inline void mmc_claim_host(struct mmc_host *host) | |||
151 | __mmc_claim_host(host, NULL); | 151 | __mmc_claim_host(host, NULL); |
152 | } | 152 | } |
153 | 153 | ||
154 | extern u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max); | ||
155 | |||
154 | #endif | 156 | #endif |