aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--Documentation/ABI/testing/sysfs-class-regulator21
-rw-r--r--drivers/regulator/core.c85
-rw-r--r--include/linux/regulator/consumer.h8
-rw-r--r--include/linux/regulator/driver.h10
-rw-r--r--include/linux/regulator/machine.h2
5 files changed, 126 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-regulator b/Documentation/ABI/testing/sysfs-class-regulator
index e091fa873792..bc578bc60628 100644
--- a/Documentation/ABI/testing/sysfs-class-regulator
+++ b/Documentation/ABI/testing/sysfs-class-regulator
@@ -349,3 +349,24 @@ Description:
349 349
350 This will be one of the same strings reported by 350 This will be one of the same strings reported by
351 the "state" attribute. 351 the "state" attribute.
352
353What: /sys/class/regulator/.../bypass
354Date: September 2012
355KernelVersion: 3.7
356Contact: Mark Brown <broonie@opensource.wolfsonmicro.com>
357Description:
358 Some regulator directories will contain a field called
359 bypass. This indicates if the device is in bypass mode.
360
361 This will be one of the following strings:
362
363 'enabled'
364 'disabled'
365 'unknown'
366
367 'enabled' means the regulator is in bypass mode.
368
369 'disabled' means that the regulator is regulating.
370
371 'unknown' means software cannot determine the state, or
372 the reported state is invalid.
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/**
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index da339fd8c755..ea3e35816621 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -177,6 +177,8 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode);
177unsigned int regulator_get_mode(struct regulator *regulator); 177unsigned int regulator_get_mode(struct regulator *regulator);
178int regulator_set_optimum_mode(struct regulator *regulator, int load_uA); 178int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);
179 179
180int regulator_allow_bypass(struct regulator *regulator, bool allow);
181
180/* regulator notifier block */ 182/* regulator notifier block */
181int regulator_register_notifier(struct regulator *regulator, 183int regulator_register_notifier(struct regulator *regulator,
182 struct notifier_block *nb); 184 struct notifier_block *nb);
@@ -328,6 +330,12 @@ static inline int regulator_set_optimum_mode(struct regulator *regulator,
328 return REGULATOR_MODE_NORMAL; 330 return REGULATOR_MODE_NORMAL;
329} 331}
330 332
333static inline int regulator_allow_bypass(struct regulator *regulator,
334 bool allow)
335{
336 return 0;
337}
338
331static inline int regulator_register_notifier(struct regulator *regulator, 339static inline int regulator_register_notifier(struct regulator *regulator,
332 struct notifier_block *nb) 340 struct notifier_block *nb)
333{ 341{
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index bac4c871f3bd..c9869cfbf261 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -32,6 +32,8 @@ enum regulator_status {
32 REGULATOR_STATUS_NORMAL, 32 REGULATOR_STATUS_NORMAL,
33 REGULATOR_STATUS_IDLE, 33 REGULATOR_STATUS_IDLE,
34 REGULATOR_STATUS_STANDBY, 34 REGULATOR_STATUS_STANDBY,
35 /* The regulator is enabled but not regulating */
36 REGULATOR_STATUS_BYPASS,
35 /* in case that any other status doesn't apply */ 37 /* in case that any other status doesn't apply */
36 REGULATOR_STATUS_UNDEFINED, 38 REGULATOR_STATUS_UNDEFINED,
37}; 39};
@@ -67,6 +69,9 @@ enum regulator_status {
67 * @get_optimum_mode: Get the most efficient operating mode for the regulator 69 * @get_optimum_mode: Get the most efficient operating mode for the regulator
68 * when running with the specified parameters. 70 * when running with the specified parameters.
69 * 71 *
72 * @set_bypass: Set the regulator in bypass mode.
73 * @get_bypass: Get the regulator bypass mode state.
74 *
70 * @enable_time: Time taken for the regulator voltage output voltage to 75 * @enable_time: Time taken for the regulator voltage output voltage to
71 * stabilise after being enabled, in microseconds. 76 * stabilise after being enabled, in microseconds.
72 * @set_ramp_delay: Set the ramp delay for the regulator. The driver should 77 * @set_ramp_delay: Set the ramp delay for the regulator. The driver should
@@ -133,6 +138,10 @@ struct regulator_ops {
133 unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV, 138 unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV,
134 int output_uV, int load_uA); 139 int output_uV, int load_uA);
135 140
141 /* control and report on bypass mode */
142 int (*set_bypass)(struct regulator_dev *dev, bool enable);
143 int (*get_bypass)(struct regulator_dev *dev, bool *enable);
144
136 /* the operations below are for configuration of regulator state when 145 /* the operations below are for configuration of regulator state when
137 * its parent PMIC enters a global STANDBY/HIBERNATE state */ 146 * its parent PMIC enters a global STANDBY/HIBERNATE state */
138 147
@@ -253,6 +262,7 @@ struct regulator_dev {
253 int exclusive; 262 int exclusive;
254 u32 use_count; 263 u32 use_count;
255 u32 open_count; 264 u32 open_count;
265 u32 bypass_count;
256 266
257 /* lists we belong to */ 267 /* lists we belong to */
258 struct list_head list; /* list of all regulators */ 268 struct list_head list; /* list of all regulators */
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index 40dd0a394cfa..36adbc82de6a 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -32,6 +32,7 @@ struct regulator;
32 * board/machine. 32 * board/machine.
33 * STATUS: Regulator can be enabled and disabled. 33 * STATUS: Regulator can be enabled and disabled.
34 * DRMS: Dynamic Regulator Mode Switching is enabled for this regulator. 34 * DRMS: Dynamic Regulator Mode Switching is enabled for this regulator.
35 * BYPASS: Regulator can be put into bypass mode
35 */ 36 */
36 37
37#define REGULATOR_CHANGE_VOLTAGE 0x1 38#define REGULATOR_CHANGE_VOLTAGE 0x1
@@ -39,6 +40,7 @@ struct regulator;
39#define REGULATOR_CHANGE_MODE 0x4 40#define REGULATOR_CHANGE_MODE 0x4
40#define REGULATOR_CHANGE_STATUS 0x8 41#define REGULATOR_CHANGE_STATUS 0x8
41#define REGULATOR_CHANGE_DRMS 0x10 42#define REGULATOR_CHANGE_DRMS 0x10
43#define REGULATOR_CHANGE_BYPASS 0x20
42 44
43/** 45/**
44 * struct regulator_state - regulator state during low power system states 46 * struct regulator_state - regulator state during low power system states