Hi Quentin, On 2024-02-23 10:05, Quentin Schulz wrote: > From: Quentin Schulz <quentin.sch...@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+ub...@0leil.net> > Signed-off-by: Quentin Schulz <quentin.sch...@theobroma-systems.com> > --- > drivers/power/pmic/rk8xx.c | 85 +++++++ > drivers/power/regulator/rk8xx.c | 514 > +++++++++++++++++++++++++++++++++++++++- > include/power/rk8xx_pmic.h | 19 ++ > 3 files changed, 616 insertions(+), 2 deletions(-) > > diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c > index 4e3a17337ee..15cb82029cc 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,47 @@ static int rk8xx_reg_count(struct udevice *dev) > return RK808_NUM_OF_REGS; > } > > +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) > +}; > + > static int rk8xx_write(struct udevice *dev, uint reg, const uint8_t *buff, > int len) > { > int ret; > > + 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);
I am getting following build error on PineTab2 [1] with this: aarch64-linux-gnu-ld.bfd: drivers/power/pmic/rk8xx.o: in function `rk8xx_write': drivers/power/pmic/rk8xx.c:144:(.text.rk8xx_write+0x60): undefined reference to `dm_spi_claim_bus' aarch64-linux-gnu-ld.bfd: drivers/power/pmic/rk8xx.c:150:(.text.rk8xx_write+0x84): undefined reference to `spi_write_then_read' aarch64-linux-gnu-ld.bfd: drivers/power/pmic/rk8xx.c:155:(.text.rk8xx_write+0x90): undefined reference to `dm_spi_release_bus' aarch64-linux-gnu-ld.bfd: drivers/power/pmic/rk8xx.o: in function `rk8xx_read': drivers/power/pmic/rk8xx.c:182:(.text.rk8xx_read+0x60): undefined reference to `dm_spi_claim_bus' aarch64-linux-gnu-ld.bfd: drivers/power/pmic/rk8xx.c:188:(.text.rk8xx_read+0x84): undefined reference to `spi_write_then_read' aarch64-linux-gnu-ld.bfd: drivers/power/pmic/rk8xx.c:193:(.text.rk8xx_read+0x90): undefined reference to `dm_spi_release_bus' make[2]: *** [scripts/Makefile.spl:527: spl/u-boot-spl] Error 1 make[1]: *** [Makefile:2055: spl/u-boot-spl] Error 2 On PineTab2 this driver is enabled in SPL and this build error happens because SPL_SPI and/or SPL_DM_SPI is not enabled. The RK8XX driver is enabled in SPL to be able to quickly power down the tablet if it was powered on because a power cable was connected. CONFIG_ROCKCHIP_RK8XX_DISABLE_BOOT_ON_POWERON=y CONFIG_SPL_I2C=y CONFIG_SPL_PMIC_RK8XX=y [1] https://patchwork.ozlabs.org/patch/1895031/ > + > + return ret; > + } > + > ret = dm_i2c_write(dev, reg, buff, len); > if (ret) { > debug("write error to device: %p register: %#x!\n", dev, reg); > @@ -120,6 +170,31 @@ static int rk8xx_read(struct udevice *dev, uint reg, > uint8_t *buff, int len) > { > int ret; > > + 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); Same build error here. Regards, Jonas > + > + return ret; > + } > + > ret = dm_i2c_read(dev, reg, buff, len); > if (ret) { > debug("read error from device: %p register: %#x!\n", dev, reg); > @@ -181,6 +256,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 +299,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 +347,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" }, [snip]