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 | { |
