[U-Boot] [PATCH 05/19] dm: pmic: add implementation of driver model regulator uclass

Przemyslaw Marczak p.marczak at samsung.com
Wed Oct 8 22:48:41 CEST 2014


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.marczak at 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.marczak at 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.marczak at 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



More information about the U-Boot mailing list