aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChunyan Zhang <zhang.chunyan@linaro.org>2018-01-26 08:08:47 -0500
committerMark Brown <broonie@kernel.org>2018-01-26 09:43:55 -0500
commitf7efad10b5c492892b1e5decf5d3ebb29fa5c9af (patch)
tree10ca83d0c4c018b03cdaf9a9597e3d75bf2e1a1c
parentaa27bbc6c6c60227c096d515f55ffe6cdfef7d2b (diff)
regulator: add PM suspend and resume hooks
In this patch, consumers are allowed to set suspend voltage, and this actually just set the "uV" in constraint::regulator_state, when the regulator_suspend_late() was called by PM core through callback when the system is entering into suspend, the regulator device would act suspend activity then. And it assumes that if any consumer set suspend voltage, the regulator device should be enabled in the suspend state. And if the suspend voltage of a regulator device for all consumers was set zero, the regulator device would be off in the suspend state. This patch also provides a new function hook to regulator devices for resuming from suspend states. Signed-off-by: Chunyan Zhang <zhang.chunyan@linaro.org> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/regulator/core.c255
-rw-r--r--drivers/regulator/of_regulator.c14
-rw-r--r--include/linux/regulator/driver.h2
-rw-r--r--include/linux/regulator/machine.h13
4 files changed, 251 insertions, 33 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 080c2334edc5..949e317e4d6e 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -236,6 +236,12 @@ static int regulator_check_voltage(struct regulator_dev *rdev,
236 return 0; 236 return 0;
237} 237}
238 238
239/* return 0 if the state is valid */
240static int regulator_check_states(suspend_state_t state)
241{
242 return (state > PM_SUSPEND_MAX || state == PM_SUSPEND_TO_IDLE);
243}
244
239/* Make sure we select a voltage that suits the needs of all 245/* Make sure we select a voltage that suits the needs of all
240 * regulator consumers 246 * regulator consumers
241 */ 247 */
@@ -327,6 +333,24 @@ static int regulator_mode_constrain(struct regulator_dev *rdev,
327 return -EINVAL; 333 return -EINVAL;
328} 334}
329 335
336static inline struct regulator_state *
337regulator_get_suspend_state(struct regulator_dev *rdev, suspend_state_t state)
338{
339 if (rdev->constraints == NULL)
340 return NULL;
341
342 switch (state) {
343 case PM_SUSPEND_STANDBY:
344 return &rdev->constraints->state_standby;
345 case PM_SUSPEND_MEM:
346 return &rdev->constraints->state_mem;
347 case PM_SUSPEND_MAX:
348 return &rdev->constraints->state_disk;
349 default:
350 return NULL;
351 }
352}
353
330static ssize_t regulator_uV_show(struct device *dev, 354static ssize_t regulator_uV_show(struct device *dev,
331 struct device_attribute *attr, char *buf) 355 struct device_attribute *attr, char *buf)
332{ 356{
@@ -734,9 +758,14 @@ static int drms_uA_update(struct regulator_dev *rdev)
734} 758}
735 759
736static int suspend_set_state(struct regulator_dev *rdev, 760static int suspend_set_state(struct regulator_dev *rdev,
737 struct regulator_state *rstate) 761 suspend_state_t state)
738{ 762{
739 int ret = 0; 763 int ret = 0;
764 struct regulator_state *rstate;
765
766 rstate = regulator_get_suspend_state(rdev, state);
767 if (rstate == NULL)
768 return -EINVAL;
740 769
741 /* If we have no suspend mode configration don't set anything; 770 /* If we have no suspend mode configration don't set anything;
742 * only warn if the driver implements set_suspend_voltage or 771 * only warn if the driver implements set_suspend_voltage or
@@ -779,28 +808,8 @@ static int suspend_set_state(struct regulator_dev *rdev,
779 return ret; 808 return ret;
780 } 809 }
781 } 810 }
782 return ret;
783}
784 811
785/* locks held by caller */ 812 return ret;
786static int suspend_prepare(struct regulator_dev *rdev, suspend_state_t state)
787{
788 if (!rdev->constraints)
789 return -EINVAL;
790
791 switch (state) {
792 case PM_SUSPEND_STANDBY:
793 return suspend_set_state(rdev,
794 &rdev->constraints->state_standby);
795 case PM_SUSPEND_MEM:
796 return suspend_set_state(rdev,
797 &rdev->constraints->state_mem);
798 case PM_SUSPEND_MAX:
799 return suspend_set_state(rdev,
800 &rdev->constraints->state_disk);
801 default:
802 return -EINVAL;
803 }
804} 813}
805 814
806static void print_constraints(struct regulator_dev *rdev) 815static void print_constraints(struct regulator_dev *rdev)
@@ -1069,7 +1078,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
1069 1078
1070 /* do we need to setup our suspend state */ 1079 /* do we need to setup our suspend state */
1071 if (rdev->constraints->initial_state) { 1080 if (rdev->constraints->initial_state) {
1072 ret = suspend_prepare(rdev, rdev->constraints->initial_state); 1081 ret = suspend_set_state(rdev, rdev->constraints->initial_state);
1073 if (ret < 0) { 1082 if (ret < 0) {
1074 rdev_err(rdev, "failed to set suspend state\n"); 1083 rdev_err(rdev, "failed to set suspend state\n");
1075 return ret; 1084 return ret;
@@ -2898,6 +2907,32 @@ out:
2898 return ret; 2907 return ret;
2899} 2908}
2900 2909
2910static int _regulator_do_set_suspend_voltage(struct regulator_dev *rdev,
2911 int min_uV, int max_uV, suspend_state_t state)
2912{
2913 struct regulator_state *rstate;
2914 int uV, sel;
2915
2916 rstate = regulator_get_suspend_state(rdev, state);
2917 if (rstate == NULL)
2918 return -EINVAL;
2919
2920 if (min_uV < rstate->min_uV)
2921 min_uV = rstate->min_uV;
2922 if (max_uV > rstate->max_uV)
2923 max_uV = rstate->max_uV;
2924
2925 sel = regulator_map_voltage(rdev, min_uV, max_uV);
2926 if (sel < 0)
2927 return sel;
2928
2929 uV = rdev->desc->ops->list_voltage(rdev, sel);
2930 if (uV >= min_uV && uV <= max_uV)
2931 rstate->uV = uV;
2932
2933 return 0;
2934}
2935
2901static int regulator_set_voltage_unlocked(struct regulator *regulator, 2936static int regulator_set_voltage_unlocked(struct regulator *regulator,
2902 int min_uV, int max_uV, 2937 int min_uV, int max_uV,
2903 suspend_state_t state) 2938 suspend_state_t state)
@@ -2993,7 +3028,11 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
2993 } 3028 }
2994 } 3029 }
2995 3030
2996 ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); 3031 if (state == PM_SUSPEND_ON)
3032 ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
3033 else
3034 ret = _regulator_do_set_suspend_voltage(rdev, min_uV,
3035 max_uV, state);
2997 if (ret < 0) 3036 if (ret < 0)
2998 goto out2; 3037 goto out2;
2999 3038
@@ -3049,6 +3088,89 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
3049} 3088}
3050EXPORT_SYMBOL_GPL(regulator_set_voltage); 3089EXPORT_SYMBOL_GPL(regulator_set_voltage);
3051 3090
3091static inline int regulator_suspend_toggle(struct regulator_dev *rdev,
3092 suspend_state_t state, bool en)
3093{
3094 struct regulator_state *rstate;
3095
3096 rstate = regulator_get_suspend_state(rdev, state);
3097 if (rstate == NULL)
3098 return -EINVAL;
3099
3100 if (!rstate->changeable)
3101 return -EPERM;
3102
3103 rstate->enabled = en;
3104
3105 return 0;
3106}
3107
3108int regulator_suspend_enable(struct regulator_dev *rdev,
3109 suspend_state_t state)
3110{
3111 return regulator_suspend_toggle(rdev, state, true);
3112}
3113EXPORT_SYMBOL_GPL(regulator_suspend_enable);
3114
3115int regulator_suspend_disable(struct regulator_dev *rdev,
3116 suspend_state_t state)
3117{
3118 struct regulator *regulator;
3119 struct regulator_voltage *voltage;
3120
3121 /*
3122 * if any consumer wants this regulator device keeping on in
3123 * suspend states, don't set it as disabled.
3124 */
3125 list_for_each_entry(regulator, &rdev->consumer_list, list) {
3126 voltage = &regulator->voltage[state];
3127 if (voltage->min_uV || voltage->max_uV)
3128 return 0;
3129 }
3130
3131 return regulator_suspend_toggle(rdev, state, false);
3132}
3133EXPORT_SYMBOL_GPL(regulator_suspend_disable);
3134
3135static int _regulator_set_suspend_voltage(struct regulator *regulator,
3136 int min_uV, int max_uV,
3137 suspend_state_t state)
3138{
3139 struct regulator_dev *rdev = regulator->rdev;
3140 struct regulator_state *rstate;
3141
3142 rstate = regulator_get_suspend_state(rdev, state);
3143 if (rstate == NULL)
3144 return -EINVAL;
3145
3146 if (rstate->min_uV == rstate->max_uV) {
3147 rdev_err(rdev, "The suspend voltage can't be changed!\n");
3148 return -EPERM;
3149 }
3150
3151 return regulator_set_voltage_unlocked(regulator, min_uV, max_uV, state);
3152}
3153
3154int regulator_set_suspend_voltage(struct regulator *regulator, int min_uV,
3155 int max_uV, suspend_state_t state)
3156{
3157 int ret = 0;
3158
3159 /* PM_SUSPEND_ON is handled by regulator_set_voltage() */
3160 if (regulator_check_states(state) || state == PM_SUSPEND_ON)
3161 return -EINVAL;
3162
3163 regulator_lock_supply(regulator->rdev);
3164
3165 ret = _regulator_set_suspend_voltage(regulator, min_uV,
3166 max_uV, state);
3167
3168 regulator_unlock_supply(regulator->rdev);
3169
3170 return ret;
3171}
3172EXPORT_SYMBOL_GPL(regulator_set_suspend_voltage);
3173
3052/** 3174/**
3053 * regulator_set_voltage_time - get raise/fall time 3175 * regulator_set_voltage_time - get raise/fall time
3054 * @regulator: regulator source 3176 * @regulator: regulator source
@@ -3923,12 +4045,6 @@ static void regulator_dev_release(struct device *dev)
3923 kfree(rdev); 4045 kfree(rdev);
3924} 4046}
3925 4047
3926static struct class regulator_class = {
3927 .name = "regulator",
3928 .dev_release = regulator_dev_release,
3929 .dev_groups = regulator_dev_groups,
3930};
3931
3932static void rdev_init_debugfs(struct regulator_dev *rdev) 4048static void rdev_init_debugfs(struct regulator_dev *rdev)
3933{ 4049{
3934 struct device *parent = rdev->dev.parent; 4050 struct device *parent = rdev->dev.parent;
@@ -4179,8 +4295,87 @@ void regulator_unregister(struct regulator_dev *rdev)
4179} 4295}
4180EXPORT_SYMBOL_GPL(regulator_unregister); 4296EXPORT_SYMBOL_GPL(regulator_unregister);
4181 4297
4298#ifdef CONFIG_SUSPEND
4299static int _regulator_suspend_late(struct device *dev, void *data)
4300{
4301 struct regulator_dev *rdev = dev_to_rdev(dev);
4302 suspend_state_t *state = data;
4303 int ret;
4304
4305 mutex_lock(&rdev->mutex);
4306 ret = suspend_set_state(rdev, *state);
4307 mutex_unlock(&rdev->mutex);
4308
4309 return ret;
4310}
4182 4311
4183/** 4312/**
4313 * regulator_suspend_late - prepare regulators for system wide suspend
4314 * @state: system suspend state
4315 *
4316 * Configure each regulator with it's suspend operating parameters for state.
4317 */
4318static int regulator_suspend_late(struct device *dev)
4319{
4320 suspend_state_t state = pm_suspend_target_state;
4321
4322 return class_for_each_device(&regulator_class, NULL, &state,
4323 _regulator_suspend_late);
4324}
4325static int _regulator_resume_early(struct device *dev, void *data)
4326{
4327 int ret = 0;
4328 struct regulator_dev *rdev = dev_to_rdev(dev);
4329 suspend_state_t *state = data;
4330 struct regulator_state *rstate;
4331
4332 rstate = regulator_get_suspend_state(rdev, *state);
4333 if (rstate == NULL)
4334 return -EINVAL;
4335
4336 mutex_lock(&rdev->mutex);
4337
4338 if (rdev->desc->ops->resume_early &&
4339 (rstate->enabled == ENABLE_IN_SUSPEND ||
4340 rstate->enabled == DISABLE_IN_SUSPEND))
4341 ret = rdev->desc->ops->resume_early(rdev);
4342
4343 mutex_unlock(&rdev->mutex);
4344
4345 return ret;
4346}
4347
4348static int regulator_resume_early(struct device *dev)
4349{
4350 suspend_state_t state = pm_suspend_target_state;
4351
4352 return class_for_each_device(&regulator_class, NULL, &state,
4353 _regulator_resume_early);
4354}
4355
4356#else /* !CONFIG_SUSPEND */
4357
4358#define regulator_suspend_late NULL
4359#define regulator_resume_early NULL
4360
4361#endif /* !CONFIG_SUSPEND */
4362
4363#ifdef CONFIG_PM
4364static const struct dev_pm_ops __maybe_unused regulator_pm_ops = {
4365 .suspend_late = regulator_suspend_late,
4366 .resume_early = regulator_resume_early,
4367};
4368#endif
4369
4370static struct class regulator_class = {
4371 .name = "regulator",
4372 .dev_release = regulator_dev_release,
4373 .dev_groups = regulator_dev_groups,
4374#ifdef CONFIG_PM
4375 .pm = &regulator_pm_ops,
4376#endif
4377};
4378/**
4184 * regulator_has_full_constraints - the system has fully specified constraints 4379 * regulator_has_full_constraints - the system has fully specified constraints
4185 * 4380 *
4186 * Calling this function will cause the regulator API to disable all 4381 * Calling this function will cause the regulator API to disable all
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 41dad42b18f0..a09ef6cc2e9c 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -184,9 +184,23 @@ static void of_get_regulation_constraints(struct device_node *np,
184 else 184 else
185 suspend_state->enabled = DO_NOTHING_IN_SUSPEND; 185 suspend_state->enabled = DO_NOTHING_IN_SUSPEND;
186 186
187 if (!of_property_read_u32(np, "regulator-suspend-min-microvolt",
188 &pval))
189 suspend_state->min_uV = pval;
190
191 if (!of_property_read_u32(np, "regulator-suspend-max-microvolt",
192 &pval))
193 suspend_state->max_uV = pval;
194
187 if (!of_property_read_u32(suspend_np, 195 if (!of_property_read_u32(suspend_np,
188 "regulator-suspend-microvolt", &pval)) 196 "regulator-suspend-microvolt", &pval))
189 suspend_state->uV = pval; 197 suspend_state->uV = pval;
198 else /* otherwise use min_uV as default suspend voltage */
199 suspend_state->uV = suspend_state->min_uV;
200
201 if (of_property_read_bool(suspend_np,
202 "regulator-changeable-in-suspend"))
203 suspend_state->changeable = true;
190 204
191 if (i == PM_SUSPEND_MEM) 205 if (i == PM_SUSPEND_MEM)
192 constraints->initial_state = PM_SUSPEND_MEM; 206 constraints->initial_state = PM_SUSPEND_MEM;
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 94417b4226bd..4c00486b7a78 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -214,6 +214,8 @@ struct regulator_ops {
214 /* set regulator suspend operating mode (defined in consumer.h) */ 214 /* set regulator suspend operating mode (defined in consumer.h) */
215 int (*set_suspend_mode) (struct regulator_dev *, unsigned int mode); 215 int (*set_suspend_mode) (struct regulator_dev *, unsigned int mode);
216 216
217 int (*resume_early)(struct regulator_dev *rdev);
218
217 int (*set_pull_down) (struct regulator_dev *); 219 int (*set_pull_down) (struct regulator_dev *);
218}; 220};
219 221
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index c4a56df8931b..93a04893c739 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -66,17 +66,24 @@ enum regulator_active_discharge {
66 * state. One of enabled or disabled must be set for the 66 * state. One of enabled or disabled must be set for the
67 * configuration to be applied. 67 * configuration to be applied.
68 * 68 *
69 * @uV: Operating voltage during suspend. 69 * @uV: Default operating voltage during suspend, it can be adjusted
70 * among <min_uV, max_uV>.
71 * @min_uV: Minimum suspend voltage may be set.
72 * @max_uV: Maximum suspend voltage may be set.
70 * @mode: Operating mode during suspend. 73 * @mode: Operating mode during suspend.
71 * @enabled: operations during suspend. 74 * @enabled: operations during suspend.
72 * - DO_NOTHING_IN_SUSPEND 75 * - DO_NOTHING_IN_SUSPEND
73 * - DISABLE_IN_SUSPEND 76 * - DISABLE_IN_SUSPEND
74 * - ENABLE_IN_SUSPEND 77 * - ENABLE_IN_SUSPEND
78 * @changeable: Is this state can be switched between enabled/disabled,
75 */ 79 */
76struct regulator_state { 80struct regulator_state {
77 int uV; /* suspend voltage */ 81 int uV;
78 unsigned int mode; /* suspend regulator operating mode */ 82 int min_uV;
83 int max_uV;
84 unsigned int mode;
79 int enabled; 85 int enabled;
86 bool changeable;
80}; 87};
81 88
82/** 89/**