Message ID | 53C58DCB.90502@nvidia.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Tue, Jul 15, 2014 at 11:23:39PM +0300, Tuomas Tynkkynen wrote: > That sounds indeed useful for this case. How'd the following interface > sound for the register offset / selector-to-register-value conversion? > The I2C address would be a bit trickier to get as it would touch the > regmap stuff as well, but perhaps it would be a good idea to have a > phandle to the I2C device itself, and then parse the reg field for > the address. This looks fine, can you submit properly please? For the I2C address why not just have an interface to get the regmap and then provide a way to get the underlying device back from the regmap?
On Tue, Jul 15, 2014 at 11:52:52PM +0100, Mark Brown wrote: > On Tue, Jul 15, 2014 at 11:23:39PM +0300, Tuomas Tynkkynen wrote: > > > That sounds indeed useful for this case. How'd the following interface > > sound for the register offset / selector-to-register-value conversion? > > The I2C address would be a bit trickier to get as it would touch the > > regmap stuff as well, but perhaps it would be a good idea to have a > > phandle to the I2C device itself, and then parse the reg field for > > the address. > > This looks fine, can you submit properly please? For the I2C address > why not just have an interface to get the regmap and then provide a way > to get the underlying device back from the regmap? Is it mandatory for regulators to use regmap? Also I'm not sure how this will work with MFDs, since the device may not be the actual bus device, but rather a child of the MFD (and what we want access to is the MFD). Perhaps for regmaps that would work in most cases since MFDs seem to aften share the regmap with their children. However, the code in regulator_register() at least indicates that even then it's possible to have a regmap in children that's different from the top-level MFD. Thierry
On Wed, Jul 16, 2014 at 10:01:34AM +0200, Thierry Reding wrote: > On Tue, Jul 15, 2014 at 11:52:52PM +0100, Mark Brown wrote: > > This looks fine, can you submit properly please? For the I2C address > > why not just have an interface to get the regmap and then provide a way > > to get the underlying device back from the regmap? > Is it mandatory for regulators to use regmap? Also I'm not sure how this No, but this is for a limited subset of devices that the hardware knows how to write to directly which means that they're restricted to things that can be supported with regmap (or already know how to interact with the hardware and don't need this interface at all). The proposed patch already relies on regmap - it's passing back the information the regmap helpers use. > will work with MFDs, since the device may not be the actual bus device, > but rather a child of the MFD (and what we want access to is the MFD). > Perhaps for regmaps that would work in most cases since MFDs seem to > aften share the regmap with their children. However, the code in > regulator_register() at least indicates that even then it's possible to > have a regmap in children that's different from the top-level MFD. Right, drivers can say exactly which regmap to use.
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index c563d93..a5efb96 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2228,6 +2228,63 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector) EXPORT_SYMBOL_GPL(regulator_list_voltage); /** + * regulator_get_hardware_vsel_register - get the HW voltage selector register + * @regulator: regulator source + * @vsel_reg: voltage selector register, output parameter + * @vsel_mask: mask for voltage selector bitfield, output parameter + * + * Returns the hardware register offset and bitmask used for setting the + * regulator voltage. This might be useful when configuring voltage-scaling + * hardware or firmware that can make I2C requests behind the kernel's back, + * for example. + * + * On success, the output parameters @vsel_reg and @vsel_mask are filled in + * and 0 is returned, otherwise a negative errno is returned. + */ +int regulator_get_hardware_vsel_register(struct regulator *regulator, + unsigned *vsel_reg, + unsigned *vsel_mask) +{ + struct regulator_dev *rdev = regulator->rdev; + struct regulator_ops *ops = rdev->desc->ops; + + if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap) + return -EOPNOTSUPP; + + *vsel_reg = rdev->desc->vsel_reg; + *vsel_mask = rdev->desc->vsel_mask; + + return 0; +} +EXPORT_SYMBOL_GPL(regulator_get_hardware_vsel_register); + +/** + * regulator_list_hardware_vsel - get the HW-specific register value for a selector + * @regulator: regulator source + * @selector: identify voltage to list + * + * Converts the selector to a hardware-specific voltage selector that can be + * directly written to the regulator registers. The address of the voltage + * register can be determined by calling @regulator_get_hardware_vsel_register. + * + * On error a negative errno is returned. + */ +int regulator_list_hardware_vsel(struct regulator *regulator, + unsigned selector) +{ + struct regulator_dev *rdev = regulator->rdev; + struct regulator_ops *ops = rdev->desc->ops; + + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap) + return -EOPNOTSUPP; + + return selector; +} +EXPORT_SYMBOL_GPL(regulator_list_hardware_vsel); + +/** * regulator_get_linear_step - return the voltage step size between VSEL values * @regulator: regulator source * diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index 14ec18d..fe4cdb2 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -215,6 +215,12 @@ int regulator_set_optimum_mode(struct regulator *regulator, int load_uA); int regulator_allow_bypass(struct regulator *regulator, bool allow); +int regulator_get_hardware_vsel_register(struct regulator *regulator, + unsigned *vsel_reg, + unsigned *vsel_mask); +int regulator_list_hardware_vsel(struct regulator *regulator, + unsigned selector); + /* regulator notifier block */ int regulator_register_notifier(struct regulator *regulator, struct notifier_block *nb);