Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Chunyan Zhang and committed by
Mark Brown
f7efad10 aa27bbc6

+251 -33
+225 -30
drivers/regulator/core.c
··· 236 236 return 0; 237 237 } 238 238 239 + /* return 0 if the state is valid */ 240 + static int regulator_check_states(suspend_state_t state) 241 + { 242 + return (state > PM_SUSPEND_MAX || state == PM_SUSPEND_TO_IDLE); 243 + } 244 + 239 245 /* Make sure we select a voltage that suits the needs of all 240 246 * regulator consumers 241 247 */ ··· 331 325 } 332 326 333 327 return -EINVAL; 328 + } 329 + 330 + static inline struct regulator_state * 331 + regulator_get_suspend_state(struct regulator_dev *rdev, suspend_state_t state) 332 + { 333 + if (rdev->constraints == NULL) 334 + return NULL; 335 + 336 + switch (state) { 337 + case PM_SUSPEND_STANDBY: 338 + return &rdev->constraints->state_standby; 339 + case PM_SUSPEND_MEM: 340 + return &rdev->constraints->state_mem; 341 + case PM_SUSPEND_MAX: 342 + return &rdev->constraints->state_disk; 343 + default: 344 + return NULL; 345 + } 334 346 } 335 347 336 348 static ssize_t regulator_uV_show(struct device *dev, ··· 758 734 } 759 735 760 736 static int suspend_set_state(struct regulator_dev *rdev, 761 - struct regulator_state *rstate) 737 + suspend_state_t state) 762 738 { 763 739 int ret = 0; 740 + struct regulator_state *rstate; 741 + 742 + rstate = regulator_get_suspend_state(rdev, state); 743 + if (rstate == NULL) 744 + return -EINVAL; 764 745 765 746 /* If we have no suspend mode configration don't set anything; 766 747 * only warn if the driver implements set_suspend_voltage or ··· 808 779 return ret; 809 780 } 810 781 } 782 + 811 783 return ret; 812 - } 813 - 814 - /* locks held by caller */ 815 - static int suspend_prepare(struct regulator_dev *rdev, suspend_state_t state) 816 - { 817 - if (!rdev->constraints) 818 - return -EINVAL; 819 - 820 - switch (state) { 821 - case PM_SUSPEND_STANDBY: 822 - return suspend_set_state(rdev, 823 - &rdev->constraints->state_standby); 824 - case PM_SUSPEND_MEM: 825 - return suspend_set_state(rdev, 826 - &rdev->constraints->state_mem); 827 - case PM_SUSPEND_MAX: 828 - return suspend_set_state(rdev, 829 - &rdev->constraints->state_disk); 830 - default: 831 - return -EINVAL; 832 - } 833 784 } 834 785 835 786 static void print_constraints(struct regulator_dev *rdev) ··· 1078 1069 1079 1070 /* do we need to setup our suspend state */ 1080 1071 if (rdev->constraints->initial_state) { 1081 - ret = suspend_prepare(rdev, rdev->constraints->initial_state); 1072 + ret = suspend_set_state(rdev, rdev->constraints->initial_state); 1082 1073 if (ret < 0) { 1083 1074 rdev_err(rdev, "failed to set suspend state\n"); 1084 1075 return ret; ··· 2907 2898 return ret; 2908 2899 } 2909 2900 2901 + static int _regulator_do_set_suspend_voltage(struct regulator_dev *rdev, 2902 + int min_uV, int max_uV, suspend_state_t state) 2903 + { 2904 + struct regulator_state *rstate; 2905 + int uV, sel; 2906 + 2907 + rstate = regulator_get_suspend_state(rdev, state); 2908 + if (rstate == NULL) 2909 + return -EINVAL; 2910 + 2911 + if (min_uV < rstate->min_uV) 2912 + min_uV = rstate->min_uV; 2913 + if (max_uV > rstate->max_uV) 2914 + max_uV = rstate->max_uV; 2915 + 2916 + sel = regulator_map_voltage(rdev, min_uV, max_uV); 2917 + if (sel < 0) 2918 + return sel; 2919 + 2920 + uV = rdev->desc->ops->list_voltage(rdev, sel); 2921 + if (uV >= min_uV && uV <= max_uV) 2922 + rstate->uV = uV; 2923 + 2924 + return 0; 2925 + } 2926 + 2910 2927 static int regulator_set_voltage_unlocked(struct regulator *regulator, 2911 2928 int min_uV, int max_uV, 2912 2929 suspend_state_t state) ··· 3028 2993 } 3029 2994 } 3030 2995 3031 - ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); 2996 + if (state == PM_SUSPEND_ON) 2997 + ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); 2998 + else 2999 + ret = _regulator_do_set_suspend_voltage(rdev, min_uV, 3000 + max_uV, state); 3032 3001 if (ret < 0) 3033 3002 goto out2; 3034 3003 ··· 3087 3048 return ret; 3088 3049 } 3089 3050 EXPORT_SYMBOL_GPL(regulator_set_voltage); 3051 + 3052 + static inline int regulator_suspend_toggle(struct regulator_dev *rdev, 3053 + suspend_state_t state, bool en) 3054 + { 3055 + struct regulator_state *rstate; 3056 + 3057 + rstate = regulator_get_suspend_state(rdev, state); 3058 + if (rstate == NULL) 3059 + return -EINVAL; 3060 + 3061 + if (!rstate->changeable) 3062 + return -EPERM; 3063 + 3064 + rstate->enabled = en; 3065 + 3066 + return 0; 3067 + } 3068 + 3069 + int regulator_suspend_enable(struct regulator_dev *rdev, 3070 + suspend_state_t state) 3071 + { 3072 + return regulator_suspend_toggle(rdev, state, true); 3073 + } 3074 + EXPORT_SYMBOL_GPL(regulator_suspend_enable); 3075 + 3076 + int regulator_suspend_disable(struct regulator_dev *rdev, 3077 + suspend_state_t state) 3078 + { 3079 + struct regulator *regulator; 3080 + struct regulator_voltage *voltage; 3081 + 3082 + /* 3083 + * if any consumer wants this regulator device keeping on in 3084 + * suspend states, don't set it as disabled. 3085 + */ 3086 + list_for_each_entry(regulator, &rdev->consumer_list, list) { 3087 + voltage = &regulator->voltage[state]; 3088 + if (voltage->min_uV || voltage->max_uV) 3089 + return 0; 3090 + } 3091 + 3092 + return regulator_suspend_toggle(rdev, state, false); 3093 + } 3094 + EXPORT_SYMBOL_GPL(regulator_suspend_disable); 3095 + 3096 + static int _regulator_set_suspend_voltage(struct regulator *regulator, 3097 + int min_uV, int max_uV, 3098 + suspend_state_t state) 3099 + { 3100 + struct regulator_dev *rdev = regulator->rdev; 3101 + struct regulator_state *rstate; 3102 + 3103 + rstate = regulator_get_suspend_state(rdev, state); 3104 + if (rstate == NULL) 3105 + return -EINVAL; 3106 + 3107 + if (rstate->min_uV == rstate->max_uV) { 3108 + rdev_err(rdev, "The suspend voltage can't be changed!\n"); 3109 + return -EPERM; 3110 + } 3111 + 3112 + return regulator_set_voltage_unlocked(regulator, min_uV, max_uV, state); 3113 + } 3114 + 3115 + int regulator_set_suspend_voltage(struct regulator *regulator, int min_uV, 3116 + int max_uV, suspend_state_t state) 3117 + { 3118 + int ret = 0; 3119 + 3120 + /* PM_SUSPEND_ON is handled by regulator_set_voltage() */ 3121 + if (regulator_check_states(state) || state == PM_SUSPEND_ON) 3122 + return -EINVAL; 3123 + 3124 + regulator_lock_supply(regulator->rdev); 3125 + 3126 + ret = _regulator_set_suspend_voltage(regulator, min_uV, 3127 + max_uV, state); 3128 + 3129 + regulator_unlock_supply(regulator->rdev); 3130 + 3131 + return ret; 3132 + } 3133 + EXPORT_SYMBOL_GPL(regulator_set_suspend_voltage); 3090 3134 3091 3135 /** 3092 3136 * regulator_set_voltage_time - get raise/fall time ··· 4045 3923 kfree(rdev); 4046 3924 } 4047 3925 4048 - static struct class regulator_class = { 4049 - .name = "regulator", 4050 - .dev_release = regulator_dev_release, 4051 - .dev_groups = regulator_dev_groups, 4052 - }; 4053 - 4054 3926 static void rdev_init_debugfs(struct regulator_dev *rdev) 4055 3927 { 4056 3928 struct device *parent = rdev->dev.parent; ··· 4295 4179 } 4296 4180 EXPORT_SYMBOL_GPL(regulator_unregister); 4297 4181 4182 + #ifdef CONFIG_SUSPEND 4183 + static int _regulator_suspend_late(struct device *dev, void *data) 4184 + { 4185 + struct regulator_dev *rdev = dev_to_rdev(dev); 4186 + suspend_state_t *state = data; 4187 + int ret; 4298 4188 4189 + mutex_lock(&rdev->mutex); 4190 + ret = suspend_set_state(rdev, *state); 4191 + mutex_unlock(&rdev->mutex); 4192 + 4193 + return ret; 4194 + } 4195 + 4196 + /** 4197 + * regulator_suspend_late - prepare regulators for system wide suspend 4198 + * @state: system suspend state 4199 + * 4200 + * Configure each regulator with it's suspend operating parameters for state. 4201 + */ 4202 + static int regulator_suspend_late(struct device *dev) 4203 + { 4204 + suspend_state_t state = pm_suspend_target_state; 4205 + 4206 + return class_for_each_device(&regulator_class, NULL, &state, 4207 + _regulator_suspend_late); 4208 + } 4209 + static int _regulator_resume_early(struct device *dev, void *data) 4210 + { 4211 + int ret = 0; 4212 + struct regulator_dev *rdev = dev_to_rdev(dev); 4213 + suspend_state_t *state = data; 4214 + struct regulator_state *rstate; 4215 + 4216 + rstate = regulator_get_suspend_state(rdev, *state); 4217 + if (rstate == NULL) 4218 + return -EINVAL; 4219 + 4220 + mutex_lock(&rdev->mutex); 4221 + 4222 + if (rdev->desc->ops->resume_early && 4223 + (rstate->enabled == ENABLE_IN_SUSPEND || 4224 + rstate->enabled == DISABLE_IN_SUSPEND)) 4225 + ret = rdev->desc->ops->resume_early(rdev); 4226 + 4227 + mutex_unlock(&rdev->mutex); 4228 + 4229 + return ret; 4230 + } 4231 + 4232 + static int regulator_resume_early(struct device *dev) 4233 + { 4234 + suspend_state_t state = pm_suspend_target_state; 4235 + 4236 + return class_for_each_device(&regulator_class, NULL, &state, 4237 + _regulator_resume_early); 4238 + } 4239 + 4240 + #else /* !CONFIG_SUSPEND */ 4241 + 4242 + #define regulator_suspend_late NULL 4243 + #define regulator_resume_early NULL 4244 + 4245 + #endif /* !CONFIG_SUSPEND */ 4246 + 4247 + #ifdef CONFIG_PM 4248 + static const struct dev_pm_ops __maybe_unused regulator_pm_ops = { 4249 + .suspend_late = regulator_suspend_late, 4250 + .resume_early = regulator_resume_early, 4251 + }; 4252 + #endif 4253 + 4254 + static struct class regulator_class = { 4255 + .name = "regulator", 4256 + .dev_release = regulator_dev_release, 4257 + .dev_groups = regulator_dev_groups, 4258 + #ifdef CONFIG_PM 4259 + .pm = &regulator_pm_ops, 4260 + #endif 4261 + }; 4299 4262 /** 4300 4263 * regulator_has_full_constraints - the system has fully specified constraints 4301 4264 *
+14
drivers/regulator/of_regulator.c
··· 184 184 else 185 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 195 if (!of_property_read_u32(suspend_np, 188 196 "regulator-suspend-microvolt", &pval)) 189 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 205 if (i == PM_SUSPEND_MEM) 192 206 constraints->initial_state = PM_SUSPEND_MEM;
+2
include/linux/regulator/driver.h
··· 214 214 /* set regulator suspend operating mode (defined in consumer.h) */ 215 215 int (*set_suspend_mode) (struct regulator_dev *, unsigned int mode); 216 216 217 + int (*resume_early)(struct regulator_dev *rdev); 218 + 217 219 int (*set_pull_down) (struct regulator_dev *); 218 220 }; 219 221
+10 -3
include/linux/regulator/machine.h
··· 66 66 * state. One of enabled or disabled must be set for the 67 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 73 * @mode: Operating mode during suspend. 71 74 * @enabled: operations during suspend. 72 75 * - DO_NOTHING_IN_SUSPEND 73 76 * - DISABLE_IN_SUSPEND 74 77 * - ENABLE_IN_SUSPEND 78 + * @changeable: Is this state can be switched between enabled/disabled, 75 79 */ 76 80 struct regulator_state { 77 - int uV; /* suspend voltage */ 78 - unsigned int mode; /* suspend regulator operating mode */ 81 + int uV; 82 + int min_uV; 83 + int max_uV; 84 + unsigned int mode; 79 85 int enabled; 86 + bool changeable; 80 87 }; 81 88 82 89 /**