All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v4 0/6] power: pmic: support more PMIC
@ 2019-09-26  7:43 Elaine Zhang
  2019-09-26  7:43 ` [U-Boot] [PATCH v4 1/6] dm: regulator: support regulator more state Elaine Zhang
                   ` (6 more replies)
  0 siblings, 7 replies; 9+ messages in thread
From: Elaine Zhang @ 2019-09-26  7:43 UTC (permalink / raw)
  To: u-boot

Support more PMIC and improve compatibility between pmics.

Change in V4:
[PATCH v4 1/6]: No change.
[PATCH v4 2/6]: No change.
[PATCH v4 3/6]: No change.
[PATCH v4 4/6]: No change.
[PATCH v4 5/6]: Resolve code conflicts after ptach v3 5/8 and 6/8 deletion.
[PATCH v4 6/6]: Resolve code conflicts after ptach v3 5/8 and 6/8 deletion.
Remove [PATCH v3 5/8] and [PATCH v3 6/8], There is no application scenario.

Change in V3:
[PATCH v3 1/8]: Add document instructions, Correct error handling.
[PATCH v3 2/8]: No change.
[PATCH v3 3/8]: No change.
[PATCH v3 4/8]: No change.
[PATCH v3 5/8]: Update commit message.
[PATCH v3 6/8]: Update commit message.
[PATCH v3 7/8]: No change.
[PATCH v3 8/8]: No change.

Change in V2:
[PATCH v2 1/8]: Add regulator suspend volatge and en/disable test.
[PATCH v2 2/8]: Split the [PATCH v1 2/7], rk808 and rk818 updates.
[PATCH v2 3/8]: Split the [PATCH v1 2/7], support rk816 pmic and update commit message.
[PATCH v2 4/8]: Update commit message.
[PATCH v2 5/8]: No change.
[PATCH v2 6/8]: No change.
[PATCH v2 7/8]: Remove rk809 keywords and update commit message.
[PATCH v2 8/8]: Update commit message.

Elaine Zhang (3):
  power: regulator: rk8xx: update the driver for rk808 and rk818
  power: pmic: rk816: support rk816 pmic
  power: pmic: rk805: support rk805 pmic

Joseph Chen (3):
  dm: regulator: support regulator more state
  power: pmic: rk817: support rk817 pmic
  power: pmic: rk809: support rk809 pmic

 doc/device-tree-bindings/regulator/regulator.txt |  27 +
 drivers/power/pmic/rk8xx.c                       |  89 ++-
 drivers/power/regulator/regulator-uclass.c       |  70 ++
 drivers/power/regulator/rk8xx.c                  | 939 +++++++++++++++++++++--
 include/power/regulator.h                        |  64 ++
 include/power/rk8xx_pmic.h                       |  42 +
 test/dm/regulator.c                              |  46 ++
 7 files changed, 1189 insertions(+), 88 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH v4 1/6] dm: regulator: support regulator more state
  2019-09-26  7:43 [U-Boot] [PATCH v4 0/6] power: pmic: support more PMIC Elaine Zhang
@ 2019-09-26  7:43 ` Elaine Zhang
  2019-10-16  2:06   ` Kever Yang
  2019-09-26  7:43 ` [U-Boot] [PATCH v4 2/6] power: regulator: rk8xx: update the driver for rk808 and rk818 Elaine Zhang
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 9+ messages in thread
From: Elaine Zhang @ 2019-09-26  7:43 UTC (permalink / raw)
  To: u-boot

From: Joseph Chen <chenjh@rock-chips.com>

support parse regulator standard property:
regulator-off-in-suspend;
regulator-init-microvolt;
regulator-suspend-microvolt:
 regulator_get_suspend_enable
 regulator_set_suspend_enable
 regulator_get_suspend_value
 regulator_set_suspend_value

Signed-off-by: Joseph Chen <chenjh@rock-chips.com>
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
Reviewed-by: Kever Yang<kever.yang@rock-chips.com>
---
 doc/device-tree-bindings/regulator/regulator.txt | 27 +++++++++
 drivers/power/regulator/regulator-uclass.c       | 70 ++++++++++++++++++++++++
 include/power/regulator.h                        | 64 ++++++++++++++++++++++
 test/dm/regulator.c                              | 46 ++++++++++++++++
 4 files changed, 207 insertions(+)

diff --git a/doc/device-tree-bindings/regulator/regulator.txt b/doc/device-tree-bindings/regulator/regulator.txt
index 4ba642b7c77f..6c9a02120fde 100644
--- a/doc/device-tree-bindings/regulator/regulator.txt
+++ b/doc/device-tree-bindings/regulator/regulator.txt
@@ -36,6 +36,28 @@ Optional properties:
 - regulator-always-on: regulator should never be disabled
 - regulator-boot-on: enabled by bootloader/firmware
 - regulator-ramp-delay: ramp delay for regulator (in uV/us)
+- regulator-init-microvolt: a init allowed Voltage value
+- regulator-state-(standby|mem|disk)
+  type: object
+  description:
+    sub-nodes for regulator state in Standby, Suspend-to-RAM, and
+    Suspend-to-DISK modes. Equivalent with standby, mem, and disk Linux
+    sleep states.
+
+    properties:
+      regulator-on-in-suspend:
+        description: regulator should be on in suspend state.
+        type: boolean
+
+      regulator-off-in-suspend:
+        description: regulator should be off in suspend state.
+        type: boolean
+
+      regulator-suspend-microvolt:
+        description: the default voltage which regulator would be set in
+          suspend. This property is now deprecated, instead setting voltage
+          for suspend mode via the API which regulator driver provides is
+          recommended.
 
 Note
 The "regulator-name" constraint is used for setting the device's uclass
@@ -59,7 +81,12 @@ ldo0 {
 	regulator-max-microvolt = <1800000>;
 	regulator-min-microamp = <100000>;
 	regulator-max-microamp = <100000>;
+	regulator-init-microvolt = <1800000>;
 	regulator-always-on;
 	regulator-boot-on;
 	regulator-ramp-delay = <12000>;
+	regulator-state-mem {
+		regulator-on-in-suspend;
+		regulator-suspend-microvolt = <1800000>;
+	};
 };
diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c
index 76be95bcd159..b49c0829ed31 100644
--- a/drivers/power/regulator/regulator-uclass.c
+++ b/drivers/power/regulator/regulator-uclass.c
@@ -77,6 +77,33 @@ int regulator_set_value(struct udevice *dev, int uV)
 	return ret;
 }
 
+int regulator_set_suspend_value(struct udevice *dev, int uV)
+{
+	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+	struct dm_regulator_uclass_platdata *uc_pdata;
+
+	uc_pdata = dev_get_uclass_platdata(dev);
+	if (uc_pdata->min_uV != -ENODATA && uV < uc_pdata->min_uV)
+		return -EINVAL;
+	if (uc_pdata->max_uV != -ENODATA && uV > uc_pdata->max_uV)
+		return -EINVAL;
+
+	if (!ops->set_suspend_value)
+		return -ENOSYS;
+
+	return ops->set_suspend_value(dev, uV);
+}
+
+int regulator_get_suspend_value(struct udevice *dev)
+{
+	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+	if (!ops->get_suspend_value)
+		return -ENOSYS;
+
+	return ops->get_suspend_value(dev);
+}
+
 /*
  * To be called with at most caution as there is no check
  * before setting the actual voltage value.
@@ -170,6 +197,26 @@ int regulator_set_enable_if_allowed(struct udevice *dev, bool enable)
 	return ret;
 }
 
+int regulator_set_suspend_enable(struct udevice *dev, bool enable)
+{
+	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+	if (!ops->set_suspend_enable)
+		return -ENOSYS;
+
+	return ops->set_suspend_enable(dev, enable);
+}
+
+int regulator_get_suspend_enable(struct udevice *dev)
+{
+	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+	if (!ops->get_suspend_enable)
+		return -ENOSYS;
+
+	return ops->get_suspend_enable(dev);
+}
+
 int regulator_get_mode(struct udevice *dev)
 {
 	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
@@ -235,6 +282,14 @@ int regulator_autoset(struct udevice *dev)
 	int ret = 0;
 
 	uc_pdata = dev_get_uclass_platdata(dev);
+
+	ret = regulator_set_suspend_enable(dev, uc_pdata->suspend_on);
+	if (!ret && uc_pdata->suspend_on) {
+		ret = regulator_set_suspend_value(dev, uc_pdata->suspend_uV);
+		if (!ret)
+			return ret;
+	}
+
 	if (!uc_pdata->always_on && !uc_pdata->boot_on)
 		return -EMEDIUMTYPE;
 
@@ -243,6 +298,8 @@ int regulator_autoset(struct udevice *dev)
 
 	if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
 		ret = regulator_set_value(dev, uc_pdata->min_uV);
+	if (uc_pdata->init_uV > 0)
+		ret = regulator_set_value(dev, uc_pdata->init_uV);
 	if (!ret && (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA))
 		ret = regulator_set_current(dev, uc_pdata->min_uA);
 
@@ -363,6 +420,7 @@ static int regulator_post_bind(struct udevice *dev)
 static int regulator_pre_probe(struct udevice *dev)
 {
 	struct dm_regulator_uclass_platdata *uc_pdata;
+	ofnode node;
 
 	uc_pdata = dev_get_uclass_platdata(dev);
 	if (!uc_pdata)
@@ -373,6 +431,8 @@ static int regulator_pre_probe(struct udevice *dev)
 						-ENODATA);
 	uc_pdata->max_uV = dev_read_u32_default(dev, "regulator-max-microvolt",
 						-ENODATA);
+	uc_pdata->init_uV = dev_read_u32_default(dev, "regulator-init-microvolt",
+						-ENODATA);
 	uc_pdata->min_uA = dev_read_u32_default(dev, "regulator-min-microamp",
 						-ENODATA);
 	uc_pdata->max_uA = dev_read_u32_default(dev, "regulator-max-microamp",
@@ -382,6 +442,16 @@ static int regulator_pre_probe(struct udevice *dev)
 	uc_pdata->ramp_delay = dev_read_u32_default(dev, "regulator-ramp-delay",
 						    0);
 
+	node = dev_read_subnode(dev, "regulator-state-mem");
+	if (ofnode_valid(node)) {
+		uc_pdata->suspend_on = !ofnode_read_bool(node, "regulator-off-in-suspend");
+		if (ofnode_read_u32(node, "regulator-suspend-microvolt", &uc_pdata->suspend_uV))
+			uc_pdata->suspend_uV = uc_pdata->max_uA;
+	} else {
+		uc_pdata->suspend_on = true;
+		uc_pdata->suspend_uV = uc_pdata->max_uA;
+	}
+
 	/* Those values are optional (-ENODATA if unset) */
 	if ((uc_pdata->min_uV != -ENODATA) &&
 	    (uc_pdata->max_uV != -ENODATA) &&
diff --git a/include/power/regulator.h b/include/power/regulator.h
index 6c6e2cd4f996..dd61eb4ccbde 100644
--- a/include/power/regulator.h
+++ b/include/power/regulator.h
@@ -168,6 +168,7 @@ struct dm_regulator_uclass_platdata {
 	int mode_count;
 	int min_uV;
 	int max_uV;
+	int init_uV;
 	int min_uA;
 	int max_uA;
 	unsigned int ramp_delay;
@@ -177,6 +178,8 @@ struct dm_regulator_uclass_platdata {
 	int flags;
 	u8 ctrl_reg;
 	u8 volt_reg;
+	bool suspend_on;
+	u32 suspend_uV;
 };
 
 /* Regulator device operations */
@@ -194,6 +197,19 @@ struct dm_regulator_ops {
 	int (*set_value)(struct udevice *dev, int uV);
 
 	/**
+	 * The regulator suspend output value function calls operates
+	 * on a micro Volts.
+	 *
+	 * get/set_suspen_value - get/set suspend mode output value
+	 * @dev          - regulator device
+	 * Sets:
+	 * @uV           - set the suspend output value [micro Volts]
+	 * @return output value [uV] on success or negative errno if fail.
+	 */
+	int (*set_suspend_value)(struct udevice *dev, int uV);
+	int (*get_suspend_value)(struct udevice *dev);
+
+	/**
 	 * The regulator output current function calls operates on a micro Amps.
 	 *
 	 * get/set_current - get/set output current of the given output number
@@ -218,6 +234,19 @@ struct dm_regulator_ops {
 	int (*set_enable)(struct udevice *dev, bool enable);
 
 	/**
+	 * The most basic feature of the regulator output is its enable state
+	 * in suspend mode.
+	 *
+	 * get/set_suspend_enable - get/set enable state of the suspend output
+	 * @dev           - regulator device
+	 * Sets:
+	 * @enable         - set true - enable or false - disable
+	 * @return true/false for get or -errno if fail; 0 / -errno for set.
+	 */
+	int (*set_suspend_enable)(struct udevice *dev, bool enable);
+	int (*get_suspend_enable)(struct udevice *dev);
+
+	/**
 	 * The 'get/set_mode()' function calls should operate on a driver-
 	 * specific mode id definitions, which should be found in:
 	 * field 'id' of struct dm_regulator_mode.
@@ -262,6 +291,23 @@ int regulator_get_value(struct udevice *dev);
 int regulator_set_value(struct udevice *dev, int uV);
 
 /**
+ * regulator_set_suspend_value: set the suspend microvoltage value of a given regulator.
+ *
+ * @dev    - pointer to the regulator device
+ * @uV     - the output suspend value to set [micro Volts]
+ * @return - 0 on success or -errno val if fails
+ */
+int regulator_set_suspend_value(struct udevice *dev, int uV);
+
+/**
+ * regulator_get_suspend_value: get the suspend microvoltage value of a given regulator.
+ *
+ * @dev    - pointer to the regulator device
+ * @return - positive output value [uV] on success or negative errno if fail.
+ */
+int regulator_get_suspend_value(struct udevice *dev);
+
+/**
  * regulator_set_value_force: set the microvoltage value of a given regulator
  *			      without any min-,max condition check
  *
@@ -317,6 +363,24 @@ int regulator_set_enable(struct udevice *dev, bool enable);
 int regulator_set_enable_if_allowed(struct udevice *dev, bool enable);
 
 /**
+ * regulator_set_suspend_enable: set regulator suspend enable state
+ *
+ * @dev    - pointer to the regulator device
+ * @enable - set true or false
+ * @return - 0 on success or -errno val if fails
+ */
+int regulator_set_suspend_enable(struct udevice *dev, bool enable);
+
+
+/**
+ * regulator_get_suspend_enable: get regulator suspend enable state
+ *
+ * @dev    - pointer to the regulator device
+ * @return - true/false of enable state or -errno val if fails
+ */
+int regulator_get_suspend_enable(struct udevice *dev);
+
+/**
  * regulator_get_mode: get active operation mode id of a given regulator
  *
  * @dev    - pointer to the regulator device
diff --git a/test/dm/regulator.c b/test/dm/regulator.c
index e510539542b6..1641aff77cb6 100644
--- a/test/dm/regulator.c
+++ b/test/dm/regulator.c
@@ -215,6 +215,52 @@ static int dm_test_power_regulator_set_get_mode(struct unit_test_state *uts)
 }
 DM_TEST(dm_test_power_regulator_set_get_mode, DM_TESTF_SCAN_FDT);
 
+/* Test regulator set and get suspend Voltage method */
+static int dm_test_power_regulator_set_get_suspend_voltage(struct unit_test_state *uts)
+{
+	struct dm_regulator_uclass_platdata *uc_pdata;
+	struct udevice *dev;
+	const char *platname;
+	int val_set, val_get;
+
+	/* Set and get Voltage of BUCK1 - set to 'min' constraint */
+	platname = regulator_names[BUCK1][PLATNAME];
+	ut_assertok(regulator_get_by_platname(platname, &dev));
+
+	uc_pdata = dev_get_uclass_platdata(dev);
+	ut_assert(uc_pdata);
+
+	val_set = uc_pdata->min_uV;
+	ut_assertok(regulator_set_suspend_value(dev, val_set));
+
+	val_get = regulator_get_suspend_value(dev);
+	ut_assert(val_get >= 0);
+
+	ut_asserteq(val_set, val_get);
+
+	return 0;
+}
+DM_TEST(dm_test_power_regulator_set_get_suspend_voltage, DM_TESTF_SCAN_FDT);
+
+/* Test regulator set and get suspend Enable method */
+static int dm_test_power_regulator_set_get_suspend_enable(struct unit_test_state *uts)
+{
+	const char *platname;
+	struct udevice *dev;
+	bool val_set = true;
+
+	/* Set the Enable of LDO1 - default is disabled */
+	platname = regulator_names[LDO1][PLATNAME];
+	ut_assertok(regulator_get_by_platname(platname, &dev));
+	ut_assertok(regulator_set_suspend_enable(dev, val_set));
+
+	/* Get the Enable state of LDO1 and compare it with the requested one */
+	ut_asserteq(regulator_get_suspend_enable(dev), val_set);
+
+	return 0;
+}
+DM_TEST(dm_test_power_regulator_set_get_suspend_enable, DM_TESTF_SCAN_FDT);
+
 /* Test regulator autoset method */
 static int dm_test_power_regulator_autoset(struct unit_test_state *uts)
 {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH v4 2/6] power: regulator: rk8xx: update the driver for rk808 and rk818
  2019-09-26  7:43 [U-Boot] [PATCH v4 0/6] power: pmic: support more PMIC Elaine Zhang
  2019-09-26  7:43 ` [U-Boot] [PATCH v4 1/6] dm: regulator: support regulator more state Elaine Zhang
