[PATCH v3 05/16] power: rk8xx: add support for RK806
Kever Yang
kever.yang at rock-chips.com
Mon Mar 11 11:12:04 CET 2024
On 2024/3/4 19:29, Quentin Schulz wrote:
> From: Quentin Schulz <quentin.schulz at 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 at 0leil.net>
> Signed-off-by: Quentin Schulz <quentin.schulz at theobroma-systems.com>
Reviewed-by: Kever Yang <kever.yang at 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
>
More information about the U-Boot
mailing list