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 I/O API.
The regulator framework is based on a 'structure dm_regulator_ops', which provides all regulator functions call types. The optional and useful regulator features are two descriptor types: - struct regulator_desc - describes the regulator name and value limits should be set by device driver for each regulator number. - struct regulator_mode_desc - also should be defined as mode array for each regulator, since regulators supports few modes, at least: ON/OFF. The regulator driver operations are clear and described in file: include/power/regulator.h: Each regulator "struct driver.ops" should point to "struct dm_regulator_ops". If do, then the drivers can use the regulator api(if implemented): - pmic_ldo_cnt(...) - pmic_buck_cnt(...) - pmic_get_ldo_val(...) - pmic_set_ldo_val(...) - pmic_get_ldo_mode(...) - pmic_set_ldo_mode(...) - pmic_get_buck_val(...) - pmic_set_buck_val(...) - pmic_get_buck_mode(...) - pmic_set_buck_mode(...) To get the regulator device we can use two functions: - pmic_get_by_name(...) - pmic_get_by_interface(...) 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.marc...@samsung.com> --- drivers/power/Makefile | 1 + drivers/power/regulator-uclass.c | 250 ++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/power/pmic.h | 18 +++ include/power/regulator.h | 267 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 537 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 8def501..9a0b8c4 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_POWER_SPI) += power_spi.o obj-$(CONFIG_DM_PMIC_SPI) += pmic_spi.o obj-$(CONFIG_DM_PMIC_I2C) += pmic_i2c.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..4c9614e --- /dev/null +++ b/drivers/power/regulator-uclass.c @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2014 Samsung Electronics + * Przemyslaw Marczak <p.marc...@samsung.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <linux/types.h> +#include <fdtdec.h> +#include <power/pmic.h> +#include <i2c.h> +#include <compiler.h> +#include <dm.h> +#include <dm/device.h> +#include <dm/lists.h> +#include <dm/device-internal.h> +#include <errno.h> + +DECLARE_GLOBAL_DATA_PTR; + +int pmic_ldo_cnt(struct udevice *dev) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->get_ldo_cnt) + return -EPERM; + + return ops->get_ldo_cnt(dev); +} + +int pmic_buck_cnt(struct udevice *dev) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->get_buck_cnt) + return -EPERM; + + return ops->get_buck_cnt(dev); +} + +struct regulator_desc *pmic_ldo_desc(struct udevice *dev, int ldo) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return NULL; + + if (!ops->get_val_desc) + return NULL; + + return ops->get_val_desc(dev, DESC_TYPE_LDO, ldo); +} + +struct regulator_desc *pmic_buck_desc(struct udevice *dev, int buck) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return NULL; + + if (!ops->get_val_desc) + return NULL; + + return ops->get_val_desc(dev, DESC_TYPE_BUCK, buck); +} + +struct regulator_mode_desc *pmic_ldo_mode_desc(struct udevice *dev, int ldo, + int *mode_cnt) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return NULL; + + if (!ops->get_mode_desc_array) + return NULL; + + return ops->get_mode_desc_array(dev, DESC_TYPE_LDO, ldo, mode_cnt); +} + +struct regulator_mode_desc *pmic_buck_mode_desc(struct udevice *dev, int buck, + int *mode_cnt) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return NULL; + + if (!ops->get_mode_desc_array) + return NULL; + + return ops->get_mode_desc_array(dev, DESC_TYPE_BUCK, buck, mode_cnt); +} + +int pmic_get_ldo_val(struct udevice *dev, int ldo) +{ + const struct dm_regulator_ops *ops; + int val = -1; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->ldo_val) + return -EPERM; + + if (ops->ldo_val(dev, PMIC_OP_GET, ldo, &val)) + return -EIO; + + return val; +} + +int pmic_set_ldo_val(struct udevice *dev, int ldo, int val) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->ldo_val) + return -EPERM; + + if (ops->ldo_val(dev, PMIC_OP_SET, ldo, &val)) + return -EIO; + + return 0; +} + +int pmic_get_ldo_mode(struct udevice *dev, int ldo) +{ + const struct dm_regulator_ops *ops; + int mode; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->ldo_mode) + return -EPERM; + + if (ops->ldo_mode(dev, PMIC_OP_GET, ldo, &mode)) + return -EIO; + + return mode; +} + +int pmic_set_ldo_mode(struct udevice *dev, int ldo, int mode) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->ldo_mode) + return -EPERM; + + if (ops->ldo_mode(dev, PMIC_OP_SET, ldo, &mode)) + return -EIO; + + return 0; +} + +int pmic_get_buck_val(struct udevice *dev, int buck) +{ + const struct dm_regulator_ops *ops; + int val; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->buck_val) + return -EPERM; + + if (ops->buck_val(dev, PMIC_OP_GET, buck, &val)) + return -EIO; + + return val; +} + +int pmic_set_buck_val(struct udevice *dev, int buck, int val) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->buck_val) + return -EPERM; + + if (ops->buck_val(dev, PMIC_OP_SET, buck, &val)) + return -EIO; + + return 0; +} + +int pmic_get_buck_mode(struct udevice *dev, int buck) +{ + const struct dm_regulator_ops *ops; + int mode; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->buck_mode) + return -EPERM; + + if (ops->buck_mode(dev, PMIC_OP_GET, buck, &mode)) + return -EIO; + + return mode; +} + +int pmic_set_buck_mode(struct udevice *dev, int buck, int mode) +{ + const struct dm_regulator_ops *ops; + + ops = pmic_get_uclass_ops(dev, UCLASS_PMIC_REGULATOR); + if (!ops) + return -ENODEV; + + if (!ops->buck_mode) + return -EPERM; + + if (ops->buck_mode(dev, PMIC_OP_SET, buck, &mode)) + return -EIO; + + return 0; +} + +UCLASS_DRIVER(pmic_regulator) = { + .id = UCLASS_PMIC_REGULATOR, + .name = "regulator", +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index e6d9d39..147222c 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -31,6 +31,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/pmic.h b/include/power/pmic.h index 7114650..5a06ba4 100644 --- a/include/power/pmic.h +++ b/include/power/pmic.h @@ -119,6 +119,24 @@ enum pmic_op_type { PMIC_OP_SET, }; +static __inline__ const void *pmic_get_uclass_ops(struct udevice *dev, + int uclass_id) +{ + const void *ops; + + if (!dev) + return NULL; + + if (dev->driver->id != uclass_id) + return NULL; + + ops = dev->driver->ops; + if (!ops) + return NULL; + + return ops; +} + /* drivers/power/pmic-uclass.c */ int power_init_dm(void); struct udevice *pmic_get_by_name(int uclass_id, char *name); diff --git a/include/power/regulator.h b/include/power/regulator.h new file mode 100644 index 0000000..3e2fea6 --- /dev/null +++ b/include/power/regulator.h @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2014 Samsung Electronics + * Przemyslaw Marczak <p.marc...@samsung.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _INCLUDE_REGULATOR_H_ +#define _INCLUDE_REGULATOR_H_ + +#define DESC_NAME_LEN 20 + +/* enum regulator_desc_type - used for lbo/buck descriptor calls */ +enum regulator_desc_type { + DESC_TYPE_LDO, + DESC_TYPE_BUCK, +}; + +/** + * struct regulator_desc - this structure holds an information about each + * ldo/buck 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 or DESC_TYPE_BUCK + * @number - hardware ldo/buck number + * @min_uV - minimum voltage (micro Volts) + * @max_uV - maximum voltage (micro Volts) + * @name - name of LDO - usually will be taken from device tree and can + * describe ldo/buck really connected hardware +*/ +struct regulator_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 + * ldo/buck operation modes. Probably in most cases - an array of modes for + * each ldo/buck. This will be probably a driver static data since modes + * are device specific more than platform specific. + * + * @type - one of: DESC_TYPE_LDO or DESC_TYPE_BUCK + * @val - a driver specific value for this mode + * @name - the name of mode - for command purposes + */ +struct regulator_mode_desc { + int mode; + int reg_val; + char *name; +}; + +/* PMIC regulator device operations */ +struct dm_regulator_ops { + /* Number of LDOs and BUCKs */ + int (*get_ldo_cnt)(struct udevice *dev); + int (*get_buck_cnt)(struct udevice *dev); + + /** + * LDO and BUCK attribute descriptors can be usually const static data, + * but ldo/buck value limits are often defined in the device-tree, + * so those are platform dependent attributes. + */ + struct regulator_desc *(*get_val_desc)(struct udevice *dev, int d_type, + int d_num); + + /** + * LDO/BUCK mode descriptors are device specific, so in this case + * we have also the same static data for each driver device. + * But each LDO/BUCK regulator can support different modes, + * so this is the reason why returns mode descriptors array for each + * regulator number. + */ + struct regulator_mode_desc *(*get_mode_desc_array)(struct udevice *dev, + int desc_type, + int desc_num, + int *desc_mode_cnt); + + /** + * The 'ldo/reg_val()' function calls should operate on a micro Volts + * values, however the regulator commands operates in mili Volts. + * + * The 'ldo/buck_mode()' function calls as a taken/returned mode value + * should always use a 'mode' field value from structure type: + * 'regulator_mode_desc'. So for this purpose each driver should defines + * its own mode types for friendly use with regulator commands. + */ + + /* LDO operations */ + int (*ldo_val)(struct udevice *dev, int operation, int ldo, + int *val); + int (*ldo_mode)(struct udevice *dev, int operation, int ldo, + int *mode); + + /* Buck converters operations */ + int (*buck_val)(struct udevice *dev, int operation, int buck, + int *val); + int (*buck_mode)(struct udevice *dev, int operation, int buck, + int *mode); +}; + +/** + * pmic_ldo_cnt - returns the number of driver registered linear regulators + * and this is used for pmic regulator commands purposes. + * + * @dev - pointer to regulator device + * Returns: a null or positive number of LDO or negative value of errno. + */ +int pmic_ldo_cnt(struct udevice *dev); + +/** + * pmic_buck_cnt - returns the number of driver registered step-down converters + * and this is used for pmic regulator commands purposes. + * + * @dev - pointer to regulator device + * Returns: a null or positive number of BUCK or negative value of errno. + */ +int pmic_buck_cnt(struct udevice *dev); + +/** + * pmic_ldo_desc - returns a pointer to the regulator value descriptor + * of a given device LDO number. + * + * @dev - pointer to regulator device + * @ldo - descriptor number: device specific output number + * Returns: pointer to descriptor if found or NULL on error. + */ +struct regulator_desc *pmic_ldo_desc(struct udevice *dev, int ldo); + +/** + * pmic_buck_desc - returns a pointer to the regulator value descriptor + * of a given device BUCK number. + * + * @dev - pointer to regulator device + * @buck - descriptor number: device specific output number + * Returns: pointer to descriptor if found or NULL on error. + */ +struct regulator_desc *pmic_buck_desc(struct udevice *dev, int buck); + +/** + * pmic_ldo_mode_desc - returns a pointer to the array of regulator mode + * descriptors of a given device regulator type and number. + * + * @dev - pointer to regulator device + * @ldo - output number: device specific + * @mode_cnt - pointer to the returned descriptor array entries + * Returns: pointer to descriptor if found or NULL on error. + */ +struct regulator_mode_desc *pmic_ldo_mode_desc(struct udevice *dev, int ldo, + int *mode_cnt); + +/** + * pmic_buck_mode_desc - returns a pointer to the array of regulator mode + * descriptors of a given device regulator type and number. + * + * @dev - pointer to regulator device + * @ldo - output number: device specific + * @mode_cnt - pointer to the returned descriptor array entries + * Returns: pointer to descriptor if found or NULL on error. + */ +struct regulator_mode_desc *pmic_buck_mode_desc(struct udevice *dev, int buck, + int *mode_cnt); + +/** + * pmic_get_ldo_val: returns LDO voltage value of a given device regulator + * number. + * + * @dev - pointer to regulator device + * @ldo - output number: device specific + * Returns: - ldo number voltage - unit: uV (micro Volts) or -errno if fails + */ +int pmic_get_ldo_val(struct udevice *dev, int ldo); + +/** + * pmic_set_ldo_val: set LDO voltage value of a given device regulator + * number to the given value + * + * @dev - pointer to regulator device + * @ldo - output number: device specific + * @val - voltage value to set - unit: uV (micro Volts) + * Returns - 0 on success or -errno val if fails + */ +int pmic_set_ldo_val(struct udevice *dev, int ldo, int val); + +/** + * pmic_get_ldo_mode: get LDO mode type of a given device regulator + * number + * + * @dev - pointer to regulator device + * @ldo - output number: device specific + * Returns - mode number on success or -errno val if fails + * Note: + * The regulator driver should return one of defined, continuous mode number, + * rather than a raw register value. The struct type 'regulator_mode_desc' has + * a mode field for this purpose and reg_val for a raw register value. + */ +int pmic_get_ldo_mode(struct udevice *dev, int ldo); + +/** + * pmic_set_ldo_mode: set given regulator LDO mode to the given mode type + * + * @dev - pointer to regulator device + * @ldo - 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, continuous mode number, + * rather than a raw register value. The struct type 'regulator_mode_desc' has + * a mode field for this purpose and reg_val for a raw register value. + */ +int pmic_set_ldo_mode(struct udevice *dev, int ldo, int mode); + +/** + * pmic_get_buck_val: returns BUCK voltage value of a given device regulator + * number. + * + * @dev - pointer to regulator device + * @ldo - output number: device specific + * Returns - BUCK number voltage - unit: uV (micro Volts) or -errno if fails + */ +int pmic_get_buck_val(struct udevice *dev, int buck); + +/** + * pmic_set_buck_val: set BUCK voltage value of a given device regulator + * number to the given value + * + * @dev - pointer to regulator device + * @buck - output number: device specific + * @val - voltage value to set - unit: uV (micro Volts) + * Returns - 0 on success or -errno val if fails + */ +int pmic_set_buck_val(struct udevice *dev, int buck, int val); + +/** + * pmic_get_buck_mode: get BUCK mode type of a given device regulator + * number + * + * @dev - pointer to regulator device + * @buck - output number: device specific + * Returns - mode number on success or -errno val if fails + * Note: + * The regulator driver should return one of defined, continuous mode number, + * rather than a raw register value. The struct type 'regulator_mode_desc' has + * the 'mode' field for this purpose and the 'reg_val' for a raw register value. + */ +int pmic_get_buck_mode(struct udevice *dev, int buck); + +/** + * pmic_set_buck_mode: set given regulator buck mode to the given mode type + * + * @dev - pointer to regulator device + * @buck - 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, continuous mode number, + * rather than a raw register value. The struct type 'regulator_mode_desc' has + * the 'mode' field for this purpose and the 'reg_val' for a raw register value. + */ +int pmic_set_buck_mode(struct udevice *dev, int buck, int mode); + +#endif /* _INCLUDE_REGULATOR_H_ */ -- 1.9.1 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot