Message ID | 1425399883-14053-5-git-send-email-p.marczak@samsung.com |
---|---|
State | Changes Requested |
Delegated to: | Simon Glass |
Headers | show |
Hi Przemyslaw, On 3 March 2015 at 09:24, Przemyslaw Marczak <p.marczak@samsung.com> wrote: > This is the implementation of driver model regulator uclass api. > To use it, the CONFIG_DM_PMIC is required with driver implementation, > since it provides pmic devices basic I/O API. > > The regulator framework is based on a 'struct dm_regulator_ops'. > It provides a common function calls, for it's basic features: > - regulator_get_cnt() - number of outputs each type > - regulator_get_value_desc() - describe output value limits > - regulator_get_mode_desc() - describe output operation modes > - regulator_get/set_value() - output value (uV) > - regulator_get/set_state() - output on/off state Would get/set_enable() be better? > - regulator_get/set_mode() - output operation mode > > To get the regulator device: > - regulator_get() - by name only > - regulator_i2c_get() - by i2c bus address (of pmic parent) > - regulator_spi_get() - by spi bus address (of pmic parent) For the last two, why are we using bus address? This should be by a phandle reference or nane. > > An optional and useful regulator framework features are two descriptors: > - struct regulator_desc - describes the regulator name and output value limits > should be defined by device driver for each regulator output. > > - struct regulator_mode_desc - (array) describes a number of operation modes > supported by each regulator output. > > The regulator framework features are described in file: > - include/power/regulator.h > > Main files: > - drivers/power/regulator-uclass.c - provides regulator common functions api > - include/power/regulator.h - define all structures required by the regulator > > Changes: > - new uclass-id: UCLASS_PMIC_REGULATOR > - new config: CONFIG_DM_REGULATOR > > Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com> > --- > Changes V2: > - new operations for regulator uclass: > -- get/set output state - for output on/off setting > --- add enum: REGULATOR_OFF, REGULATOR_ON > > - regulator uclass code rework and cleanup: > -- change name of: > --- enum 'regulator_desc_type' to 'regulator_type' > --- add type DVS > --- struct 'regulator_desc' to 'regulator_value_desc' > > -- regulator ops function calls: > --- remove 'ldo/buck' from naming > --- add new argument 'type' for define regulator type > > -- regulator.h - update comments > --- > drivers/power/Makefile | 1 + > drivers/power/regulator-uclass.c | 227 ++++++++++++++++++++++++++++ > include/dm/uclass-id.h | 1 + > include/power/regulator.h | 310 +++++++++++++++++++++++++++++++++++++++ > 4 files changed, 539 insertions(+) > create mode 100644 drivers/power/regulator-uclass.c > create mode 100644 include/power/regulator.h > > diff --git a/drivers/power/Makefile b/drivers/power/Makefile > index 5c9a189..a6b7012 100644 > --- a/drivers/power/Makefile > +++ b/drivers/power/Makefile > @@ -22,3 +22,4 @@ obj-$(CONFIG_POWER_FSL) += power_fsl.o > obj-$(CONFIG_POWER_I2C) += power_i2c.o > obj-$(CONFIG_POWER_SPI) += power_spi.o > obj-$(CONFIG_DM_PMIC) += pmic-uclass.o > +obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o > diff --git a/drivers/power/regulator-uclass.c b/drivers/power/regulator-uclass.c > new file mode 100644 > index 0000000..6b5c678 > --- /dev/null > +++ b/drivers/power/regulator-uclass.c > @@ -0,0 +1,227 @@ > +/* > + * Copyright (C) 2014-2015 Samsung Electronics > + * Przemyslaw Marczak <p.marczak@samsung.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > +#include <common.h> > +#include <linux/types.h> > +#include <fdtdec.h> > +#include <dm.h> > +#include <power/pmic.h> > +#include <power/regulator.h> > +#include <compiler.h> > +#include <dm/device.h> > +#include <dm/lists.h> > +#include <dm/device-internal.h> > +#include <errno.h> > + > +DECLARE_GLOBAL_DATA_PTR; > + > +int regulator_get_cnt(struct udevice *dev, int type, int *cnt) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENODEV; This is an error so you should be able to just assert(). Failing that let's use -ENXIO as you do below. > + > + if (!ops->get_cnt) > + return -EPERM; -ENOSYS for these. > + > + return ops->get_cnt(dev, type, cnt); > +} > + > +int regulator_get_value_desc(struct udevice *dev, int type, int number, > + struct regulator_value_desc **desc) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENXIO; > + > + if (!ops->get_value_desc) > + return -EPERM; > + > + return ops->get_value_desc(dev, type, number, desc); > +} > + > +int regulator_get_mode_desc(struct udevice *dev, int type, int number, > + int *mode_cnt, struct regulator_mode_desc **desc) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENXIO; > + > + if (!ops->get_mode_desc_array) > + return -EPERM; > + > + return ops->get_mode_desc_array(dev, type, number, mode_cnt, desc); > +} > + > +int regulator_get_value(struct udevice *dev, int type, int number, int *value) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENODEV; > + > + if (!ops->get_value) > + return -EPERM; > + > + return ops->get_value(dev, type, number, value); > +} > + > +int regulator_set_value(struct udevice *dev, int type, int number, int value) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENODEV; > + > + if (!ops->set_value) > + return -EPERM; > + > + return ops->set_value(dev, type, number, value); > +} > + > +int regulator_get_state(struct udevice *dev, int type, int number, int *state) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENODEV; > + > + if (!ops->get_state) > + return -EPERM; > + > + return ops->get_state(dev, type, number, state); > +} > + > +int regulator_set_state(struct udevice *dev, int type, int number, int state) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENODEV; > + > + if (!ops->set_state) > + return -EPERM; > + > + return ops->set_state(dev, type, number, state); > +} > + > +int regulator_get_mode(struct udevice *dev, int type, int number, int *mode) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENODEV; > + > + if (!ops->get_mode) > + return -EPERM; > + > + return ops->get_mode(dev, type, number, mode); > +} > + > +int regulator_set_mode(struct udevice *dev, int type, int number, int mode) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENODEV; > + > + if (!ops->set_mode) > + return -EPERM; > + > + return ops->set_mode(dev, type, number, mode); > +} > + > +int regulator_get(char *name, struct udevice **regulator) > +{ > + struct udevice *dev; > + struct uclass *uc; > + int ret; > + > + ret = uclass_get(UCLASS_PMIC_REGULATOR, &uc); > + if (ret) { > + error("Regulator uclass not initialized!"); > + return ret; > + } > + > + uclass_foreach_dev(dev, uc) { > + if (!dev) > + continue; > + > + if (!strncmp(name, dev->name, strlen(name))) { > + ret = device_probe(dev); > + if (ret) > + error("Dev: %s probe failed", dev->name); > + *regulator = dev; > + return ret; > + } > + } > + > + *regulator = NULL; > + return -EINVAL; > +} > + > +int regulator_i2c_get(int bus, int addr, struct udevice **regulator) > +{ > + struct udevice *pmic; > + int ret; > + > + /* First get parent pmic device */ > + ret = pmic_i2c_get(bus, addr, &pmic); > + if (ret) { > + error("Chip: %d on bus %d not found!", addr, bus); > + return ret; > + } > + > + /* Get the first regulator child of pmic device */ > + if (device_get_first_child_by_uclass_id(pmic, UCLASS_PMIC_REGULATOR, > + regulator)) { > + error("PMIC: %s regulator child not found!", pmic->name); > + *regulator = NULL; > + return ret; > + } > + > + return 0; > +} > + > +int regulator_spi_get(int bus, int cs, struct udevice **regulator) > +{ > + struct udevice *pmic; > + int ret; > + > + /* First get parent pmic device */ > + ret = pmic_spi_get(bus, cs, &pmic); > + if (ret) { > + error("Chip: %d on bus %d not found!", cs, bus); > + return ret; > + } > + > + /* Get the first regulator child of pmic device */ > + if (device_get_first_child_by_uclass_id(pmic, UCLASS_PMIC_REGULATOR, > + regulator)) { > + error("PMIC: %s regulator child not found!", pmic->name); > + *regulator = NULL; > + return ret; > + } > + > + return 0; > +} > + > +UCLASS_DRIVER(regulator) = { > + .id = UCLASS_PMIC_REGULATOR, > + .name = "regulator", > +}; > diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h > index ff360ac..0a1e664 100644 > --- a/include/dm/uclass-id.h > +++ b/include/dm/uclass-id.h > @@ -37,6 +37,7 @@ enum uclass_id { > > /* PMIC uclass and PMIC related uclasses */ > UCLASS_PMIC, > + UCLASS_PMIC_REGULATOR, > > UCLASS_COUNT, > UCLASS_INVALID = -1, > diff --git a/include/power/regulator.h b/include/power/regulator.h > new file mode 100644 > index 0000000..ee8a280 > --- /dev/null > +++ b/include/power/regulator.h > @@ -0,0 +1,310 @@ > +/* > + * Copyright (C) 2014-2015 Samsung Electronics > + * Przemyslaw Marczak <p.marczak@samsung.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#ifndef _INCLUDE_REGULATOR_H_ > +#define _INCLUDE_REGULATOR_H_ > + > +#define DESC_NAME_LEN 20 > + > +/* enum regulator_type - used for regulator_*() variant calls */ > +enum regulator_type { > + REGULATOR_TYPE_LDO = 0, > + REGULATOR_TYPE_BUCK, > + REGULATOR_TYPE_DVS, > +}; > + > +/* enum regulator_out_state - used for ldo/buck output state setting */ > +enum regulator_out_state { > + REGULATOR_OFF = 0, > + REGULATOR_ON, > +}; If we will only ever have on/off perhaps we don't need this enum and could just use a bool? > + > +/** > + * struct regulator_value_desc - this structure holds an information about > + * each regulator voltage limits. There is no "step" voltage value - so driver > + * should take care of this. This is rather platform specific so can be > + * taken from the device-tree. > + * > + * @type - one of: DESC_TYPE_LDO, DESC_TYPE_BUCK or DESC_TYPE_DVS > + * @number - hardware internal regulator number What is this numbering and where does it come from? It is specified by the PMIC datasheet? Can you expand the comment a bit? Actually I think this numbering should go away and we should use names instead. > + * @min_uV - minimum voltage (micro Volts) > + * @max_uV - maximum voltage (micro Volts) > + * @name - name of regulator - usually will be taken from device tree and > + * can describe regulator output connected hardware, e.g. "eMMC" > +*/ > +struct regulator_value_desc { > + int type; > + int number; > + int min_uV; > + int max_uV; > + char name[DESC_NAME_LEN]; What do you think about making this a const char * and we alloc it with strdup()? > +}; > + > +/** > + * struct regulator_mode_desc - this structure holds an information about > + * each regulator operation modes. Probably in most cases - an array. > + * This will be probably a driver static data since it's device specific. driver-static (I think you mean) > + * > + * @mode - a driver specific mode number - used for regulator command > + * @register_value - a driver specific value for this mode driver-specific, you are creating an adjective > + * @name - the name of mode - used for regulator command > + */ > +struct regulator_mode_desc { > + int mode; > + int register_value; > + char *name; > +}; > + > +/* PMIC regulator device operations */ > +struct dm_regulator_ops { > + /** > + * get_cnt - get the number of a given regulator 'type' outputs > + * > + * @dev - regulator device > + * @type - regulator type, one of enum regulator_type > + * Gets: > + * @cnt - regulator count > + * Returns: 0 on success or negative value of errno. > + */ > + int (*get_cnt)(struct udevice *dev, int type, int *cnt); get_count Return count in return value instead of a parameter. > + > + /** > + * Regulator output value descriptor is specific for each output. > + * It's usually driver static data, but output value limits are > + * often defined in the device-tree, so those are platform dependent > + * attributes. > + * > + * get_value_desc - get value descriptor of the given regulator output > + * @dev - regulator device > + * @type - regulator type, one of enum regulator_type > + * @number - regulator number > + * Gets: > + * @desc - pointer to the descriptor > + * Returns: 0 on success or negative value of errno. > + */ > + int (*get_value_desc)(struct udevice *dev, int type, int number, > + struct regulator_value_desc **desc); You could use descp, to indicate it returns a pointer. > + > + /** > + * Regulator output mode descriptors are device specific. > + * It's usually driver static data. > + * Each regulator output can support different mode types, > + * so usually will return an array with a number 'mode_desc_cnt' > + * of mode descriptors. > + * > + * get_mode_desc_array - get mode descriptor array of the given > + * regulator output number > + * @dev - regulator device > + * @type - regulator type, one of 'enum regulator_type' > + * @number - regulator number regulator_num would be better > + * Gets: > + * @mode_desc_cnt - descriptor array entry count > + * @desc - pointer to the descriptor array > + * Returns: 0 on success or negative value of errno. > + */ > + int (*get_mode_desc_array)(struct udevice *dev, int type, So should type be an enum? > + int number, int *mode_desc_cnt, > + struct regulator_mode_desc **desc); > + > + /** > + * The regulator output value function calls operates on a micro Volts, > + * however the regulator commands operates on a mili Volt unit. > + * > + * get/set_value - get/set output value of the given output number > + * @dev - regulator device > + * @type - regulator type, one of 'enum regulator_type' > + * @number - regulator number > + * Sets/Gets: > + * @value - set or get output value > + * Returns: 0 on success or negative value of errno. > + */ > + int (*get_value)(struct udevice *dev, int type, int number, int *value); Return value in return value instead of a parameter. > + int (*set_value)(struct udevice *dev, int type, int number, int value); > + > + /** > + * The most basic feature of the regulator output is it's on/off state. its > + * > + * get/set_state - get/set on/off state of the given output number > + * @dev - regulator device > + * @type - regulator type, one of 'enum regulator_type' > + * @number - regulator number > + * Sets/Gets: > + * @state - set or get one of 'enum regulator_out_state' > + * Returns: 0 on success or negative value of errno. > + */ > + int (*get_state)(struct udevice *dev, int type, int number, int *state); Return state in return value instead of a parameter. > + int (*set_state)(struct udevice *dev, int type, int number, int state); > + > + /** > + * The 'get/set_mode()' function calls should operate on a driver > + * specific mode definitions, which should be found in: > + * field 'mode' of struct regulator_mode_desc. > + * > + * get/set_mode - get/set operation mode of the given output number > + * @dev - regulator device > + * @type - regulator type, one of 'enum regulator_type' > + * @number - regulator number > + * Sets/Gets: > + * @mode - set or get output mode > + * Returns: 0 on success or negative value of errno. > + */ > + int (*get_mode)(struct udevice *dev, int type, int number, int *mode); Return mode in return value. > + int (*set_mode)(struct udevice *dev, int type, int number, int mode); > +}; > + > +/** > + * regulator_get_cnt: returns the number of driver registered regulators. driver-registered > + * This is used for pmic regulator command purposes. > + * > + * @dev - pointer to the regulator device > + * @type - regulator type: device specific > + * Gets: > + * @cnt - regulator count > + * Returns: 0 on success or negative value of errno. > + */ > +int regulator_get_cnt(struct udevice *dev, int type, int *cnt); regulator_get_count. Return count in return value instead of a parameter. > + > +/** > + * regulator_get_value_desc: returns a pointer to the regulator value > + * descriptor of a given device regulator output number. > + * > + * @dev - pointer to the regulator device > + * @type - regulator descriptor type > + * @number - descriptor number (regulator output number) > + * Gets: > + * @desc - pointer to the descriptor > + * Returns: 0 on success or negative value of errno. > + */ > +int regulator_get_value_desc(struct udevice *dev, int type, int number, > + struct regulator_value_desc **desc); > + > +/** > + * regulator_get_mode_desc: returns a pointer to the array of regulator mode > + * descriptors of a given device regulator type and number. > + * > + * @dev - pointer to the regulator device > + * @type - regulator type: device specific > + * @number - output number: device specific > + * Gets: > + * @mode_cnt - descriptor array entry count > + * @desc - pointer to the descriptor array > + * Returns: 0 on success or negative value of errno. > + */ > +int regulator_get_mode_desc(struct udevice *dev, int type, int number, > + int *mode_cnt, struct regulator_mode_desc **desc); > + > +/** > + * regulator_get_value: returns voltage value of a given device > + * regulator type number. > + * > + * @dev - pointer to the regulator device > + * @type - regulator type: device specific > + * @number - output number: device specific > + * Gets: > + * @val - returned voltage - unit: uV (micro Volts) > + * Returns: 0 on success or negative value of errno. You may as well return the voltage in the return value, unless it can be -ve (I assume not?) > + */ > +int regulator_get_value(struct udevice *dev, int type, int number, int *val); > + > +/** > + * regulator_set_value: set the voltage value of a given device regulator type > + * number to the given one passed by the argument: @val > + * > + * @dev - pointer to the regulator device > + * @type - regulator type: device specific > + * @number - output number: device specific > + * @val - voltage value to set - unit: uV (micro Volts) > + * Returns - 0 on success or -errno val if fails > + */ > +int regulator_set_value(struct udevice *dev, int type, int number, int val); > + > +/** > + * regulator_get_state: returns output state of a given device > + * regulator type number. > + * > + * @dev - pointer to the regulator device > + * @type - regulator type, device specific > + * @number - regulator number, device specific > + * Gets: > + * @state - returned regulator number output state: > + * - REGULATOR_OFF (0) - disable > + * - REGULATOR_ON (1) - enable > + * Returns: - 0 on success or -errno val if fails > + */ > +int regulator_get_state(struct udevice *dev, int type, int number, int *state); Return state in return value instead of a parameter. > + > +/** > + * regulator_set_state: set output state of a given device regulator type > + * number to the given one passed by the argument: @state > + * > + * @dev - pointer to the regulator device > + * @type - regulator type: device specific > + * @number - output number: device specific > + * @state - output state to set > + * - enum REGULATOR_OFF == 0 - disable > + * - enum REGULATOR_ON == 1 - enable > + * Returns - 0 on success or -errno val if fails > + */ > +int regulator_set_state(struct udevice *dev, int type, int number, int state); > + > +/** > + * regulator_get_mode: get mode number of a given device regulator type number > + * > + * @dev - pointer to the regulator device > + * @type - output number: device specific > + * @number - output number: device specific > + * Gets: > + * @mode - returned mode number > + * Returns - 0 on success or -errno val if fails > + * Note: > + * The regulator driver should return one of defined, mode number rather > + * than the raw register value. The struct type 'regulator_mode_desc' has > + * a mode field for this purpose and register_value for a raw register value. > + */ > +int regulator_get_mode(struct udevice *dev, int type, int number, int *mode); Return mode in return value instead of a parameter. > + > +/** > + * regulator_set_mode: set given regulator type and number mode to the given > + * one passed by the argument: @mode > + * > + * @dev - pointer to the regulator device > + * @type - output number: device specific > + * @number - output number: device specific > + * @mode - mode type (struct regulator_mode_desc.mode) > + * Returns - 0 on success or -errno value if fails > + * Note: > + * The regulator driver should take one of defined, mode number rather > + * than a raw register value. The struct type 'regulator_mode_desc' has > + * a mode field for this purpose and register_value for a raw register value. > + */ > +int regulator_set_mode(struct udevice *dev, int type, int number, int mode); > + > +/** > + * regulator_..._get: returns the pointer to the pmic regulator device > + * by specified arguments: > + * > + * NAME: > + * @name - device name (useful for specific names) > + * or SPI/I2C interface: > + * @bus - device I2C/SPI bus number > + * @addr_cs - device specific address for I2C or chip select for SPI, > + * on the given bus number > + * Gets: > + * @regulator - pointer to the pmic device > + * Returns: 0 on success or negative value of errno. > + * > + * The returned 'regulator' device can be used with: > + * - regulator_get/set_* > + * and if pmic_platdata is given, then also with: > + * - pmic_if_* calls > + * The last one is used for the pmic command purposes. > + */ > +int regulator_get(char *name, struct udevice **regulator); > +int regulator_i2c_get(int bus, int addr, struct udevice **regulator); > +int regulator_spi_get(int bus, int cs, struct udevice **regulator); Hoping you don't need these last two! > + > +#endif /* _INCLUDE_REGULATOR_H_ */ > -- > 1.9.1 > Regards, Simon
Hi, On 03/03/2015 05:24 PM, Przemyslaw Marczak wrote: > This is the implementation of driver model regulator uclass api. > To use it, the CONFIG_DM_PMIC is required with driver implementation, > since it provides pmic devices basic I/O API. > > The regulator framework is based on a 'struct dm_regulator_ops'. > It provides a common function calls, for it's basic features: > - regulator_get_cnt() - number of outputs each type > - regulator_get_value_desc() - describe output value limits > - regulator_get_mode_desc() - describe output operation modes > - regulator_get/set_value() - output value (uV) > - regulator_get/set_state() - output on/off state > - regulator_get/set_mode() - output operation mode > > To get the regulator device: > - regulator_get() - by name only > - regulator_i2c_get() - by i2c bus address (of pmic parent) > - regulator_spi_get() - by spi bus address (of pmic parent) > > An optional and useful regulator framework features are two descriptors: > - struct regulator_desc - describes the regulator name and output value limits > should be defined by device driver for each regulator output. > > - struct regulator_mode_desc - (array) describes a number of operation modes > supported by each regulator output. > > The regulator framework features are described in file: > - include/power/regulator.h > > Main files: > - drivers/power/regulator-uclass.c - provides regulator common functions api > - include/power/regulator.h - define all structures required by the regulator > > Changes: > - new uclass-id: UCLASS_PMIC_REGULATOR > - new config: CONFIG_DM_REGULATOR > > Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com> > --- > Changes V2: > - new operations for regulator uclass: > -- get/set output state - for output on/off setting > --- add enum: REGULATOR_OFF, REGULATOR_ON > > - regulator uclass code rework and cleanup: > -- change name of: > --- enum 'regulator_desc_type' to 'regulator_type' > --- add type DVS > --- struct 'regulator_desc' to 'regulator_value_desc' > > -- regulator ops function calls: > --- remove 'ldo/buck' from naming > --- add new argument 'type' for define regulator type > > -- regulator.h - update comments > --- > drivers/power/Makefile | 1 + > drivers/power/regulator-uclass.c | 227 ++++++++++++++++++++++++++++ > include/dm/uclass-id.h | 1 + > include/power/regulator.h | 310 +++++++++++++++++++++++++++++++++++++++ > 4 files changed, 539 insertions(+) > create mode 100644 drivers/power/regulator-uclass.c > create mode 100644 include/power/regulator.h > > diff --git a/drivers/power/Makefile b/drivers/power/Makefile > index 5c9a189..a6b7012 100644 > --- a/drivers/power/Makefile > +++ b/drivers/power/Makefile > @@ -22,3 +22,4 @@ obj-$(CONFIG_POWER_FSL) += power_fsl.o > obj-$(CONFIG_POWER_I2C) += power_i2c.o > obj-$(CONFIG_POWER_SPI) += power_spi.o > obj-$(CONFIG_DM_PMIC) += pmic-uclass.o > +obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o > diff --git a/drivers/power/regulator-uclass.c b/drivers/power/regulator-uclass.c > new file mode 100644 > index 0000000..6b5c678 > --- /dev/null > +++ b/drivers/power/regulator-uclass.c > @@ -0,0 +1,227 @@ > +/* > + * Copyright (C) 2014-2015 Samsung Electronics > + * Przemyslaw Marczak <p.marczak@samsung.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > +#include <common.h> > +#include <linux/types.h> > +#include <fdtdec.h> > +#include <dm.h> > +#include <power/pmic.h> > +#include <power/regulator.h> > +#include <compiler.h> > +#include <dm/device.h> > +#include <dm/lists.h> > +#include <dm/device-internal.h> > +#include <errno.h> > + > +DECLARE_GLOBAL_DATA_PTR; > + > +int regulator_get_cnt(struct udevice *dev, int type, int *cnt) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENODEV; > + > + if (!ops->get_cnt) > + return -EPERM; > + > + return ops->get_cnt(dev, type, cnt); > +} > + > +int regulator_get_value_desc(struct udevice *dev, int type, int number, > + struct regulator_value_desc **desc) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENXIO; > + > + if (!ops->get_value_desc) > + return -EPERM; > + > + return ops->get_value_desc(dev, type, number, desc); > +} > + > +int regulator_get_mode_desc(struct udevice *dev, int type, int number, > + int *mode_cnt, struct regulator_mode_desc **desc) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENXIO; > + > + if (!ops->get_mode_desc_array) > + return -EPERM; > + > + return ops->get_mode_desc_array(dev, type, number, mode_cnt, desc); > +} > + > +int regulator_get_value(struct udevice *dev, int type, int number, int *value) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENODEV; > + > + if (!ops->get_value) > + return -EPERM; > + > + return ops->get_value(dev, type, number, value); > +} > + > +int regulator_set_value(struct udevice *dev, int type, int number, int value) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENODEV; > + > + if (!ops->set_value) > + return -EPERM; > + > + return ops->set_value(dev, type, number, value); > +} > + > +int regulator_get_state(struct udevice *dev, int type, int number, int *state) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENODEV; > + > + if (!ops->get_state) > + return -EPERM; > + > + return ops->get_state(dev, type, number, state); > +} > + > +int regulator_set_state(struct udevice *dev, int type, int number, int state) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENODEV; > + > + if (!ops->set_state) > + return -EPERM; > + > + return ops->set_state(dev, type, number, state); > +} > + > +int regulator_get_mode(struct udevice *dev, int type, int number, int *mode) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENODEV; > + > + if (!ops->get_mode) > + return -EPERM; > + > + return ops->get_mode(dev, type, number, mode); > +} > + > +int regulator_set_mode(struct udevice *dev, int type, int number, int mode) > +{ > + const struct dm_regulator_ops *ops; > + > + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); > + if (!ops) > + return -ENODEV; > + > + if (!ops->set_mode) > + return -EPERM; > + > + return ops->set_mode(dev, type, number, mode); > +} > + > +int regulator_get(char *name, struct udevice **regulator) > +{ > + struct udevice *dev; > + struct uclass *uc; > + int ret; > + > + ret = uclass_get(UCLASS_PMIC_REGULATOR, &uc); > + if (ret) { > + error("Regulator uclass not initialized!"); > + return ret; > + } > + > + uclass_foreach_dev(dev, uc) { > + if (!dev) > + continue; > + > + if (!strncmp(name, dev->name, strlen(name))) { > + ret = device_probe(dev); > + if (ret) > + error("Dev: %s probe failed", dev->name); > + *regulator = dev; Shouldn't we set regulator=NULL if device_probe() returns an error? > + return ret; > + } > + } > + > + *regulator = NULL; > + return -EINVAL; > +} > + > +int regulator_i2c_get(int bus, int addr, struct udevice **regulator) > +{ > + struct udevice *pmic; > + int ret; > + > + /* First get parent pmic device */ > + ret = pmic_i2c_get(bus, addr, &pmic); > + if (ret) { > + error("Chip: %d on bus %d not found!", addr, bus); > + return ret; > + } > + > + /* Get the first regulator child of pmic device */ > + if (device_get_first_child_by_uclass_id(pmic, UCLASS_PMIC_REGULATOR, > + regulator)) { > + error("PMIC: %s regulator child not found!", pmic->name); > + *regulator = NULL; > + return ret; > + } > + > + return 0; > +} > + > +int regulator_spi_get(int bus, int cs, struct udevice **regulator) > +{ > + struct udevice *pmic; > + int ret; > + > + /* First get parent pmic device */ > + ret = pmic_spi_get(bus, cs, &pmic); > + if (ret) { > + error("Chip: %d on bus %d not found!", cs, bus); > + return ret; > + } > + > + /* Get the first regulator child of pmic device */ > + if (device_get_first_child_by_uclass_id(pmic, UCLASS_PMIC_REGULATOR, > + regulator)) { > + error("PMIC: %s regulator child not found!", pmic->name); > + *regulator = NULL; > + return ret; > + } > + > + return 0; > +} > + > +UCLASS_DRIVER(regulator) = { > + .id = UCLASS_PMIC_REGULATOR, > + .name = "regulator", > +}; > diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h > index ff360ac..0a1e664 100644 > --- a/include/dm/uclass-id.h > +++ b/include/dm/uclass-id.h > @@ -37,6 +37,7 @@ enum uclass_id { > > /* PMIC uclass and PMIC related uclasses */ > UCLASS_PMIC, > + UCLASS_PMIC_REGULATOR, > > UCLASS_COUNT, > UCLASS_INVALID = -1, > diff --git a/include/power/regulator.h b/include/power/regulator.h > new file mode 100644 > index 0000000..ee8a280 > --- /dev/null > +++ b/include/power/regulator.h > @@ -0,0 +1,310 @@ > +/* > + * Copyright (C) 2014-2015 Samsung Electronics > + * Przemyslaw Marczak <p.marczak@samsung.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#ifndef _INCLUDE_REGULATOR_H_ > +#define _INCLUDE_REGULATOR_H_ > + > +#define DESC_NAME_LEN 20 > + > +/* enum regulator_type - used for regulator_*() variant calls */ > +enum regulator_type { > + REGULATOR_TYPE_LDO = 0, > + REGULATOR_TYPE_BUCK, > + REGULATOR_TYPE_DVS, > +}; > + > +/* enum regulator_out_state - used for ldo/buck output state setting */ > +enum regulator_out_state { > + REGULATOR_OFF = 0, > + REGULATOR_ON, > +}; > + > +/** > + * struct regulator_value_desc - this structure holds an information about > + * each regulator voltage limits. There is no "step" voltage value - so driver > + * should take care of this. This is rather platform specific so can be > + * taken from the device-tree. > + * > + * @type - one of: DESC_TYPE_LDO, DESC_TYPE_BUCK or DESC_TYPE_DVS > + * @number - hardware internal regulator number > + * @min_uV - minimum voltage (micro Volts) > + * @max_uV - maximum voltage (micro Volts) > + * @name - name of regulator - usually will be taken from device tree and > + * can describe regulator output connected hardware, e.g. "eMMC" > +*/ > +struct regulator_value_desc { > + int type; > + int number; > + int min_uV; > + int max_uV; > + char name[DESC_NAME_LEN]; > +}; > + > +/** > + * struct regulator_mode_desc - this structure holds an information about > + * each regulator operation modes. Probably in most cases - an array. > + * This will be probably a driver static data since it's device specific. > + * > + * @mode - a driver specific mode number - used for regulator command > + * @register_value - a driver specific value for this mode > + * @name - the name of mode - used for regulator command > + */ > +struct regulator_mode_desc { > + int mode; > + int register_value; > + char *name; > +}; > + > +/* PMIC regulator device operations */ > +struct dm_regulator_ops { > + /** > + * get_cnt - get the number of a given regulator 'type' outputs > + * > + * @dev - regulator device > + * @type - regulator type, one of enum regulator_type > + * Gets: > + * @cnt - regulator count > + * Returns: 0 on success or negative value of errno. > + */ > + int (*get_cnt)(struct udevice *dev, int type, int *cnt); > + > + /** > + * Regulator output value descriptor is specific for each output. > + * It's usually driver static data, but output value limits are > + * often defined in the device-tree, so those are platform dependent > + * attributes. > + * > + * get_value_desc - get value descriptor of the given regulator output > + * @dev - regulator device > + * @type - regulator type, one of enum regulator_type > + * @number - regulator number > + * Gets: > + * @desc - pointer to the descriptor > + * Returns: 0 on success or negative value of errno. > + */ > + int (*get_value_desc)(struct udevice *dev, int type, int number, > + struct regulator_value_desc **desc); > + > + /** > + * Regulator output mode descriptors are device specific. > + * It's usually driver static data. > + * Each regulator output can support different mode types, > + * so usually will return an array with a number 'mode_desc_cnt' > + * of mode descriptors. > + * > + * get_mode_desc_array - get mode descriptor array of the given > + * regulator output number > + * @dev - regulator device > + * @type - regulator type, one of 'enum regulator_type' > + * @number - regulator number > + * Gets: > + * @mode_desc_cnt - descriptor array entry count > + * @desc - pointer to the descriptor array > + * Returns: 0 on success or negative value of errno. > + */ > + int (*get_mode_desc_array)(struct udevice *dev, int type, > + int number, int *mode_desc_cnt, > + struct regulator_mode_desc **desc); > + > + /** > + * The regulator output value function calls operates on a micro Volts, > + * however the regulator commands operates on a mili Volt unit. > + * > + * get/set_value - get/set output value of the given output number > + * @dev - regulator device > + * @type - regulator type, one of 'enum regulator_type' > + * @number - regulator number > + * Sets/Gets: > + * @value - set or get output value > + * Returns: 0 on success or negative value of errno. > + */ > + int (*get_value)(struct udevice *dev, int type, int number, int *value); > + int (*set_value)(struct udevice *dev, int type, int number, int value); > + > + /** > + * The most basic feature of the regulator output is it's on/off state. > + * > + * get/set_state - get/set on/off state of the given output number > + * @dev - regulator device > + * @type - regulator type, one of 'enum regulator_type' > + * @number - regulator number > + * Sets/Gets: > + * @state - set or get one of 'enum regulator_out_state' > + * Returns: 0 on success or negative value of errno. > + */ > + int (*get_state)(struct udevice *dev, int type, int number, int *state); > + int (*set_state)(struct udevice *dev, int type, int number, int state); > + > + /** > + * The 'get/set_mode()' function calls should operate on a driver > + * specific mode definitions, which should be found in: > + * field 'mode' of struct regulator_mode_desc. > + * > + * get/set_mode - get/set operation mode of the given output number > + * @dev - regulator device > + * @type - regulator type, one of 'enum regulator_type' > + * @number - regulator number > + * Sets/Gets: > + * @mode - set or get output mode > + * Returns: 0 on success or negative value of errno. > + */ > + int (*get_mode)(struct udevice *dev, int type, int number, int *mode); > + int (*set_mode)(struct udevice *dev, int type, int number, int mode); > +}; > + > +/** > + * regulator_get_cnt: returns the number of driver registered regulators. > + * This is used for pmic regulator command purposes. > + * > + * @dev - pointer to the regulator device > + * @type - regulator type: device specific > + * Gets: > + * @cnt - regulator count > + * Returns: 0 on success or negative value of errno. > + */ > +int regulator_get_cnt(struct udevice *dev, int type, int *cnt); > + > +/** > + * regulator_get_value_desc: returns a pointer to the regulator value > + * descriptor of a given device regulator output number. > + * > + * @dev - pointer to the regulator device > + * @type - regulator descriptor type > + * @number - descriptor number (regulator output number) > + * Gets: > + * @desc - pointer to the descriptor > + * Returns: 0 on success or negative value of errno. > + */ > +int regulator_get_value_desc(struct udevice *dev, int type, int number, > + struct regulator_value_desc **desc); > + > +/** > + * regulator_get_mode_desc: returns a pointer to the array of regulator mode > + * descriptors of a given device regulator type and number. > + * > + * @dev - pointer to the regulator device > + * @type - regulator type: device specific > + * @number - output number: device specific > + * Gets: > + * @mode_cnt - descriptor array entry count > + * @desc - pointer to the descriptor array > + * Returns: 0 on success or negative value of errno. > + */ > +int regulator_get_mode_desc(struct udevice *dev, int type, int number, > + int *mode_cnt, struct regulator_mode_desc **desc); > + > +/** > + * regulator_get_value: returns voltage value of a given device > + * regulator type number. > + * > + * @dev - pointer to the regulator device > + * @type - regulator type: device specific > + * @number - output number: device specific > + * Gets: > + * @val - returned voltage - unit: uV (micro Volts) > + * Returns: 0 on success or negative value of errno. > + */ > +int regulator_get_value(struct udevice *dev, int type, int number, int *val); > + > +/** > + * regulator_set_value: set the voltage value of a given device regulator type > + * number to the given one passed by the argument: @val > + * > + * @dev - pointer to the regulator device > + * @type - regulator type: device specific > + * @number - output number: device specific > + * @val - voltage value to set - unit: uV (micro Volts) > + * Returns - 0 on success or -errno val if fails > + */ > +int regulator_set_value(struct udevice *dev, int type, int number, int val); > + > +/** > + * regulator_get_state: returns output state of a given device > + * regulator type number. > + * > + * @dev - pointer to the regulator device > + * @type - regulator type, device specific > + * @number - regulator number, device specific > + * Gets: > + * @state - returned regulator number output state: > + * - REGULATOR_OFF (0) - disable > + * - REGULATOR_ON (1) - enable > + * Returns: - 0 on success or -errno val if fails > + */ > +int regulator_get_state(struct udevice *dev, int type, int number, int *state); > + > +/** > + * regulator_set_state: set output state of a given device regulator type > + * number to the given one passed by the argument: @state > + * > + * @dev - pointer to the regulator device > + * @type - regulator type: device specific > + * @number - output number: device specific > + * @state - output state to set > + * - enum REGULATOR_OFF == 0 - disable > + * - enum REGULATOR_ON == 1 - enable > + * Returns - 0 on success or -errno val if fails > + */ > +int regulator_set_state(struct udevice *dev, int type, int number, int state); > + > +/** > + * regulator_get_mode: get mode number of a given device regulator type number > + * > + * @dev - pointer to the regulator device > + * @type - output number: device specific > + * @number - output number: device specific > + * Gets: > + * @mode - returned mode number > + * Returns - 0 on success or -errno val if fails > + * Note: > + * The regulator driver should return one of defined, mode number rather > + * than the raw register value. The struct type 'regulator_mode_desc' has > + * a mode field for this purpose and register_value for a raw register value. > + */ > +int regulator_get_mode(struct udevice *dev, int type, int number, int *mode); > + > +/** > + * regulator_set_mode: set given regulator type and number mode to the given > + * one passed by the argument: @mode > + * > + * @dev - pointer to the regulator device > + * @type - output number: device specific > + * @number - output number: device specific > + * @mode - mode type (struct regulator_mode_desc.mode) > + * Returns - 0 on success or -errno value if fails > + * Note: > + * The regulator driver should take one of defined, mode number rather > + * than a raw register value. The struct type 'regulator_mode_desc' has > + * a mode field for this purpose and register_value for a raw register value. > + */ > +int regulator_set_mode(struct udevice *dev, int type, int number, int mode); > + > +/** > + * regulator_..._get: returns the pointer to the pmic regulator device > + * by specified arguments: > + * > + * NAME: > + * @name - device name (useful for specific names) > + * or SPI/I2C interface: > + * @bus - device I2C/SPI bus number > + * @addr_cs - device specific address for I2C or chip select for SPI, > + * on the given bus number > + * Gets: > + * @regulator - pointer to the pmic device > + * Returns: 0 on success or negative value of errno. > + * > + * The returned 'regulator' device can be used with: > + * - regulator_get/set_* > + * and if pmic_platdata is given, then also with: > + * - pmic_if_* calls > + * The last one is used for the pmic command purposes. > + */ > +int regulator_get(char *name, struct udevice **regulator); > +int regulator_i2c_get(int bus, int addr, struct udevice **regulator); > +int regulator_spi_get(int bus, int cs, struct udevice **regulator); > + > +#endif /* _INCLUDE_REGULATOR_H_ */ > Br, Robert
Hello Simon, On 03/06/2015 03:12 PM, Simon Glass wrote: > Hi Przemyslaw, > > On 3 March 2015 at 09:24, Przemyslaw Marczak <p.marczak@samsung.com> wrote: >> This is the implementation of driver model regulator uclass api. >> To use it, the CONFIG_DM_PMIC is required with driver implementation, >> since it provides pmic devices basic I/O API. >> >> The regulator framework is based on a 'struct dm_regulator_ops'. >> It provides a common function calls, for it's basic features: >> - regulator_get_cnt() - number of outputs each type >> - regulator_get_value_desc() - describe output value limits >> - regulator_get_mode_desc() - describe output operation modes >> - regulator_get/set_value() - output value (uV) >> - regulator_get/set_state() - output on/off state > > Would get/set_enable() be better? > >> - regulator_get/set_mode() - output operation mode >> >> To get the regulator device: >> - regulator_get() - by name only >> - regulator_i2c_get() - by i2c bus address (of pmic parent) >> - regulator_spi_get() - by spi bus address (of pmic parent) > > For the last two, why are we using bus address? This should be by a > phandle reference or nane. > >> >> An optional and useful regulator framework features are two descriptors: >> - struct regulator_desc - describes the regulator name and output value limits >> should be defined by device driver for each regulator output. >> >> - struct regulator_mode_desc - (array) describes a number of operation modes >> supported by each regulator output. >> >> The regulator framework features are described in file: >> - include/power/regulator.h >> >> Main files: >> - drivers/power/regulator-uclass.c - provides regulator common functions api >> - include/power/regulator.h - define all structures required by the regulator >> >> Changes: >> - new uclass-id: UCLASS_PMIC_REGULATOR >> - new config: CONFIG_DM_REGULATOR >> >> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com> >> --- >> Changes V2: >> - new operations for regulator uclass: >> -- get/set output state - for output on/off setting >> --- add enum: REGULATOR_OFF, REGULATOR_ON >> >> - regulator uclass code rework and cleanup: >> -- change name of: >> --- enum 'regulator_desc_type' to 'regulator_type' >> --- add type DVS >> --- struct 'regulator_desc' to 'regulator_value_desc' >> >> -- regulator ops function calls: >> --- remove 'ldo/buck' from naming >> --- add new argument 'type' for define regulator type >> >> -- regulator.h - update comments >> --- >> drivers/power/Makefile | 1 + >> drivers/power/regulator-uclass.c | 227 ++++++++++++++++++++++++++++ >> include/dm/uclass-id.h | 1 + >> include/power/regulator.h | 310 +++++++++++++++++++++++++++++++++++++++ >> 4 files changed, 539 insertions(+) >> create mode 100644 drivers/power/regulator-uclass.c >> create mode 100644 include/power/regulator.h >> >> diff --git a/drivers/power/Makefile b/drivers/power/Makefile >> index 5c9a189..a6b7012 100644 >> --- a/drivers/power/Makefile >> +++ b/drivers/power/Makefile >> @@ -22,3 +22,4 @@ obj-$(CONFIG_POWER_FSL) += power_fsl.o >> obj-$(CONFIG_POWER_I2C) += power_i2c.o >> obj-$(CONFIG_POWER_SPI) += power_spi.o >> obj-$(CONFIG_DM_PMIC) += pmic-uclass.o >> +obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o >> diff --git a/drivers/power/regulator-uclass.c b/drivers/power/regulator-uclass.c >> new file mode 100644 >> index 0000000..6b5c678 >> --- /dev/null >> +++ b/drivers/power/regulator-uclass.c >> @@ -0,0 +1,227 @@ >> +/* >> + * Copyright (C) 2014-2015 Samsung Electronics >> + * Przemyslaw Marczak <p.marczak@samsung.com> >> + * >> + * SPDX-License-Identifier: GPL-2.0+ >> + */ >> +#include <common.h> >> +#include <linux/types.h> >> +#include <fdtdec.h> >> +#include <dm.h> >> +#include <power/pmic.h> >> +#include <power/regulator.h> >> +#include <compiler.h> >> +#include <dm/device.h> >> +#include <dm/lists.h> >> +#include <dm/device-internal.h> >> +#include <errno.h> >> + >> +DECLARE_GLOBAL_DATA_PTR; >> + >> +int regulator_get_cnt(struct udevice *dev, int type, int *cnt) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENODEV; > > This is an error so you should be able to just assert(). Failing that > let's use -ENXIO as you do below. > >> + >> + if (!ops->get_cnt) >> + return -EPERM; > > -ENOSYS for these. > Ah, I missed this one, will fix in V4. >> + >> + return ops->get_cnt(dev, type, cnt); >> +} >> + >> +int regulator_get_value_desc(struct udevice *dev, int type, int number, >> + struct regulator_value_desc **desc) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENXIO; >> + >> + if (!ops->get_value_desc) >> + return -EPERM; >> + >> + return ops->get_value_desc(dev, type, number, desc); >> +} >> + >> +int regulator_get_mode_desc(struct udevice *dev, int type, int number, >> + int *mode_cnt, struct regulator_mode_desc **desc) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENXIO; >> + >> + if (!ops->get_mode_desc_array) >> + return -EPERM; >> + >> + return ops->get_mode_desc_array(dev, type, number, mode_cnt, desc); >> +} >> + >> +int regulator_get_value(struct udevice *dev, int type, int number, int *value) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENODEV; >> + >> + if (!ops->get_value) >> + return -EPERM; >> + >> + return ops->get_value(dev, type, number, value); >> +} >> + >> +int regulator_set_value(struct udevice *dev, int type, int number, int value) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENODEV; >> + >> + if (!ops->set_value) >> + return -EPERM; >> + >> + return ops->set_value(dev, type, number, value); >> +} >> + >> +int regulator_get_state(struct udevice *dev, int type, int number, int *state) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENODEV; >> + >> + if (!ops->get_state) >> + return -EPERM; >> + >> + return ops->get_state(dev, type, number, state); >> +} >> + >> +int regulator_set_state(struct udevice *dev, int type, int number, int state) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENODEV; >> + >> + if (!ops->set_state) >> + return -EPERM; >> + >> + return ops->set_state(dev, type, number, state); >> +} >> + >> +int regulator_get_mode(struct udevice *dev, int type, int number, int *mode) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENODEV; >> + >> + if (!ops->get_mode) >> + return -EPERM; >> + >> + return ops->get_mode(dev, type, number, mode); >> +} >> + >> +int regulator_set_mode(struct udevice *dev, int type, int number, int mode) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENODEV; >> + >> + if (!ops->set_mode) >> + return -EPERM; >> + >> + return ops->set_mode(dev, type, number, mode); >> +} >> + >> +int regulator_get(char *name, struct udevice **regulator) >> +{ >> + struct udevice *dev; >> + struct uclass *uc; >> + int ret; >> + >> + ret = uclass_get(UCLASS_PMIC_REGULATOR, &uc); >> + if (ret) { >> + error("Regulator uclass not initialized!"); >> + return ret; >> + } >> + >> + uclass_foreach_dev(dev, uc) { >> + if (!dev) >> + continue; >> + >> + if (!strncmp(name, dev->name, strlen(name))) { >> + ret = device_probe(dev); >> + if (ret) >> + error("Dev: %s probe failed", dev->name); >> + *regulator = dev; >> + return ret; >> + } >> + } >> + >> + *regulator = NULL; >> + return -EINVAL; >> +} >> + >> +int regulator_i2c_get(int bus, int addr, struct udevice **regulator) >> +{ >> + struct udevice *pmic; >> + int ret; >> + >> + /* First get parent pmic device */ >> + ret = pmic_i2c_get(bus, addr, &pmic); >> + if (ret) { >> + error("Chip: %d on bus %d not found!", addr, bus); >> + return ret; >> + } >> + >> + /* Get the first regulator child of pmic device */ >> + if (device_get_first_child_by_uclass_id(pmic, UCLASS_PMIC_REGULATOR, >> + regulator)) { >> + error("PMIC: %s regulator child not found!", pmic->name); >> + *regulator = NULL; >> + return ret; >> + } >> + >> + return 0; >> +} >> + >> +int regulator_spi_get(int bus, int cs, struct udevice **regulator) >> +{ >> + struct udevice *pmic; >> + int ret; >> + >> + /* First get parent pmic device */ >> + ret = pmic_spi_get(bus, cs, &pmic); >> + if (ret) { >> + error("Chip: %d on bus %d not found!", cs, bus); >> + return ret; >> + } >> + >> + /* Get the first regulator child of pmic device */ >> + if (device_get_first_child_by_uclass_id(pmic, UCLASS_PMIC_REGULATOR, >> + regulator)) { >> + error("PMIC: %s regulator child not found!", pmic->name); >> + *regulator = NULL; >> + return ret; >> + } >> + >> + return 0; >> +} >> + >> +UCLASS_DRIVER(regulator) = { >> + .id = UCLASS_PMIC_REGULATOR, >> + .name = "regulator", >> +}; >> diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h >> index ff360ac..0a1e664 100644 >> --- a/include/dm/uclass-id.h >> +++ b/include/dm/uclass-id.h >> @@ -37,6 +37,7 @@ enum uclass_id { >> >> /* PMIC uclass and PMIC related uclasses */ >> UCLASS_PMIC, >> + UCLASS_PMIC_REGULATOR, >> >> UCLASS_COUNT, >> UCLASS_INVALID = -1, >> diff --git a/include/power/regulator.h b/include/power/regulator.h >> new file mode 100644 >> index 0000000..ee8a280 >> --- /dev/null >> +++ b/include/power/regulator.h >> @@ -0,0 +1,310 @@ >> +/* >> + * Copyright (C) 2014-2015 Samsung Electronics >> + * Przemyslaw Marczak <p.marczak@samsung.com> >> + * >> + * SPDX-License-Identifier: GPL-2.0+ >> + */ >> + >> +#ifndef _INCLUDE_REGULATOR_H_ >> +#define _INCLUDE_REGULATOR_H_ >> + >> +#define DESC_NAME_LEN 20 >> + >> +/* enum regulator_type - used for regulator_*() variant calls */ >> +enum regulator_type { >> + REGULATOR_TYPE_LDO = 0, >> + REGULATOR_TYPE_BUCK, >> + REGULATOR_TYPE_DVS, >> +}; >> + >> +/* enum regulator_out_state - used for ldo/buck output state setting */ >> +enum regulator_out_state { >> + REGULATOR_OFF = 0, >> + REGULATOR_ON, >> +}; > > If we will only ever have on/off perhaps we don't need this enum and > could just use a bool? > Fixed in V3. >> + >> +/** >> + * struct regulator_value_desc - this structure holds an information about >> + * each regulator voltage limits. There is no "step" voltage value - so driver >> + * should take care of this. This is rather platform specific so can be >> + * taken from the device-tree. >> + * >> + * @type - one of: DESC_TYPE_LDO, DESC_TYPE_BUCK or DESC_TYPE_DVS >> + * @number - hardware internal regulator number > > What is this numbering and where does it come from? It is specified by > the PMIC datasheet? Can you expand the comment a bit? > > Actually I think this numbering should go away and we should use names instead. > This suggestion is implemented in V3. >> + * @min_uV - minimum voltage (micro Volts) >> + * @max_uV - maximum voltage (micro Volts) >> + * @name - name of regulator - usually will be taken from device tree and >> + * can describe regulator output connected hardware, e.g. "eMMC" >> +*/ >> +struct regulator_value_desc { >> + int type; >> + int number; >> + int min_uV; >> + int max_uV; >> + char name[DESC_NAME_LEN]; > > What do you think about making this a const char * and we alloc it > with strdup()? > Also implemented in V3. >> +}; >> + >> +/** >> + * struct regulator_mode_desc - this structure holds an information about >> + * each regulator operation modes. Probably in most cases - an array. >> + * This will be probably a driver static data since it's device specific. > > driver-static (I think you mean) > >> + * >> + * @mode - a driver specific mode number - used for regulator command >> + * @register_value - a driver specific value for this mode > > driver-specific, you are creating an adjective > >> + * @name - the name of mode - used for regulator command >> + */ >> +struct regulator_mode_desc { >> + int mode; >> + int register_value; >> + char *name; >> +}; >> + >> +/* PMIC regulator device operations */ >> +struct dm_regulator_ops { >> + /** >> + * get_cnt - get the number of a given regulator 'type' outputs >> + * >> + * @dev - regulator device >> + * @type - regulator type, one of enum regulator_type >> + * Gets: >> + * @cnt - regulator count >> + * Returns: 0 on success or negative value of errno. >> + */ >> + int (*get_cnt)(struct udevice *dev, int type, int *cnt); > > get_count > > Return count in return value instead of a parameter. > >> + >> + /** >> + * Regulator output value descriptor is specific for each output. >> + * It's usually driver static data, but output value limits are >> + * often defined in the device-tree, so those are platform dependent >> + * attributes. >> + * >> + * get_value_desc - get value descriptor of the given regulator output >> + * @dev - regulator device >> + * @type - regulator type, one of enum regulator_type >> + * @number - regulator number >> + * Gets: >> + * @desc - pointer to the descriptor >> + * Returns: 0 on success or negative value of errno. >> + */ >> + int (*get_value_desc)(struct udevice *dev, int type, int number, >> + struct regulator_value_desc **desc); > > You could use descp, to indicate it returns a pointer. > >> + >> + /** >> + * Regulator output mode descriptors are device specific. >> + * It's usually driver static data. >> + * Each regulator output can support different mode types, >> + * so usually will return an array with a number 'mode_desc_cnt' >> + * of mode descriptors. >> + * >> + * get_mode_desc_array - get mode descriptor array of the given >> + * regulator output number >> + * @dev - regulator device >> + * @type - regulator type, one of 'enum regulator_type' >> + * @number - regulator number > > regulator_num would be better > >> + * Gets: >> + * @mode_desc_cnt - descriptor array entry count >> + * @desc - pointer to the descriptor array >> + * Returns: 0 on success or negative value of errno. >> + */ >> + int (*get_mode_desc_array)(struct udevice *dev, int type, > > So should type be an enum? > >> + int number, int *mode_desc_cnt, >> + struct regulator_mode_desc **desc); >> + >> + /** >> + * The regulator output value function calls operates on a micro Volts, >> + * however the regulator commands operates on a mili Volt unit. >> + * >> + * get/set_value - get/set output value of the given output number >> + * @dev - regulator device >> + * @type - regulator type, one of 'enum regulator_type' >> + * @number - regulator number >> + * Sets/Gets: >> + * @value - set or get output value >> + * Returns: 0 on success or negative value of errno. >> + */ >> + int (*get_value)(struct udevice *dev, int type, int number, int *value); > > Return value in return value instead of a parameter. > >> + int (*set_value)(struct udevice *dev, int type, int number, int value); >> + >> + /** >> + * The most basic feature of the regulator output is it's on/off state. > > its > >> + * >> + * get/set_state - get/set on/off state of the given output number >> + * @dev - regulator device >> + * @type - regulator type, one of 'enum regulator_type' >> + * @number - regulator number >> + * Sets/Gets: >> + * @state - set or get one of 'enum regulator_out_state' >> + * Returns: 0 on success or negative value of errno. >> + */ >> + int (*get_state)(struct udevice *dev, int type, int number, int *state); > > Return state in return value instead of a parameter. > >> + int (*set_state)(struct udevice *dev, int type, int number, int state); >> + >> + /** >> + * The 'get/set_mode()' function calls should operate on a driver >> + * specific mode definitions, which should be found in: >> + * field 'mode' of struct regulator_mode_desc. >> + * >> + * get/set_mode - get/set operation mode of the given output number >> + * @dev - regulator device >> + * @type - regulator type, one of 'enum regulator_type' >> + * @number - regulator number >> + * Sets/Gets: >> + * @mode - set or get output mode >> + * Returns: 0 on success or negative value of errno. >> + */ >> + int (*get_mode)(struct udevice *dev, int type, int number, int *mode); > > Return mode in return value. > >> + int (*set_mode)(struct udevice *dev, int type, int number, int mode); >> +}; >> + >> +/** >> + * regulator_get_cnt: returns the number of driver registered regulators. > > driver-registered > >> + * This is used for pmic regulator command purposes. >> + * >> + * @dev - pointer to the regulator device >> + * @type - regulator type: device specific >> + * Gets: >> + * @cnt - regulator count >> + * Returns: 0 on success or negative value of errno. >> + */ >> +int regulator_get_cnt(struct udevice *dev, int type, int *cnt); > > regulator_get_count. Return count in return value instead of a parameter. > >> + >> +/** >> + * regulator_get_value_desc: returns a pointer to the regulator value >> + * descriptor of a given device regulator output number. >> + * >> + * @dev - pointer to the regulator device >> + * @type - regulator descriptor type >> + * @number - descriptor number (regulator output number) >> + * Gets: >> + * @desc - pointer to the descriptor >> + * Returns: 0 on success or negative value of errno. >> + */ >> +int regulator_get_value_desc(struct udevice *dev, int type, int number, >> + struct regulator_value_desc **desc); >> + >> +/** >> + * regulator_get_mode_desc: returns a pointer to the array of regulator mode >> + * descriptors of a given device regulator type and number. >> + * >> + * @dev - pointer to the regulator device >> + * @type - regulator type: device specific >> + * @number - output number: device specific >> + * Gets: >> + * @mode_cnt - descriptor array entry count >> + * @desc - pointer to the descriptor array >> + * Returns: 0 on success or negative value of errno. >> + */ >> +int regulator_get_mode_desc(struct udevice *dev, int type, int number, >> + int *mode_cnt, struct regulator_mode_desc **desc); >> + >> +/** >> + * regulator_get_value: returns voltage value of a given device >> + * regulator type number. >> + * >> + * @dev - pointer to the regulator device >> + * @type - regulator type: device specific >> + * @number - output number: device specific >> + * Gets: >> + * @val - returned voltage - unit: uV (micro Volts) >> + * Returns: 0 on success or negative value of errno. > > You may as well return the voltage in the return value, unless it can > be -ve (I assume not?) > >> + */ >> +int regulator_get_value(struct udevice *dev, int type, int number, int *val); >> + >> +/** >> + * regulator_set_value: set the voltage value of a given device regulator type >> + * number to the given one passed by the argument: @val >> + * >> + * @dev - pointer to the regulator device >> + * @type - regulator type: device specific >> + * @number - output number: device specific >> + * @val - voltage value to set - unit: uV (micro Volts) >> + * Returns - 0 on success or -errno val if fails >> + */ >> +int regulator_set_value(struct udevice *dev, int type, int number, int val); >> + >> +/** >> + * regulator_get_state: returns output state of a given device >> + * regulator type number. >> + * >> + * @dev - pointer to the regulator device >> + * @type - regulator type, device specific >> + * @number - regulator number, device specific >> + * Gets: >> + * @state - returned regulator number output state: >> + * - REGULATOR_OFF (0) - disable >> + * - REGULATOR_ON (1) - enable >> + * Returns: - 0 on success or -errno val if fails >> + */ >> +int regulator_get_state(struct udevice *dev, int type, int number, int *state); > > Return state in return value instead of a parameter. > >> + >> +/** >> + * regulator_set_state: set output state of a given device regulator type >> + * number to the given one passed by the argument: @state >> + * >> + * @dev - pointer to the regulator device >> + * @type - regulator type: device specific >> + * @number - output number: device specific >> + * @state - output state to set >> + * - enum REGULATOR_OFF == 0 - disable >> + * - enum REGULATOR_ON == 1 - enable >> + * Returns - 0 on success or -errno val if fails >> + */ >> +int regulator_set_state(struct udevice *dev, int type, int number, int state); >> + >> +/** >> + * regulator_get_mode: get mode number of a given device regulator type number >> + * >> + * @dev - pointer to the regulator device >> + * @type - output number: device specific >> + * @number - output number: device specific >> + * Gets: >> + * @mode - returned mode number >> + * Returns - 0 on success or -errno val if fails >> + * Note: >> + * The regulator driver should return one of defined, mode number rather >> + * than the raw register value. The struct type 'regulator_mode_desc' has >> + * a mode field for this purpose and register_value for a raw register value. >> + */ >> +int regulator_get_mode(struct udevice *dev, int type, int number, int *mode); > > Return mode in return value instead of a parameter. > >> + >> +/** >> + * regulator_set_mode: set given regulator type and number mode to the given >> + * one passed by the argument: @mode >> + * >> + * @dev - pointer to the regulator device >> + * @type - output number: device specific >> + * @number - output number: device specific >> + * @mode - mode type (struct regulator_mode_desc.mode) >> + * Returns - 0 on success or -errno value if fails >> + * Note: >> + * The regulator driver should take one of defined, mode number rather >> + * than a raw register value. The struct type 'regulator_mode_desc' has >> + * a mode field for this purpose and register_value for a raw register value. >> + */ >> +int regulator_set_mode(struct udevice *dev, int type, int number, int mode); >> + >> +/** >> + * regulator_..._get: returns the pointer to the pmic regulator device >> + * by specified arguments: >> + * >> + * NAME: >> + * @name - device name (useful for specific names) >> + * or SPI/I2C interface: >> + * @bus - device I2C/SPI bus number >> + * @addr_cs - device specific address for I2C or chip select for SPI, >> + * on the given bus number >> + * Gets: >> + * @regulator - pointer to the pmic device >> + * Returns: 0 on success or negative value of errno. >> + * >> + * The returned 'regulator' device can be used with: >> + * - regulator_get/set_* >> + * and if pmic_platdata is given, then also with: >> + * - pmic_if_* calls >> + * The last one is used for the pmic command purposes. >> + */ >> +int regulator_get(char *name, struct udevice **regulator); >> +int regulator_i2c_get(int bus, int addr, struct udevice **regulator); >> +int regulator_spi_get(int bus, int cs, struct udevice **regulator); > > Hoping you don't need these last two! > >> + >> +#endif /* _INCLUDE_REGULATOR_H_ */ >> -- >> 1.9.1 >> > > Regards, > Simon > Thank you,
Hello Robert, On 03/10/2015 12:41 PM, Robert Baldyga wrote: > Hi, > > On 03/03/2015 05:24 PM, Przemyslaw Marczak wrote: >> This is the implementation of driver model regulator uclass api. >> To use it, the CONFIG_DM_PMIC is required with driver implementation, >> since it provides pmic devices basic I/O API. >> >> The regulator framework is based on a 'struct dm_regulator_ops'. >> It provides a common function calls, for it's basic features: >> - regulator_get_cnt() - number of outputs each type >> - regulator_get_value_desc() - describe output value limits >> - regulator_get_mode_desc() - describe output operation modes >> - regulator_get/set_value() - output value (uV) >> - regulator_get/set_state() - output on/off state >> - regulator_get/set_mode() - output operation mode >> >> To get the regulator device: >> - regulator_get() - by name only >> - regulator_i2c_get() - by i2c bus address (of pmic parent) >> - regulator_spi_get() - by spi bus address (of pmic parent) >> >> An optional and useful regulator framework features are two descriptors: >> - struct regulator_desc - describes the regulator name and output value limits >> should be defined by device driver for each regulator output. >> >> - struct regulator_mode_desc - (array) describes a number of operation modes >> supported by each regulator output. >> >> The regulator framework features are described in file: >> - include/power/regulator.h >> >> Main files: >> - drivers/power/regulator-uclass.c - provides regulator common functions api >> - include/power/regulator.h - define all structures required by the regulator >> >> Changes: >> - new uclass-id: UCLASS_PMIC_REGULATOR >> - new config: CONFIG_DM_REGULATOR >> >> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com> >> --- >> Changes V2: >> - new operations for regulator uclass: >> -- get/set output state - for output on/off setting >> --- add enum: REGULATOR_OFF, REGULATOR_ON >> >> - regulator uclass code rework and cleanup: >> -- change name of: >> --- enum 'regulator_desc_type' to 'regulator_type' >> --- add type DVS >> --- struct 'regulator_desc' to 'regulator_value_desc' >> >> -- regulator ops function calls: >> --- remove 'ldo/buck' from naming >> --- add new argument 'type' for define regulator type >> >> -- regulator.h - update comments >> --- >> drivers/power/Makefile | 1 + >> drivers/power/regulator-uclass.c | 227 ++++++++++++++++++++++++++++ >> include/dm/uclass-id.h | 1 + >> include/power/regulator.h | 310 +++++++++++++++++++++++++++++++++++++++ >> 4 files changed, 539 insertions(+) >> create mode 100644 drivers/power/regulator-uclass.c >> create mode 100644 include/power/regulator.h >> >> diff --git a/drivers/power/Makefile b/drivers/power/Makefile >> index 5c9a189..a6b7012 100644 >> --- a/drivers/power/Makefile >> +++ b/drivers/power/Makefile >> @@ -22,3 +22,4 @@ obj-$(CONFIG_POWER_FSL) += power_fsl.o >> obj-$(CONFIG_POWER_I2C) += power_i2c.o >> obj-$(CONFIG_POWER_SPI) += power_spi.o >> obj-$(CONFIG_DM_PMIC) += pmic-uclass.o >> +obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o >> diff --git a/drivers/power/regulator-uclass.c b/drivers/power/regulator-uclass.c >> new file mode 100644 >> index 0000000..6b5c678 >> --- /dev/null >> +++ b/drivers/power/regulator-uclass.c >> @@ -0,0 +1,227 @@ >> +/* >> + * Copyright (C) 2014-2015 Samsung Electronics >> + * Przemyslaw Marczak <p.marczak@samsung.com> >> + * >> + * SPDX-License-Identifier: GPL-2.0+ >> + */ >> +#include <common.h> >> +#include <linux/types.h> >> +#include <fdtdec.h> >> +#include <dm.h> >> +#include <power/pmic.h> >> +#include <power/regulator.h> >> +#include <compiler.h> >> +#include <dm/device.h> >> +#include <dm/lists.h> >> +#include <dm/device-internal.h> >> +#include <errno.h> >> + >> +DECLARE_GLOBAL_DATA_PTR; >> + >> +int regulator_get_cnt(struct udevice *dev, int type, int *cnt) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENODEV; >> + >> + if (!ops->get_cnt) >> + return -EPERM; >> + >> + return ops->get_cnt(dev, type, cnt); >> +} >> + >> +int regulator_get_value_desc(struct udevice *dev, int type, int number, >> + struct regulator_value_desc **desc) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENXIO; >> + >> + if (!ops->get_value_desc) >> + return -EPERM; >> + >> + return ops->get_value_desc(dev, type, number, desc); >> +} >> + >> +int regulator_get_mode_desc(struct udevice *dev, int type, int number, >> + int *mode_cnt, struct regulator_mode_desc **desc) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENXIO; >> + >> + if (!ops->get_mode_desc_array) >> + return -EPERM; >> + >> + return ops->get_mode_desc_array(dev, type, number, mode_cnt, desc); >> +} >> + >> +int regulator_get_value(struct udevice *dev, int type, int number, int *value) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENODEV; >> + >> + if (!ops->get_value) >> + return -EPERM; >> + >> + return ops->get_value(dev, type, number, value); >> +} >> + >> +int regulator_set_value(struct udevice *dev, int type, int number, int value) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENODEV; >> + >> + if (!ops->set_value) >> + return -EPERM; >> + >> + return ops->set_value(dev, type, number, value); >> +} >> + >> +int regulator_get_state(struct udevice *dev, int type, int number, int *state) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENODEV; >> + >> + if (!ops->get_state) >> + return -EPERM; >> + >> + return ops->get_state(dev, type, number, state); >> +} >> + >> +int regulator_set_state(struct udevice *dev, int type, int number, int state) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENODEV; >> + >> + if (!ops->set_state) >> + return -EPERM; >> + >> + return ops->set_state(dev, type, number, state); >> +} >> + >> +int regulator_get_mode(struct udevice *dev, int type, int number, int *mode) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENODEV; >> + >> + if (!ops->get_mode) >> + return -EPERM; >> + >> + return ops->get_mode(dev, type, number, mode); >> +} >> + >> +int regulator_set_mode(struct udevice *dev, int type, int number, int mode) >> +{ >> + const struct dm_regulator_ops *ops; >> + >> + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); >> + if (!ops) >> + return -ENODEV; >> + >> + if (!ops->set_mode) >> + return -EPERM; >> + >> + return ops->set_mode(dev, type, number, mode); >> +} >> + >> +int regulator_get(char *name, struct udevice **regulator) >> +{ >> + struct udevice *dev; >> + struct uclass *uc; >> + int ret; >> + >> + ret = uclass_get(UCLASS_PMIC_REGULATOR, &uc); >> + if (ret) { >> + error("Regulator uclass not initialized!"); >> + return ret; >> + } >> + >> + uclass_foreach_dev(dev, uc) { >> + if (!dev) >> + continue; >> + >> + if (!strncmp(name, dev->name, strlen(name))) { >> + ret = device_probe(dev); >> + if (ret) >> + error("Dev: %s probe failed", dev->name); >> + *regulator = dev; > > Shouldn't we set regulator=NULL if device_probe() returns an error? > Thanks, this is fixed in V3. > > Br, > Robert > Best regards,
diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 5c9a189..a6b7012 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_POWER_FSL) += power_fsl.o obj-$(CONFIG_POWER_I2C) += power_i2c.o obj-$(CONFIG_POWER_SPI) += power_spi.o obj-$(CONFIG_DM_PMIC) += pmic-uclass.o +obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o diff --git a/drivers/power/regulator-uclass.c b/drivers/power/regulator-uclass.c new file mode 100644 index 0000000..6b5c678 --- /dev/null +++ b/drivers/power/regulator-uclass.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2014-2015 Samsung Electronics + * Przemyslaw Marczak <p.marczak@samsung.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <linux/types.h> +#include <fdtdec.h> +#include <dm.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <compiler.h> +#include <dm/device.h> +#include <dm/lists.h> +#include <dm/device-internal.h> +#include <errno.h> + +DECLARE_GLOBAL_DATA_PTR; + +int regulator_get_cnt(struct udevice *dev, int type, int *cnt) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->get_cnt) + return -EPERM; + + return ops->get_cnt(dev, type, cnt); +} + +int regulator_get_value_desc(struct udevice *dev, int type, int number, + struct regulator_value_desc **desc) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENXIO; + + if (!ops->get_value_desc) + return -EPERM; + + return ops->get_value_desc(dev, type, number, desc); +} + +int regulator_get_mode_desc(struct udevice *dev, int type, int number, + int *mode_cnt, struct regulator_mode_desc **desc) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENXIO; + + if (!ops->get_mode_desc_array) + return -EPERM; + + return ops->get_mode_desc_array(dev, type, number, mode_cnt, desc); +} + +int regulator_get_value(struct udevice *dev, int type, int number, int *value) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->get_value) + return -EPERM; + + return ops->get_value(dev, type, number, value); +} + +int regulator_set_value(struct udevice *dev, int type, int number, int value) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->set_value) + return -EPERM; + + return ops->set_value(dev, type, number, value); +} + +int regulator_get_state(struct udevice *dev, int type, int number, int *state) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->get_state) + return -EPERM; + + return ops->get_state(dev, type, number, state); +} + +int regulator_set_state(struct udevice *dev, int type, int number, int state) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->set_state) + return -EPERM; + + return ops->set_state(dev, type, number, state); +} + +int regulator_get_mode(struct udevice *dev, int type, int number, int *mode) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->get_mode) + return -EPERM; + + return ops->get_mode(dev, type, number, mode); +} + +int regulator_set_mode(struct udevice *dev, int type, int number, int mode) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->set_mode) + return -EPERM; + + return ops->set_mode(dev, type, number, mode); +} + +int regulator_get(char *name, struct udevice **regulator) +{ + struct udevice *dev; + struct uclass *uc; + int ret; + + ret = uclass_get(UCLASS_PMIC_REGULATOR, &uc); + if (ret) { + error("Regulator uclass not initialized!"); + return ret; + } + + uclass_foreach_dev(dev, uc) { + if (!dev) + continue; + + if (!strncmp(name, dev->name, strlen(name))) { + ret = device_probe(dev); + if (ret) + error("Dev: %s probe failed", dev->name); + *regulator = dev; + return ret; + } + } + + *regulator = NULL; + return -EINVAL; +} + +int regulator_i2c_get(int bus, int addr, struct udevice **regulator) +{ + struct udevice *pmic; + int ret; + + /* First get parent pmic device */ + ret = pmic_i2c_get(bus, addr, &pmic); + if (ret) { + error("Chip: %d on bus %d not found!", addr, bus); + return ret; + } + + /* Get the first regulator child of pmic device */ + if (device_get_first_child_by_uclass_id(pmic, UCLASS_PMIC_REGULATOR, + regulator)) { + error("PMIC: %s regulator child not found!", pmic->name); + *regulator = NULL; + return ret; + } + + return 0; +} + +int regulator_spi_get(int bus, int cs, struct udevice **regulator) +{ + struct udevice *pmic; + int ret; + + /* First get parent pmic device */ + ret = pmic_spi_get(bus, cs, &pmic); + if (ret) { + error("Chip: %d on bus %d not found!", cs, bus); + return ret; + } + + /* Get the first regulator child of pmic device */ + if (device_get_first_child_by_uclass_id(pmic, UCLASS_PMIC_REGULATOR, + regulator)) { + error("PMIC: %s regulator child not found!", pmic->name); + *regulator = NULL; + return ret; + } + + return 0; +} + +UCLASS_DRIVER(regulator) = { + .id = UCLASS_PMIC_REGULATOR, + .name = "regulator", +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index ff360ac..0a1e664 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -37,6 +37,7 @@ enum uclass_id { /* PMIC uclass and PMIC related uclasses */ UCLASS_PMIC, + UCLASS_PMIC_REGULATOR, UCLASS_COUNT, UCLASS_INVALID = -1, diff --git a/include/power/regulator.h b/include/power/regulator.h new file mode 100644 index 0000000..ee8a280 --- /dev/null +++ b/include/power/regulator.h @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2014-2015 Samsung Electronics + * Przemyslaw Marczak <p.marczak@samsung.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _INCLUDE_REGULATOR_H_ +#define _INCLUDE_REGULATOR_H_ + +#define DESC_NAME_LEN 20 + +/* enum regulator_type - used for regulator_*() variant calls */ +enum regulator_type { + REGULATOR_TYPE_LDO = 0, + REGULATOR_TYPE_BUCK, + REGULATOR_TYPE_DVS, +}; + +/* enum regulator_out_state - used for ldo/buck output state setting */ +enum regulator_out_state { + REGULATOR_OFF = 0, + REGULATOR_ON, +}; + +/** + * struct regulator_value_desc - this structure holds an information about + * each regulator voltage limits. There is no "step" voltage value - so driver + * should take care of this. This is rather platform specific so can be + * taken from the device-tree. + * + * @type - one of: DESC_TYPE_LDO, DESC_TYPE_BUCK or DESC_TYPE_DVS + * @number - hardware internal regulator number + * @min_uV - minimum voltage (micro Volts) + * @max_uV - maximum voltage (micro Volts) + * @name - name of regulator - usually will be taken from device tree and + * can describe regulator output connected hardware, e.g. "eMMC" +*/ +struct regulator_value_desc { + int type; + int number; + int min_uV; + int max_uV; + char name[DESC_NAME_LEN]; +}; + +/** + * struct regulator_mode_desc - this structure holds an information about + * each regulator operation modes. Probably in most cases - an array. + * This will be probably a driver static data since it's device specific. + * + * @mode - a driver specific mode number - used for regulator command + * @register_value - a driver specific value for this mode + * @name - the name of mode - used for regulator command + */ +struct regulator_mode_desc { + int mode; + int register_value; + char *name; +}; + +/* PMIC regulator device operations */ +struct dm_regulator_ops { + /** + * get_cnt - get the number of a given regulator 'type' outputs + * + * @dev - regulator device + * @type - regulator type, one of enum regulator_type + * Gets: + * @cnt - regulator count + * Returns: 0 on success or negative value of errno. + */ + int (*get_cnt)(struct udevice *dev, int type, int *cnt); + + /** + * Regulator output value descriptor is specific for each output. + * It's usually driver static data, but output value limits are + * often defined in the device-tree, so those are platform dependent + * attributes. + * + * get_value_desc - get value descriptor of the given regulator output + * @dev - regulator device + * @type - regulator type, one of enum regulator_type + * @number - regulator number + * Gets: + * @desc - pointer to the descriptor + * Returns: 0 on success or negative value of errno. + */ + int (*get_value_desc)(struct udevice *dev, int type, int number, + struct regulator_value_desc **desc); + + /** + * Regulator output mode descriptors are device specific. + * It's usually driver static data. + * Each regulator output can support different mode types, + * so usually will return an array with a number 'mode_desc_cnt' + * of mode descriptors. + * + * get_mode_desc_array - get mode descriptor array of the given + * regulator output number + * @dev - regulator device + * @type - regulator type, one of 'enum regulator_type' + * @number - regulator number + * Gets: + * @mode_desc_cnt - descriptor array entry count + * @desc - pointer to the descriptor array + * Returns: 0 on success or negative value of errno. + */ + int (*get_mode_desc_array)(struct udevice *dev, int type, + int number, int *mode_desc_cnt, + struct regulator_mode_desc **desc); + + /** + * The regulator output value function calls operates on a micro Volts, + * however the regulator commands operates on a mili Volt unit. + * + * get/set_value - get/set output value of the given output number + * @dev - regulator device + * @type - regulator type, one of 'enum regulator_type' + * @number - regulator number + * Sets/Gets: + * @value - set or get output value + * Returns: 0 on success or negative value of errno. + */ + int (*get_value)(struct udevice *dev, int type, int number, int *value); + int (*set_value)(struct udevice *dev, int type, int number, int value); + + /** + * The most basic feature of the regulator output is it's on/off state. + * + * get/set_state - get/set on/off state of the given output number + * @dev - regulator device + * @type - regulator type, one of 'enum regulator_type' + * @number - regulator number + * Sets/Gets: + * @state - set or get one of 'enum regulator_out_state' + * Returns: 0 on success or negative value of errno. + */ + int (*get_state)(struct udevice *dev, int type, int number, int *state); + int (*set_state)(struct udevice *dev, int type, int number, int state); + + /** + * The 'get/set_mode()' function calls should operate on a driver + * specific mode definitions, which should be found in: + * field 'mode' of struct regulator_mode_desc. + * + * get/set_mode - get/set operation mode of the given output number + * @dev - regulator device + * @type - regulator type, one of 'enum regulator_type' + * @number - regulator number + * Sets/Gets: + * @mode - set or get output mode + * Returns: 0 on success or negative value of errno. + */ + int (*get_mode)(struct udevice *dev, int type, int number, int *mode); + int (*set_mode)(struct udevice *dev, int type, int number, int mode); +}; + +/** + * regulator_get_cnt: returns the number of driver registered regulators. + * This is used for pmic regulator command purposes. + * + * @dev - pointer to the regulator device + * @type - regulator type: device specific + * Gets: + * @cnt - regulator count + * Returns: 0 on success or negative value of errno. + */ +int regulator_get_cnt(struct udevice *dev, int type, int *cnt); + +/** + * regulator_get_value_desc: returns a pointer to the regulator value + * descriptor of a given device regulator output number. + * + * @dev - pointer to the regulator device + * @type - regulator descriptor type + * @number - descriptor number (regulator output number) + * Gets: + * @desc - pointer to the descriptor + * Returns: 0 on success or negative value of errno. + */ +int regulator_get_value_desc(struct udevice *dev, int type, int number, + struct regulator_value_desc **desc); + +/** + * regulator_get_mode_desc: returns a pointer to the array of regulator mode + * descriptors of a given device regulator type and number. + * + * @dev - pointer to the regulator device + * @type - regulator type: device specific + * @number - output number: device specific + * Gets: + * @mode_cnt - descriptor array entry count + * @desc - pointer to the descriptor array + * Returns: 0 on success or negative value of errno. + */ +int regulator_get_mode_desc(struct udevice *dev, int type, int number, + int *mode_cnt, struct regulator_mode_desc **desc); + +/** + * regulator_get_value: returns voltage value of a given device + * regulator type number. + * + * @dev - pointer to the regulator device + * @type - regulator type: device specific + * @number - output number: device specific + * Gets: + * @val - returned voltage - unit: uV (micro Volts) + * Returns: 0 on success or negative value of errno. + */ +int regulator_get_value(struct udevice *dev, int type, int number, int *val); + +/** + * regulator_set_value: set the voltage value of a given device regulator type + * number to the given one passed by the argument: @val + * + * @dev - pointer to the regulator device + * @type - regulator type: device specific + * @number - output number: device specific + * @val - voltage value to set - unit: uV (micro Volts) + * Returns - 0 on success or -errno val if fails + */ +int regulator_set_value(struct udevice *dev, int type, int number, int val); + +/** + * regulator_get_state: returns output state of a given device + * regulator type number. + * + * @dev - pointer to the regulator device + * @type - regulator type, device specific + * @number - regulator number, device specific + * Gets: + * @state - returned regulator number output state: + * - REGULATOR_OFF (0) - disable + * - REGULATOR_ON (1) - enable + * Returns: - 0 on success or -errno val if fails + */ +int regulator_get_state(struct udevice *dev, int type, int number, int *state); + +/** + * regulator_set_state: set output state of a given device regulator type + * number to the given one passed by the argument: @state + * + * @dev - pointer to the regulator device + * @type - regulator type: device specific + * @number - output number: device specific + * @state - output state to set + * - enum REGULATOR_OFF == 0 - disable + * - enum REGULATOR_ON == 1 - enable + * Returns - 0 on success or -errno val if fails + */ +int regulator_set_state(struct udevice *dev, int type, int number, int state); + +/** + * regulator_get_mode: get mode number of a given device regulator type number + * + * @dev - pointer to the regulator device + * @type - output number: device specific + * @number - output number: device specific + * Gets: + * @mode - returned mode number + * Returns - 0 on success or -errno val if fails + * Note: + * The regulator driver should return one of defined, mode number rather + * than the raw register value. The struct type 'regulator_mode_desc' has + * a mode field for this purpose and register_value for a raw register value. + */ +int regulator_get_mode(struct udevice *dev, int type, int number, int *mode); + +/** + * regulator_set_mode: set given regulator type and number mode to the given + * one passed by the argument: @mode + * + * @dev - pointer to the regulator device + * @type - output number: device specific + * @number - output number: device specific + * @mode - mode type (struct regulator_mode_desc.mode) + * Returns - 0 on success or -errno value if fails + * Note: + * The regulator driver should take one of defined, mode number rather + * than a raw register value. The struct type 'regulator_mode_desc' has + * a mode field for this purpose and register_value for a raw register value. + */ +int regulator_set_mode(struct udevice *dev, int type, int number, int mode); + +/** + * regulator_..._get: returns the pointer to the pmic regulator device + * by specified arguments: + * + * NAME: + * @name - device name (useful for specific names) + * or SPI/I2C interface: + * @bus - device I2C/SPI bus number + * @addr_cs - device specific address for I2C or chip select for SPI, + * on the given bus number + * Gets: + * @regulator - pointer to the pmic device + * Returns: 0 on success or negative value of errno. + * + * The returned 'regulator' device can be used with: + * - regulator_get/set_* + * and if pmic_platdata is given, then also with: + * - pmic_if_* calls + * The last one is used for the pmic command purposes. + */ +int regulator_get(char *name, struct udevice **regulator); +int regulator_i2c_get(int bus, int addr, struct udevice **regulator); +int regulator_spi_get(int bus, int cs, struct udevice **regulator); + +#endif /* _INCLUDE_REGULATOR_H_ */
This is the implementation of driver model regulator uclass api. To use it, the CONFIG_DM_PMIC is required with driver implementation, since it provides pmic devices basic I/O API. The regulator framework is based on a 'struct dm_regulator_ops'. It provides a common function calls, for it's basic features: - regulator_get_cnt() - number of outputs each type - regulator_get_value_desc() - describe output value limits - regulator_get_mode_desc() - describe output operation modes - regulator_get/set_value() - output value (uV) - regulator_get/set_state() - output on/off state - regulator_get/set_mode() - output operation mode To get the regulator device: - regulator_get() - by name only - regulator_i2c_get() - by i2c bus address (of pmic parent) - regulator_spi_get() - by spi bus address (of pmic parent) An optional and useful regulator framework features are two descriptors: - struct regulator_desc - describes the regulator name and output value limits should be defined by device driver for each regulator output. - struct regulator_mode_desc - (array) describes a number of operation modes supported by each regulator output. The regulator framework features are described in file: - include/power/regulator.h Main files: - drivers/power/regulator-uclass.c - provides regulator common functions api - include/power/regulator.h - define all structures required by the regulator Changes: - new uclass-id: UCLASS_PMIC_REGULATOR - new config: CONFIG_DM_REGULATOR Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com> --- Changes V2: - new operations for regulator uclass: -- get/set output state - for output on/off setting --- add enum: REGULATOR_OFF, REGULATOR_ON - regulator uclass code rework and cleanup: -- change name of: --- enum 'regulator_desc_type' to 'regulator_type' --- add type DVS --- struct 'regulator_desc' to 'regulator_value_desc' -- regulator ops function calls: --- remove 'ldo/buck' from naming --- add new argument 'type' for define regulator type -- regulator.h - update comments --- drivers/power/Makefile | 1 + drivers/power/regulator-uclass.c | 227 ++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/power/regulator.h | 310 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 539 insertions(+) create mode 100644 drivers/power/regulator-uclass.c create mode 100644 include/power/regulator.h