diff options
-rw-r--r-- | drivers/mmc/core/core.c | 100 | ||||
-rw-r--r-- | include/linux/mmc/host.h | 5 |
2 files changed, 105 insertions, 0 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index df6ce4a06cf3..1445ea8f10a6 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -21,6 +21,7 @@ | |||
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 | #include <linux/log2.h> |
24 | #include <linux/regulator/consumer.h> | ||
24 | 25 | ||
25 | #include <linux/mmc/card.h> | 26 | #include <linux/mmc/card.h> |
26 | #include <linux/mmc/host.h> | 27 | #include <linux/mmc/host.h> |
@@ -523,6 +524,105 @@ u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max) | |||
523 | } | 524 | } |
524 | EXPORT_SYMBOL(mmc_vddrange_to_ocrmask); | 525 | EXPORT_SYMBOL(mmc_vddrange_to_ocrmask); |
525 | 526 | ||
527 | #ifdef CONFIG_REGULATOR | ||
528 | |||
529 | /** | ||
530 | * mmc_regulator_get_ocrmask - return mask of supported voltages | ||
531 | * @supply: regulator to use | ||
532 | * | ||
533 | * This returns either a negative errno, or a mask of voltages that | ||
534 | * can be provided to MMC/SD/SDIO devices using the specified voltage | ||
535 | * regulator. This would normally be called before registering the | ||
536 | * MMC host adapter. | ||
537 | */ | ||
538 | int mmc_regulator_get_ocrmask(struct regulator *supply) | ||
539 | { | ||
540 | int result = 0; | ||
541 | int count; | ||
542 | int i; | ||
543 | |||
544 | count = regulator_count_voltages(supply); | ||
545 | if (count < 0) | ||
546 | return count; | ||
547 | |||
548 | for (i = 0; i < count; i++) { | ||
549 | int vdd_uV; | ||
550 | int vdd_mV; | ||
551 | |||
552 | vdd_uV = regulator_list_voltage(supply, i); | ||
553 | if (vdd_uV <= 0) | ||
554 | continue; | ||
555 | |||
556 | vdd_mV = vdd_uV / 1000; | ||
557 | result |= mmc_vddrange_to_ocrmask(vdd_mV, vdd_mV); | ||
558 | } | ||
559 | |||
560 | return result; | ||
561 | } | ||
562 | EXPORT_SYMBOL(mmc_regulator_get_ocrmask); | ||
563 | |||
564 | /** | ||
565 | * mmc_regulator_set_ocr - set regulator to match host->ios voltage | ||
566 | * @vdd_bit: zero for power off, else a bit number (host->ios.vdd) | ||
567 | * @supply: regulator to use | ||
568 | * | ||
569 | * Returns zero on success, else negative errno. | ||
570 | * | ||
571 | * MMC host drivers may use this to enable or disable a regulator using | ||
572 | * a particular supply voltage. This would normally be called from the | ||
573 | * set_ios() method. | ||
574 | */ | ||
575 | int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit) | ||
576 | { | ||
577 | int result = 0; | ||
578 | int min_uV, max_uV; | ||
579 | int enabled; | ||
580 | |||
581 | enabled = regulator_is_enabled(supply); | ||
582 | if (enabled < 0) | ||
583 | return enabled; | ||
584 | |||
585 | if (vdd_bit) { | ||
586 | int tmp; | ||
587 | int voltage; | ||
588 | |||
589 | /* REVISIT mmc_vddrange_to_ocrmask() may have set some | ||
590 | * bits this regulator doesn't quite support ... don't | ||
591 | * be too picky, most cards and regulators are OK with | ||
592 | * a 0.1V range goof (it's a small error percentage). | ||
593 | */ | ||
594 | tmp = vdd_bit - ilog2(MMC_VDD_165_195); | ||
595 | if (tmp == 0) { | ||
596 | min_uV = 1650 * 1000; | ||
597 | max_uV = 1950 * 1000; | ||
598 | } else { | ||
599 | min_uV = 1900 * 1000 + tmp * 100 * 1000; | ||
600 | max_uV = min_uV + 100 * 1000; | ||
601 | } | ||
602 | |||
603 | /* avoid needless changes to this voltage; the regulator | ||
604 | * might not allow this operation | ||
605 | */ | ||
606 | voltage = regulator_get_voltage(supply); | ||
607 | if (voltage < 0) | ||
608 | result = voltage; | ||
609 | else if (voltage < min_uV || voltage > max_uV) | ||
610 | result = regulator_set_voltage(supply, min_uV, max_uV); | ||
611 | else | ||
612 | result = 0; | ||
613 | |||
614 | if (result == 0 && !enabled) | ||
615 | result = regulator_enable(supply); | ||
616 | } else if (enabled) { | ||
617 | result = regulator_disable(supply); | ||
618 | } | ||
619 | |||
620 | return result; | ||
621 | } | ||
622 | EXPORT_SYMBOL(mmc_regulator_set_ocr); | ||
623 | |||
624 | #endif | ||
625 | |||
526 | /* | 626 | /* |
527 | * Mask off any voltages we don't support and select | 627 | * Mask off any voltages we don't support and select |
528 | * the lowest voltage | 628 | * the lowest voltage |
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 4e457256bd33..3e7615e9087e 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h | |||
@@ -192,5 +192,10 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host) | |||
192 | wake_up_process(host->sdio_irq_thread); | 192 | wake_up_process(host->sdio_irq_thread); |
193 | } | 193 | } |
194 | 194 | ||
195 | struct regulator; | ||
196 | |||
197 | int mmc_regulator_get_ocrmask(struct regulator *supply); | ||
198 | int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit); | ||
199 | |||
195 | #endif | 200 | #endif |
196 | 201 | ||