Index: rkpmic.c =================================================================== RCS file: /cvs/src/sys/dev/fdt/rkpmic.c,v retrieving revision 1.12 diff -u -p -r1.12 rkpmic.c --- rkpmic.c 12 Oct 2022 13:39:50 -0000 1.12 +++ rkpmic.c 6 Apr 2023 06:37:20 -0000 @@ -58,6 +58,12 @@ struct rkpmic_regdata { const struct rkpmic_vsel_range *vsel_range; }; +struct rkpmic_switch { + const char *name; + char *supply; + uint8_t reg, mask; +}; + /* * Used by RK805 for BUCK1, BUCK2 * 0-59: 0.7125V-1.45V, step=12.5mV @@ -227,6 +233,12 @@ const struct rkpmic_regdata rk809_regdat { } }; +const struct rkpmic_switch rk809_switches[] = { + { "SWITCH_REG1", "vcc9-supply", 0xb4, (1U << 2) }, + { "SWITCH_REG2", "vcc8-supply", 0xb4, (1U << 3) }, + { } +}; + /* * Used by RK817 for BOOST * 0-7: 4.7V-5.4V,step=100mV @@ -262,6 +274,7 @@ struct rkpmic_softc { int sc_rtc_ctrl_reg, sc_rtc_status_reg; struct todr_chip_handle sc_todr; const struct rkpmic_regdata *sc_regdata; + const struct rkpmic_switch *sc_switches; }; int rkpmic_match(struct device *, void *, void *); @@ -275,6 +288,7 @@ struct cfdriver rkpmic_cd = { NULL, "rkpmic", DV_DULL }; +int rkpmic_id(struct rkpmic_softc *, uint8_t, unsigned int); void rkpmic_attach_regulator(struct rkpmic_softc *, int); uint8_t rkpmic_reg_read(struct rkpmic_softc *, int); void rkpmic_reg_write(struct rkpmic_softc *, int, uint8_t); @@ -300,7 +314,8 @@ rkpmic_attach(struct device *parent, str struct rkpmic_softc *sc = (struct rkpmic_softc *)self; struct i2c_attach_args *ia = aux; int node = *(int *)ia->ia_cookie; - const char *chip; + unsigned int chip; + uint8_t chipreg; sc->sc_tag = ia->ia_tag; sc->sc_addr = ia->ia_addr; @@ -312,27 +327,41 @@ rkpmic_attach(struct device *parent, str todr_attach(&sc->sc_todr); if (OF_is_compatible(node, "rockchip,rk805")) { - chip = "RK805"; + chip = 0x805; + chipreg = 0x17; + sc->sc_rtc_ctrl_reg = RK805_RTC_CTRL; sc->sc_rtc_status_reg = RK805_RTC_STATUS; sc->sc_regdata = rk805_regdata; } else if (OF_is_compatible(node, "rockchip,rk808")) { - chip = "RK808"; + chip = 0x808; + chipreg = 0x17; + sc->sc_rtc_ctrl_reg = RK808_RTC_CTRL; sc->sc_rtc_status_reg = RK808_RTC_STATUS; sc->sc_regdata = rk808_regdata; } else if (OF_is_compatible(node, "rockchip,rk809")) { - chip = "RK809"; + chip = 0x809; + chipreg = 0xed; + sc->sc_rtc_ctrl_reg = RK809_RTC_CTRL; sc->sc_rtc_status_reg = RK809_RTC_STATUS; sc->sc_regdata = rk809_regdata; - } else { - chip = "RK817"; + sc->sc_switches = rk809_switches; + } else if (OF_is_compatible(node, "rockchip,rk817")) { + chip = 0x817; + chipreg = 0xed; + sc->sc_rtc_ctrl_reg = RK809_RTC_CTRL; sc->sc_rtc_status_reg = RK809_RTC_STATUS; sc->sc_regdata = rk817_regdata; + } else { + printf(": matched on unhandled device\n"); + return; } - printf(": %s\n", chip); + + if (rkpmic_id(sc, chipreg, chip) != 0) + return; node = OF_getnodebyname(node, "regulators"); if (node == 0) @@ -341,6 +370,34 @@ rkpmic_attach(struct device *parent, str rkpmic_attach_regulator(sc, node); } +int +rkpmic_id(struct rkpmic_softc *sc, uint8_t reg, unsigned int name) +{ + uint8_t chip_name_v[2]; + unsigned int chip_name, chip_v; + 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, + ®, sizeof(reg), chip_name_v, sizeof(chip_name_v), I2C_F_POLL); + iic_release_bus(sc->sc_tag, I2C_F_POLL); + if (error) { + printf(": can't read chip name and id (@%02x)\n", reg); + return (-1); + } + + chip_name = (chip_name_v[0] << 4) | (chip_name_v[1] >> 4); + if (chip_name != name) { + printf(": unexpected chip id %03x (!=%03x)\n", chip_name, name); + return (-1); + } + + chip_v = chip_name_v[1] & 0x0f; + printf(": RK%03x rev %u\n", chip_name, chip_v); + + return (0); +} + struct rkpmic_regulator { struct rkpmic_softc *rr_sc; @@ -353,6 +410,16 @@ struct rkpmic_regulator { uint32_t rkpmic_get_voltage(void *); int rkpmic_set_voltage(void *, uint32_t); +struct rkpmic_switch_regulator { + struct rkpmic_softc *sr_sc; + const struct rkpmic_switch *sr_sw; + struct regulator_device sr_rd; +}; + +void rkpmic_attach_switch(struct rkpmic_softc *, + const struct rkpmic_switch *, int); +uint32_t rkpmic_switch_get_voltage(void *); + void rkpmic_attach_regulator(struct rkpmic_softc *sc, int node) { @@ -367,8 +434,20 @@ rkpmic_attach_regulator(struct rkpmic_so if (strcmp(sc->sc_regdata[i].name, name) == 0) break; } - if (sc->sc_regdata[i].name == NULL) - return; + if (sc->sc_regdata[i].name == NULL) { + if (sc->sc_switches == NULL) + return; + for (i = 0; sc->sc_switches[i].name; i++) { + if (strcmp(sc->sc_switches[i].name, name) == 0) { + rkpmic_attach_switch(sc, + &sc->sc_switches[i], node); + return; + } + } + + if (sc->sc_switches[i].name == NULL) + return; + } rr = malloc(sizeof(*rr), M_DEVBUF, M_WAITOK | M_ZERO); rr->rr_sc = sc; @@ -452,6 +531,38 @@ rkpmic_set_voltage(void *cookie, uint32_ rkpmic_reg_write(rr->rr_sc, rr->rr_reg, reg); return 0; +} + +void +rkpmic_attach_switch(struct rkpmic_softc *sc, const struct rkpmic_switch *sw, + int node) +{ + struct rkpmic_switch_regulator *sr; + + sr = malloc(sizeof(*sr), M_DEVBUF, M_WAITOK | M_ZERO); + + /* XXX attach a notifier to the parent regulator */ + + sr->sr_sc = sc; + sr->sr_sw = sw; + + sr->sr_rd.rd_node = node; + sr->sr_rd.rd_cookie = sr; + sr->sr_rd.rd_get_voltage = rkpmic_switch_get_voltage; + /* XXX sr->sr_fd.rd_enable could flip the EN bit */ + regulator_register(&sr->sr_rd); +} + +uint32_t +rkpmic_switch_get_voltage(void *cookie) +{ + struct rkpmic_switch_regulator *sr = cookie; + uint32_t phandle; + + /* XXX read our EN bit and the parent state? */ + + phandle = OF_getpropint(sr->sr_rd.rd_node, sr->sr_sw->supply, 0); + return regulator_get_voltage(phandle); } int