From c23d9011ad4d0159a8e33f63bec23a4cc4aa8d4d Mon Sep 17 00:00:00 2001 From: kurt Date: Mon, 8 Mar 2021 12:53:35 +0000 Subject: [PATCH] Add support for rk809 as seen on the Rock Pi N10 with the rk3399pro. Add support for multiple linear ranges for voltage regulators and use for all rkpmic ICs. ok kettenis@ --- sys/dev/fdt/rkpmic.c | 319 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 262 insertions(+), 57 deletions(-) diff --git a/sys/dev/fdt/rkpmic.c b/sys/dev/fdt/rkpmic.c index fd4c8ed3038..3589f135138 100644 --- a/sys/dev/fdt/rkpmic.c +++ b/sys/dev/fdt/rkpmic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rkpmic.c,v 1.7 2020/11/12 10:47:07 patrick Exp $ */ +/* $OpenBSD: rkpmic.c,v 1.8 2021/03/08 12:53:35 kurt Exp $ */ /* * Copyright (c) 2017 Mark Kettenis * @@ -30,48 +30,202 @@ extern todr_chip_handle_t todr_handle; -#define RK808_SECONDS 0x00 -#define RK808_MINUTES 0x01 -#define RK808_HOURS 0x02 -#define RK808_DAYS 0x03 -#define RK808_MONTHS 0x04 -#define RK808_YEARS 0x05 -#define RK808_WEEKS 0x06 +#define RK80X_SECONDS 0x00 +#define RK80X_MINUTES 0x01 +#define RK80X_HOURS 0x02 +#define RK80X_DAYS 0x03 +#define RK80X_MONTHS 0x04 +#define RK80X_YEARS 0x05 +#define RK80X_WEEKS 0x06 +#define RK80X_NRTC_REGS 7 + +#define RK805_RTC_CTRL 0x10 #define RK808_RTC_CTRL 0x10 -#define RK808_RTC_CTRL_STOP_RTC 0x01 +#define RK809_RTC_CTRL 0x0d +#define RK80X_RTC_CTRL_STOP_RTC 0x01 + +#define RK805_RTC_STATUS 0x11 #define RK808_RTC_STATUS 0x11 -#define RK808_RTC_STATUS_POWER_UP 0x80 +#define RK809_RTC_STATUS 0x0e +#define RK80X_RTC_STATUS_POWER_UP 0x80 -#define RK808_NRTC_REGS 7 +struct rkpmic_vsel_range { + uint32_t base, delta; + uint8_t vsel_min, vsel_max; +}; struct rkpmic_regdata { const char *name; uint8_t reg, mask; - uint32_t base, delta; + struct rkpmic_vsel_range *vsel_range; +}; + +/* + * Used by RK805 for BUCK1, BUCK2 + * 0-59: 0.7125V-1.45V, step=12.5mV + * 60-62: 1.8V-2.2V, step=200mV + * 63: 2.3V + */ +struct rkpmic_vsel_range rk805_vsel_range1[] = { + { 712500, 12500, 0, 59 }, + { 1800000, 200000, 60, 62 }, + { 2300000, 0, 63, 63 }, + {} +}; + +/* + * Used by RK805 for BUCK4 + * 0-27: 0.8V-3.5V, step=100mV + */ +struct rkpmic_vsel_range rk805_vsel_range2[] = { + { 800000, 100000, 0, 27 }, + {} +}; + +/* + * Used by RK805 for LDO1-3 + * 0-26: 0.8V-3.4V, step=100mV + */ +struct rkpmic_vsel_range rk805_vsel_range3[] = { + { 800000, 100000, 0, 26 }, + {} }; struct rkpmic_regdata rk805_regdata[] = { - { "DCDC_REG1", 0x2f, 0x3f, 712500, 12500 }, - { "DCDC_REG2", 0x33, 0x3f, 712500, 12500 }, - { "DCDC_REG4", 0x38, 0x1f, 800000, 100000 }, - { "LDO_REG1", 0x3b, 0x1f, 800000, 100000 }, - { "LDO_REG2", 0x3d, 0x1f, 800000, 100000 }, - { "LDO_REG3", 0x3f, 0x1f, 800000, 100000 }, + { "DCDC_REG1", 0x2f, 0x3f, rk805_vsel_range1 }, + { "DCDC_REG2", 0x33, 0x3f, rk805_vsel_range1 }, + { "DCDC_REG4", 0x38, 0x1f, rk805_vsel_range2 }, + { "LDO_REG1", 0x3b, 0x1f, rk805_vsel_range3 }, + { "LDO_REG2", 0x3d, 0x1f, rk805_vsel_range3 }, + { "LDO_REG3", 0x3f, 0x1f, rk805_vsel_range3 }, { } }; +/* + * Used by RK808 for BUCK1 & BUCK2 + * 0-63: 0.7125V-1.5V, step=12.5mV + */ +struct rkpmic_vsel_range rk808_vsel_range1[] = { + { 712500, 12500, 0, 63 }, + {} +}; + +/* + * Used by RK808 for BUCK4 + * 0-15: 1.8V-3.3V,step=100mV + */ +struct rkpmic_vsel_range rk808_vsel_range2[] = { + { 1800000, 100000, 0, 15 }, + {} +}; + +/* + * Used by RK808 for LDO1-2, 4-5, 8 + * 0-16: 1.8V-3.4V, step=100mV + */ +struct rkpmic_vsel_range rk808_vsel_range3[] = { + { 1800000, 100000, 0, 16 }, + {} +}; + +/* + * Used by RK808 for LDO3 + * 0-12: 0.8V~2.0V, step=100mV + * 13: 2.2V + * 15: 2.5V + */ +struct rkpmic_vsel_range rk808_vsel_range4[] = { + { 800000, 100000, 0, 12 }, + { 2200000, 0, 13, 13 }, + { 2500000, 0, 15, 15 }, + {} +}; + +/* + * Used by RK808 for LDO6-7 + * 0-17: 0.8V-2.5V,step=100mV + */ +struct rkpmic_vsel_range rk808_vsel_range5[] = { + { 800000, 100000, 0, 17 }, + {} +}; + struct rkpmic_regdata rk808_regdata[] = { - { "DCDC_REG1", 0x2f, 0x3f, 712500, 12500 }, - { "DCDC_REG2", 0x33, 0x3f, 712500, 12500 }, - { "DCDC_REG4", 0x38, 0x0f, 1800000, 100000 }, - { "LDO_REG1", 0x3b, 0x1f, 1800000, 100000 }, - { "LDO_REG2", 0x3d, 0x1f, 1800000, 100000 }, - { "LDO_REG3", 0x3f, 0x0f, 800000, 100000 }, - { "LDO_REG4", 0x41, 0x1f, 1800000, 100000 }, - { "LDO_REG5", 0x43, 0x1f, 1800000, 100000 }, - { "LDO_REG6", 0x45, 0x1f, 800000, 100000 }, - { "LDO_REG7", 0x47, 0x1f, 800000, 100000 }, - { "LDO_REG8", 0x49, 0x1f, 1800000, 100000 }, + { "DCDC_REG1", 0x2f, 0x3f, rk808_vsel_range1 }, + { "DCDC_REG2", 0x33, 0x3f, rk808_vsel_range1 }, + { "DCDC_REG4", 0x38, 0x0f, rk808_vsel_range2 }, + { "LDO_REG1", 0x3b, 0x1f, rk808_vsel_range3 }, + { "LDO_REG2", 0x3d, 0x1f, rk808_vsel_range3 }, + { "LDO_REG3", 0x3f, 0x0f, rk808_vsel_range4 }, + { "LDO_REG4", 0x41, 0x1f, rk808_vsel_range3 }, + { "LDO_REG5", 0x43, 0x1f, rk808_vsel_range3 }, + { "LDO_REG6", 0x45, 0x1f, rk808_vsel_range5 }, + { "LDO_REG7", 0x47, 0x1f, rk808_vsel_range5 }, + { "LDO_REG8", 0x49, 0x1f, rk808_vsel_range3 }, + { } +}; + +/* + * Used by RK809 for BUCK1-3 + * 0-80: 0.5V-1.5V,step=12.5mV + * 81-89: 1.6V-2.4V,step=100mV + */ +struct rkpmic_vsel_range rk809_vsel_range1[] = { + { 500000, 12500, 0, 80 }, + { 1600000, 100000, 81, 89 }, + {} +}; + +/* + * Used by RK809 for BUCK4 + * 0-80: 0.5V-1.5V,step=12.5mV + * 81-99: 1.6V-3.4V,step=100mV + */ +struct rkpmic_vsel_range rk809_vsel_range2[] = { + { 500000, 12500, 0, 80 }, + { 1600000, 100000, 81, 99 }, + {} +}; + +/* + * Used by RK809 for BUCK5 + * 0: 1.5V + * 1-3: 1.8V-2.2V,step=200mV + * 4-5: 2.8V-3.0V,step=200mV + * 6-7: 3.3V-3.6V,step=300mV + */ +struct rkpmic_vsel_range rk809_vsel_range3[] = { + { 1500000, 0, 0, 0 }, + { 1800000, 200000, 1, 3 }, + { 2800000, 200000, 4, 5 }, + { 3300000, 300000, 6, 7 }, + {} +}; + +/* + * Used by RK809 for LDO1-7 + * 0-112: 0.6V-3.4V,step=25mV + */ +struct rkpmic_vsel_range rk809_vsel_range4[] = { + { 600000, 25000, 0, 112 }, + {} +}; + +struct rkpmic_regdata rk809_regdata[] = { + { "DCDC_REG1", 0xbb, 0x7f, rk809_vsel_range1 }, + { "DCDC_REG2", 0xbe, 0x7f, rk809_vsel_range1 }, + { "DCDC_REG3", 0xc1, 0x7f, rk809_vsel_range1 }, + { "DCDC_REG4", 0xc4, 0x7f, rk809_vsel_range2 }, + { "DCDC_REG5", 0xde, 0x0f, rk809_vsel_range3}, + { "LDO_REG1", 0xcc, 0x7f, rk809_vsel_range4 }, + { "LDO_REG2", 0xce, 0x7f, rk809_vsel_range4 }, + { "LDO_REG3", 0xd0, 0x7f, rk809_vsel_range4 }, + { "LDO_REG4", 0xd2, 0x7f, rk809_vsel_range4 }, + { "LDO_REG5", 0xd4, 0x7f, rk809_vsel_range4 }, + { "LDO_REG6", 0xd6, 0x7f, rk809_vsel_range4 }, + { "LDO_REG7", 0xd8, 0x7f, rk809_vsel_range4 }, + { "LDO_REG8", 0xda, 0x7f, rk809_vsel_range4 }, + { "LDO_REG9", 0xdc, 0x7f, rk809_vsel_range4 }, { } }; @@ -80,6 +234,7 @@ struct rkpmic_softc { i2c_tag_t sc_tag; i2c_addr_t sc_addr; + int sc_rtc_ctrl_reg, sc_rtc_status_reg; struct todr_chip_handle sc_todr; struct rkpmic_regdata *sc_regdata; }; @@ -109,7 +264,8 @@ rkpmic_match(struct device *parent, void *match, void *aux) struct i2c_attach_args *ia = aux; return (strcmp(ia->ia_name, "rockchip,rk805") == 0 || - strcmp(ia->ia_name, "rockchip,rk808") == 0); + strcmp(ia->ia_name, "rockchip,rk808") == 0 || + strcmp(ia->ia_name, "rockchip,rk809") == 0); } void @@ -131,10 +287,19 @@ rkpmic_attach(struct device *parent, struct device *self, void *aux) if (OF_is_compatible(node, "rockchip,rk805")) { chip = "RK805"; + sc->sc_rtc_ctrl_reg = RK805_RTC_CTRL; + sc->sc_rtc_status_reg = RK805_RTC_STATUS; sc->sc_regdata = rk805_regdata; - } else { + } else if (OF_is_compatible(node, "rockchip,rk808")) { chip = "RK808"; + sc->sc_rtc_ctrl_reg = RK808_RTC_CTRL; + sc->sc_rtc_status_reg = RK808_RTC_STATUS; sc->sc_regdata = rk808_regdata; + } else { + chip = "RK809"; + sc->sc_rtc_ctrl_reg = RK809_RTC_CTRL; + sc->sc_rtc_status_reg = RK809_RTC_STATUS; + sc->sc_regdata = rk809_regdata; } printf(": %s\n", chip); @@ -149,7 +314,7 @@ struct rkpmic_regulator { struct rkpmic_softc *rr_sc; uint8_t rr_reg, rr_mask; - uint32_t rr_base, rr_delta; + struct rkpmic_vsel_range *rr_vsel_range; struct regulator_device rr_rd; }; @@ -179,8 +344,7 @@ rkpmic_attach_regulator(struct rkpmic_softc *sc, int node) rr->rr_reg = sc->sc_regdata[i].reg; rr->rr_mask = sc->sc_regdata[i].mask; - rr->rr_base = sc->sc_regdata[i].base; - rr->rr_delta = sc->sc_regdata[i].delta; + rr->rr_vsel_range = sc->sc_regdata[i].vsel_range; rr->rr_rd.rd_node = node; rr->rr_rd.rd_cookie = rr; @@ -193,27 +357,68 @@ uint32_t rkpmic_get_voltage(void *cookie) { struct rkpmic_regulator *rr = cookie; + struct rkpmic_vsel_range *vsel_range = rr->rr_vsel_range; uint8_t vsel; + uint32_t ret = 0; + + vsel = rkpmic_reg_read(rr->rr_sc, rr->rr_reg) & rr->rr_mask; - vsel = rkpmic_reg_read(rr->rr_sc, rr->rr_reg); - return rr->rr_base + (vsel & rr->rr_mask) * rr->rr_delta; + while (vsel_range->base) { + ret = vsel_range->base; + if (vsel >= vsel_range->vsel_min && + vsel <= vsel_range->vsel_max) { + ret += (vsel - vsel_range->vsel_min) * + vsel_range->delta; + break; + } else + ret += (vsel_range->vsel_max - vsel_range->vsel_min) * + vsel_range->delta; + vsel_range++; + + } + + return ret; } int rkpmic_set_voltage(void *cookie, uint32_t voltage) { struct rkpmic_regulator *rr = cookie; - uint32_t vmin = rr->rr_base; - uint32_t vmax = vmin + rr->rr_mask * rr->rr_delta; - uint8_t vsel; + struct rkpmic_vsel_range *vsel_range = rr->rr_vsel_range; + uint32_t vmin, vmax, volt; + uint8_t reg, vsel; + + while (vsel_range->base) { + vmin = vsel_range->base; + vmax = vmin + (vsel_range->vsel_max - vsel_range->vsel_min) * + vsel_range->delta; + if (voltage < vmin) + return EINVAL; + if (voltage <= vmax) { + vsel = vsel_range->vsel_min; + volt = vsel_range->base; + while (vsel <= vsel_range->vsel_max) { + if (volt == voltage) + break; + else { + vsel++; + volt += vsel_range->delta; + } + } + if (volt != voltage) + return EINVAL; + break; + } + vsel_range++; + } - if (voltage < vmin || voltage > vmax) + if (vsel_range->base == 0) return EINVAL; - vsel = rkpmic_reg_read(rr->rr_sc, rr->rr_reg); - vsel &= ~rr->rr_mask; - vsel |= (voltage - rr->rr_base) / rr->rr_delta; - rkpmic_reg_write(rr->rr_sc, rr->rr_reg, vsel); + reg = rkpmic_reg_read(rr->rr_sc, rr->rr_reg); + reg &= ~rr->rr_mask; + reg |= vsel; + rkpmic_reg_write(rr->rr_sc, rr->rr_reg, reg); return 0; } @@ -319,14 +524,14 @@ rkpmic_reg_write(struct rkpmic_softc *sc, int reg, uint8_t val) int rkpmic_clock_read(struct rkpmic_softc *sc, struct clock_ymdhms *dt) { - uint8_t regs[RK808_NRTC_REGS]; - uint8_t cmd = RK808_SECONDS; + uint8_t regs[RK80X_NRTC_REGS]; + uint8_t cmd = RK80X_SECONDS; uint8_t status; int error; iic_acquire_bus(sc->sc_tag, I2C_F_POLL); error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, - &cmd, sizeof(cmd), regs, RK808_NRTC_REGS, I2C_F_POLL); + &cmd, sizeof(cmd), regs, RK80X_NRTC_REGS, I2C_F_POLL); iic_release_bus(sc->sc_tag, I2C_F_POLL); if (error) { @@ -335,7 +540,7 @@ rkpmic_clock_read(struct rkpmic_softc *sc, struct clock_ymdhms *dt) } /* - * Convert the RK808's register values into something useable. + * Convert the RK80x's register values into something useable. */ dt->dt_sec = FROMBCD(regs[0]); dt->dt_min = FROMBCD(regs[1]); @@ -345,8 +550,8 @@ rkpmic_clock_read(struct rkpmic_softc *sc, struct clock_ymdhms *dt) dt->dt_year = FROMBCD(regs[5]) + 2000; /* Consider the time to be invalid if the POWER_UP bit is set. */ - status = rkpmic_reg_read(sc, RK808_RTC_STATUS); - if (status & RK808_RTC_STATUS_POWER_UP) + status = rkpmic_reg_read(sc, sc->sc_rtc_status_reg); + if (status & RK80X_RTC_STATUS_POWER_UP) return EINVAL; return 0; @@ -355,12 +560,12 @@ rkpmic_clock_read(struct rkpmic_softc *sc, struct clock_ymdhms *dt) int rkpmic_clock_write(struct rkpmic_softc *sc, struct clock_ymdhms *dt) { - uint8_t regs[RK808_NRTC_REGS]; - uint8_t cmd = RK808_SECONDS; + uint8_t regs[RK80X_NRTC_REGS]; + uint8_t cmd = RK80X_SECONDS; int error; /* - * Convert our time representation into something the RK808 + * Convert our time representation into something the RK80x * can understand. */ regs[0] = TOBCD(dt->dt_sec); @@ -372,15 +577,15 @@ rkpmic_clock_write(struct rkpmic_softc *sc, struct clock_ymdhms *dt) regs[6] = TOBCD(dt->dt_wday); /* Stop RTC such that we can write to it. */ - rkpmic_reg_write(sc, RK808_RTC_CTRL, RK808_RTC_CTRL_STOP_RTC); + rkpmic_reg_write(sc, sc->sc_rtc_ctrl_reg, RK80X_RTC_CTRL_STOP_RTC); iic_acquire_bus(sc->sc_tag, I2C_F_POLL); error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, - &cmd, sizeof(cmd), regs, RK808_NRTC_REGS, I2C_F_POLL); + &cmd, sizeof(cmd), regs, RK80X_NRTC_REGS, I2C_F_POLL); iic_release_bus(sc->sc_tag, I2C_F_POLL); /* Restart RTC. */ - rkpmic_reg_write(sc, RK808_RTC_CTRL, 0); + rkpmic_reg_write(sc, sc->sc_rtc_ctrl_reg, 0); if (error) { printf("%s: can't write RTC\n", sc->sc_dev.dv_xname); @@ -388,7 +593,7 @@ rkpmic_clock_write(struct rkpmic_softc *sc, struct clock_ymdhms *dt) } /* Clear POWER_UP bit to indicate the time is now valid. */ - rkpmic_reg_write(sc, RK808_RTC_STATUS, RK808_RTC_STATUS_POWER_UP); + rkpmic_reg_write(sc, sc->sc_rtc_status_reg, RK80X_RTC_STATUS_POWER_UP); return 0; } -- 2.20.1