@ 2019-09-26  7:43 ` Elaine Zhang
  2019-09-26  7:43 ` [U-Boot] [PATCH v4 3/6] power: pmic: rk816: support rk816 pmic Elaine Zhang
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Elaine Zhang @ 2019-09-26  7:43 UTC (permalink / raw)
  To: u-boot

In order to adapt the following pmics, make the interface more compatible.
Support buck and ldo suspend voltage setting and getting.
Supprot buck and ldo suspend enable/disable setting and getting.

Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
Reviewed-by: Kever Yang<kever.yang@rock-chips.com>
---
 drivers/power/regulator/rk8xx.c | 547 ++++++++++++++++++++++++++++++++++------
 1 file changed, 465 insertions(+), 82 deletions(-)

diff --git a/drivers/power/regulator/rk8xx.c b/drivers/power/regulator/rk8xx.c
index aa4f3a161c47..ef83f66c8b6e 100644
--- a/drivers/power/regulator/rk8xx.c
+++ b/drivers/power/regulator/rk8xx.c
@@ -19,6 +19,9 @@
 #define ENABLE_DRIVER
 #endif
 
+/* Not used or exisit register and configure */
+#define NA			-1
+
 /* Field Definitions */
 #define RK808_BUCK_VSEL_MASK	0x3f
 #define RK808_BUCK4_VSEL_MASK	0xf
@@ -32,49 +35,61 @@
 #define RK818_USB_ILIM_SEL_MASK		0x0f
 #define RK818_USB_CHG_SD_VSEL_MASK	0x70
 
+/*
+ * Ramp delay
+ */
+#define RK808_RAMP_RATE_OFFSET		3
+#define RK808_RAMP_RATE_MASK		(3 << RK808_RAMP_RATE_OFFSET)
+#define RK808_RAMP_RATE_2MV_PER_US	(0 << RK808_RAMP_RATE_OFFSET)
+#define RK808_RAMP_RATE_4MV_PER_US	(1 << RK808_RAMP_RATE_OFFSET)
+#define RK808_RAMP_RATE_6MV_PER_US	(2 << RK808_RAMP_RATE_OFFSET)
+#define RK808_RAMP_RATE_10MV_PER_US	(3 << RK808_RAMP_RATE_OFFSET)
 
 struct rk8xx_reg_info {
 	uint min_uv;
 	uint step_uv;
-	s8 vsel_reg;
+	u8 vsel_reg;
+	u8 vsel_sleep_reg;
+	u8 config_reg;
 	u8 vsel_mask;
+	u8 min_sel;
 };
 
 static const struct rk8xx_reg_info rk808_buck[] = {
-	{ 712500, 12500, REG_BUCK1_ON_VSEL, RK808_BUCK_VSEL_MASK, },
-	{ 712500, 12500, REG_BUCK2_ON_VSEL, RK808_BUCK_VSEL_MASK, },
-	{ 712500, 12500, -1, RK808_BUCK_VSEL_MASK, },
-	{ 1800000, 100000, REG_BUCK4_ON_VSEL, RK808_BUCK4_VSEL_MASK, },
+	{ 712500,   12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK808_BUCK_VSEL_MASK, },
+	{ 712500,   12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK808_BUCK_VSEL_MASK, },
+	{ 712500,   12500, NA,		      NA,		  REG_BUCK3_CONFIG, RK808_BUCK_VSEL_MASK, },
+	{ 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK808_BUCK4_VSEL_MASK, },
 };
 
 static const struct rk8xx_reg_info rk818_buck[] = {
-	{ 712500, 12500, REG_BUCK1_ON_VSEL, RK818_BUCK_VSEL_MASK, },
-	{ 712500, 12500, REG_BUCK2_ON_VSEL, RK818_BUCK_VSEL_MASK, },
-	{ 712500, 12500, -1, RK818_BUCK_VSEL_MASK, },
-	{ 1800000, 100000, REG_BUCK4_ON_VSEL, RK818_BUCK4_VSEL_MASK, },
+	{ 712500,   12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, },
+	{ 712500,   12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, },
+	{ 712500,   12500, NA,		      NA,		  REG_BUCK3_CONFIG, RK818_BUCK_VSEL_MASK, },
+	{ 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, },
 };
 
 #ifdef ENABLE_DRIVER
 static const struct rk8xx_reg_info rk808_ldo[] = {
-	{ 1800000, 100000, REG_LDO1_ON_VSEL, RK808_LDO_VSEL_MASK, },
-	{ 1800000, 100000, REG_LDO2_ON_VSEL, RK808_LDO_VSEL_MASK, },
-	{ 800000, 100000, REG_LDO3_ON_VSEL, RK808_BUCK4_VSEL_MASK, },
-	{ 1800000, 100000, REG_LDO4_ON_VSEL, RK808_LDO_VSEL_MASK, },
-	{ 1800000, 100000, REG_LDO5_ON_VSEL, RK808_LDO_VSEL_MASK, },
-	{ 800000, 100000, REG_LDO6_ON_VSEL, RK808_LDO_VSEL_MASK, },
-	{ 800000, 100000, REG_LDO7_ON_VSEL, RK808_LDO_VSEL_MASK, },
-	{ 1800000, 100000, REG_LDO8_ON_VSEL, RK808_LDO_VSEL_MASK, },
+	{ 1800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
+	{ 1800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
+	{  800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK808_BUCK4_VSEL_MASK, },
+	{ 1800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
+	{ 1800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
+	{  800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
+	{  800000, 100000, REG_LDO7_ON_VSEL, REG_LDO7_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
+	{ 1800000, 100000, REG_LDO8_ON_VSEL, REG_LDO8_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
 };
 
 static const struct rk8xx_reg_info rk818_ldo[] = {
-	{ 1800000, 100000, REG_LDO1_ON_VSEL, RK818_LDO_VSEL_MASK, },
-	{ 1800000, 100000, REG_LDO2_ON_VSEL, RK818_LDO_VSEL_MASK, },
-	{ 800000, 100000, REG_LDO3_ON_VSEL, RK818_LDO3_ON_VSEL_MASK, },
-	{ 1800000, 100000, REG_LDO4_ON_VSEL, RK818_LDO_VSEL_MASK, },
-	{ 1800000, 100000, REG_LDO5_ON_VSEL, RK818_LDO_VSEL_MASK, },
-	{ 800000, 100000, REG_LDO6_ON_VSEL, RK818_LDO_VSEL_MASK, },
-	{ 800000, 100000, REG_LDO7_ON_VSEL, RK818_LDO_VSEL_MASK, },
-	{ 1800000, 100000, REG_LDO8_ON_VSEL, RK818_LDO_VSEL_MASK, },
+	{ 1800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+	{ 1800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+	{  800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK818_LDO3_ON_VSEL_MASK, },
+	{ 1800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+	{ 1800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+	{  800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+	{  800000, 100000, REG_LDO7_ON_VSEL, REG_LDO7_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+	{ 1800000, 100000, REG_LDO8_ON_VSEL, REG_LDO8_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
 };
 #endif
 
@@ -87,7 +102,7 @@ static const uint rk818_chrg_shutdown_vsel_array[] = {
 };
 
 static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
-					     int num)
+						 int num, int uvolt)
 {
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
 	switch (priv->variant) {
@@ -100,15 +115,20 @@ static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
 
 static int _buck_set_value(struct udevice *pmic, int buck, int uvolt)
 {
-	const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck - 1);
+	const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt);
 	int mask = info->vsel_mask;
 	int val;
 
-	if (info->vsel_reg == -1)
+	if (info->vsel_reg == NA)
 		return -ENOSYS;
-	val = (uvolt - info->min_uv) / info->step_uv;
-	debug("%s: reg=%x, mask=%x, val=%x\n", __func__, info->vsel_reg, mask,
-	      val);
+	if (info->step_uv == 0)	/* Fixed voltage */
+		val = info->min_sel;
+	else
+		val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
+
+	debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
+	      __func__, uvolt, buck + 1, info->vsel_reg, mask, val);
+
 
 	return pmic_clrsetbits(pmic, info->vsel_reg, mask, val);
 }
@@ -117,24 +137,115 @@ static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
 {
 	uint mask;
 	int ret;
+	struct rk8xx_priv *priv = dev_get_priv(pmic);
 
-	buck--;
-	mask = 1 << buck;
-	if (enable) {
-		ret = pmic_clrsetbits(pmic, REG_DCDC_ILMAX, 0, 3 << (buck * 2));
-		if (ret)
-			return ret;
-		ret = pmic_clrsetbits(pmic, REG_DCDC_UV_ACT, 1 << buck, 0);
-		if (ret)
-			return ret;
+	switch (priv->variant) {
+	case RK808_ID:
+	case RK818_ID:
+		mask = 1 << buck;
+		if (enable) {
+			ret = pmic_clrsetbits(pmic, REG_DCDC_ILMAX,
+					      0, 3 << (buck * 2));
+			if (ret)
+				return ret;
+		}
+		ret = pmic_clrsetbits(pmic, REG_DCDC_EN, mask,
+				      enable ? mask : 0);
+		break;
+	default:
+		ret = -EINVAL;
 	}
 
-	return pmic_clrsetbits(pmic, REG_DCDC_EN, mask, enable ? mask : 0);
+	return ret;
 }
 
 #ifdef ENABLE_DRIVER
+static int _buck_set_suspend_value(struct udevice *pmic, int buck, int uvolt)
+{
+	const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt);
+	int mask = info->vsel_mask;
+	int val;
+
+	if (info->vsel_sleep_reg == NA)
+		return -ENOSYS;
+
+	if (info->step_uv == 0)
+		val = info->min_sel;
+	else
+		val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
+
+	debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
+	      __func__, uvolt, buck + 1, info->vsel_sleep_reg, mask, val);
+
+	return pmic_clrsetbits(pmic, info->vsel_sleep_reg, mask, val);
+}
+
+static int _buck_get_enable(struct udevice *pmic, int buck)
+{
+	struct rk8xx_priv *priv = dev_get_priv(pmic);
+	uint mask = 0;
+	int ret = 0;
+
+	switch (priv->variant) {
+	case RK808_ID:
+	case RK818_ID:
+		mask = 1 << buck;
+		ret = pmic_reg_read(pmic, REG_DCDC_EN);
+		if (ret < 0)
+			return ret;
+		break;
+	}
+
+	if (ret < 0)
+		return ret;
+
+	return ret & mask ? true : false;
+}
+
+static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable)
+{
+	uint mask;
+	int ret;
+	struct rk8xx_priv *priv = dev_get_priv(pmic);
+
+	switch (priv->variant) {
+	case RK808_ID:
+	case RK818_ID:
+		mask = 1 << buck;
+		ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF1, mask,
+				      enable ? 0 : mask);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int _buck_get_suspend_enable(struct udevice *pmic, int buck)
+{
+	struct rk8xx_priv *priv = dev_get_priv(pmic);
+	int ret, val;
+	uint mask;
+
+	switch (priv->variant) {
+	case RK808_ID:
+	case RK818_ID:
+		mask = 1 << buck;
+		val = pmic_reg_read(pmic, REG_SLEEP_SET_OFF1);
+		if (val < 0)
+			return val;
+		ret = val & mask ? 0 : 1;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic,
-					     int num)
+						int num, int uvolt)
 {
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
 	switch (priv->variant) {
@@ -145,14 +256,93 @@ static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic,
 	}
 }
 
+static int _ldo_get_enable(struct udevice *pmic, int ldo)
+{
+	struct rk8xx_priv *priv = dev_get_priv(pmic);
+	uint mask = 0;
+	int ret = 0;
+
+	switch (priv->variant) {
+	case RK808_ID:
+	case RK818_ID:
+		mask = 1 << ldo;
+		ret = pmic_reg_read(pmic, REG_LDO_EN);
+		if (ret < 0)
+			return ret;
+		break;
+	}
+
+	if (ret < 0)
+		return ret;
+
+	return ret & mask ? true : false;
+}
+
+static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable)
+{
+	struct rk8xx_priv *priv = dev_get_priv(pmic);
+	uint mask;
+	int ret = 0;
+
+	switch (priv->variant) {
+	case RK808_ID:
+	case RK818_ID:
+		mask = 1 << ldo;
+		ret = pmic_clrsetbits(pmic, REG_LDO_EN, mask,
+				      enable ? mask : 0);
+		break;
+	}
+
+	return ret;
+}
+
+static int _ldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable)
+{
+	struct rk8xx_priv *priv = dev_get_priv(pmic);
+	uint mask;
+	int ret = 0;
+
+	switch (priv->variant) {
+	case RK808_ID:
+	case RK818_ID:
+		mask = 1 << ldo;
+		ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF2, mask,
+				      enable ? 0 : mask);
+		break;
+	}
+
+	return ret;
+}
+
+static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo)
+{
+	struct rk8xx_priv *priv = dev_get_priv(pmic);
+	int val, ret = 0;
+	uint mask;
+
+	switch (priv->variant) {
+	case RK808_ID:
+	case RK818_ID:
+		mask = 1 << ldo;
+		val = pmic_reg_read(pmic, REG_SLEEP_SET_OFF2);
+		if (val < 0)
+			return val;
+		ret = val & mask ? 0 : 1;
+		break;
+	}
+
+	return ret;
+}
+
 static int buck_get_value(struct udevice *dev)
 {
 	int buck = dev->driver_data - 1;
-	const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck);
+	/* We assume level-1 voltage is enough for usage in U-Boot */
+	const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0);
 	int mask = info->vsel_mask;
 	int ret, val;
 
-	if (info->vsel_reg == -1)
+	if (info->vsel_reg == NA)
 		return -ENOSYS;
 	ret = pmic_reg_read(dev->parent, info->vsel_reg);
 	if (ret < 0)
@@ -164,41 +354,74 @@ static int buck_get_value(struct udevice *dev)
 
 static int buck_set_value(struct udevice *dev, int uvolt)
 {
-	int buck = dev->driver_data;
+	int buck = dev->driver_data - 1;
 
 	return _buck_set_value(dev->parent, buck, uvolt);
 }
 
+static int buck_get_suspend_value(struct udevice *dev)
+{
+	int buck = dev->driver_data - 1;
+	/* We assume level-1 voltage is enough for usage in U-Boot */
+	const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0);
+	int mask = info->vsel_mask;
+	int ret, val;
+
+	if (info->vsel_sleep_reg == NA)
+		return -ENOSYS;
+
+	ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg);
+	if (ret < 0)
+		return ret;
+
+	val = ret & mask;
+
+	return info->min_uv + val * info->step_uv;
+}
+
+static int buck_set_suspend_value(struct udevice *dev, int uvolt)
+{
+	int buck = dev->driver_data - 1;
+
+	return _buck_set_suspend_value(dev->parent, buck, uvolt);
+}
+
 static int buck_set_enable(struct udevice *dev, bool enable)
 {
-	int buck = dev->driver_data;
+	int buck = dev->driver_data - 1;
 
 	return _buck_set_enable(dev->parent, buck, enable);
 }
 
-static int buck_get_enable(struct udevice *dev)
+static int buck_set_suspend_enable(struct udevice *dev, bool enable)
 {
 	int buck = dev->driver_data - 1;
-	int ret;
-	uint mask;
 
-	mask = 1 << buck;
+	return _buck_set_suspend_enable(dev->parent, buck, enable);
+}
 
-	ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
-	if (ret < 0)
-		return ret;
+static int buck_get_suspend_enable(struct udevice *dev)
+{
+	int buck = dev->driver_data - 1;
 
-	return ret & mask ? true : false;
+	return _buck_get_suspend_enable(dev->parent, buck);
+}
+
+static int buck_get_enable(struct udevice *dev)
+{
+	int buck = dev->driver_data - 1;
+
+	return _buck_get_enable(dev->parent, buck);
 }
 
 static int ldo_get_value(struct udevice *dev)
 {
 	int ldo = dev->driver_data - 1;
-	const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo);
+	const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0);
 	int mask = info->vsel_mask;
 	int ret, val;
 
-	if (info->vsel_reg == -1)
+	if (info->vsel_reg == NA)
 		return -ENOSYS;
 	ret = pmic_reg_read(dev->parent, info->vsel_reg);
 	if (ret < 0)
@@ -211,71 +434,217 @@ static int ldo_get_value(struct udevice *dev)
 static int ldo_set_value(struct udevice *dev, int uvolt)
 {
 	int ldo = dev->driver_data - 1;
-	const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo);
+	const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, uvolt);
 	int mask = info->vsel_mask;
 	int val;
 
-	if (info->vsel_reg == -1)
+	if (info->vsel_reg == NA)
 		return -ENOSYS;
-	val = (uvolt - info->min_uv) / info->step_uv;
-	debug("%s: reg=%x, mask=%x, val=%x\n", __func__, info->vsel_reg, mask,
-	      val);
+
+	if (info->step_uv == 0)
+		val = info->min_sel;
+	else
+		val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
+
+	debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
+	      __func__, uvolt, ldo + 1, info->vsel_reg, mask, val);
 
 	return pmic_clrsetbits(dev->parent, info->vsel_reg, mask, val);
 }
 
