@@ -9,8 +9,10 @@
#include <dm/lists.h>
#include <errno.h>
#include <log.h>
+#include <linux/bitfield.h>
#include <power/rk8xx_pmic.h>
#include <power/pmic.h>
+#include <spi.h>
#include <sysreset.h>
static int rk8xx_sysreset_request(struct udevice *dev, enum sysreset_t type)
@@ -32,6 +34,10 @@ static int rk8xx_sysreset_request(struct udevice *dev, enum sysreset_t type)
pmic_clrsetbits(dev->parent, RK817_REG_SYS_CFG3, 0,
BIT(0));
break;
+ case RK806_ID:
+ pmic_clrsetbits(dev->parent, RK806_REG_SYS_CFG3, 0,
+ BIT(0));
+ break;
default:
printf("Unknown PMIC RK%x: Cannot shutdown\n",
priv->variant);
@@ -83,6 +89,11 @@ void rk8xx_off_for_plugin(struct udevice *dev)
}
}
+static struct reg_data rk806_init_reg[] = {
+ /* RST_FUN */
+ { RK806_REG_SYS_CFG3, GENMASK(7, 6), BIT(7)},
+};
+
static struct reg_data rk817_init_reg[] = {
/* enable the under-voltage protection,
* the under-voltage protection will shutdown the LDO3 and reset the PMIC
@@ -92,7 +103,10 @@ static struct reg_data rk817_init_reg[] = {
static const struct pmic_child_info pmic_children_info[] = {
{ .prefix = "DCDC_REG", .driver = "rk8xx_buck"},
+ { .prefix = "dcdc-reg", .driver = "rk8xx_buck"},
{ .prefix = "LDO_REG", .driver = "rk8xx_ldo"},
+ { .prefix = "nldo-reg", .driver = "rk8xx_nldo"},
+ { .prefix = "pldo-reg", .driver = "rk8xx_pldo"},
{ .prefix = "SWITCH_REG", .driver = "rk8xx_switch"},
{ },
};
@@ -102,11 +116,51 @@ static int rk8xx_reg_count(struct udevice *dev)
return RK808_NUM_OF_REGS;
}
+#if CONFIG_IS_ENABLED(SPI) && CONFIG_IS_ENABLED(DM_SPI)
+struct rk806_cmd {
+ uint8_t len: 4; /* Payload size in bytes - 1 */
+ uint8_t reserved: 2;
+ uint8_t crc_en: 1;
+ uint8_t op: 1; /* READ=0; WRITE=1; */
+ uint8_t reg_l;
+#define REG_L_MASK GENMASK(7, 0)
+ uint8_t reg_h;
+#define REG_H_MASK GENMASK(15, 8)
+};
+#endif
+
static int rk8xx_write(struct udevice *dev, uint reg, const uint8_t *buff,
int len)
{
int ret;
+#if CONFIG_IS_ENABLED(SPI) && CONFIG_IS_ENABLED(DM_SPI)
+ if (device_get_uclass_id(dev->parent) == UCLASS_SPI) {
+ struct spi_slave *spi = dev_get_parent_priv(dev);
+ struct rk806_cmd cmd = {
+ .op = 1,
+ .len = len - 1,
+ .reg_l = FIELD_GET(REG_L_MASK, reg),
+ .reg_h = FIELD_GET(REG_H_MASK, reg),
+ };
+
+ ret = dm_spi_claim_bus(dev);
+ if (ret) {
+ debug("Couldn't claim bus for device: %p!\n", dev);
+ return ret;
+ }
+
+ ret = spi_write_then_read(spi, (u8 *)&cmd, sizeof(cmd), buff, NULL, len);
+ if (ret)
+ debug("write error to device: %p register: %#x!\n",
+ dev, reg);
+
+ dm_spi_release_bus(dev);
+
+ return ret;
+ }
+#endif
+
ret = dm_i2c_write(dev, reg, buff, len);
if (ret) {
debug("write error to device: %p register: %#x!\n", dev, reg);
@@ -120,6 +174,33 @@ static int rk8xx_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
{
int ret;
+#if CONFIG_IS_ENABLED(SPI) && CONFIG_IS_ENABLED(DM_SPI)
+ if (device_get_uclass_id(dev->parent) == UCLASS_SPI) {
+ struct spi_slave *spi = dev_get_parent_priv(dev);
+ struct rk806_cmd cmd = {
+ .op = 0,
+ .len = len - 1,
+ .reg_l = FIELD_GET(REG_L_MASK, reg),
+ .reg_h = FIELD_GET(REG_H_MASK, reg),
+ };
+
+ ret = dm_spi_claim_bus(dev);
+ if (ret) {
+ debug("Couldn't claim bus for device: %p!\n", dev);
+ return ret;
+ }
+
+ ret = spi_write_then_read(spi, (u8 *)&cmd, sizeof(cmd), NULL, buff, len);
+ if (ret)
+ debug("read error to device: %p register: %#x!\n",
+ dev, reg);
+
+ dm_spi_release_bus(dev);
+
+ return ret;
+ }
+#endif
+
ret = dm_i2c_read(dev, reg, buff, len);
if (ret) {
debug("read error from device: %p register: %#x!\n", dev, reg);
@@ -181,6 +262,9 @@ static int rk8xx_probe(struct udevice *dev)
device_is_compatible(dev, "rockchip,rk809")) {
id_msb = RK817_ID_MSB;
id_lsb = RK817_ID_LSB;
+ } else if (device_is_compatible(dev, "rockchip,rk806")) {
+ id_msb = RK806_ID_MSB;
+ id_lsb = RK806_ID_LSB;
} else {
id_msb = ID_MSB;
id_lsb = ID_LSB;
@@ -221,6 +305,12 @@ static int rk8xx_probe(struct udevice *dev)
value = (power_en2 & 0x0f) | ((power_en3 & 0x0f) << 4);
pmic_reg_write(dev, RK817_POWER_EN_SAVE1, value);
break;
+ case RK806_ID:
+ on_source = RK806_ON_SOURCE;
+ off_source = RK806_OFF_SOURCE;
+ init_data = rk806_init_reg;
+ init_data_num = ARRAY_SIZE(rk806_init_reg);
+ break;
default:
printf("Unknown PMIC: RK%x!!\n", priv->variant);
return -EINVAL;
@@ -263,6 +353,7 @@ static struct dm_pmic_ops rk8xx_ops = {
static const struct udevice_id rk8xx_ids[] = {
{ .compatible = "rockchip,rk805" },
+ { .compatible = "rockchip,rk806" },
{ .compatible = "rockchip,rk808" },
{ .compatible = "rockchip,rk809" },
{ .compatible = "rockchip,rk816" },
@@ -25,6 +25,19 @@
#define NA 0xff
/* Field Definitions */
+#define RK806_BUCK_CONFIG(n) (0x10 + (n) - 1)
+#define RK806_BUCK_ON_VSEL(n) (0x1a + (n) - 1)
+#define RK806_BUCK_SLP_VSEL(n) (0x24 + (n) - 1)
+#define RK806_BUCK_VSEL_MASK 0xff
+
+#define RK806_NLDO_ON_VSEL(n) (0x43 + (n) - 1)
+#define RK806_NLDO_SLP_VSEL(n) (0x48 + (n) - 1)
+#define RK806_NLDO_VSEL_MASK 0xff
+
+#define RK806_PLDO_ON_VSEL(n) (0x4e + (n) - 1)
+#define RK806_PLDO_SLP_VSEL(n) (0x54 + (n) - 1)
+#define RK806_PLDO_VSEL_MASK 0xff
+
#define RK808_BUCK_VSEL_MASK 0x3f
#define RK808_BUCK4_VSEL_MASK 0xf
#define RK808_LDO_VSEL_MASK 0x1f
@@ -91,6 +104,49 @@ struct rk8xx_reg_info {
u8 max_sel;
};
+static const struct rk8xx_reg_info rk806_buck[] = {
+ /* buck 1 */
+ { 500000, 6250, RK806_BUCK_ON_VSEL(1), RK806_BUCK_SLP_VSEL(1), RK806_BUCK_CONFIG(1), RK806_BUCK_VSEL_MASK, 0x00, 0x9f },
+ { 1500000, 25000, RK806_BUCK_ON_VSEL(1), RK806_BUCK_SLP_VSEL(1), RK806_BUCK_CONFIG(1), RK806_BUCK_VSEL_MASK, 0xa0, 0xeb },
+ { 3400000, 0, RK806_BUCK_ON_VSEL(1), RK806_BUCK_SLP_VSEL(1), RK806_BUCK_CONFIG(1), RK806_BUCK_VSEL_MASK, 0xec, 0xff },
+ /* buck 2 */
+ { 500000, 6250, RK806_BUCK_ON_VSEL(2), RK806_BUCK_SLP_VSEL(2), RK806_BUCK_CONFIG(2), RK806_BUCK_VSEL_MASK, 0x00, 0x9f },
+ { 1500000, 25000, RK806_BUCK_ON_VSEL(2), RK806_BUCK_SLP_VSEL(2), RK806_BUCK_CONFIG(2), RK806_BUCK_VSEL_MASK, 0xa0, 0xeb },
+ { 3400000, 0, RK806_BUCK_ON_VSEL(2), RK806_BUCK_SLP_VSEL(2), RK806_BUCK_CONFIG(2), RK806_BUCK_VSEL_MASK, 0xec, 0xff },
+ /* buck 3 */
+ { 500000, 6250, RK806_BUCK_ON_VSEL(3), RK806_BUCK_SLP_VSEL(3), RK806_BUCK_CONFIG(3), RK806_BUCK_VSEL_MASK, 0x00, 0x9f },
+ { 1500000, 25000, RK806_BUCK_ON_VSEL(3), RK806_BUCK_SLP_VSEL(3), RK806_BUCK_CONFIG(3), RK806_BUCK_VSEL_MASK, 0xa0, 0xeb },
+ { 3400000, 0, RK806_BUCK_ON_VSEL(3), RK806_BUCK_SLP_VSEL(3), RK806_BUCK_CONFIG(3), RK806_BUCK_VSEL_MASK, 0xec, 0xff },
+ /* buck 4 */
+ { 500000, 6250, RK806_BUCK_ON_VSEL(4), RK806_BUCK_SLP_VSEL(4), RK806_BUCK_CONFIG(4), RK806_BUCK_VSEL_MASK, 0x00, 0x9f },
+ { 1500000, 25000, RK806_BUCK_ON_VSEL(4), RK806_BUCK_SLP_VSEL(4), RK806_BUCK_CONFIG(4), RK806_BUCK_VSEL_MASK, 0xa0, 0xeb },
+ { 3400000, 0, RK806_BUCK_ON_VSEL(4), RK806_BUCK_SLP_VSEL(4), RK806_BUCK_CONFIG(4), RK806_BUCK_VSEL_MASK, 0xec, 0xff },
+ /* buck 5 */
+ { 500000, 6250, RK806_BUCK_ON_VSEL(5), RK806_BUCK_SLP_VSEL(5), RK806_BUCK_CONFIG(5), RK806_BUCK_VSEL_MASK, 0x00, 0x9f },
+ { 1500000, 25000, RK806_BUCK_ON_VSEL(5), RK806_BUCK_SLP_VSEL(5), RK806_BUCK_CONFIG(5), RK806_BUCK_VSEL_MASK, 0xa0, 0xeb },
+ { 3400000, 0, RK806_BUCK_ON_VSEL(5), RK806_BUCK_SLP_VSEL(5), RK806_BUCK_CONFIG(5), RK806_BUCK_VSEL_MASK, 0xec, 0xff },
+ /* buck 6 */
+ { 500000, 6250, RK806_BUCK_ON_VSEL(6), RK806_BUCK_SLP_VSEL(6), RK806_BUCK_CONFIG(6), RK806_BUCK_VSEL_MASK, 0x00, 0x9f },
+ { 1500000, 25000, RK806_BUCK_ON_VSEL(6), RK806_BUCK_SLP_VSEL(6), RK806_BUCK_CONFIG(6), RK806_BUCK_VSEL_MASK, 0xa0, 0xeb },
+ { 3400000, 0, RK806_BUCK_ON_VSEL(6), RK806_BUCK_SLP_VSEL(6), RK806_BUCK_CONFIG(6), RK806_BUCK_VSEL_MASK, 0xec, 0xff },
+ /* buck 7 */
+ { 500000, 6250, RK806_BUCK_ON_VSEL(7), RK806_BUCK_SLP_VSEL(7), RK806_BUCK_CONFIG(7), RK806_BUCK_VSEL_MASK, 0x00, 0x9f },
+ { 1500000, 25000, RK806_BUCK_ON_VSEL(7), RK806_BUCK_SLP_VSEL(7), RK806_BUCK_CONFIG(7), RK806_BUCK_VSEL_MASK, 0xa0, 0xeb },
+ { 3400000, 0, RK806_BUCK_ON_VSEL(7), RK806_BUCK_SLP_VSEL(7), RK806_BUCK_CONFIG(7), RK806_BUCK_VSEL_MASK, 0xec, 0xff },
+ /* buck 8 */
+ { 500000, 6250, RK806_BUCK_ON_VSEL(8), RK806_BUCK_SLP_VSEL(8), RK806_BUCK_CONFIG(8), RK806_BUCK_VSEL_MASK, 0x00, 0x9f },
+ { 1500000, 25000, RK806_BUCK_ON_VSEL(8), RK806_BUCK_SLP_VSEL(8), RK806_BUCK_CONFIG(8), RK806_BUCK_VSEL_MASK, 0xa0, 0xeb },
+ { 3400000, 0, RK806_BUCK_ON_VSEL(8), RK806_BUCK_SLP_VSEL(8), RK806_BUCK_CONFIG(8), RK806_BUCK_VSEL_MASK, 0xec, 0xff },
+ /* buck 9 */
+ { 500000, 6250, RK806_BUCK_ON_VSEL(9), RK806_BUCK_SLP_VSEL(9), RK806_BUCK_CONFIG(9), RK806_BUCK_VSEL_MASK, 0x00, 0x9f },
+ { 1500000, 25000, RK806_BUCK_ON_VSEL(9), RK806_BUCK_SLP_VSEL(9), RK806_BUCK_CONFIG(9), RK806_BUCK_VSEL_MASK, 0xa0, 0xeb },
+ { 3400000, 0, RK806_BUCK_ON_VSEL(9), RK806_BUCK_SLP_VSEL(9), RK806_BUCK_CONFIG(9), RK806_BUCK_VSEL_MASK, 0xec, 0xff },
+ /* buck 10 */
+ { 500000, 6250, RK806_BUCK_ON_VSEL(10), RK806_BUCK_SLP_VSEL(10), RK806_BUCK_CONFIG(10), RK806_BUCK_VSEL_MASK, 0x00, 0x9f },
+ { 1500000, 25000, RK806_BUCK_ON_VSEL(10), RK806_BUCK_SLP_VSEL(10), RK806_BUCK_CONFIG(10), RK806_BUCK_VSEL_MASK, 0xa0, 0xeb },
+ { 3400000, 0, RK806_BUCK_ON_VSEL(10), RK806_BUCK_SLP_VSEL(10), RK806_BUCK_CONFIG(10), RK806_BUCK_VSEL_MASK, 0xec, 0xff },
+};
+
static const struct rk8xx_reg_info rk808_buck[] = {
{ 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK808_BUCK_VSEL_MASK, 0x00, 0x3f },
{ 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK808_BUCK_VSEL_MASK, 0x00, 0x3f },
@@ -148,6 +204,45 @@ static const struct rk8xx_reg_info rk818_buck[] = {
};
#ifdef ENABLE_DRIVER
+static const struct rk8xx_reg_info rk806_nldo[] = {
+ /* nldo 1 */
+ { 500000, 12500, RK806_NLDO_ON_VSEL(1), RK806_NLDO_SLP_VSEL(1), NA, RK806_NLDO_VSEL_MASK, 0x00, 0xe7},
+ { 3400000, 0, RK806_NLDO_ON_VSEL(1), RK806_NLDO_SLP_VSEL(1), NA, RK806_NLDO_VSEL_MASK, 0xe8, 0xff},
+ /* nldo 2 */
+ { 500000, 12500, RK806_NLDO_ON_VSEL(2), RK806_NLDO_SLP_VSEL(2), NA, RK806_NLDO_VSEL_MASK, 0x00, 0xe7},
+ { 3400000, 0, RK806_NLDO_ON_VSEL(2), RK806_NLDO_SLP_VSEL(2), NA, RK806_NLDO_VSEL_MASK, 0xe8, 0xff},
+ /* nldo 3 */
+ { 500000, 12500, RK806_NLDO_ON_VSEL(3), RK806_NLDO_SLP_VSEL(3), NA, RK806_NLDO_VSEL_MASK, 0x00, 0xe7},
+ { 3400000, 0, RK806_NLDO_ON_VSEL(3), RK806_NLDO_SLP_VSEL(3), NA, RK806_NLDO_VSEL_MASK, 0xe8, 0xff},
+ /* nldo 4 */
+ { 500000, 12500, RK806_NLDO_ON_VSEL(4), RK806_NLDO_SLP_VSEL(4), NA, RK806_NLDO_VSEL_MASK, 0x00, 0xe7},
+ { 3400000, 0, RK806_NLDO_ON_VSEL(4), RK806_NLDO_SLP_VSEL(4), NA, RK806_NLDO_VSEL_MASK, 0xe8, 0xff},
+ /* nldo 5 */
+ { 500000, 12500, RK806_NLDO_ON_VSEL(5), RK806_NLDO_SLP_VSEL(5), NA, RK806_NLDO_VSEL_MASK, 0x00, 0xe7},
+ { 3400000, 0, RK806_NLDO_ON_VSEL(5), RK806_NLDO_SLP_VSEL(5), NA, RK806_NLDO_VSEL_MASK, 0xe8, 0xff},
+};
+
+static const struct rk8xx_reg_info rk806_pldo[] = {
+ /* pldo 1 */
+ { 500000, 12500, RK806_PLDO_ON_VSEL(1), RK806_PLDO_SLP_VSEL(1), NA, RK806_PLDO_VSEL_MASK, 0x00, 0xe7},
+ { 3400000, 0, RK806_PLDO_ON_VSEL(1), RK806_PLDO_SLP_VSEL(1), NA, RK806_PLDO_VSEL_MASK, 0xe8, 0xff},
+ /* pldo 2 */
+ { 500000, 12500, RK806_PLDO_ON_VSEL(2), RK806_PLDO_SLP_VSEL(2), NA, RK806_PLDO_VSEL_MASK, 0x00, 0xe7},
+ { 3400000, 0, RK806_PLDO_ON_VSEL(2), RK806_PLDO_SLP_VSEL(2), NA, RK806_PLDO_VSEL_MASK, 0xe8, 0xff},
+ /* pldo 3 */
+ { 500000, 12500, RK806_PLDO_ON_VSEL(3), RK806_PLDO_SLP_VSEL(3), NA, RK806_PLDO_VSEL_MASK, 0x00, 0xe7},
+ { 3400000, 0, RK806_PLDO_ON_VSEL(3), RK806_PLDO_SLP_VSEL(3), NA, RK806_PLDO_VSEL_MASK, 0xe8, 0xff},
+ /* pldo 4 */
+ { 500000, 12500, RK806_PLDO_ON_VSEL(4), RK806_PLDO_SLP_VSEL(4), NA, RK806_PLDO_VSEL_MASK, 0x00, 0xe7},
+ { 3400000, 0, RK806_PLDO_ON_VSEL(4), RK806_PLDO_SLP_VSEL(4), NA, RK806_PLDO_VSEL_MASK, 0xe8, 0xff},
+ /* pldo 5 */
+ { 500000, 12500, RK806_PLDO_ON_VSEL(5), RK806_PLDO_SLP_VSEL(5), NA, RK806_PLDO_VSEL_MASK, 0x00, 0xe7},
+ { 3400000, 0, RK806_PLDO_ON_VSEL(5), RK806_PLDO_SLP_VSEL(5), NA, RK806_PLDO_VSEL_MASK, 0xe8, 0xff},
+ /* pldo 6 */
+ { 500000, 12500, RK806_PLDO_ON_VSEL(6), RK806_PLDO_SLP_VSEL(6), NA, RK806_PLDO_VSEL_MASK, 0x00, 0xe7},
+ { 3400000, 0, RK806_PLDO_ON_VSEL(6), RK806_PLDO_SLP_VSEL(6), NA, RK806_PLDO_VSEL_MASK, 0xe8, 0xff},
+};
+
static const struct rk8xx_reg_info rk808_ldo[] = {
{ 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, },
@@ -230,7 +325,12 @@ static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
default:
return &rk816_buck[num + 4];
}
-
+ case RK806_ID:
+ if (uvolt < 1500000)
+ return &rk806_buck[num * 3 + 0];
+ else if (uvolt < 3400000)
+ return &rk806_buck[num * 3 + 1];
+ return &rk806_buck[num * 3 + 2];
case RK809_ID:
case RK817_ID:
switch (num) {
@@ -314,7 +414,11 @@ static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
value = ((0 << buck) | (1 << (buck + 4)));
ret = pmic_reg_write(pmic, en_reg, value);
break;
-
+ case RK806_ID:
+ value = RK806_POWER_EN_CLRSETBITS(buck % 4, enable);
+ en_reg = RK806_POWER_EN((buck + 1) / 4);
+ ret = pmic_reg_write(pmic, en_reg, value);
+ break;
case RK808_ID:
case RK818_ID:
mask = 1 << buck;
@@ -389,6 +493,10 @@ static int _buck_get_enable(struct udevice *pmic, int buck)
ret = pmic_reg_read(pmic, RK816_REG_DCDC_EN1);
}
break;
+ case RK806_ID:
+ mask = BIT(buck % 4);
+ ret = pmic_reg_read(pmic, RK806_POWER_EN((buck + 1) / 4));
+ break;
case RK808_ID:
case RK818_ID:
mask = 1 << buck;
@@ -428,6 +536,20 @@ static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable)
ret = pmic_clrsetbits(pmic, RK816_REG_DCDC_SLP_EN, mask,
enable ? mask : 0);
break;
+ case RK806_ID:
+ {
+ u8 reg;
+
+ if (buck + 1 >= 9) {
+ reg = RK806_POWER_SLP_EN1;
+ mask = BIT(buck + 1 - 3);
+ } else {
+ reg = RK806_POWER_SLP_EN0;
+ mask = BIT(buck + 1);
+ }
+ ret = pmic_clrsetbits(pmic, reg, mask, enable ? mask : 0);
+ }
+ break;
case RK808_ID:
case RK818_ID:
mask = 1 << buck;
@@ -465,6 +587,21 @@ static int _buck_get_suspend_enable(struct udevice *pmic, int buck)
return val;
ret = val & mask ? 1 : 0;
break;
+ case RK806_ID:
+ {
+ u8 reg;
+
+ if (buck + 1 >= 9) {
+ reg = RK806_POWER_SLP_EN1;
+ mask = BIT(buck + 1 - 3);
+ } else {
+ reg = RK806_POWER_SLP_EN0;
+ mask = BIT(buck + 1);
+ }
+ val = pmic_reg_read(pmic, reg);
+ }
+ ret = (val & mask) ? 1 : 0;
+ break;
case RK808_ID:
case RK818_ID:
mask = 1 << buck;
@@ -514,6 +651,34 @@ static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic,
}
}
+static const struct rk8xx_reg_info *get_nldo_reg(struct udevice *pmic,
+ int num, int uvolt)
+{
+ const struct rk8xx_priv *priv = dev_get_priv(pmic);
+
+ switch (priv->variant) {
+ case RK806_ID:
+ default:
+ if (uvolt < 3400000)
+ return &rk806_nldo[num * 2 + 0];
+ return &rk806_nldo[num * 2 + 1];
+ }
+}
+
+static const struct rk8xx_reg_info *get_pldo_reg(struct udevice *pmic,
+ int num, int uvolt)
+{
+ const struct rk8xx_priv *priv = dev_get_priv(pmic);
+
+ switch (priv->variant) {
+ case RK806_ID:
+ default:
+ if (uvolt < 3400000)
+ return &rk806_pldo[num * 2 + 0];
+ return &rk806_pldo[num * 2 + 1];
+ }
+}
+
static int _ldo_get_enable(struct udevice *pmic, int ldo)
{
struct rk8xx_priv *priv = dev_get_priv(pmic);
@@ -561,6 +726,63 @@ static int _ldo_get_enable(struct udevice *pmic, int ldo)
return ret & mask ? true : false;
}
+static int _nldo_get_enable(struct udevice *pmic, int nldo)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ uint mask = 0;
+ int ret = 0;
+ u8 en_reg = 0;
+
+ switch (priv->variant) {
+ case RK806_ID:
+ default:
+ if (nldo + 1 >= 5) {
+ mask = BIT(2);
+ en_reg = RK806_POWER_EN(5);
+ } else {
+ mask = BIT(nldo);
+ en_reg = RK806_POWER_EN(3);
+ }
+ ret = pmic_reg_read(pmic, en_reg);
+ break;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ return (ret & mask) ? 1 : 0;
+}
+
+static int _pldo_get_enable(struct udevice *pmic, int pldo)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ uint mask = 0;
+ int ret = 0;
+ u8 en_reg = 0;
+
+ switch (priv->variant) {
+ case RK806_ID:
+ default:
+ if (pldo + 1 <= 3) {
+ mask = BIT(pldo + 1);
+ en_reg = RK806_POWER_EN(4);
+ } else if (pldo + 1 == 6) {
+ mask = BIT(0);
+ en_reg = RK806_POWER_EN(4);
+ } else {
+ mask = BIT((pldo + 1) % 4);
+ en_reg = RK806_POWER_EN(5);
+ }
+ ret = pmic_reg_read(pmic, en_reg);
+ break;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ return (ret & mask) ? 1 : 0;
+}
+
static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable)
{
struct rk8xx_priv *priv = dev_get_priv(pmic);
@@ -616,6 +838,62 @@ static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable)
return ret;
}
+static int _nldo_set_enable(struct udevice *pmic, int nldo, bool enable)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ uint value, en_reg;
+ int ret = 0;
+
+ switch (priv->variant) {
+ case RK806_ID:
+ default:
+ if (nldo + 1 >= 5) {
+ value = RK806_POWER_EN_CLRSETBITS(2, enable);
+ en_reg = RK806_POWER_EN(5);
+ } else {
+ value = RK806_POWER_EN_CLRSETBITS(nldo, enable);
+ en_reg = RK806_POWER_EN(3);
+ }
+ ret = pmic_reg_write(pmic, en_reg, value);
+ break;
+ }
+
+ if (enable)
+ udelay(500);
+
+ return ret;
+}
+
+static int _pldo_set_enable(struct udevice *pmic, int pldo, bool enable)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ uint value, en_reg;
+ int ret = 0;
+
+ switch (priv->variant) {
+ case RK806_ID:
+ default:
+ /* PLDO */
+ if (pldo + 1 <= 3) {
+ value = RK806_POWER_EN_CLRSETBITS(pldo + 1, enable);
+ en_reg = RK806_POWER_EN(4);
+ } else if (pldo + 1 == 6) {
+ value = RK806_POWER_EN_CLRSETBITS(0, enable);
+ en_reg = RK806_POWER_EN(4);
+ } else {
+ value = RK806_POWER_EN_CLRSETBITS((pldo + 1) % 4, enable);
+ en_reg = RK806_POWER_EN(5);
+ }
+ ret = pmic_reg_write(pmic, en_reg, value);
+ break;
+ }
+
+ if (enable)
+ udelay(500);
+
+ return ret;
+}
+
static int _ldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable)
{
struct rk8xx_priv *priv = dev_get_priv(pmic);
@@ -652,6 +930,43 @@ static int _ldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable)
return ret;
}
+static int _nldo_set_suspend_enable(struct udevice *pmic, int nldo, bool enable)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ uint mask;
+ int ret = 0;
+
+ switch (priv->variant) {
+ case RK806_ID:
+ default:
+ mask = BIT(nldo);
+ ret = pmic_clrsetbits(pmic, RK806_POWER_SLP_EN1, mask, enable ? mask : 0);
+ break;
+ }
+
+ return ret;
+}
+
+static int _pldo_set_suspend_enable(struct udevice *pmic, int pldo, bool enable)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ uint mask;
+ int ret = 0;
+
+ switch (priv->variant) {
+ case RK806_ID:
+ default:
+ if (pldo + 1 >= 6)
+ mask = BIT(0);
+ else
+ mask = BIT(pldo + 1);
+ ret = pmic_clrsetbits(pmic, RK806_POWER_SLP_EN2, mask, enable ? mask : 0);
+ break;
+ }
+
+ return ret;
+}
+
static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo)
{
struct rk8xx_priv *priv = dev_get_priv(pmic);
@@ -696,6 +1011,45 @@ static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo)
return ret;
}
+static int _nldo_get_suspend_enable(struct udevice *pmic, int nldo)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ int val, ret = 0;
+ uint mask;
+
+ switch (priv->variant) {
+ case RK806_ID:
+ default:
+ mask = BIT(nldo);
+ val = pmic_reg_read(pmic, RK806_POWER_SLP_EN1);
+ ret = (val & mask) ? 1 : 0;
+ break;
+ }
+
+ return ret;
+}
+
+static int _pldo_get_suspend_enable(struct udevice *pmic, int pldo)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ int val, ret = 0;
+ uint mask;
+
+ switch (priv->variant) {
+ case RK806_ID:
+ default:
+ if (pldo + 1 >= 6)
+ mask = BIT(0);
+ else
+ mask = BIT(pldo + 1);
+ val = pmic_reg_read(pmic, RK806_POWER_SLP_EN2);
+ ret = (val & mask) ? 1 : 0;
+ break;
+ }
+
+ return ret;
+}
+
static int buck_get_value(struct udevice *dev)
{
int buck = dev->driver_data - 1;
@@ -803,6 +1157,22 @@ static int ldo_get_value(struct udevice *dev)
return _ldo_get_value(dev, info);
}
+static int nldo_get_value(struct udevice *dev)
+{
+ int nldo = dev->driver_data - 1;
+ const struct rk8xx_reg_info *info = get_nldo_reg(dev->parent, nldo, 0);
+
+ return _ldo_get_value(dev, info);
+}
+
+static int pldo_get_value(struct udevice *dev)
+{
+ int pldo = dev->driver_data - 1;
+ const struct rk8xx_reg_info *info = get_pldo_reg(dev->parent, pldo, 0);
+
+ return _ldo_get_value(dev, info);
+}
+
static int _ldo_set_value(struct udevice *dev, const struct rk8xx_reg_info *info, int uvolt)
{
int mask = info->vsel_mask;
@@ -830,6 +1200,22 @@ static int ldo_set_value(struct udevice *dev, int uvolt)
return _ldo_set_value(dev, info, uvolt);
}
+static int nldo_set_value(struct udevice *dev, int uvolt)
+{
+ int nldo = dev->driver_data - 1;
+ const struct rk8xx_reg_info *info = get_nldo_reg(dev->parent, nldo, uvolt);
+
+ return _ldo_set_value(dev, info, uvolt);
+}
+
+static int pldo_set_value(struct udevice *dev, int uvolt)
+{
+ int pldo = dev->driver_data - 1;
+ const struct rk8xx_reg_info *info = get_pldo_reg(dev->parent, pldo, uvolt);
+
+ return _ldo_set_value(dev, info, uvolt);
+}
+
static int _ldo_set_suspend_value(struct udevice *dev, const struct rk8xx_reg_info *info, int uvolt)
{
int mask = info->vsel_mask;
@@ -857,6 +1243,22 @@ static int ldo_set_suspend_value(struct udevice *dev, int uvolt)
return _ldo_set_suspend_value(dev->parent, info, uvolt);
}
+static int nldo_set_suspend_value(struct udevice *dev, int uvolt)
+{
+ int nldo = dev->driver_data - 1;
+ const struct rk8xx_reg_info *info = get_nldo_reg(dev->parent, nldo, uvolt);
+
+ return _ldo_set_suspend_value(dev->parent, info, uvolt);
+}
+
+static int pldo_set_suspend_value(struct udevice *dev, int uvolt)
+{
+ int pldo = dev->driver_data - 1;
+ const struct rk8xx_reg_info *info = get_pldo_reg(dev->parent, pldo, uvolt);
+
+ return _ldo_set_suspend_value(dev->parent, info, uvolt);
+}
+
static int _ldo_get_suspend_value(struct udevice *dev, const struct rk8xx_reg_info *info)
{
int mask = info->vsel_mask;
@@ -882,6 +1284,22 @@ static int ldo_get_suspend_value(struct udevice *dev)
return _ldo_get_suspend_value(dev->parent, info);
}
+static int nldo_get_suspend_value(struct udevice *dev)
+{
+ int nldo = dev->driver_data - 1;
+ const struct rk8xx_reg_info *info = get_nldo_reg(dev->parent, nldo, 0);
+
+ return _ldo_get_suspend_value(dev->parent, info);
+}
+
+static int pldo_get_suspend_value(struct udevice *dev)
+{
+ int pldo = dev->driver_data - 1;
+ const struct rk8xx_reg_info *info = get_pldo_reg(dev->parent, pldo, 0);
+
+ return _ldo_get_suspend_value(dev->parent, info);
+}
+
static int ldo_set_enable(struct udevice *dev, bool enable)
{
int ldo = dev->driver_data - 1;
@@ -889,6 +1307,20 @@ static int ldo_set_enable(struct udevice *dev, bool enable)
return _ldo_set_enable(dev->parent, ldo, enable);
}
+static int nldo_set_enable(struct udevice *dev, bool enable)
+{
+ int nldo = dev->driver_data - 1;
+
+ return _nldo_set_enable(dev->parent, nldo, enable);
+}
+
+static int pldo_set_enable(struct udevice *dev, bool enable)
+{
+ int pldo = dev->driver_data - 1;
+
+ return _pldo_set_enable(dev->parent, pldo, enable);
+}
+
static int ldo_set_suspend_enable(struct udevice *dev, bool enable)
{
int ldo = dev->driver_data - 1;
@@ -896,6 +1328,20 @@ static int ldo_set_suspend_enable(struct udevice *dev, bool enable)
return _ldo_set_suspend_enable(dev->parent, ldo, enable);
}
+static int nldo_set_suspend_enable(struct udevice *dev, bool enable)
+{
+ int nldo = dev->driver_data - 1;
+
+ return _nldo_set_suspend_enable(dev->parent, nldo, enable);
+}
+
+static int pldo_set_suspend_enable(struct udevice *dev, bool enable)
+{
+ int pldo = dev->driver_data - 1;
+
+ return _pldo_set_suspend_enable(dev->parent, pldo, enable);
+}
+
static int ldo_get_suspend_enable(struct udevice *dev)
{
int ldo = dev->driver_data - 1;
@@ -903,6 +1349,20 @@ static int ldo_get_suspend_enable(struct udevice *dev)
return _ldo_get_suspend_enable(dev->parent, ldo);
}
+static int nldo_get_suspend_enable(struct udevice *dev)
+{
+ int nldo = dev->driver_data - 1;
+
+ return _nldo_get_suspend_enable(dev->parent, nldo);
+}
+
+static int pldo_get_suspend_enable(struct udevice *dev)
+{
+ int pldo = dev->driver_data - 1;
+
+ return _pldo_get_suspend_enable(dev->parent, pldo);
+}
+
static int ldo_get_enable(struct udevice *dev)
{
int ldo = dev->driver_data - 1;
@@ -910,6 +1370,20 @@ static int ldo_get_enable(struct udevice *dev)
return _ldo_get_enable(dev->parent, ldo);
}
+static int nldo_get_enable(struct udevice *dev)
+{
+ int nldo = dev->driver_data - 1;
+
+ return _nldo_get_enable(dev->parent, nldo);
+}
+
+static int pldo_get_enable(struct udevice *dev)
+{
+ int pldo = dev->driver_data - 1;
+
+ return _pldo_get_enable(dev->parent, pldo);
+}
+
static int switch_set_enable(struct udevice *dev, bool enable)
{
struct rk8xx_priv *priv = dev_get_priv(dev->parent);
@@ -1133,6 +1607,28 @@ static const struct dm_regulator_ops rk8xx_ldo_ops = {
.get_suspend_enable = ldo_get_suspend_enable,
};
+static const struct dm_regulator_ops rk8xx_nldo_ops = {
+ .get_value = nldo_get_value,
+ .set_value = nldo_set_value,
+ .set_suspend_value = nldo_set_suspend_value,
+ .get_suspend_value = nldo_get_suspend_value,
+ .get_enable = nldo_get_enable,
+ .set_enable = nldo_set_enable,
+ .set_suspend_enable = nldo_set_suspend_enable,
+ .get_suspend_enable = nldo_get_suspend_enable,
+};
+
+static const struct dm_regulator_ops rk8xx_pldo_ops = {
+ .get_value = pldo_get_value,
+ .set_value = pldo_set_value,
+ .set_suspend_value = pldo_set_suspend_value,
+ .get_suspend_value = pldo_get_suspend_value,
+ .get_enable = pldo_get_enable,
+ .set_enable = pldo_set_enable,
+ .set_suspend_enable = pldo_set_suspend_enable,
+ .get_suspend_enable = pldo_get_suspend_enable,
+};
+
static const struct dm_regulator_ops rk8xx_switch_ops = {
.get_value = switch_get_value,
.set_value = switch_set_value,
@@ -1158,6 +1654,20 @@ U_BOOT_DRIVER(rk8xx_ldo) = {
.probe = rk8xx_ldo_probe,
};
+U_BOOT_DRIVER(rk8xx_nldo) = {
+ .name = "rk8xx_nldo",
+ .id = UCLASS_REGULATOR,
+ .ops = &rk8xx_nldo_ops,
+ .probe = rk8xx_ldo_probe,
+};
+
+U_BOOT_DRIVER(rk8xx_pldo) = {
+ .name = "rk8xx_pldo",
+ .id = UCLASS_REGULATOR,
+ .ops = &rk8xx_pldo_ops,
+ .probe = rk8xx_ldo_probe,
+};
+
U_BOOT_DRIVER(rk8xx_switch) = {
.name = "rk8xx_switch",
.id = UCLASS_REGULATOR,
@@ -182,8 +182,19 @@ enum {
RK816_REG_LDO_EN2,
};
+enum {
+ RK806_POWER_SLP_EN0 = 0x06,
+ RK806_POWER_SLP_EN1,
+ RK806_POWER_SLP_EN2,
+ RK806_REG_SYS_CFG3 = 0x72,
+ RK806_WDT_REG,
+ RK806_ON_SOURCE,
+ RK806_OFF_SOURCE
+};
+
enum {
RK805_ID = 0x8050,
+ RK806_ID = 0x8060,
RK808_ID = 0x0000,
RK809_ID = 0x8090,
RK816_ID = 0x8160,
@@ -201,6 +212,14 @@ enum {
#define RK817_POWER_EN_SAVE0 0x99
#define RK817_POWER_EN_SAVE1 0xa4
+#define RK806_POWER_EN(x) (0x00 + (x))
+/* POWER_ENx register lower 4 bits are write-protected unless the associated top bit is set */
+#define RK806_POWER_EN_CLRSETBITS(bit, val) (((val) << (bit)) | (1 << ((bit) + 4)))
+
+#define RK806_POWER_SLP_EN(x) (0x06 + (x))
+
+#define RK806_ID_MSB 0x5a
+#define RK806_ID_LSB 0x5b
#define RK817_ID_MSB 0xed
#define RK817_ID_LSB 0xee
#define RK8XX_ID_MSK 0xfff0