[PATCH v2 05/16] power: rk8xx: add support for RK806
Jonas Karlman
jonas at kwiboo.se
Thu Feb 29 12:47:59 CET 2024
Hi Quentin,
On 2024-02-23 10:05, 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>
> ---
> 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]
More information about the U-Boot
mailing list