-static int ldo_set_enable(struct udevice *dev, bool enable)
+static int ldo_set_suspend_value(struct udevice *dev, int uvolt)
 {
 	int ldo = dev->driver_data - 1;
-	uint mask;
+	const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, uvolt);
+	int mask = info->vsel_mask;
+	int val;
+
+	if (info->vsel_sleep_reg == NA)
+		return -ENOSYS;
 
-	mask = 1 << ldo;
+	if (info->step_uv == 0)
+		val = info->min_sel;
+	else
+		val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
 
-	return pmic_clrsetbits(dev->parent, REG_LDO_EN, mask,
-			       enable ? mask : 0);
+	debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
+	      __func__, uvolt, ldo + 1, info->vsel_sleep_reg, mask, val);
+
+	return pmic_clrsetbits(dev->parent, info->vsel_sleep_reg, mask, val);
 }
 
-static int ldo_get_enable(struct udevice *dev)
+static int ldo_get_suspend_value(struct udevice *dev)
 {
 	int ldo = dev->driver_data - 1;
-	int ret;
-	uint mask;
+	const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0);
+	int mask = info->vsel_mask;
+	int val, ret;
 
-	mask = 1 << ldo;
+	if (info->vsel_sleep_reg == NA)
+		return -ENOSYS;
 
-	ret = pmic_reg_read(dev->parent, REG_LDO_EN);
+	ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg);
 	if (ret < 0)
 		return ret;
 
-	return ret & mask ? true : false;
+	val = ret & mask;
+
+	return info->min_uv + val * info->step_uv;
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+	int ldo = dev->driver_data - 1;
+
+	return _ldo_set_enable(dev->parent, ldo, enable);
+}
+
+static int ldo_set_suspend_enable(struct udevice *dev, bool enable)
+{
+	int ldo = dev->driver_data - 1;
+
+	return _ldo_set_suspend_enable(dev->parent, ldo, enable);
+}
+
+static int ldo_get_suspend_enable(struct udevice *dev)
+{
+	int ldo = dev->driver_data - 1;
+
+	return _ldo_get_suspend_enable(dev->parent, ldo);
+}
+
+static int ldo_get_enable(struct udevice *dev)
+{
+	int ldo = dev->driver_data - 1;
+
+	return _ldo_get_enable(dev->parent, ldo);
 }
 
 static int switch_set_enable(struct udevice *dev, bool enable)
 {
-	int sw = dev->driver_data - 1;
-	uint mask;
+	struct rk8xx_priv *priv = dev_get_priv(dev->parent);
+	int ret = 0, sw = dev->driver_data - 1;
+	uint mask = 0;
+
+	switch (priv->variant) {
+	case RK808_ID:
+		mask = 1 << (sw + 5);
+		ret = pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask,
+				      enable ? mask : 0);
+		break;
+	case RK818_ID:
+		mask = 1 << 6;
+		ret = pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask,
+				      enable ? mask : 0);
+		break;
+	}
 
-	mask = 1 << (sw + 5);
+	debug("%s: switch%d, enable=%d, mask=0x%x\n",
+	      __func__, sw + 1, enable, mask);
 
-	return pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask,
-			       enable ? mask : 0);
+	return ret;
 }
 
 static int switch_get_enable(struct udevice *dev)
 {
-	int sw = dev->driver_data - 1;
-	int ret;
-	uint mask;
+	struct rk8xx_priv *priv = dev_get_priv(dev->parent);
+	int ret = 0, sw = dev->driver_data - 1;
+	uint mask = 0;
 
-	mask = 1 << (sw + 5);
+	switch (priv->variant) {
+	case RK808_ID:
+		mask = 1 << (sw + 5);
+		ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
+		break;
+	case RK818_ID:
+		mask = 1 << 6;
+		ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
+		break;
+	}
 
-	ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
 	if (ret < 0)
 		return ret;
 
 	return ret & mask ? true : false;
 }
 
