aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2009-03-11 07:30:43 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2009-03-31 04:56:26 -0400
commit5c13941acc513669c7d07b28789c3f9ba66ddddf (patch)
tree0f8170e9af5e3ee25e06c20520d3b2cd85733070 /drivers/mmc/core
parent66b659e685bca1f2f6d6102bac74cafbc7eef5c2 (diff)
MMC: regulator utilities
Glue between MMC and regulator stacks ... verified with some OMAP3 boards using adjustable and configured-as-fixed regulators on several MMC controllers. These calls are intended to be used by MMC host adapters using at least one regulator per host. Examples include slots with regulators supporting multiple voltages and ones using multiple voltage rails (e.g. DAT4..DAT7 using a separate supply, or a split rail chip like certain SDIO WLAN or eMMC solutions). Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Acked-by: Pierre Ossman <drzeus@drzeus.cx> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r--drivers/mmc/core/core.c100
1 files changed, 100 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}
524EXPORT_SYMBOL(mmc_vddrange_to_ocrmask); 525EXPORT_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 */
538int 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}
562EXPORT_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 */
575int 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}
622EXPORT_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