aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-08-31 13:36:37 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-09-09 23:25:10 -0400
commitf59c8f9fe689790248ae7aa7426579982050638c (patch)
tree8913b43ef7c4799323cc0d14fc1447da5ca2e052 /drivers
parent4cbe5a555fa58a79b6ecbb6c531b8bab0650778d (diff)
regulator: core: Support bypass mode
Many regulators support a bypass mode where they simply switch their input supply to the output. This is mainly used in low power retention states where power consumption is extremely low so higher voltage or less clean supplies can be used. Support this by providing ops for the drivers and a consumer API which allows the device to be put into bypass mode if all consumers enable it and the machine enables permission for this. This is not supported as a mode since the existing modes are rarely used due to fuzzy definition and mostly redundant with modern hardware which is able to respond promptly to load changes. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Reviewed-by: Graeme Gregory <gg@slimlogic.co.uk>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/regulator/core.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 48385318175a..64e16053975e 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -77,6 +77,7 @@ struct regulator {
77 struct device *dev; 77 struct device *dev;
78 struct list_head list; 78 struct list_head list;
79 unsigned int always_on:1; 79 unsigned int always_on:1;
80 unsigned int bypass:1;
80 int uA_load; 81 int uA_load;
81 int min_uV; 82 int min_uV;
82 int max_uV; 83 int max_uV;
@@ -394,6 +395,9 @@ static ssize_t regulator_status_show(struct device *dev,
394 case REGULATOR_STATUS_STANDBY: 395 case REGULATOR_STATUS_STANDBY:
395 label = "standby"; 396 label = "standby";
396 break; 397 break;
398 case REGULATOR_STATUS_BYPASS:
399 label = "bypass";
400 break;
397 case REGULATOR_STATUS_UNDEFINED: 401 case REGULATOR_STATUS_UNDEFINED:
398 label = "undefined"; 402 label = "undefined";
399 break; 403 break;
@@ -585,6 +589,27 @@ static ssize_t regulator_suspend_standby_state_show(struct device *dev,
585static DEVICE_ATTR(suspend_standby_state, 0444, 589static DEVICE_ATTR(suspend_standby_state, 0444,
586 regulator_suspend_standby_state_show, NULL); 590 regulator_suspend_standby_state_show, NULL);
587 591
592static ssize_t regulator_bypass_show(struct device *dev,
593 struct device_attribute *attr, char *buf)
594{
595 struct regulator_dev *rdev = dev_get_drvdata(dev);
596 const char *report;
597 bool bypass;
598 int ret;
599
600 ret = rdev->desc->ops->get_bypass(rdev, &bypass);
601
602 if (ret != 0)
603 report = "unknown";
604 else if (bypass)
605 report = "enabled";
606 else
607 report = "disabled";
608
609 return sprintf(buf, "%s\n", report);
610}
611static DEVICE_ATTR(bypass, 0444,
612 regulator_bypass_show, NULL);
588 613
589/* 614/*
590 * These are the only attributes are present for all regulators. 615 * These are the only attributes are present for all regulators.
@@ -2674,6 +2699,59 @@ out:
2674EXPORT_SYMBOL_GPL(regulator_set_optimum_mode); 2699EXPORT_SYMBOL_GPL(regulator_set_optimum_mode);
2675 2700
2676/** 2701/**
2702 * regulator_allow_bypass - allow the regulator to go into bypass mode
2703 *
2704 * @regulator: Regulator to configure
2705 * @allow: enable or disable bypass mode
2706 *
2707 * Allow the regulator to go into bypass mode if all other consumers
2708 * for the regulator also enable bypass mode and the machine
2709 * constraints allow this. Bypass mode means that the regulator is
2710 * simply passing the input directly to the output with no regulation.
2711 */
2712int regulator_allow_bypass(struct regulator *regulator, bool enable)
2713{
2714 struct regulator_dev *rdev = regulator->rdev;
2715 int ret = 0;
2716
2717 if (!rdev->desc->ops->set_bypass)
2718 return 0;
2719
2720 if (rdev->constraints &&
2721 !(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_BYPASS))
2722 return 0;
2723
2724 mutex_lock(&rdev->mutex);
2725
2726 if (enable && !regulator->bypass) {
2727 rdev->bypass_count++;
2728
2729 if (rdev->bypass_count == rdev->open_count) {
2730 ret = rdev->desc->ops->set_bypass(rdev, enable);
2731 if (ret != 0)
2732 rdev->bypass_count--;
2733 }
2734
2735 } else if (!enable && regulator->bypass) {
2736 rdev->bypass_count--;
2737
2738 if (rdev->bypass_count != rdev->open_count) {
2739 ret = rdev->desc->ops->set_bypass(rdev, enable);
2740 if (ret != 0)
2741 rdev->bypass_count++;
2742 }
2743 }
2744
2745 if (ret == 0)
2746 regulator->bypass = enable;
2747
2748 mutex_unlock(&rdev->mutex);
2749
2750 return ret;
2751}
2752EXPORT_SYMBOL_GPL(regulator_allow_bypass);
2753
2754/**
2677 * regulator_register_notifier - register regulator event notifier 2755 * regulator_register_notifier - register regulator event notifier
2678 * @regulator: regulator source 2756 * @regulator: regulator source
2679 * @nb: notifier block 2757 * @nb: notifier block
@@ -3036,6 +3114,11 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
3036 if (status < 0) 3114 if (status < 0)
3037 return status; 3115 return status;
3038 } 3116 }
3117 if (ops->get_bypass) {
3118 status = device_create_file(dev, &dev_attr_bypass);
3119 if (status < 0)
3120 return status;
3121 }
3039 3122
3040 /* some attributes are type-specific */ 3123 /* some attributes are type-specific */
3041 if (rdev->desc->type == REGULATOR_CURRENT) { 3124 if (rdev->desc->type == REGULATOR_CURRENT) {
@@ -3124,6 +3207,8 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
3124 &rdev->use_count); 3207 &rdev->use_count);
3125 debugfs_create_u32("open_count", 0444, rdev->debugfs, 3208 debugfs_create_u32("open_count", 0444, rdev->debugfs,
3126 &rdev->open_count); 3209 &rdev->open_count);
3210 debugfs_create_u32("bypass_count", 0444, rdev->debugfs,
3211 &rdev->bypass_count);
3127} 3212}
3128 3213
3129/** 3214/**