+static int switch_set_suspend_value(struct udevice *dev, int uvolt)
+{
+	return 0;
+}
+
+static int switch_get_suspend_value(struct udevice *dev)
+{
+	return 0;
+}
+
+static int switch_set_suspend_enable(struct udevice *dev, bool enable)
+{
+	struct rk8xx_priv *priv = dev_get_priv(dev->parent);
+	int ret = 0, sw = dev->driver_data - 1;
+	uint mask = 0;
+
+	switch (priv->variant) {
+	case RK808_ID:
+		mask = 1 << (sw + 5);
+		ret = pmic_clrsetbits(dev->parent, REG_SLEEP_SET_OFF1, mask,
+				      enable ? 0 : mask);
+		break;
+	case RK818_ID:
+		mask = 1 << 6;
+		ret = pmic_clrsetbits(dev->parent, REG_SLEEP_SET_OFF1, mask,
+				      enable ? 0 : mask);
+		break;
+	}
+
+	debug("%s: switch%d, enable=%d, mask=0x%x\n",
+	      __func__, sw + 1, enable, mask);
+
+	return ret;
+}
+
+static int switch_get_suspend_enable(struct udevice *dev)
+{
+	struct rk8xx_priv *priv = dev_get_priv(dev->parent);
+	int val, ret = 0, sw = dev->driver_data - 1;
+	uint mask = 0;
+
+	switch (priv->variant) {
+	case RK808_ID:
+		mask = 1 << (sw + 5);
+		val = pmic_reg_read(dev->parent, REG_SLEEP_SET_OFF1);
+		if (val < 0)
+			return val;
+		ret = val & mask ? 0 : 1;
+		break;
+	case RK818_ID:
+		mask = 1 << 6;
+		val = pmic_reg_read(dev->parent, REG_SLEEP_SET_OFF1);
+		if (val < 0)
+			return val;
+		ret = val & mask ? 0 : 1;
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * RK8xx switch does not need to set the voltage,
+ * but if dts set regulator-min-microvolt/regulator-max-microvolt,
+ * will cause regulator set value fail and not to enable this switch.
+ * So add an empty function to return success.
+ */
+static int switch_get_value(struct udevice *dev)
+{
+	return 0;
+}
+
+static int switch_set_value(struct udevice *dev, int uvolt)
+{
+	return 0;
+}
+
 static int rk8xx_buck_probe(struct udevice *dev)
 {
 	struct dm_regulator_uclass_platdata *uc_pdata;
@@ -315,20 +684,34 @@ static int rk8xx_switch_probe(struct udevice *dev)
 static const struct dm_regulator_ops rk8xx_buck_ops = {
 	.get_value  = buck_get_value,
 	.set_value  = buck_set_value,
+	.set_suspend_value = buck_set_suspend_value,
+	.get_suspend_value = buck_get_suspend_value,
 	.get_enable = buck_get_enable,
 	.set_enable = buck_set_enable,
+	.set_suspend_enable = buck_set_suspend_enable,
+	.get_suspend_enable = buck_get_suspend_enable,
 };
 
 static const struct dm_regulator_ops rk8xx_ldo_ops = {
 	.get_value  = ldo_get_value,
 	.set_value  = ldo_set_value,
+	.set_suspend_value = ldo_set_suspend_value,
+	.get_suspend_value = ldo_get_suspend_value,
 	.get_enable = ldo_get_enable,
 	.set_enable = ldo_set_enable,
+	.set_suspend_enable = ldo_set_suspend_enable,
+	.get_suspend_enable = ldo_get_suspend_enable,
 };
 
 static const struct dm_regulator_ops rk8xx_switch_ops = {
+	.get_value  = switch_get_value,
+	.set_value  = switch_set_value,
 	.get_enable = switch_get_enable,
 	.set_enable = switch_set_enable,
+	.set_suspend_enable = switch_set_suspend_enable,
+	.get_suspend_enable = switch_get_suspend_enable,
+	.set_suspend_value = switch_set_suspend_value,
+	.get_suspend_value = switch_get_suspend_value,
 };
 
 U_BOOT_DRIVER(rk8xx_buck) = {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH v4 3/6] power: pmic: rk816: support rk816 pmic
  2019-09-26  7:43 [U-Boot] [PATCH v4 0/6] power: pmic: support more PMIC Elaine Zhang
  2019-09-26  7:43 ` [U-Boot] [PATCH v4 1/6] dm: regulator: support regulator more state Elaine Zhang
  2019-09-26  7:43 ` [U-Boot] [PATCH v4 2/6] power: regulator: rk8xx: update the driver for rk808 and rk818 Elaine Zhang
@ 2019-09-26  7:43 ` Elaine Zhang
  2019-09-26  7:43 ` [U-Boot] [PATCH v4 4/6] power: pmic: rk805: support rk805 pmic Elaine Zhang
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Elaine Zhang @ 2019-09-26  7:43 UTC (permalink / raw)
  To: u-boot

The RK816 is a Power Management IC (PMIC) for multimedia
and handheld devices. They contains the following components:
    - Regulators(4*BUCKs, 1*BOOST, 6*LDOs, 1*SWITCH)
    - RTC
    - Clocking

Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
Reviewed-by: Kever Yang<kever.yang@rock-chips.com>
---
 drivers/power/pmic/rk8xx.c      |   1 +
 drivers/power/regulator/rk8xx.c | 130 ++++++++++++++++++++++++++++++++++++++--
 include/power/rk8xx_pmic.h      |  11 +++-
 3 files changed, 136 insertions(+), 6 deletions(-)

diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c
index 25c339ab12cc..1900de9d1cdb 100644
--- a/drivers/power/pmic/rk8xx.c
+++ b/drivers/power/pmic/rk8xx.c
@@ -95,6 +95,7 @@ static struct dm_pmic_ops rk8xx_ops = {
 
 static const struct udevice_id rk8xx_ids[] = {
 	{ .compatible = "rockchip,rk808" },
+	{ .compatible = "rockchip,rk816" },
 	{ .compatible = "rockchip,rk818" },
 	{ }
 };
diff --git a/drivers/power/regulator/rk8xx.c b/drivers/power/regulator/rk8xx.c
index ef83f66c8b6e..3188d3c6350d 100644
--- a/drivers/power/regulator/rk8xx.c
+++ b/drivers/power/regulator/rk8xx.c
@@ -62,6 +62,21 @@ static const struct rk8xx_reg_info rk808_buck[] = {
 	{ 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK808_BUCK4_VSEL_MASK, },
 };
 
+static const struct rk8xx_reg_info rk816_buck[] = {
+	/* buck 1 */
+	{  712500,  12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, },
+	{ 1800000, 200000, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, },
+	{ 2300000,      0, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, },
+	/* buck 2 */
+	{  712500,  12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, },
+	{ 1800000, 200000, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, },
+	{ 2300000,      0, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, },
+	/* buck 3 */
+	{ 712500,   12500, NA,		      NA,		  REG_BUCK3_CONFIG, RK818_BUCK_VSEL_MASK, },
+	/* buck 4 */
+	{  800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, },
+};
+
 static const struct rk8xx_reg_info rk818_buck[] = {
 	{ 712500,   12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, },
 	{ 712500,   12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, },
@@ -81,6 +96,15 @@ static const struct rk8xx_reg_info rk808_ldo[] = {
 	{ 1800000, 100000, REG_LDO8_ON_VSEL, REG_LDO8_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
 };
 
+static const struct rk8xx_reg_info rk816_ldo[] = {
+	{ 800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+	{ 800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+	{ 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+	{ 800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+	{ 800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+	{ 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
+};
+
 static const struct rk8xx_reg_info rk818_ldo[] = {
 	{ 1800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
 	{ 1800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
@@ -105,7 +129,21 @@ static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
 						 int num, int uvolt)
 {
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
+
 	switch (priv->variant) {
+	case RK816_ID:
+		switch (num) {
+		case 0:
+		case 1:
+			if (uvolt <= 1450000)
+				return &rk816_buck[num * 3 + 0];
+			else if (uvolt <= 2200000)
+				return &rk816_buck[num * 3 + 1];
+			else
+				return &rk816_buck[num * 3 + 2];
+		default:
+			return &rk816_buck[num + 4];
+		}
 	case RK818_ID:
 		return &rk818_buck[num];
 	default:
@@ -116,11 +154,13 @@ static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
 static int _buck_set_value(struct udevice *pmic, int buck, int uvolt)
 {
 	const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt);
+	struct rk8xx_priv *priv = dev_get_priv(pmic);
 	int mask = info->vsel_mask;
 	int val;
 
 	if (info->vsel_reg == NA)
 		return -ENOSYS;
+
 	if (info->step_uv == 0)	/* Fixed voltage */
 		val = info->min_sel;
 	else
@@ -129,17 +169,36 @@ static int _buck_set_value(struct udevice *pmic, int buck, int uvolt)
 	debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
 	      __func__, uvolt, buck + 1, info->vsel_reg, mask, val);
 
-
-	return pmic_clrsetbits(pmic, info->vsel_reg, mask, val);
+	if (priv->variant == RK816_ID) {
+		pmic_clrsetbits(pmic, info->vsel_reg, mask, val);
+		return pmic_clrsetbits(pmic, RK816_REG_DCDC_EN2,
+				       1 << 7, 1 << 7);
+	} else {
+		return pmic_clrsetbits(pmic, info->vsel_reg, mask, val);
+	}
 }
 
 static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
 {
-	uint mask;
+	uint mask, value, en_reg;
 	int ret;
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
 
 	switch (priv->variant) {
+	case RK816_ID:
+		if (buck >= 4) {
+			buck -= 4;
+			en_reg = RK816_REG_DCDC_EN2;
+		} else {
+			en_reg = RK816_REG_DCDC_EN1;
+		}
+		if (enable)
+			value = ((1 << buck) | (1 << (buck + 4)));
+		else
+			value = ((0 << buck) | (1 << (buck + 4)));
+		ret = pmic_reg_write(pmic, en_reg, value);
+		break;
+
 	case RK808_ID:
 	case RK818_ID:
 		mask = 1 << buck;
@@ -187,6 +246,15 @@ static int _buck_get_enable(struct udevice *pmic, int buck)
 	int ret = 0;
 
 	switch (priv->variant) {
+	case RK816_ID:
+		if (buck >= 4) {
+			mask = 1 << (buck - 4);
+			ret = pmic_reg_read(pmic, RK816_REG_DCDC_EN2);
+		} else {
+			mask = 1 << buck;
+			ret = pmic_reg_read(pmic, RK816_REG_DCDC_EN1);
+		}
+		break;
 	case RK808_ID:
 	case RK818_ID:
 		mask = 1 << buck;
@@ -209,6 +277,11 @@ static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable)
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
 
 	switch (priv->variant) {
+	case RK816_ID:
+		mask = 1 << buck;
+		ret = pmic_clrsetbits(pmic, RK816_REG_DCDC_SLP_EN, mask,
+				      enable ? mask : 0);
+		break;
 	case RK808_ID:
 	case RK818_ID:
 		mask = 1 << buck;
@@ -229,6 +302,13 @@ static int _buck_get_suspend_enable(struct udevice *pmic, int buck)
 	uint mask;
 
 	switch (priv->variant) {
+	case RK816_ID:
+		mask = 1 << buck;
+		val = pmic_reg_read(pmic, RK816_REG_DCDC_SLP_EN);
+		if (val < 0)
+			return val;
+		ret = val & mask ? 1 : 0;
+		break;
 	case RK808_ID:
 	case RK818_ID:
 		mask = 1 << buck;
@@ -248,7 +328,10 @@ static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic,
 						int num, int uvolt)
 {
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
+
 	switch (priv->variant) {
+	case RK816_ID:
+		return &rk816_ldo[num];
 	case RK818_ID:
 		return &rk818_ldo[num];
 	default:
@@ -263,6 +346,15 @@ static int _ldo_get_enable(struct udevice *pmic, int ldo)
 	int ret = 0;
 
 	switch (priv->variant) {
+	case RK816_ID:
+		if (ldo >= 4) {
+			mask = 1 << (ldo - 4);
+			ret = pmic_reg_read(pmic, RK816_REG_LDO_EN2);
+		} else {
+			mask = 1 << ldo;
+			ret = pmic_reg_read(pmic, RK816_REG_LDO_EN1);
+		}
+		break;
 	case RK808_ID:
 	case RK818_ID:
 		mask = 1 << ldo;
@@ -278,18 +370,33 @@ static int _ldo_get_enable(struct udevice *pmic, int ldo)
 	return ret & mask ? true : false;
 }
 
+
 static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable)
 {
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
-	uint mask;
+	uint mask, value, en_reg;
 	int ret = 0;
 
 	switch (priv->variant) {
+	case RK816_ID:
+		if (ldo >= 4) {
+			ldo -= 4;
+			en_reg = RK816_REG_LDO_EN2;
+		} else {
+			en_reg = RK816_REG_LDO_EN1;
+		}
+		if (enable)
+			value = ((1 << ldo) | (1 << (ldo + 4)));
+		else
+			value = ((0 << ldo) | (1 << (ldo + 4)));
+
+		ret = pmic_reg_write(pmic, en_reg, value);
+		break;
 	case RK808_ID:
 	case RK818_ID:
 		mask = 1 << ldo;
 		ret = pmic_clrsetbits(pmic, REG_LDO_EN, mask,
-				      enable ? mask : 0);
+				       enable ? mask : 0);
 		break;
 	}
 
@@ -303,6 +410,11 @@ static int _ldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable)
 	int ret = 0;
 
 	switch (priv->variant) {
+	case RK816_ID:
+		mask = 1 << ldo;
+		ret = pmic_clrsetbits(pmic, RK816_REG_LDO_SLP_EN, mask,
+				      enable ? mask : 0);
+		break;
 	case RK808_ID:
 	case RK818_ID:
 		mask = 1 << ldo;
@@ -321,6 +433,13 @@ static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo)
 	uint mask;
 
 	switch (priv->variant) {
+	case RK816_ID:
+		mask = 1 << ldo;
+		val = pmic_reg_read(pmic, RK816_REG_LDO_SLP_EN);
+		if (val < 0)
+			return val;
+		ret = val & mask ? 1 : 0;
+		break;
 	case RK808_ID:
 	case RK818_ID:
 		mask = 1 << ldo;
@@ -344,6 +463,7 @@ static int buck_get_value(struct udevice *dev)
 
 	if (info->vsel_reg == NA)
 		return -ENOSYS;
+
 	ret = pmic_reg_read(dev->parent, info->vsel_reg);
 	if (ret < 0)
 		return ret;
diff --git a/include/power/rk8xx_pmic.h b/include/power/rk8xx_pmic.h
index c06248f75183..44e8d687dfba 100644
--- a/include/power/rk8xx_pmic.h
+++ b/include/power/rk8xx_pmic.h
@@ -170,8 +170,17 @@ enum {
 };
 
 enum {
-	RK805_ID = 0x8050,
+	RK816_REG_DCDC_EN1 = 0x23,
+	RK816_REG_DCDC_EN2,
+	RK816_REG_DCDC_SLP_EN,
+	RK816_REG_LDO_SLP_EN,
+	RK816_REG_LDO_EN1 = 0x27,
+	RK816_REG_LDO_EN2,
+};
+
+enum {
 	RK808_ID = 0x0000,
+	RK816_ID = 0x8160,
 	RK818_ID = 0x8180,
 };
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH v4 4/6] power: pmic: rk805: support rk805 pmic
  2019-09-26  7:43 [U-Boot] [PATCH v4 0/6] power: pmic: support more PMIC Elaine Zhang
                   ` (2 preceding siblings ...)
  2019-09-26  7:43 ` [U-Boot] [PATCH v4 3/6] power: pmic: rk816: support rk816 pmic Elaine Zhang
@ 2019-09-26  7:43 ` Elaine Zhang
  2019-09-26  7:44 ` [U-Boot] [PATCH v4 5/6] power: pmic: rk817: support rk817 pmic Elaine Zhang
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Elaine Zhang @ 2019-09-26  7:43 UTC (permalink / raw)
  To: u-boot

The RK805 are a Power Management IC (PMIC) for multimedia
and handheld devices. They contains the following components:
    - Regulators(4*BUCKs, 3*LDOs)
    - RTC
    - Clocking

Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
Reviewed-by: Kever Yang<kever.yang@rock-chips.com>
---
 drivers/power/pmic/rk8xx.c      |  1 +
 drivers/power/regulator/rk8xx.c | 17 +++++++++++++++++
 include/power/rk8xx_pmic.h      |  1 +
 3 files changed, 19 insertions(+)

diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c
index 1900de9d1cdb..00c8a2e091d8 100644
--- a/drivers/power/pmic/rk8xx.c
+++ b/drivers/power/pmic/rk8xx.c
@@ -94,6 +94,7 @@ static struct dm_pmic_ops rk8xx_ops = {
 };
 
 static const struct udevice_id rk8xx_ids[] = {
+	{ .compatible = "rockchip,rk805" },
 	{ .compatible = "rockchip,rk808" },
 	{ .compatible = "rockchip,rk816" },
 	{ .compatible = "rockchip,rk818" },
diff --git a/drivers/power/regulator/rk8xx.c b/drivers/power/regulator/rk8xx.c
index 3188d3c6350d..e9d83635988b 100644
--- a/drivers/power/regulator/rk8xx.c
+++ b/drivers/power/regulator/rk8xx.c
@@ -38,7 +38,14 @@
 /*
  * Ramp delay
  */
+#define RK805_RAMP_RATE_OFFSET		3
+#define RK805_RAMP_RATE_MASK		(3 << RK805_RAMP_RATE_OFFSET)
+#define RK805_RAMP_RATE_3MV_PER_US	(0 << RK805_RAMP_RATE_OFFSET)
+#define RK805_RAMP_RATE_6MV_PER_US	(1 << RK805_RAMP_RATE_OFFSET)
+#define RK805_RAMP_RATE_12_5MV_PER_US	(2 << RK805_RAMP_RATE_OFFSET)
+#define RK805_RAMP_RATE_25MV_PER_US	(3 << RK805_RAMP_RATE_OFFSET)
 #define RK808_RAMP_RATE_OFFSET		3
+
 #define RK808_RAMP_RATE_MASK		(3 << RK808_RAMP_RATE_OFFSET)
 #define RK808_RAMP_RATE_2MV_PER_US	(0 << RK808_RAMP_RATE_OFFSET)
 #define RK808_RAMP_RATE_4MV_PER_US	(1 << RK808_RAMP_RATE_OFFSET)
@@ -131,6 +138,7 @@ static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
 
 	switch (priv->variant) {
+	case RK805_ID:
 	case RK816_ID:
 		switch (num) {
 		case 0:
@@ -185,6 +193,7 @@ static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
 
 	switch (priv->variant) {
+	case RK805_ID:
 	case RK816_ID:
 		if (buck >= 4) {
 			buck -= 4;
@@ -246,6 +255,7 @@ static int _buck_get_enable(struct udevice *pmic, int buck)
 	int ret = 0;
 
 	switch (priv->variant) {
+	case RK805_ID:
 	case RK816_ID:
 		if (buck >= 4) {
 			mask = 1 << (buck - 4);
@@ -277,6 +287,7 @@ static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable)
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
 
 	switch (priv->variant) {
+	case RK805_ID:
 	case RK816_ID:
 		mask = 1 << buck;
 		ret = pmic_clrsetbits(pmic, RK816_REG_DCDC_SLP_EN, mask,
@@ -302,6 +313,7 @@ static int _buck_get_suspend_enable(struct udevice *pmic, int buck)
 	uint mask;
 
 	switch (priv->variant) {
+	case RK805_ID:
 	case RK816_ID:
 		mask = 1 << buck;
 		val = pmic_reg_read(pmic, RK816_REG_DCDC_SLP_EN);
@@ -330,6 +342,7 @@ static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic,
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
 
 	switch (priv->variant) {
+	case RK805_ID:
 	case RK816_ID:
 		return &rk816_ldo[num];
 	case RK818_ID:
@@ -346,6 +359,7 @@ static int _ldo_get_enable(struct udevice *pmic, int ldo)
 	int ret = 0;
 
 	switch (priv->variant) {
+	case RK805_ID:
 	case RK816_ID:
 		if (ldo >= 4) {
 			mask = 1 << (ldo - 4);
@@ -378,6 +392,7 @@ static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable)
 	int ret = 0;
 
 	switch (priv->variant) {
+	case RK805_ID:
 	case RK816_ID:
 		if (ldo >= 4) {
 			ldo -= 4;
@@ -410,6 +425,7 @@ static int _ldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable)
 	int ret = 0;
 
 	switch (priv->variant) {
+	case RK805_ID:
 	case RK816_ID:
 		mask = 1 << ldo;
 		ret = pmic_clrsetbits(pmic, RK816_REG_LDO_SLP_EN, mask,
@@ -433,6 +449,7 @@ static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo)
 	uint mask;
 
 	switch (priv->variant) {
+	case RK805_ID:
 	case RK816_ID:
 		mask = 1 << ldo;
 		val = pmic_reg_read(pmic, RK816_REG_LDO_SLP_EN);
diff --git a/include/power/rk8xx_pmic.h b/include/power/rk8xx_pmic.h
index 44e8d687dfba..7784c2a5e473 100644
--- a/include/power/rk8xx_pmic.h
+++ b/include/power/rk8xx_pmic.h
@@ -179,6 +179,7 @@ enum {
 };
 
 enum {
+	RK805_ID = 0x8050,
 	RK808_ID = 0x0000,
 	RK816_ID = 0x8160,
 	RK818_ID = 0x8180,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH v4 5/6] power: pmic: rk817: support rk817 pmic
  2019-09-26  7:43 [U-Boot] [PATCH v4 0/6] power: pmic: support more PMIC Elaine Zhang
                   ` (3 preceding siblings ...)
  2019-09-26  7:43 ` [U-Boot] [PATCH v4 4/6] power: pmic: rk805: support rk805 pmic Elaine Zhang
@ 2019-09-26  7:44 ` Elaine Zhang
  2019-09-26  7:45 ` [U-Boot] [PATCH v4 6/6] power: pmic: rk809: support rk809 pmic Elaine Zhang
  2019-10-14  9:08 ` [U-Boot] [PATCH v4 0/6] power: pmic: support more PMIC Kever Yang
  6 siblings, 0 replies; 9+ messages in thread
From: Elaine Zhang @ 2019-09-26  7:44 UTC (permalink / raw)
  To: u-boot

From: Joseph Chen <chenjh@rock-chips.com>

The RK817 is a Power Management IC (PMIC) for multimedia
and handheld devices. They contains the following components:
    - Regulators(4*BUCKs, 1* BOOST, 9*LDOs, 1*SWITCH)
    - RTC
    - Clocking

Signed-off-by: Joseph Chen <chenjh@rock-chips.com>
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
Reviewed-by: Kever Yang<kever.yang@rock-chips.com>
---
 drivers/power/pmic/rk8xx.c      |  84 +++++++++++++++++-
 drivers/power/regulator/rk8xx.c | 189 +++++++++++++++++++++++++++++++++++++++-
 include/power/rk8xx_pmic.h      |  31 +++++++
 3 files changed, 297 insertions(+), 7 deletions(-)

diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c
index 00c8a2e091d8..df0bf83a054c 100644
--- a/drivers/power/pmic/rk8xx.c
+++ b/drivers/power/pmic/rk8xx.c
@@ -10,6 +10,13 @@
 #include <power/rk8xx_pmic.h>
 #include <power/pmic.h>
 
+static struct reg_data rk817_init_reg[] = {
+/* enable the under-voltage protection,
+ * the under-voltage protection will shutdown the LDO3 and reset the PMIC
+ */
+	{ RK817_BUCK4_CMIN, 0x60, 0x60},
+};
+
 static const struct pmic_child_info pmic_children_info[] = {
 	{ .prefix = "DCDC_REG", .driver = "rk8xx_buck"},
 	{ .prefix = "LDO_REG", .driver = "rk8xx_ldo"},
@@ -76,13 +83,83 @@ static int rk8xx_bind(struct udevice *dev)
 static int rk8xx_probe(struct udevice *dev)
 {
 	struct rk8xx_priv *priv = dev_get_priv(dev);
-	uint8_t msb, lsb;
+	struct reg_data *init_data = NULL;
+	int init_data_num = 0;
+	int ret = 0, i, show_variant;
+	u8 msb, lsb, id_msb, id_lsb;
+	u8 on_source = 0, off_source = 0;
+	u8 power_en0, power_en1, power_en2, power_en3;
+	u8 value;
 
 	/* read Chip variant */
-	rk8xx_read(dev, ID_MSB, &msb, 1);
-	rk8xx_read(dev, ID_LSB, &lsb, 1);
+	if (device_is_compatible(dev, "rockchip,rk817")) {
+		id_msb = RK817_ID_MSB;
+		id_lsb = RK817_ID_LSB;
+	} else {
+		id_msb = ID_MSB;
+		id_lsb = ID_LSB;
+	}
+
+	ret = rk8xx_read(dev, id_msb, &msb, 1);
+	if (ret)
+		return ret;
+	ret = rk8xx_read(dev, id_lsb, &lsb, 1);
+	if (ret)
+		return ret;
 
 	priv->variant = ((msb << 8) | lsb) & RK8XX_ID_MSK;
+	show_variant = priv->variant;
+	switch (priv->variant) {
+	case RK808_ID:
+		show_variant = 0x808;	/* RK808 hardware ID is 0 */
+		break;
+	case RK805_ID:
+	case RK816_ID:
+	case RK818_ID:
+		on_source = RK8XX_ON_SOURCE;
+		off_source = RK8XX_OFF_SOURCE;
+		break;
+	case RK817_ID:
+		on_source = RK817_ON_SOURCE;
+		off_source = RK817_OFF_SOURCE;
+		init_data = rk817_init_reg;
+		init_data_num = ARRAY_SIZE(rk817_init_reg);
+		power_en0 = pmic_reg_read(dev, RK817_POWER_EN0);
+		power_en1 = pmic_reg_read(dev, RK817_POWER_EN1);
+		power_en2 = pmic_reg_read(dev, RK817_POWER_EN2);
+		power_en3 = pmic_reg_read(dev, RK817_POWER_EN3);
+
+		value = (power_en0 & 0x0f) | ((power_en1 & 0x0f) << 4);
+		pmic_reg_write(dev, RK817_POWER_EN_SAVE0, value);
+		value = (power_en2 & 0x0f) | ((power_en3 & 0x0f) << 4);
+		pmic_reg_write(dev, RK817_POWER_EN_SAVE1, value);
+		break;
+	default:
+		printf("Unknown PMIC: RK%x!!\n", priv->variant);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < init_data_num; i++) {
+		ret = pmic_clrsetbits(dev,
+				      init_data[i].reg,
+				      init_data[i].mask,
+				      init_data[i].val);
+		if (ret < 0) {
+			printf("%s: i2c set reg 0x%x failed, ret=%d\n",
+			       __func__, init_data[i].reg, ret);
+		}
+
+		debug("%s: reg[0x%x] = 0x%x\n", __func__, init_data[i].reg,
+		      pmic_reg_read(dev, init_data[i].reg));
+	}
+
+	printf("PMIC:  RK%x ", show_variant);
+
+	if (on_source && off_source)
+		printf("(on=0x%02x, off=0x%02x)",
+		       pmic_reg_read(dev, on_source),
+		       pmic_reg_read(dev, off_source));
+	printf("\n");
 
 	return 0;
 }
@@ -97,6 +174,7 @@ static const struct udevice_id rk8xx_ids[] = {
 	{ .compatible = "rockchip,rk805" },
 	{ .compatible = "rockchip,rk808" },
 	{ .compatible = "rockchip,rk816" },
+	{ .compatible = "rockchip,rk817" },
 	{ .compatible = "rockchip,rk818" },
 	{ }
 };
diff --git a/drivers/power/regulator/rk8xx.c b/drivers/power/regulator/rk8xx.c
index e9d83635988b..3c4a18b0f0c7 100644
--- a/drivers/power/regulator/rk8xx.c
+++ b/drivers/power/regulator/rk8xx.c
@@ -27,6 +27,21 @@
 #define RK808_BUCK4_VSEL_MASK	0xf
 #define RK808_LDO_VSEL_MASK	0x1f
 
+/* RK817 BUCK */
+#define RK817_BUCK_ON_VSEL(n)		(0xbb + 3 * (n - 1))
+#define RK817_BUCK_SLP_VSEL(n)		(0xbc + 3 * (n - 1))
+#define RK817_BUCK_VSEL_MASK		0x7f
+#define RK817_BUCK_CONFIG(i)		(0xba + (i) * 3)
+
+/* RK817 LDO */
+#define RK817_LDO_ON_VSEL(n)		(0xcc + 2 * (n - 1))
+#define RK817_LDO_SLP_VSEL(n)		(0xcd + 2 * (n - 1))
+#define RK817_LDO_VSEL_MASK		0x7f
+
+/* RK817 ENABLE */
+#define RK817_POWER_EN(n)		(0xb1 + (n))
+#define RK817_POWER_SLP_EN(n)		(0xb5 + (n))
+
 #define RK818_BUCK_VSEL_MASK		0x3f
 #define RK818_BUCK4_VSEL_MASK		0x1f
 #define RK818_LDO_VSEL_MASK		0x1f
@@ -45,13 +60,19 @@
 #define RK805_RAMP_RATE_12_5MV_PER_US	(2 << RK805_RAMP_RATE_OFFSET)
 #define RK805_RAMP_RATE_25MV_PER_US	(3 << RK805_RAMP_RATE_OFFSET)
 #define RK808_RAMP_RATE_OFFSET		3
-
 #define RK808_RAMP_RATE_MASK		(3 << RK808_RAMP_RATE_OFFSET)
 #define RK808_RAMP_RATE_2MV_PER_US	(0 << RK808_RAMP_RATE_OFFSET)
 #define RK808_RAMP_RATE_4MV_PER_US	(1 << RK808_RAMP_RATE_OFFSET)
 #define RK808_RAMP_RATE_6MV_PER_US	(2 << RK808_RAMP_RATE_OFFSET)
 #define RK808_RAMP_RATE_10MV_PER_US	(3 << RK808_RAMP_RATE_OFFSET)
 
+#define RK817_RAMP_RATE_OFFSET		6
+#define RK817_RAMP_RATE_MASK		(0x3 << RK817_RAMP_RATE_OFFSET)
+#define RK817_RAMP_RATE_3MV_PER_US	(0x0 << RK817_RAMP_RATE_OFFSET)
+#define RK817_RAMP_RATE_6_3MV_PER_US	(0x1 << RK817_RAMP_RATE_OFFSET)
+#define RK817_RAMP_RATE_12_5MV_PER_US	(0x2 << RK817_RAMP_RATE_OFFSET)
+#define RK817_RAMP_RATE_25MV_PER_US	(0x3 << RK817_RAMP_RATE_OFFSET)
+
 struct rk8xx_reg_info {
 	uint min_uv;
 	uint step_uv;
@@ -84,6 +105,25 @@ static const struct rk8xx_reg_info rk816_buck[] = {
 	{  800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, },
 };
 
+static const struct rk8xx_reg_info rk817_buck[] = {
+	/* buck 1 */
+	{  500000,  12500, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x00, },
+	{ 1500000, 100000, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x50, },
+	{ 2400000,	0, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x59, },
+	/* buck 2 */
+	{  500000,  12500, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x00, },
+	{ 1500000, 100000, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x50, },
+	{ 2400000,	0, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x59, },
+	/* buck 3 */
+	{  500000,  12500, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x00, },
+	{ 1500000, 100000, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x50, },
+	{ 2400000,	0, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x59, },
+	/* buck 4 */
+	{  500000,  12500, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x00, },
+	{ 1500000, 100000, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x50, },
+	{ 3400000,	0, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x63, },
+};
+
 static const struct rk8xx_reg_info rk818_buck[] = {
 	{ 712500,   12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, },
 	{ 712500,   12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, },
@@ -112,6 +152,36 @@ static const struct rk8xx_reg_info rk816_ldo[] = {
 	{ 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
 };
 
+static const struct rk8xx_reg_info rk817_ldo[] = {
+	/* ldo1 */
+	{  600000, 25000, RK817_LDO_ON_VSEL(1), RK817_LDO_SLP_VSEL(1), NA, RK817_LDO_VSEL_MASK, 0x00, },
+	{ 3400000,     0, RK817_LDO_ON_VSEL(1), RK817_LDO_SLP_VSEL(1), NA, RK817_LDO_VSEL_MASK, 0x70, },
+	/* ldo2 */
+	{  600000, 25000, RK817_LDO_ON_VSEL(2), RK817_LDO_SLP_VSEL(2), NA, RK817_LDO_VSEL_MASK, 0x00, },
+	{ 3400000,     0, RK817_LDO_ON_VSEL(2), RK817_LDO_SLP_VSEL(2), NA, RK817_LDO_VSEL_MASK, 0x70, },
+	/* ldo3 */
+	{  600000, 25000, RK817_LDO_ON_VSEL(3), RK817_LDO_SLP_VSEL(3), NA, RK817_LDO_VSEL_MASK, 0x00, },
+	{ 3400000,     0, RK817_LDO_ON_VSEL(3), RK817_LDO_SLP_VSEL(3), NA, RK817_LDO_VSEL_MASK, 0x70, },
+	/* ldo4 */
+	{  600000, 25000, RK817_LDO_ON_VSEL(4), RK817_LDO_SLP_VSEL(4), NA, RK817_LDO_VSEL_MASK, 0x00, },
+	{ 3400000,     0, RK817_LDO_ON_VSEL(4), RK817_LDO_SLP_VSEL(4), NA, RK817_LDO_VSEL_MASK, 0x70, },
+	/* ldo5 */
+	{  600000, 25000, RK817_LDO_ON_VSEL(5), RK817_LDO_SLP_VSEL(5), NA, RK817_LDO_VSEL_MASK, 0x00, },
+	{ 3400000,     0, RK817_LDO_ON_VSEL(5), RK817_LDO_SLP_VSEL(5), NA, RK817_LDO_VSEL_MASK, 0x70, },
+	/* ldo6 */
+	{  600000, 25000, RK817_LDO_ON_VSEL(6), RK817_LDO_SLP_VSEL(6), NA, RK817_LDO_VSEL_MASK, 0x00, },
+	{ 3400000,     0, RK817_LDO_ON_VSEL(6), RK817_LDO_SLP_VSEL(6), NA, RK817_LDO_VSEL_MASK, 0x70, },
+	/* ldo7 */
+	{  600000, 25000, RK817_LDO_ON_VSEL(7), RK817_LDO_SLP_VSEL(7), NA, RK817_LDO_VSEL_MASK, 0x00, },
+	{ 3400000,     0, RK817_LDO_ON_VSEL(7), RK817_LDO_SLP_VSEL(7), NA, RK817_LDO_VSEL_MASK, 0x70, },
+	/* ldo8 */
+	{  600000, 25000, RK817_LDO_ON_VSEL(8), RK817_LDO_SLP_VSEL(8), NA, RK817_LDO_VSEL_MASK, 0x00, },
+	{ 3400000,     0, RK817_LDO_ON_VSEL(8), RK817_LDO_SLP_VSEL(8), NA, RK817_LDO_VSEL_MASK, 0x70, },
+	/* ldo9 */
+	{  600000, 25000, RK817_LDO_ON_VSEL(9), RK817_LDO_SLP_VSEL(9), NA, RK817_LDO_VSEL_MASK, 0x00, },
+	{ 3400000,     0, RK817_LDO_ON_VSEL(9), RK817_LDO_SLP_VSEL(9), NA, RK817_LDO_VSEL_MASK, 0x70, },
+};
+
 static const struct rk8xx_reg_info rk818_ldo[] = {
 	{ 1800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
 	{ 1800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
@@ -152,6 +222,24 @@ static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
 		default:
 			return &rk816_buck[num + 4];
 		}
+
+	case RK817_ID:
+		switch (num) {
+		case 0 ... 2:
+			if (uvolt < 1500000)
+				return &rk817_buck[num * 3 + 0];
+			else if (uvolt < 2400000)
+				return &rk817_buck[num * 3 + 1];
+			else
+				return &rk817_buck[num * 3 + 2];
+		case 3:
+			if (uvolt < 1500000)
+				return &rk817_buck[num * 3 + 0];
+			else if (uvolt < 3400000)
+				return &rk817_buck[num * 3 + 1];
+			else
+				return &rk817_buck[num * 3 + 2];
+		}
 	case RK818_ID:
 		return &rk818_buck[num];
 	default:
@@ -189,7 +277,7 @@ static int _buck_set_value(struct udevice *pmic, int buck, int uvolt)
 static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
 {
 	uint mask, value, en_reg;
-	int ret;
+	int ret = 0;
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
 
 	switch (priv->variant) {
@@ -220,6 +308,15 @@ static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
 		ret = pmic_clrsetbits(pmic, REG_DCDC_EN, mask,
 				      enable ? mask : 0);
 		break;
+	case RK817_ID:
+		if (buck < 4) {
+			if (enable)
+				value = ((1 << buck) | (1 << (buck + 4)));
+			else
+				value = ((0 << buck) | (1 << (buck + 4)));
+			ret = pmic_reg_write(pmic, RK817_POWER_EN(0), value);
+		}
+		break;
 	default:
 		ret = -EINVAL;
 	}
@@ -272,6 +369,12 @@ static int _buck_get_enable(struct udevice *pmic, int buck)
 		if (ret < 0)
 			return ret;
 		break;
+	case RK817_ID:
+		if (buck < 4) {
+			mask = 1 << buck;
+			ret = pmic_reg_read(pmic, RK817_POWER_EN(0));
+		}
+		break;
 	}
 
 	if (ret < 0)
@@ -282,7 +385,7 @@ static int _buck_get_enable(struct udevice *pmic, int buck)
 
 static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable)
 {
-	uint mask;
+	uint mask = 0;
 	int ret;
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
 
@@ -299,6 +402,12 @@ static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable)
 		ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF1, mask,
 				      enable ? 0 : mask);
 		break;
+	case RK817_ID:
+		if (buck < 4)
+			mask = 1 << buck;
+		ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(0), mask,
+				      enable ? mask : 0);
+		break;
 	default:
 		ret = -EINVAL;
 	}
@@ -310,7 +419,7 @@ static int _buck_get_suspend_enable(struct udevice *pmic, int buck)
 {
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
 	int ret, val;
-	uint mask;
+	uint mask = 0;
 
 	switch (priv->variant) {
 	case RK805_ID:
@@ -329,6 +438,15 @@ static int _buck_get_suspend_enable(struct udevice *pmic, int buck)
 			return val;
 		ret = val & mask ? 0 : 1;
 		break;
+	case RK817_ID:
+		if (buck < 4)
+			mask = 1 << buck;
+
+		val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(0));
+		if (val < 0)
+			return val;
+		ret = val & mask ? 1 : 0;
+		break;
 	default:
 		ret = -EINVAL;
 	}
@@ -345,6 +463,11 @@ static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic,
 	case RK805_ID:
 	case RK816_ID:
 		return &rk816_ldo[num];
+	case RK817_ID:
+		if (uvolt < 3400000)
+			return &rk817_ldo[num * 2 + 0];
+		else
+			return &rk817_ldo[num * 2 + 1];
 	case RK818_ID:
 		return &rk818_ldo[num];
 	default:
@@ -376,6 +499,20 @@ static int _ldo_get_enable(struct udevice *pmic, int ldo)
 		if (ret < 0)
 			return ret;
 		break;
+	case RK817_ID:
+		if (ldo < 4) {
+			mask = 1 << ldo;
+			ret = pmic_reg_read(pmic, RK817_POWER_EN(1));
+		} else if (ldo < 8) {
+			mask = 1 << (ldo - 4);
+			ret = pmic_reg_read(pmic, RK817_POWER_EN(2));
+		} else if (ldo == 8) {
+			mask = 1 << 0;
+			ret = pmic_reg_read(pmic, RK817_POWER_EN(3));
+		} else {
+			return false;
+		}
+		break;
 	}
 
 	if (ret < 0)
@@ -413,6 +550,24 @@ static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable)
 		ret = pmic_clrsetbits(pmic, REG_LDO_EN, mask,
 				       enable ? mask : 0);
 		break;
+	case RK817_ID:
+		if (ldo < 4) {
+			en_reg = RK817_POWER_EN(1);
+		} else if (ldo < 8) {
+			ldo -= 4;
+			en_reg = RK817_POWER_EN(2);
+		} else if (ldo == 8) {
+			ldo = 0;	/* BIT 0 */
+			en_reg = RK817_POWER_EN(3);
+		} else {
+			return -EINVAL;
+		}
+		if (enable)
+			value = ((1 << ldo) | (1 << (ldo + 4)));
+		else
+			value = ((0 << ldo) | (1 << (ldo + 4)));
+		ret = pmic_reg_write(pmic, en_reg, value);
+		break;
 	}
 
 	return ret;
@@ -437,6 +592,17 @@ static int _ldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable)
 		ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF2, mask,
 				      enable ? 0 : mask);
 		break;
+	case RK817_ID:
+		if (ldo == 8) {
+			mask = 1 << 4;	/* LDO9 */
+			ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(0), mask,
+					      enable ? mask : 0);
+		} else {
+			mask = 1 << ldo;
+			ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(1), mask,
+					      enable ? mask : 0);
+		}
+		break;
 	}
 
 	return ret;
@@ -465,6 +631,21 @@ static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo)
 			return val;
 		ret = val & mask ? 0 : 1;
 		break;
+	case RK817_ID:
+		if (ldo == 8) {
+			mask = 1 << 4;	/* LDO9 */
+			val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(0));
+			if (val < 0)
+				return val;
+			ret = val & mask ? 1 : 0;
+		} else {
+			mask = 1 << ldo;
+			val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(1));
+			if (val < 0)
+				return val;
+			ret = val & mask ? 1 : 0;
+		}
+		break;
 	}
 
 	return ret;
diff --git a/include/power/rk8xx_pmic.h b/include/power/rk8xx_pmic.h
index 7784c2a5e473..d93cecedddf7 100644
--- a/include/power/rk8xx_pmic.h
+++ b/include/power/rk8xx_pmic.h
@@ -170,6 +170,10 @@ enum {
 };
 
 enum {
+	RK817_REG_SYS_CFG3 = 0xf4,
+};
+
+enum {
 	RK816_REG_DCDC_EN1 = 0x23,
 	RK816_REG_DCDC_EN2,
 	RK816_REG_DCDC_SLP_EN,
@@ -182,11 +186,38 @@ enum {
 	RK805_ID = 0x8050,
 	RK808_ID = 0x0000,
 	RK816_ID = 0x8160,
+	RK817_ID = 0x8170,
 	RK818_ID = 0x8180,
 };
 
+enum {
+	RK817_POWER_EN0 = 0xb1,
+	RK817_POWER_EN1,
+	RK817_POWER_EN2,
+	RK817_POWER_EN3,
+};
+
+#define RK817_POWER_EN_SAVE0	0x99
+#define RK817_POWER_EN_SAVE1	0xa4
+
+#define RK817_ID_MSB	0xed
+#define RK817_ID_LSB	0xee
 #define RK8XX_ID_MSK	0xfff0
 
+#define RK817_PMIC_SYS_CFG3	0xf4
+#define RK817_GPIO_INT_CFG	0xfe
+
+#define RK8XX_ON_SOURCE		0xae
+#define RK8XX_OFF_SOURCE	0xaf
+#define RK817_BUCK4_CMIN	0xc6
+#define RK817_ON_SOURCE		0xf5
+#define RK817_OFF_SOURCE	0xf6
+
+struct reg_data {
+	u8 reg;
+	u8 val;
+	u8 mask;
+};
 struct rk8xx_reg_table {
 	char *name;
 	u8 reg_ctl;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH v4 6/6] power: pmic: rk809: support rk809 pmic
  2019-09-26  7:43 [U-Boot] [PATCH v4 0/6] power: pmic: support more PMIC Elaine Zhang
                   ` (4 preceding siblings ...)
  2019-09-26  7:44 ` [U-Boot] [PATCH v4 5/6] power: pmic: rk817: support rk817 pmic Elaine Zhang
@ 2019-09-26  7:45 ` Elaine Zhang
  2019-10-14  9:08 ` [U-Boot] [PATCH v4 0/6] power: pmic: support more PMIC Kever Yang
  6 siblings, 0 replies; 9+ messages in thread
From: Elaine Zhang @ 2019-09-26  7:45 UTC (permalink / raw)
  To: u-boot

From: Joseph Chen <chenjh@rock-chips.com>

The RK809 is a Power Management IC (PMIC) for multimedia
and handheld devices. They contains the following components:
    - Regulators(5*BUCKs, 9*LDOs, 2*SWITCHs)
    - RTC
    - Clocking

Signed-off-by: Joseph Chen <chenjh@rock-chips.com>
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
Reviewed-by: Kever Yang<kever.yang@rock-chips.com>
---
 drivers/power/pmic/rk8xx.c      |  5 ++-
 drivers/power/regulator/rk8xx.c | 70 ++++++++++++++++++++++++++++++++++++++++-
 include/power/rk8xx_pmic.h      |  1 +
 3 files changed, 74 insertions(+), 2 deletions(-)

diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c
index df0bf83a054c..52e6d9d8c0e8 100644
--- a/drivers/power/pmic/rk8xx.c
+++ b/drivers/power/pmic/rk8xx.c
@@ -92,7 +92,8 @@ static int rk8xx_probe(struct udevice *dev)
 	u8 value;
 
 	/* read Chip variant */
-	if (device_is_compatible(dev, "rockchip,rk817")) {
+	if (device_is_compatible(dev, "rockchip,rk817") ||
+	    device_is_compatible(dev, "rockchip,rk809")) {
 		id_msb = RK817_ID_MSB;
 		id_lsb = RK817_ID_LSB;
 	} else {
@@ -119,6 +120,7 @@ static int rk8xx_probe(struct udevice *dev)
 		on_source = RK8XX_ON_SOURCE;
 		off_source = RK8XX_OFF_SOURCE;
 		break;
+	case RK809_ID:
 	case RK817_ID:
 		on_source = RK817_ON_SOURCE;
 		off_source = RK817_OFF_SOURCE;
@@ -173,6 +175,7 @@ static struct dm_pmic_ops rk8xx_ops = {
 static const struct udevice_id rk8xx_ids[] = {
 	{ .compatible = "rockchip,rk805" },
 	{ .compatible = "rockchip,rk808" },
+	{ .compatible = "rockchip,rk809" },
 	{ .compatible = "rockchip,rk816" },
 	{ .compatible = "rockchip,rk817" },
 	{ .compatible = "rockchip,rk818" },
diff --git a/drivers/power/regulator/rk8xx.c b/drivers/power/regulator/rk8xx.c
index 3c4a18b0f0c7..194086c6d240 100644
--- a/drivers/power/regulator/rk8xx.c
+++ b/drivers/power/regulator/rk8xx.c
@@ -27,6 +27,10 @@
 #define RK808_BUCK4_VSEL_MASK	0xf
 #define RK808_LDO_VSEL_MASK	0x1f
 
+/* RK809 BUCK5 */
+#define RK809_BUCK5_CONFIG(n)		(0xde + (n) * 1)
+#define RK809_BUCK5_VSEL_MASK		0x07
+
 /* RK817 BUCK */
 #define RK817_BUCK_ON_VSEL(n)		(0xbb + 3 * (n - 1))
 #define RK817_BUCK_SLP_VSEL(n)		(0xbc + 3 * (n - 1))
@@ -59,6 +63,7 @@
 #define RK805_RAMP_RATE_6MV_PER_US	(1 << RK805_RAMP_RATE_OFFSET)
 #define RK805_RAMP_RATE_12_5MV_PER_US	(2 << RK805_RAMP_RATE_OFFSET)
 #define RK805_RAMP_RATE_25MV_PER_US	(3 << RK805_RAMP_RATE_OFFSET)
+
 #define RK808_RAMP_RATE_OFFSET		3
 #define RK808_RAMP_RATE_MASK		(3 << RK808_RAMP_RATE_OFFSET)
 #define RK808_RAMP_RATE_2MV_PER_US	(0 << RK808_RAMP_RATE_OFFSET)
@@ -105,6 +110,14 @@ static const struct rk8xx_reg_info rk816_buck[] = {
 	{  800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, },
 };
 
+static const struct rk8xx_reg_info rk809_buck5[] = {
+	/* buck 5 */
+	{ 1500000,	0, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x00, },
+	{ 1800000, 200000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x01, },
+	{ 2800000, 200000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x04, },
+	{ 3300000, 300000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x06, },
+};
+
 static const struct rk8xx_reg_info rk817_buck[] = {
 	/* buck 1 */
 	{  500000,  12500, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x00, },
@@ -223,6 +236,7 @@ static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
 			return &rk816_buck[num + 4];
 		}
 
+	case RK809_ID:
 	case RK817_ID:
 		switch (num) {
 		case 0 ... 2:
@@ -239,6 +253,16 @@ static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
 				return &rk817_buck[num * 3 + 1];
 			else
 				return &rk817_buck[num * 3 + 2];
+		/* BUCK5 for RK809 */
+		default:
+			if (uvolt < 1800000)
+				return &rk809_buck5[0];
+			else if (uvolt < 2800000)
+				return &rk809_buck5[1];
+			else if (uvolt < 3300000)
+				return &rk809_buck5[2];
+			else
+				return &rk809_buck5[3];
 		}
 	case RK818_ID:
 		return &rk818_buck[num];
@@ -308,6 +332,7 @@ static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
 		ret = pmic_clrsetbits(pmic, REG_DCDC_EN, mask,
 				      enable ? mask : 0);
 		break;
+	case RK809_ID:
 	case RK817_ID:
 		if (buck < 4) {
 			if (enable)
@@ -315,6 +340,13 @@ static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
 			else
 				value = ((0 << buck) | (1 << (buck + 4)));
 			ret = pmic_reg_write(pmic, RK817_POWER_EN(0), value);
+		/* BUCK5 for RK809 */
+		} else {
+			if (enable)
+				value = ((1 << 1) | (1 << 5));
+			else
+				value = ((0 << 1) | (1 << 5));
+			ret = pmic_reg_write(pmic, RK817_POWER_EN(3), value);
 		}
 		break;
 	default:
@@ -369,10 +401,15 @@ static int _buck_get_enable(struct udevice *pmic, int buck)
 		if (ret < 0)
 			return ret;
 		break;
+	case RK809_ID:
 	case RK817_ID:
 		if (buck < 4) {
 			mask = 1 << buck;
 			ret = pmic_reg_read(pmic, RK817_POWER_EN(0));
+		/* BUCK5 for RK809 */
+		} else {
+			mask = 1 << 1;
+			ret = pmic_reg_read(pmic, RK817_POWER_EN(3));
 		}
 		break;
 	}
@@ -402,9 +439,12 @@ static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable)
 		ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF1, mask,
 				      enable ? 0 : mask);
 		break;
+	case RK809_ID:
 	case RK817_ID:
 		if (buck < 4)
 			mask = 1 << buck;
+		else
+			mask = 1 << 5;	/* BUCK5 for RK809 */
 		ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(0), mask,
 				      enable ? mask : 0);
 		break;
@@ -438,9 +478,12 @@ static int _buck_get_suspend_enable(struct udevice *pmic, int buck)
 			return val;
 		ret = val & mask ? 0 : 1;
 		break;
+	case RK809_ID:
 	case RK817_ID:
 		if (buck < 4)
 			mask = 1 << buck;
+		else
+			mask = 1 << 5;	/* BUCK5 for RK809 */
 
 		val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(0));
 		if (val < 0)
@@ -463,6 +506,7 @@ static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic,
 	case RK805_ID:
 	case RK816_ID:
 		return &rk816_ldo[num];
+	case RK809_ID:
 	case RK817_ID:
 		if (uvolt < 3400000)
 			return &rk817_ldo[num * 2 + 0];
@@ -499,6 +543,7 @@ static int _ldo_get_enable(struct udevice *pmic, int ldo)
 		if (ret < 0)
 			return ret;
 		break;
+	case RK809_ID:
 	case RK817_ID:
 		if (ldo < 4) {
 			mask = 1 << ldo;
@@ -521,7 +566,6 @@ static int _ldo_get_enable(struct udevice *pmic, int ldo)
 	return ret & mask ? true : false;
 }
 
-
 static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable)
 {
 	struct rk8xx_priv *priv = dev_get_priv(pmic);
@@ -550,6 +594,7 @@ static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable)
 		ret = pmic_clrsetbits(pmic, REG_LDO_EN, mask,
 				       enable ? mask : 0);
 		break;
+	case RK809_ID:
 	case RK817_ID:
 		if (ldo < 4) {
 			en_reg = RK817_POWER_EN(1);
@@ -592,6 +637,7 @@ static int _ldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable)
 		ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF2, mask,
 				      enable ? 0 : mask);
 		break;
+	case RK809_ID:
 	case RK817_ID:
 		if (ldo == 8) {
 			mask = 1 << 4;	/* LDO9 */
@@ -631,6 +677,7 @@ static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo)
 			return val;
 		ret = val & mask ? 0 : 1;
 		break;
+	case RK809_ID:
 	case RK817_ID:
 		if (ldo == 8) {
 			mask = 1 << 4;	/* LDO9 */
@@ -850,6 +897,11 @@ static int switch_set_enable(struct udevice *dev, bool enable)
 		ret = pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask,
 				      enable ? mask : 0);
 		break;
+	case RK809_ID:
+		mask = (1 << (sw + 2)) | (1 << (sw + 6));
+		ret = pmic_clrsetbits(dev->parent, RK817_POWER_EN(3), mask,
+				      enable ? mask : 0);
+		break;
 	case RK818_ID:
 		mask = 1 << 6;
 		ret = pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask,
@@ -874,6 +926,10 @@ static int switch_get_enable(struct udevice *dev)
 		mask = 1 << (sw + 5);
 		ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
 		break;
+	case RK809_ID:
+		mask = 1 << (sw + 2);
+		ret = pmic_reg_read(dev->parent, RK817_POWER_EN(3));
+		break;
 	case RK818_ID:
 		mask = 1 << 6;
 		ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
@@ -908,6 +964,11 @@ static int switch_set_suspend_enable(struct udevice *dev, bool enable)
 		ret = pmic_clrsetbits(dev->parent, REG_SLEEP_SET_OFF1, mask,
 				      enable ? 0 : mask);
 		break;
+	case RK809_ID:
+		mask = 1 << (sw + 6);
+		ret = pmic_clrsetbits(dev->parent, RK817_POWER_SLP_EN(0), mask,
+				      enable ? mask : 0);
+		break;
 	case RK818_ID:
 		mask = 1 << 6;
 		ret = pmic_clrsetbits(dev->parent, REG_SLEEP_SET_OFF1, mask,
@@ -935,6 +996,13 @@ static int switch_get_suspend_enable(struct udevice *dev)
 			return val;
 		ret = val & mask ? 0 : 1;
 		break;
+	case RK809_ID:
+		mask = 1 << (sw + 6);
+		val = pmic_reg_read(dev->parent, RK817_POWER_SLP_EN(0));
+		if (val < 0)
+			return val;
+		ret = val & mask ? 1 : 0;
+		break;
 	case RK818_ID:
 		mask = 1 << 6;
 		val = pmic_reg_read(dev->parent, REG_SLEEP_SET_OFF1);
diff --git a/include/power/rk8xx_pmic.h b/include/power/rk8xx_pmic.h
index d93cecedddf7..8ff0af35c57a 100644
--- a/include/power/rk8xx_pmic.h
+++ b/include/power/rk8xx_pmic.h
@@ -185,6 +185,7 @@ enum {
 enum {
 	RK805_ID = 0x8050,
 	RK808_ID = 0x0000,
+	RK809_ID = 0x8090,
 	RK816_ID = 0x8160,
 	RK817_ID = 0x8170,
 	RK818_ID = 0x8180,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH v4 0/6] power: pmic: support more PMIC
  2019-09-26  7:43 [U-Boot] [PATCH v4 0/6] power: pmic: support more PMIC Elaine Zhang
                   ` (5 preceding siblings ...)
  2019-09-26  7:45 ` [U-Boot] [PATCH v4 6/6] power: pmic: rk809: support rk809 pmic Elaine Zhang
@ 2019-10-14  9:08 ` Kever Yang
  6 siblings, 0 replies; 9+ messages in thread
From: Kever Yang @ 2019-10-14  9:08 UTC (permalink / raw)
  To: u-boot

patch set applied to u-boot-rockchip master.

On 2019/9/26 下午3:43, Elaine Zhang wrote:
> Support more PMIC and improve compatibility between pmics.
>
> Change in V4:
> [PATCH v4 1/6]: No change.
> [PATCH v4 2/6]: No change.
> [PATCH v4 3/6]: No change.
> [PATCH v4 4/6]: No change.
> [PATCH v4 5/6]: Resolve code conflicts after ptach v3 5/8 and 6/8 deletion.
> [PATCH v4 6/6]: Resolve code conflicts after ptach v3 5/8 and 6/8 deletion.
> Remove [PATCH v3 5/8] and [PATCH v3 6/8], There is no application scenario.
>
> Change in V3:
> [PATCH v3 1/8]: Add document instructions, Correct error handling.
> [PATCH v3 2/8]: No change.
> [PATCH v3 3/8]: No change.
> [PATCH v3 4/8]: No change.
> [PATCH v3 5/8]: Update commit message.
> [PATCH v3 6/8]: Update commit message.
> [PATCH v3 7/8]: No change.
> [PATCH v3 8/8]: No change.
>
> Change in V2:
> [PATCH v2 1/8]: Add regulator suspend volatge and en/disable test.
> [PATCH v2 2/8]: Split the [PATCH v1 2/7], rk808 and rk818 updates.
> [PATCH v2 3/8]: Split the [PATCH v1 2/7], support rk816 pmic and update commit message.
> [PATCH v2 4/8]: Update commit message.
> [PATCH v2 5/8]: No change.
> [PATCH v2 6/8]: No change.
> [PATCH v2 7/8]: Remove rk809 keywords and update commit message.
> [PATCH v2 8/8]: Update commit message.
>
> Elaine Zhang (3):
>    power: regulator: rk8xx: update the driver for rk808 and rk818
>    power: pmic: rk816: support rk816 pmic
>    power: pmic: rk805: support rk805 pmic
>
> Joseph Chen (3):
>    dm: regulator: support regulator more state
>    power: pmic: rk817: support rk817 pmic
>    power: pmic: rk809: support rk809 pmic
>
>   doc/device-tree-bindings/regulator/regulator.txt |  27 +
>   drivers/power/pmic/rk8xx.c                       |  89 ++-
>   drivers/power/regulator/regulator-uclass.c       |  70 ++
>   drivers/power/regulator/rk8xx.c                  | 939 +++++++++++++++++++++--
>   include/power/regulator.h                        |  64 ++
>   include/power/rk8xx_pmic.h                       |  42 +
>   test/dm/regulator.c                              |  46 ++
>   7 files changed, 1189 insertions(+), 88 deletions(-)
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH v4 1/6] dm: regulator: support regulator more state
  2019-09-26  7:43 ` [U-Boot] [PATCH v4 1/6] dm: regulator: support regulator more state Elaine Zhang
@ 2019-10-16  2:06   ` Kever Yang
  0 siblings, 0 replies; 9+ messages in thread
From: Kever Yang @ 2019-10-16  2:06 UTC (permalink / raw)
  To: u-boot

Hi Elaine,
     This patch can not pass the Travis test(pytest option), please help 
to update
this patch, you can leave other patches as is and update this patch only.

Thanks,
- Kever
On 2019/9/26 下午3:43, Elaine Zhang wrote:
> From: Joseph Chen <chenjh@rock-chips.com>
>
> support parse regulator standard property:
> regulator-off-in-suspend;
> regulator-init-microvolt;
> regulator-suspend-microvolt:
>   regulator_get_suspend_enable
>   regulator_set_suspend_enable
>   regulator_get_suspend_value
>   regulator_set_suspend_value
>
> Signed-off-by: Joseph Chen <chenjh@rock-chips.com>
> Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
> Reviewed-by: Kever Yang<kever.yang@rock-chips.com>
> ---
>   doc/device-tree-bindings/regulator/regulator.txt | 27 +++++++++
>   drivers/power/regulator/regulator-uclass.c       | 70 ++++++++++++++++++++++++
>   include/power/regulator.h                        | 64 ++++++++++++++++++++++
>   test/dm/regulator.c                              | 46 ++++++++++++++++
>   4 files changed, 207 insertions(+)
>
> diff --git a/doc/device-tree-bindings/regulator/regulator.txt b/doc/device-tree-bindings/regulator/regulator.txt
> index 4ba642b7c77f..6c9a02120fde 100644
> --- a/doc/device-tree-bindings/regulator/regulator.txt
> +++ b/doc/device-tree-bindings/regulator/regulator.txt
> @@ -36,6 +36,28 @@ Optional properties:
>   - regulator-always-on: regulator should never be disabled
>   - regulator-boot-on: enabled by bootloader/firmware
>   - regulator-ramp-delay: ramp delay for regulator (in uV/us)
> +- regulator-init-microvolt: a init allowed Voltage value
> +- regulator-state-(standby|mem|disk)
> +  type: object
> +  description:
> +    sub-nodes for regulator state in Standby, Suspend-to-RAM, and
> +    Suspend-to-DISK modes. Equivalent with standby, mem, and disk Linux
> +    sleep states.
> +
> +    properties:
> +      regulator-on-in-suspend:
> +        description: regulator should be on in suspend state.
> +        type: boolean
> +
> +      regulator-off-in-suspend:
> +        description: regulator should be off in suspend state.
> +        type: boolean
> +
> +      regulator-suspend-microvolt:
> +        description: the default voltage which regulator would be set in
> +          suspend. This property is now deprecated, instead setting voltage
> +          for suspend mode via the API which regulator driver provides is
> +          recommended.
>   
>   Note
>   The "regulator-name" constraint is used for setting the device's uclass
> @@ -59,7 +81,12 @@ ldo0 {
>   	regulator-max-microvolt = <1800000>;
>   	regulator-min-microamp = <100000>;
>   	regulator-max-microamp = <100000>;
> +	regulator-init-microvolt = <1800000>;
>   	regulator-always-on;
>   	regulator-boot-on;
>   	regulator-ramp-delay = <12000>;
> +	regulator-state-mem {
> +		regulator-on-in-suspend;
> +		regulator-suspend-microvolt = <1800000>;
> +	};
>   };
> diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c
> index 76be95bcd159..b49c0829ed31 100644
> --- a/drivers/power/regulator/regulator-uclass.c
> +++ b/drivers/power/regulator/regulator-uclass.c
> @@ -77,6 +77,33 @@ int regulator_set_value(struct udevice *dev, int uV)
>   	return ret;
>   }
>   
> +int regulator_set_suspend_value(struct udevice *dev, int uV)
> +{
> +	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
> +	struct dm_regulator_uclass_platdata *uc_pdata;
> +
> +	uc_pdata = dev_get_uclass_platdata(dev);
> +	if (uc_pdata->min_uV != -ENODATA && uV < uc_pdata->min_uV)
> +		return -EINVAL;
> +	if (uc_pdata->max_uV != -ENODATA && uV > uc_pdata->max_uV)
> +		return -EINVAL;
> +
> +	if (!ops->set_suspend_value)
> +		return -ENOSYS;
> +
> +	return ops->set_suspend_value(dev, uV);
> +}
> +
> +int regulator_get_suspend_value(struct udevice *dev)
> +{
> +	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
> +
> +	if (!ops->get_suspend_value)
> +		return -ENOSYS;
> +
> +	return ops->get_suspend_value(dev);
> +}
> +
>   /*
>    * To be called with at most caution as there is no check
>    * before setting the actual voltage value.
> @@ -170,6 +197,26 @@ int regulator_set_enable_if_allowed(struct udevice *dev, bool enable)
>   	return ret;
>   }
>   
> +int regulator_set_suspend_enable(struct udevice *dev, bool enable)
> +{
> +	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
> +
> +	if (!ops->set_suspend_enable)
> +		return -ENOSYS;
> +
> +	return ops->set_suspend_enable(dev, enable);
> +}
> +
> +int regulator_get_suspend_enable(struct udevice *dev)
> +{
> +	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
> +
> +	if (!ops->get_suspend_enable)
> +		return -ENOSYS;
> +
> +	return ops->get_suspend_enable(dev);
> +}
> +
>   int regulator_get_mode(struct udevice *dev)
>   {
>   	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
> @@ -235,6 +282,14 @@ int regulator_autoset(struct udevice *dev)
>   	int ret = 0;
>   
>   	uc_pdata = dev_get_uclass_platdata(dev);
> +
> +	ret = regulator_set_suspend_enable(dev, uc_pdata->suspend_on);
> +	if (!ret && uc_pdata->suspend_on) {
> +		ret = regulator_set_suspend_value(dev, uc_pdata->suspend_uV);
> +		if (!ret)
> +			return ret;
> +	}
> +
>   	if (!uc_pdata->always_on && !uc_pdata->boot_on)
>   		return -EMEDIUMTYPE;
>   
> @@ -243,6 +298,8 @@ int regulator_autoset(struct udevice *dev)
>   
>   	if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
>   		ret = regulator_set_value(dev, uc_pdata->min_uV);
> +	if (uc_pdata->init_uV > 0)
> +		ret = regulator_set_value(dev, uc_pdata->init_uV);
>   	if (!ret && (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA))
>   		ret = regulator_set_current(dev, uc_pdata->min_uA);
>   
> @@ -363,6 +420,7 @@ static int regulator_post_bind(struct udevice *dev)
>   static int regulator_pre_probe(struct udevice *dev)
>   {
>   	struct dm_regulator_uclass_platdata *uc_pdata;
> +	ofnode node;
>   
>   	uc_pdata = dev_get_uclass_platdata(dev);
>   	if (!uc_pdata)
> @@ -373,6 +431,8 @@ static int regulator_pre_probe(struct udevice *dev)
>   						-ENODATA);
>   	uc_pdata->max_uV = dev_read_u32_default(dev, "regulator-max-microvolt",
>   						-ENODATA);
> +	uc_pdata->init_uV = dev_read_u32_default(dev, "regulator-init-microvolt",
> +						-ENODATA);
>   	uc_pdata->min_uA = dev_read_u32_default(dev, "regulator-min-microamp",
>   						-ENODATA);
>   	uc_pdata->max_uA = dev_read_u32_default(dev, "regulator-max-microamp",
> @@ -382,6 +442,16 @@ static int regulator_pre_probe(struct udevice *dev)
>   	uc_pdata->ramp_delay = dev_read_u32_default(dev, "regulator-ramp-delay",
>   						    0);
>   
> +	node = dev_read_subnode(dev, "regulator-state-mem");
> +	if (ofnode_valid(node)) {
> +		uc_pdata->suspend_on = !ofnode_read_bool(node, "regulator-off-in-suspend");
> +		if (ofnode_read_u32(node, "regulator-suspend-microvolt", &uc_pdata->suspend_uV))
> +			uc_pdata->suspend_uV = uc_pdata->max_uA;
> +	} else {
> +		uc_pdata->suspend_on = true;
> +		uc_pdata->suspend_uV = uc_pdata->max_uA;
> +	}
> +
>   	/* Those values are optional (-ENODATA if unset) */
>   	if ((uc_pdata->min_uV != -ENODATA) &&
>   	    (uc_pdata->max_uV != -ENODATA) &&
> diff --git a/include/power/regulator.h b/include/power/regulator.h
> index 6c6e2cd4f996..dd61eb4ccbde 100644
> --- a/include/power/regulator.h
> +++ b/include/power/regulator.h
> @@ -168,6 +168,7 @@ struct dm_regulator_uclass_platdata {
>   	int mode_count;
>   	int min_uV;
>   	int max_uV;
> +	int init_uV;
>   	int min_uA;
>   	int max_uA;
>   	unsigned int ramp_delay;
> @@ -177,6 +178,8 @@ struct dm_regulator_uclass_platdata {
>   	int flags;
>   	u8 ctrl_reg;
>   	u8 volt_reg;
> +	bool suspend_on;
> +	u32 suspend_uV;
>   };
>   
>   /* Regulator device operations */
> @@ -194,6 +197,19 @@ struct dm_regulator_ops {
>   	int (*set_value)(struct udevice *dev, int uV);
>   
>   	/**
> +	 * The regulator suspend output value function calls operates
> +	 * on a micro Volts.
> +	 *
> +	 * get/set_suspen_value - get/set suspend mode output value
> +	 * @dev          - regulator device
> +	 * Sets:
> +	 * @uV           - set the suspend output value [micro Volts]
> +	 * @return output value [uV] on success or negative errno if fail.
> +	 */
> +	int (*set_suspend_value)(struct udevice *dev, int uV);
> +	int (*get_suspend_value)(struct udevice *dev);
> +
> +	/**
>   	 * The regulator output current function calls operates on a micro Amps.
>   	 *
>   	 * get/set_current - get/set output current of the given output number
> @@ -218,6 +234,19 @@ struct dm_regulator_ops {
>   	int (*set_enable)(struct udevice *dev, bool enable);
>   
>   	/**
> +	 * The most basic feature of the regulator output is its enable state
> +	 * in suspend mode.
> +	 *
> +	 * get/set_suspend_enable - get/set enable state of the suspend output
> +	 * @dev           - regulator device
> +	 * Sets:
> +	 * @enable         - set true - enable or false - disable
> +	 * @return true/false for get or -errno if fail; 0 / -errno for set.
> +	 */
> +	int (*set_suspend_enable)(struct udevice *dev, bool enable);
> +	int (*get_suspend_enable)(struct udevice *dev);
> +
> +	/**
>   	 * The 'get/set_mode()' function calls should operate on a driver-
>   	 * specific mode id definitions, which should be found in:
>   	 * field 'id' of struct dm_regulator_mode.
> @@ -262,6 +291,23 @@ int regulator_get_value(struct udevice *dev);
>   int regulator_set_value(struct udevice *dev, int uV);
>   
>   /**
> + * regulator_set_suspend_value: set the suspend microvoltage value of a given regulator.
> + *
> + * @dev    - pointer to the regulator device
> + * @uV     - the output suspend value to set [micro Volts]
> + * @return - 0 on success or -errno val if fails
> + */
> +int regulator_set_suspend_value(struct udevice *dev, int uV);
> +
> +/**
> + * regulator_get_suspend_value: get the suspend microvoltage value of a given regulator.
> + *
> + * @dev    - pointer to the regulator device
> + * @return - positive output value [uV] on success or negative errno if fail.
> + */
> +int regulator_get_suspend_value(struct udevice *dev);
> +
> +/**
>    * regulator_set_value_force: set the microvoltage value of a given regulator
>    *			      without any min-,max condition check
>    *
> @@ -317,6 +363,24 @@ int regulator_set_enable(struct udevice *dev, bool enable);
>   int regulator_set_enable_if_allowed(struct udevice *dev, bool enable);
>   
>   /**
> + * regulator_set_suspend_enable: set regulator suspend enable state
> + *
> + * @dev    - pointer to the regulator device
> + * @enable - set true or false
> + * @return - 0 on success or -errno val if fails
> + */
> +int regulator_set_suspend_enable(struct udevice *dev, bool enable);
> +
> +
> +/**
> + * regulator_get_suspend_enable: get regulator suspend enable state
> + *
> + * @dev    - pointer to the regulator device
> + * @return - true/false of enable state or -errno val if fails
> + */
> +int regulator_get_suspend_enable(struct udevice *dev);
> +
> +/**
>    * regulator_get_mode: get active operation mode id of a given regulator
>    *
>    * @dev    - pointer to the regulator device
> diff --git a/test/dm/regulator.c b/test/dm/regulator.c
> index e510539542b6..1641aff77cb6 100644
> --- a/test/dm/regulator.c
> +++ b/test/dm/regulator.c
> @@ -215,6 +215,52 @@ static int dm_test_power_regulator_set_get_mode(struct unit_test_state *uts)
>   }
>   DM_TEST(dm_test_power_regulator_set_get_mode, DM_TESTF_SCAN_FDT);
>   
> +/* Test regulator set and get suspend Voltage method */
> +static int dm_test_power_regulator_set_get_suspend_voltage(struct unit_test_state *uts)
> +{
> +	struct dm_regulator_uclass_platdata *uc_pdata;
> +	struct udevice *dev;
> +	const char *platname;
> +	int val_set, val_get;
> +
> +	/* Set and get Voltage of BUCK1 - set to 'min' constraint */
> +	platname = regulator_names[BUCK1][PLATNAME];
> +	ut_assertok(regulator_get_by_platname(platname, &dev));
> +
> +	uc_pdata = dev_get_uclass_platdata(dev);
> +	ut_assert(uc_pdata);
> +
> +	val_set = uc_pdata->min_uV;
> +	ut_assertok(regulator_set_suspend_value(dev, val_set));
> +
> +	val_get = regulator_get_suspend_value(dev);
> +	ut_assert(val_get >= 0);
> +
> +	ut_asserteq(val_set, val_get);
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_power_regulator_set_get_suspend_voltage, DM_TESTF_SCAN_FDT);
> +
> +/* Test regulator set and get suspend Enable method */
> +static int dm_test_power_regulator_set_get_suspend_enable(struct unit_test_state *uts)
> +{
> +	const char *platname;
> +	struct udevice *dev;
> +	bool val_set = true;
> +
> +	/* Set the Enable of LDO1 - default is disabled */
> +	platname = regulator_names[LDO1][PLATNAME];
> +	ut_assertok(regulator_get_by_platname(platname, &dev));
> +	ut_assertok(regulator_set_suspend_enable(dev, val_set));
> +
> +	/* Get the Enable state of LDO1 and compare it with the requested one */
> +	ut_asserteq(regulator_get_suspend_enable(dev), val_set);
> +
> +	return 0;
> +}
> +DM_TEST(dm_test_power_regulator_set_get_suspend_enable, DM_TESTF_SCAN_FDT);
> +
>   /* Test regulator autoset method */
>   static int dm_test_power_regulator_autoset(struct unit_test_state *uts)
>   {

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-10-16  2:06 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-26  7:43 [U-Boot] [PATCH v4 0/6] power: pmic: support more PMIC Elaine Zhang
2019-09-26  7:43 ` [U-Boot] [PATCH v4 1/6] dm: regulator: support regulator more state Elaine Zhang
2019-10-16  2:06   ` Kever Yang
2019-09-26  7:43 ` [U-Boot] [PATCH v4 2/6] power: regulator: rk8xx: update the driver for rk808 and rk818 Elaine Zhang
2019-09-26  7:43 ` [U-Boot] [PATCH v4 3/6] power: pmic: rk816: support rk816 pmic Elaine Zhang
2019-09-26  7:43 ` [U-Boot] [PATCH v4 4/6] power: pmic: rk805: support rk805 pmic Elaine Zhang
2019-09-26  7:44 ` [U-Boot] [PATCH v4 5/6] power: pmic: rk817: support rk817 pmic Elaine Zhang
2019-09-26  7:45 ` [U-Boot] [PATCH v4 6/6] power: pmic: rk809: support rk809 pmic Elaine Zhang
2019-10-14  9:08 ` [U-Boot] [PATCH v4 0/6] power: pmic: support more PMIC Kever Yang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.