Message ID | 20240304-rk3588-saradc-v3-5-7424e2ed5d3b@theobroma-systems.com |
---|---|
State | Accepted |
Delegated to: | Kever Yang |
Headers | show |
Series | rockchip: add support for SARADCv2 and RK806 PMIC and regulators | expand |
On 2024/3/4 19:29, Quentin Schulz wrote: > From: Quentin Schulz <quentin.schulz@theobroma-systems.com> > > This adds support for RK806, only the SPI variant has been tested. > > The communication "protocol" over SPI is the following: > - write three bytes: > - 1 byte: [0:3] length of the payload, [6] Enable CRC, [7] Write > - 1 byte: LSB register address > - 1 byte: MSB register address > - write/read length of payload > > The CRC is always disabled for now. > > The RK806 technically supports I2C as well, and this should be able to > support it without any change, but it wasn't tested. > > The DT node name prefix for the buck converters has changed in the > Device Tree and is now dcdc-reg. The logic for buck converters is > however manageable within the current logic inside the rk8xx regulator > driver. The same cannot be said for the NLDO and PLDO. > > Because pmic_bind_children() parses the DT nodes and extracts the LDO > index from the DT node name, NLDO and PLDO will have overlapping > indices. Therefore, we need a separate logic from the already-existing > ldo callbacks. Let's reuse as much as possible though. > > Cc: Quentin Schulz <foss+uboot@0leil.net> > Signed-off-by: Quentin Schulz <quentin.schulz@theobroma-systems.com> Reviewed-by: Kever Yang <kever.yang@rock-chips.com> Thanks, - Kever > --- > drivers/power/pmic/rk8xx.c | 91 +++++++ > drivers/power/regulator/rk8xx.c | 514 +++++++++++++++++++++++++++++++++++++++- > include/power/rk8xx_pmic.h | 19 ++ > 3 files changed, 622 insertions(+), 2 deletions(-) > > diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c > index 4e3a17337ee..82b5e0cbe32 100644 > --- a/drivers/power/pmic/rk8xx.c > +++ b/drivers/power/pmic/rk8xx.c > @@ -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 { > + char len: 4; /* Payload size in bytes - 1 */ > + char reserved: 2; > + char crc_en: 1; > + char op: 1; /* READ=0; WRITE=1; */ > + char reg_l; > +#define REG_L_MASK GENMASK(7, 0) > + char 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" }, > diff --git a/drivers/power/regulator/rk8xx.c b/drivers/power/regulator/rk8xx.c > index 212bb752a76..1bd4605d43a 100644 > --- a/drivers/power/regulator/rk8xx.c > +++ b/drivers/power/regulator/rk8xx.c > @@ -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, > diff --git a/include/power/rk8xx_pmic.h b/include/power/rk8xx_pmic.h > index 0db82419d4f..31221aa46b6 100644 > --- a/include/power/rk8xx_pmic.h > +++ b/include/power/rk8xx_pmic.h > @@ -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 >
Hi Quentin, Â Â Â This patch build fail in CI: Building current source for 1 boards (1 thread, 32 jobs per thread) Â Â sandbox:Â +Â Â sandbox64 +drivers/power/pmic/rk8xx.c:141:10: error: implicit truncation from 'int' to a one-bit wide bit-field changes value from 1 to -1 [-Werror,-Wsingle-bit-bitfield-constant-conversion] +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â .op = 1, +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ^ +1 error generated. +make[4]: *** [scripts/Makefile.build:256: drivers/power/pmic/rk8xx.o] Error 1 +make[3]: *** [scripts/Makefile.build:397: drivers/power/pmic] Error 2 +make[2]: *** [scripts/Makefile.build:397: drivers/power] Error 2 +make[1]: *** [Makefile:1887: drivers] Error 2 +make: *** [Makefile:177: sub-make] Error 2 Â Â Â 0Â Â Â 0Â Â Â 1 /1Â Â Â Â Â Â Â Â Â Â Â Â Â sandbox64 Thanks, - Kever On 2024/3/4 19:29, Quentin Schulz wrote: > From: Quentin Schulz <quentin.schulz@theobroma-systems.com> > > This adds support for RK806, only the SPI variant has been tested. > > The communication "protocol" over SPI is the following: > - write three bytes: > - 1 byte: [0:3] length of the payload, [6] Enable CRC, [7] Write > - 1 byte: LSB register address > - 1 byte: MSB register address > - write/read length of payload > > The CRC is always disabled for now. > > The RK806 technically supports I2C as well, and this should be able to > support it without any change, but it wasn't tested. > > The DT node name prefix for the buck converters has changed in the > Device Tree and is now dcdc-reg. The logic for buck converters is > however manageable within the current logic inside the rk8xx regulator > driver. The same cannot be said for the NLDO and PLDO. > > Because pmic_bind_children() parses the DT nodes and extracts the LDO > index from the DT node name, NLDO and PLDO will have overlapping > indices. Therefore, we need a separate logic from the already-existing > ldo callbacks. Let's reuse as much as possible though. > > Cc: Quentin Schulz <foss+uboot@0leil.net> > Signed-off-by: Quentin Schulz <quentin.schulz@theobroma-systems.com> > --- > drivers/power/pmic/rk8xx.c | 91 +++++++ > drivers/power/regulator/rk8xx.c | 514 +++++++++++++++++++++++++++++++++++++++- > include/power/rk8xx_pmic.h | 19 ++ > 3 files changed, 622 insertions(+), 2 deletions(-) > > diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c > index 4e3a17337ee..82b5e0cbe32 100644 > --- a/drivers/power/pmic/rk8xx.c > +++ b/drivers/power/pmic/rk8xx.c > @@ -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 { > + char len: 4; /* Payload size in bytes - 1 */ > + char reserved: 2; > + char crc_en: 1; > + char op: 1; /* READ=0; WRITE=1; */ > + char reg_l; > +#define REG_L_MASK GENMASK(7, 0) > + char 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" }, > diff --git a/drivers/power/regulator/rk8xx.c b/drivers/power/regulator/rk8xx.c > index 212bb752a76..1bd4605d43a 100644 > --- a/drivers/power/regulator/rk8xx.c > +++ b/drivers/power/regulator/rk8xx.c > @@ -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, > diff --git a/include/power/rk8xx_pmic.h b/include/power/rk8xx_pmic.h > index 0db82419d4f..31221aa46b6 100644 > --- a/include/power/rk8xx_pmic.h > +++ b/include/power/rk8xx_pmic.h > @@ -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 >
diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c index 4e3a17337ee..82b5e0cbe32 100644 --- a/drivers/power/pmic/rk8xx.c +++ b/drivers/power/pmic/rk8xx.c @@ -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 { + char len: 4; /* Payload size in bytes - 1 */ + char reserved: 2; + char crc_en: 1; + char op: 1; /* READ=0; WRITE=1; */ + char reg_l; +#define REG_L_MASK GENMASK(7, 0) + char 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" }, diff --git a/drivers/power/regulator/rk8xx.c b/drivers/power/regulator/rk8xx.c index 212bb752a76..1bd4605d43a 100644 --- a/drivers/power/regulator/rk8xx.c +++ b/drivers/power/regulator/rk8xx.c @@ -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, diff --git a/include/power/rk8xx_pmic.h b/include/power/rk8xx_pmic.h index 0db82419d4f..31221aa46b6 100644 --- a/include/power/rk8xx_pmic.h +++ b/include/power/rk8xx_pmic.h @@ -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