diff options
author | Tuomas Tynkkynen <ttynkkynen@nvidia.com> | 2014-07-21 11:38:48 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-07-25 13:43:48 -0400 |
commit | 04eca28cde52cdf9eb91e127cc358ad79a8ec53b (patch) | |
tree | cb4507f5e7f2430325312c86332fbe3ce887879b | |
parent | 7171511eaec5bf23fb06078f59784a3a0626b38f (diff) |
regulator: Add helpers for low-level register access
Add helper functions that allow regulator consumers to obtain low-level
details about the regulator hardware, like the voltage selector register
address and such. These details can be useful when configuring hardware
or firmware that want to do low-level access to regulators, with no
involvement from the kernel.
The use-case for Tegra is a voltage-controlled oscillator clocksource
which has control logic to change the supply voltage via I2C to achieve
a desired output clock rate.
Signed-off-by: Tuomas Tynkkynen <ttynkkynen@nvidia.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r-- | Documentation/power/regulator/consumer.txt | 35 | ||||
-rw-r--r-- | drivers/regulator/core.c | 71 | ||||
-rw-r--r-- | include/linux/regulator/consumer.h | 26 |
3 files changed, 132 insertions, 0 deletions
diff --git a/Documentation/power/regulator/consumer.txt b/Documentation/power/regulator/consumer.txt index 55c4175d8099..81c0e2b49cd8 100644 --- a/Documentation/power/regulator/consumer.txt +++ b/Documentation/power/regulator/consumer.txt | |||
@@ -180,3 +180,38 @@ int regulator_unregister_notifier(struct regulator *regulator, | |||
180 | 180 | ||
181 | Regulators use the kernel notifier framework to send event to their interested | 181 | Regulators use the kernel notifier framework to send event to their interested |
182 | consumers. | 182 | consumers. |
183 | |||
184 | 7. Regulator Direct Register Access | ||
185 | =================================== | ||
186 | Some kinds of power management hardware or firmware are designed such that | ||
187 | they need to do low-level hardware access to regulators, with no involvement | ||
188 | from the kernel. Examples of such devices are: | ||
189 | |||
190 | - clocksource with a voltage-controlled oscillator and control logic to change | ||
191 | the supply voltage over I2C to achieve a desired output clock rate | ||
192 | - thermal management firmware that can issue an arbitrary I2C transaction to | ||
193 | perform system poweroff during overtemperature conditions | ||
194 | |||
195 | To set up such a device/firmware, various parameters like I2C address of the | ||
196 | regulator, addresses of various regulator registers etc. need to be configured | ||
197 | to it. The regulator framework provides the following helpers for querying | ||
198 | these details. | ||
199 | |||
200 | Bus-specific details, like I2C addresses or transfer rates are handled by the | ||
201 | regmap framework. To get the regulator's regmap (if supported), use :- | ||
202 | |||
203 | struct regmap *regulator_get_regmap(struct regulator *regulator); | ||
204 | |||
205 | To obtain the hardware register offset and bitmask for the regulator's voltage | ||
206 | selector register, use :- | ||
207 | |||
208 | int regulator_get_hardware_vsel_register(struct regulator *regulator, | ||
209 | unsigned *vsel_reg, | ||
210 | unsigned *vsel_mask); | ||
211 | |||
212 | To convert a regulator framework voltage selector code (used by | ||
213 | regulator_list_voltage) to a hardware-specific voltage selector that can be | ||
214 | directly written to the voltage selector register, use :- | ||
215 | |||
216 | int regulator_list_hardware_vsel(struct regulator *regulator, | ||
217 | unsigned selector); | ||
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 4c1f999041dd..486b5908469e 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c | |||
@@ -2222,6 +2222,77 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector) | |||
2222 | EXPORT_SYMBOL_GPL(regulator_list_voltage); | 2222 | EXPORT_SYMBOL_GPL(regulator_list_voltage); |
2223 | 2223 | ||
2224 | /** | 2224 | /** |
2225 | * regulator_get_regmap - get the regulator's register map | ||
2226 | * @regulator: regulator source | ||
2227 | * | ||
2228 | * Returns the register map for the given regulator, or an ERR_PTR value | ||
2229 | * if the regulator doesn't use regmap. | ||
2230 | */ | ||
2231 | struct regmap *regulator_get_regmap(struct regulator *regulator) | ||
2232 | { | ||
2233 | struct regmap *map = regulator->rdev->regmap; | ||
2234 | |||
2235 | return map ? map : ERR_PTR(-EOPNOTSUPP); | ||
2236 | } | ||
2237 | |||
2238 | /** | ||
2239 | * regulator_get_hardware_vsel_register - get the HW voltage selector register | ||
2240 | * @regulator: regulator source | ||
2241 | * @vsel_reg: voltage selector register, output parameter | ||
2242 | * @vsel_mask: mask for voltage selector bitfield, output parameter | ||
2243 | * | ||
2244 | * Returns the hardware register offset and bitmask used for setting the | ||
2245 | * regulator voltage. This might be useful when configuring voltage-scaling | ||
2246 | * hardware or firmware that can make I2C requests behind the kernel's back, | ||
2247 | * for example. | ||
2248 | * | ||
2249 | * On success, the output parameters @vsel_reg and @vsel_mask are filled in | ||
2250 | * and 0 is returned, otherwise a negative errno is returned. | ||
2251 | */ | ||
2252 | int regulator_get_hardware_vsel_register(struct regulator *regulator, | ||
2253 | unsigned *vsel_reg, | ||
2254 | unsigned *vsel_mask) | ||
2255 | { | ||
2256 | struct regulator_dev *rdev = regulator->rdev; | ||
2257 | struct regulator_ops *ops = rdev->desc->ops; | ||
2258 | |||
2259 | if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap) | ||
2260 | return -EOPNOTSUPP; | ||
2261 | |||
2262 | *vsel_reg = rdev->desc->vsel_reg; | ||
2263 | *vsel_mask = rdev->desc->vsel_mask; | ||
2264 | |||
2265 | return 0; | ||
2266 | } | ||
2267 | EXPORT_SYMBOL_GPL(regulator_get_hardware_vsel_register); | ||
2268 | |||
2269 | /** | ||
2270 | * regulator_list_hardware_vsel - get the HW-specific register value for a selector | ||
2271 | * @regulator: regulator source | ||
2272 | * @selector: identify voltage to list | ||
2273 | * | ||
2274 | * Converts the selector to a hardware-specific voltage selector that can be | ||
2275 | * directly written to the regulator registers. The address of the voltage | ||
2276 | * register can be determined by calling @regulator_get_hardware_vsel_register. | ||
2277 | * | ||
2278 | * On error a negative errno is returned. | ||
2279 | */ | ||
2280 | int regulator_list_hardware_vsel(struct regulator *regulator, | ||
2281 | unsigned selector) | ||
2282 | { | ||
2283 | struct regulator_dev *rdev = regulator->rdev; | ||
2284 | struct regulator_ops *ops = rdev->desc->ops; | ||
2285 | |||
2286 | if (selector >= rdev->desc->n_voltages) | ||
2287 | return -EINVAL; | ||
2288 | if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap) | ||
2289 | return -EOPNOTSUPP; | ||
2290 | |||
2291 | return selector; | ||
2292 | } | ||
2293 | EXPORT_SYMBOL_GPL(regulator_list_hardware_vsel); | ||
2294 | |||
2295 | /** | ||
2225 | * regulator_get_linear_step - return the voltage step size between VSEL values | 2296 | * regulator_get_linear_step - return the voltage step size between VSEL values |
2226 | * @regulator: regulator source | 2297 | * @regulator: regulator source |
2227 | * | 2298 | * |
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index a2d9d81038d1..0b1c8d09a6b1 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h | |||
@@ -37,6 +37,7 @@ | |||
37 | 37 | ||
38 | struct device; | 38 | struct device; |
39 | struct notifier_block; | 39 | struct notifier_block; |
40 | struct regmap; | ||
40 | 41 | ||
41 | /* | 42 | /* |
42 | * Regulator operating modes. | 43 | * Regulator operating modes. |
@@ -215,6 +216,13 @@ int regulator_set_optimum_mode(struct regulator *regulator, int load_uA); | |||
215 | 216 | ||
216 | int regulator_allow_bypass(struct regulator *regulator, bool allow); | 217 | int regulator_allow_bypass(struct regulator *regulator, bool allow); |
217 | 218 | ||
219 | struct regmap *regulator_get_regmap(struct regulator *regulator); | ||
220 | int regulator_get_hardware_vsel_register(struct regulator *regulator, | ||
221 | unsigned *vsel_reg, | ||
222 | unsigned *vsel_mask); | ||
223 | int regulator_list_hardware_vsel(struct regulator *regulator, | ||
224 | unsigned selector); | ||
225 | |||
218 | /* regulator notifier block */ | 226 | /* regulator notifier block */ |
219 | int regulator_register_notifier(struct regulator *regulator, | 227 | int regulator_register_notifier(struct regulator *regulator, |
220 | struct notifier_block *nb); | 228 | struct notifier_block *nb); |
@@ -452,6 +460,24 @@ static inline int regulator_allow_bypass(struct regulator *regulator, | |||
452 | return 0; | 460 | return 0; |
453 | } | 461 | } |
454 | 462 | ||
463 | struct regmap *regulator_get_regmap(struct regulator *regulator) | ||
464 | { | ||
465 | return ERR_PTR(-EOPNOTSUPP); | ||
466 | } | ||
467 | |||
468 | int regulator_get_hardware_vsel_register(struct regulator *regulator, | ||
469 | unsigned *vsel_reg, | ||
470 | unsigned *vsel_mask) | ||
471 | { | ||
472 | return -EOPNOTSUPP; | ||
473 | } | ||
474 | |||
475 | int regulator_list_hardware_vsel(struct regulator *regulator, | ||
476 | unsigned selector) | ||
477 | { | ||
478 | return -EOPNOTSUPP; | ||
479 | } | ||
480 | |||
455 | static inline int regulator_register_notifier(struct regulator *regulator, | 481 | static inline int regulator_register_notifier(struct regulator *regulator, |
456 | struct notifier_block *nb) | 482 | struct notifier_block *nb) |
457 | { | 483 | { |