diff --git a/sys/arm64/rockchip/rk805.c b/sys/arm64/rockchip/rk805.c index 19397627a8b0..d3e04081aeb2 100644 --- a/sys/arm64/rockchip/rk805.c +++ b/sys/arm64/rockchip/rk805.c @@ -1,741 +1,856 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include #include #include #include #include #include #include #include #include +#include "clock_if.h" #include "regdev_if.h" MALLOC_DEFINE(M_RK805_REG, "RK805 regulator", "RK805 power regulator"); /* #define dprintf(sc, format, arg...) device_printf(sc->base_dev, "%s: " format, __func__, arg) */ #define dprintf(sc, format, arg...) enum rk_pmic_type { RK805 = 1, RK808, }; static struct ofw_compat_data compat_data[] = { {"rockchip,rk805", RK805}, {"rockchip,rk808", RK808}, {NULL, 0} }; struct rk805_regdef { intptr_t id; char *name; uint8_t enable_reg; uint8_t enable_mask; uint8_t voltage_reg; uint8_t voltage_mask; int voltage_min; int voltage_max; int voltage_step; int voltage_nstep; }; struct rk805_reg_sc { struct regnode *regnode; device_t base_dev; struct rk805_regdef *def; phandle_t xref; struct regnode_std_param *param; }; struct reg_list { TAILQ_ENTRY(reg_list) next; struct rk805_reg_sc *reg; }; struct rk805_softc { device_t dev; struct mtx mtx; struct resource * res[1]; void * intrcookie; struct intr_config_hook intr_hook; enum rk_pmic_type type; TAILQ_HEAD(, reg_list) regs; int nregs; }; static int rk805_regnode_status(struct regnode *regnode, int *status); static int rk805_regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay); static int rk805_regnode_get_voltage(struct regnode *regnode, int *uvolt); static struct rk805_regdef rk805_regdefs[] = { { .id = RK805_DCDC1, .name = "DCDC_REG1", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x11, .voltage_reg = RK805_DCDC1_ON_VSEL, .voltage_mask = 0x3F, .voltage_min = 712500, .voltage_max = 1450000, .voltage_step = 12500, .voltage_nstep = 64, }, { .id = RK805_DCDC2, .name = "DCDC_REG2", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x22, .voltage_reg = RK805_DCDC2_ON_VSEL, .voltage_mask = 0x3F, .voltage_min = 712500, .voltage_max = 1450000, .voltage_step = 12500, .voltage_nstep = 64, }, { .id = RK805_DCDC3, .name = "DCDC_REG3", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x44, }, { .id = RK805_DCDC4, .name = "DCDC_REG4", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x88, .voltage_reg = RK805_DCDC4_ON_VSEL, .voltage_mask = 0x3F, .voltage_min = 800000, .voltage_max = 3500000, .voltage_step = 100000, .voltage_nstep = 28, }, { .id = RK805_LDO1, .name = "LDO_REG1", .enable_reg = RK805_LDO_EN, .enable_mask = 0x11, .voltage_reg = RK805_LDO1_ON_VSEL, .voltage_mask = 0x1F, .voltage_min = 800000, .voltage_max = 3400000, .voltage_step = 100000, .voltage_nstep = 27, }, { .id = RK805_LDO2, .name = "LDO_REG2", .enable_reg = RK805_LDO_EN, .enable_mask = 0x22, .voltage_reg = RK805_LDO2_ON_VSEL, .voltage_mask = 0x1F, .voltage_min = 800000, .voltage_max = 3400000, .voltage_step = 100000, .voltage_nstep = 27, }, { .id = RK805_LDO3, .name = "LDO_REG3", .enable_reg = RK805_LDO_EN, .enable_mask = 0x44, .voltage_reg = RK805_LDO3_ON_VSEL, .voltage_mask = 0x1F, .voltage_min = 800000, .voltage_max = 3400000, .voltage_step = 100000, .voltage_nstep = 27, }, }; static struct rk805_regdef rk808_regdefs[] = { { .id = RK805_DCDC1, .name = "DCDC_REG1", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x1, .voltage_reg = RK805_DCDC1_ON_VSEL, .voltage_mask = 0x3F, .voltage_min = 712500, .voltage_max = 1500000, .voltage_step = 12500, .voltage_nstep = 64, }, { .id = RK805_DCDC2, .name = "DCDC_REG2", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x2, .voltage_reg = RK805_DCDC2_ON_VSEL, .voltage_mask = 0x3F, .voltage_min = 712500, .voltage_max = 1500000, .voltage_step = 12500, .voltage_nstep = 64, }, { /* BUCK3 voltage is calculated based on external resistor */ .id = RK805_DCDC3, .name = "DCDC_REG3", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x4, }, { .id = RK805_DCDC4, .name = "DCDC_REG4", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x8, .voltage_reg = RK805_DCDC4_ON_VSEL, .voltage_mask = 0xF, .voltage_min = 1800000, .voltage_max = 3300000, .voltage_step = 100000, .voltage_nstep = 16, }, { .id = RK808_LDO1, .name = "LDO_REG1", .enable_reg = RK808_LDO_EN, .enable_mask = 0x1, .voltage_reg = RK805_LDO1_ON_VSEL, .voltage_mask = 0x1F, .voltage_min = 1800000, .voltage_max = 3400000, .voltage_step = 100000, .voltage_nstep = 17, }, { .id = RK808_LDO2, .name = "LDO_REG2", .enable_reg = RK808_LDO_EN, .enable_mask = 0x2, .voltage_reg = RK805_LDO2_ON_VSEL, .voltage_mask = 0x1F, .voltage_min = 1800000, .voltage_max = 3400000, .voltage_step = 100000, .voltage_nstep = 17, }, { .id = RK808_LDO3, .name = "LDO_REG3", .enable_reg = RK808_LDO_EN, .enable_mask = 0x4, .voltage_reg = RK805_LDO3_ON_VSEL, .voltage_mask = 0xF, .voltage_min = 800000, .voltage_max = 2500000, .voltage_step = 100000, .voltage_nstep = 18, }, { .id = RK808_LDO4, .name = "LDO_REG4", .enable_reg = RK808_LDO_EN, .enable_mask = 0x8, .voltage_reg = RK808_LDO4_ON_VSEL, .voltage_mask = 0x1F, .voltage_min = 1800000, .voltage_max = 3400000, .voltage_step = 100000, .voltage_nstep = 17, }, { .id = RK808_LDO5, .name = "LDO_REG5", .enable_reg = RK808_LDO_EN, .enable_mask = 0x10, .voltage_reg = RK808_LDO5_ON_VSEL, .voltage_mask = 0x1F, .voltage_min = 1800000, .voltage_max = 3400000, .voltage_step = 100000, .voltage_nstep = 17, }, { .id = RK808_LDO6, .name = "LDO_REG6", .enable_reg = RK808_LDO_EN, .enable_mask = 0x20, .voltage_reg = RK808_LDO6_ON_VSEL, .voltage_mask = 0x1F, .voltage_min = 800000, .voltage_max = 2500000, .voltage_step = 100000, .voltage_nstep = 18, }, { .id = RK808_LDO7, .name = "LDO_REG7", .enable_reg = RK808_LDO_EN, .enable_mask = 0x40, .voltage_reg = RK808_LDO7_ON_VSEL, .voltage_mask = 0x1F, .voltage_min = 800000, .voltage_max = 2500000, .voltage_step = 100000, .voltage_nstep = 18, }, { .id = RK808_LDO8, .name = "LDO_REG8", .enable_reg = RK808_LDO_EN, .enable_mask = 0x80, .voltage_reg = RK808_LDO8_ON_VSEL, .voltage_mask = 0x1F, .voltage_min = 1800000, .voltage_max = 3400000, .voltage_step = 100000, .voltage_nstep = 17, }, { .id = RK808_SWITCH1, .name = "SWITCH_REG1", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x20, .voltage_min = 3000000, .voltage_max = 3000000, }, { .id = RK808_SWITCH2, .name = "SWITCH_REG2", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x40, .voltage_min = 3000000, .voltage_max = 3000000, }, }; static int rk805_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size) { int err; err = iicdev_readfrom(dev, reg, data, size, IIC_INTRWAIT); return (err); } static int -rk805_write(device_t dev, uint8_t reg, uint8_t data) +rk805_write(device_t dev, uint8_t reg, uint8_t *data, uint8_t size) { - return (iicdev_writeto(dev, reg, &data, 1, IIC_INTRWAIT)); + return (iicdev_writeto(dev, reg, data, size, IIC_INTRWAIT)); } static int rk805_regnode_init(struct regnode *regnode) { struct rk805_reg_sc *sc; struct regnode_std_param *param; int rv, udelay, uvolt, status; sc = regnode_get_softc(regnode); dprintf(sc, "Regulator %s init called\n", sc->def->name); param = regnode_get_stdparam(regnode); if (param->min_uvolt == 0) return (0); /* Check that the regulator is preset to the correct voltage */ rv = rk805_regnode_get_voltage(regnode, &uvolt); if (rv != 0) return(rv); if (uvolt >= param->min_uvolt && uvolt <= param->max_uvolt) return(0); /* * Set the regulator at the correct voltage if it is not enabled. * Do not enable it, this is will be done either by a * consumer or by regnode_set_constraint if boot_on is true */ rv = rk805_regnode_status(regnode, &status); if (rv != 0 || status == REGULATOR_STATUS_ENABLED) return (rv); rv = rk805_regnode_set_voltage(regnode, param->min_uvolt, param->max_uvolt, &udelay); if (udelay != 0) DELAY(udelay); return (rv); } static int rk805_regnode_enable(struct regnode *regnode, bool enable, int *udelay) { struct rk805_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); dprintf(sc, "%sabling regulator %s\n", enable ? "En" : "Dis", sc->def->name); rk805_read(sc->base_dev, sc->def->enable_reg, &val, 1); if (enable) val |= sc->def->enable_mask; else val &= ~sc->def->enable_mask; - rk805_write(sc->base_dev, sc->def->enable_reg, val); + rk805_write(sc->base_dev, sc->def->enable_reg, &val, 1); *udelay = 0; return (0); } static void rk805_regnode_reg_to_voltage(struct rk805_reg_sc *sc, uint8_t val, int *uv) { if (val < sc->def->voltage_nstep) *uv = sc->def->voltage_min + val * sc->def->voltage_step; else *uv = sc->def->voltage_min + (sc->def->voltage_nstep * sc->def->voltage_step); } static int rk805_regnode_voltage_to_reg(struct rk805_reg_sc *sc, int min_uvolt, int max_uvolt, uint8_t *val) { uint8_t nval; int nstep, uvolt; nval = 0; uvolt = sc->def->voltage_min; for (nstep = 0; nstep < sc->def->voltage_nstep && uvolt < min_uvolt; nstep++) { ++nval; uvolt += sc->def->voltage_step; } if (uvolt > max_uvolt) return (EINVAL); *val = nval; return (0); } static int rk805_regnode_status(struct regnode *regnode, int *status) { struct rk805_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); *status = 0; rk805_read(sc->base_dev, sc->def->enable_reg, &val, 1); if (val & sc->def->enable_mask) *status = REGULATOR_STATUS_ENABLED; return (0); } static int rk805_regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay) { struct rk805_reg_sc *sc; uint8_t val; int uvolt; sc = regnode_get_softc(regnode); if (!sc->def->voltage_step) return (ENXIO); dprintf(sc, "Setting %s to %d<->%d uvolts\n", sc->def->name, min_uvolt, max_uvolt); rk805_read(sc->base_dev, sc->def->voltage_reg, &val, 1); if (rk805_regnode_voltage_to_reg(sc, min_uvolt, max_uvolt, &val) != 0) return (ERANGE); - rk805_write(sc->base_dev, sc->def->voltage_reg, val); + rk805_write(sc->base_dev, sc->def->voltage_reg, &val, 1); rk805_read(sc->base_dev, sc->def->voltage_reg, &val, 1); *udelay = 0; rk805_regnode_reg_to_voltage(sc, val, &uvolt); dprintf(sc, "Regulator %s set to %d uvolt\n", sc->def->name, uvolt); return (0); } static int rk805_regnode_get_voltage(struct regnode *regnode, int *uvolt) { struct rk805_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); if (sc->def->voltage_min == sc->def->voltage_max) { *uvolt = sc->def->voltage_min; return (0); } if (!sc->def->voltage_step) return (ENXIO); rk805_read(sc->base_dev, sc->def->voltage_reg, &val, 1); rk805_regnode_reg_to_voltage(sc, val & sc->def->voltage_mask, uvolt); dprintf(sc, "Regulator %s is at %d uvolt\n", sc->def->name, *uvolt); return (0); } static regnode_method_t rk805_regnode_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_init, rk805_regnode_init), REGNODEMETHOD(regnode_enable, rk805_regnode_enable), REGNODEMETHOD(regnode_status, rk805_regnode_status), REGNODEMETHOD(regnode_set_voltage, rk805_regnode_set_voltage), REGNODEMETHOD(regnode_get_voltage, rk805_regnode_get_voltage), REGNODEMETHOD(regnode_check_voltage, regnode_method_check_voltage), REGNODEMETHOD_END }; DEFINE_CLASS_1(rk805_regnode, rk805_regnode_class, rk805_regnode_methods, sizeof(struct rk805_reg_sc), regnode_class); static struct rk805_reg_sc * rk805_reg_attach(device_t dev, phandle_t node, struct rk805_regdef *def) { struct rk805_reg_sc *reg_sc; struct regnode_init_def initdef; struct regnode *regnode; memset(&initdef, 0, sizeof(initdef)); if (regulator_parse_ofw_stdparam(dev, node, &initdef) != 0) { device_printf(dev, "cannot create regulator\n"); return (NULL); } if (initdef.std_param.min_uvolt == 0) initdef.std_param.min_uvolt = def->voltage_min; if (initdef.std_param.max_uvolt == 0) initdef.std_param.max_uvolt = def->voltage_max; initdef.id = def->id; initdef.ofw_node = node; regnode = regnode_create(dev, &rk805_regnode_class, &initdef); if (regnode == NULL) { device_printf(dev, "cannot create regulator\n"); return (NULL); } reg_sc = regnode_get_softc(regnode); reg_sc->regnode = regnode; reg_sc->base_dev = dev; reg_sc->def = def; reg_sc->xref = OF_xref_from_node(node); reg_sc->param = regnode_get_stdparam(regnode); regnode_register(regnode); return (reg_sc); } static int rk805_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "RockChip RK805 PMIC"); return (BUS_PROBE_DEFAULT); } static void rk805_start(void *pdev) { struct rk805_softc *sc; device_t dev; uint8_t data[2]; int err; dev = pdev; sc = device_get_softc(dev); sc->dev = dev; /* No version register in RK808 */ if (bootverbose && sc->type == RK805) { err = rk805_read(dev, RK805_CHIP_NAME, data, 1); if (err != 0) { device_printf(dev, "Cannot read chip name reg\n"); return; } err = rk805_read(dev, RK805_CHIP_VER, data + 1, 1); if (err != 0) { device_printf(dev, "Cannot read chip version reg\n"); return; } device_printf(dev, "Chip Name: %x\n", data[0] << 4 | ((data[1] >> 4) & 0xf)); device_printf(dev, "Chip Version: %x\n", data[1] & 0xf); } + /* Register this as a 1Hz clock */ + clock_register(dev, 1000000); + config_intrhook_disestablish(&sc->intr_hook); } +static int +rk805_gettime(device_t dev, struct timespec *ts) +{ + struct bcd_clocktime bct; + uint8_t data[7]; + uint8_t ctrl; + int error; + + /* Latch the RTC value into the shadow registers and set 24hr mode */ + error = rk805_read(dev, RK805_RTC_CTRL, &ctrl, 1); + if (error != 0) + return (error); + + ctrl |= RK805_RTC_READSEL; + ctrl &= ~(RK805_RTC_AMPM_MODE | RK805_RTC_GET_TIME); + error = rk805_write(dev, RK805_RTC_CTRL, &ctrl, 1); + if (error != 0) + return (error); + ctrl |= RK805_RTC_GET_TIME; + error = rk805_write(dev, RK805_RTC_CTRL, &ctrl, 1); + if (error != 0) + return (error); + ctrl &= ~RK805_RTC_GET_TIME; + error = rk805_write(dev, RK805_RTC_CTRL, &ctrl, 1); + if (error != 0) + return (error); + + /* This works as long as RK805_RTC_SECS = 0 */ + error = rk805_read(dev, RK805_RTC_SECS, data, 7); + if (error != 0) + return (error); + + /* + * If the reported year is earlier than 2019, assume the clock is unset. + * This is both later than the reset value for the RK805 and RK808 as + * well as being prior to the current time. + */ + if (data[RK805_RTC_YEARS] < 0x19) + return (EINVAL); + + memset(&bct, 0, sizeof(bct)); + bct.year = data[RK805_RTC_YEARS]; + bct.mon = data[RK805_RTC_MONTHS] & RK805_RTC_MONTHS_MASK; + bct.day = data[RK805_RTC_DAYS] & RK805_RTC_DAYS_MASK; + bct.hour = data[RK805_RTC_HOURS] & RK805_RTC_HOURS_MASK; + bct.min = data[RK805_RTC_MINUTES] & RK805_RTC_MINUTES_MASK; + bct.sec = data[RK805_RTC_SECS] & RK805_RTC_SECS_MASK; + bct.dow = data[RK805_RTC_WEEKS] & RK805_RTC_WEEKS_MASK; + /* The day of week is reported as 1-7 with 1 = Monday */ + if (bct.dow == 7) + bct.dow = 0; + bct.ispm = 0; + + if (bootverbose) + device_printf(dev, "Read RTC: %02x-%02x-%02x %02x:%02x:%02x\n", + bct.year, bct.mon, bct.day, bct.hour, bct.min, bct.sec); + + return (clock_bcd_to_ts(&bct, ts, false)); +} + +static int +rk805_settime(device_t dev, struct timespec *ts) +{ + struct bcd_clocktime bct; + uint8_t data[7]; + int error; + uint8_t ctrl; + + clock_ts_to_bcd(ts, &bct, false); + + /* This works as long as RK805_RTC_SECS = 0 */ + data[RK805_RTC_YEARS] = bct.year; + data[RK805_RTC_MONTHS] = bct.mon; + data[RK805_RTC_DAYS] = bct.day; + data[RK805_RTC_HOURS] = bct.hour; + data[RK805_RTC_MINUTES] = bct.min; + data[RK805_RTC_SECS] = bct.sec; + data[RK805_RTC_WEEKS] = bct.dow; + /* The day of week is reported as 1-7 with 1 = Monday */ + if (data[RK805_RTC_WEEKS] == 0) + data[RK805_RTC_WEEKS] = 7; + + error = rk805_read(dev, RK805_RTC_CTRL, &ctrl, 1); + if (error != 0) + return (error); + + ctrl |= RK805_RTC_CTRL_STOP; + ctrl &= ~RK805_RTC_AMPM_MODE; + error = rk805_write(dev, RK805_RTC_CTRL, &ctrl, 1); + if (error != 0) + return (error); + + error = rk805_write(dev, RK805_RTC_SECS, data, 7); + ctrl &= ~RK805_RTC_CTRL_STOP; + rk805_write(dev, RK805_RTC_CTRL, &ctrl, 1); + + if (bootverbose) + device_printf(dev, + "Set RTC at %04x-%02x-%02x %02x:%02x:%02x[.%09ld]\n", + bct.year, bct.mon, bct.day, bct.hour, bct.min, bct.sec, + bct.nsec); + + return (error); +} + static int rk805_attach(device_t dev) { struct rk805_softc *sc; struct rk805_reg_sc *reg; struct rk805_regdef *regdefs; struct reg_list *regp; phandle_t rnode, child; int i; sc = device_get_softc(dev); sc->intr_hook.ich_func = rk805_start; sc->intr_hook.ich_arg = dev; if (config_intrhook_establish(&sc->intr_hook) != 0) return (ENOMEM); sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; switch (sc->type) { case RK805: regdefs = rk805_regdefs; sc->nregs = nitems(rk805_regdefs); break; case RK808: regdefs = rk808_regdefs; sc->nregs = nitems(rk808_regdefs); break; default: device_printf(dev, "Unknown type %d\n", sc->type); return (ENXIO); } TAILQ_INIT(&sc->regs); rnode = ofw_bus_find_child(ofw_bus_get_node(dev), "regulators"); if (rnode > 0) { for (i = 0; i < sc->nregs; i++) { child = ofw_bus_find_child(rnode, regdefs[i].name); if (child == 0) continue; if (OF_hasprop(child, "regulator-name") != 1) continue; reg = rk805_reg_attach(dev, child, ®defs[i]); if (reg == NULL) { device_printf(dev, "cannot attach regulator %s\n", regdefs[i].name); continue; } regp = malloc(sizeof(*regp), M_DEVBUF, M_WAITOK | M_ZERO); regp->reg = reg; TAILQ_INSERT_TAIL(&sc->regs, regp, next); if (bootverbose) device_printf(dev, "Regulator %s attached\n", regdefs[i].name); } } return (0); } static int rk805_detach(device_t dev) { /* We cannot detach regulators */ return (EBUSY); } static int rk805_map(device_t dev, phandle_t xref, int ncells, pcell_t *cells, intptr_t *id) { struct rk805_softc *sc; struct reg_list *regp; sc = device_get_softc(dev); TAILQ_FOREACH(regp, &sc->regs, next) { if (regp->reg->xref == xref) { *id = regp->reg->def->id; return (0); } } return (ERANGE); } static device_method_t rk805_methods[] = { DEVMETHOD(device_probe, rk805_probe), DEVMETHOD(device_attach, rk805_attach), DEVMETHOD(device_detach, rk805_detach), /* regdev interface */ DEVMETHOD(regdev_map, rk805_map), + + /* Clock interface */ + DEVMETHOD(clock_gettime, rk805_gettime), + DEVMETHOD(clock_settime, rk805_settime), + DEVMETHOD_END }; static driver_t rk805_driver = { "rk805_pmu", rk805_methods, sizeof(struct rk805_softc), }; static devclass_t rk805_devclass; EARLY_DRIVER_MODULE(rk805, iicbus, rk805_driver, rk805_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); MODULE_DEPEND(rk805, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); MODULE_VERSION(rk805, 1); diff --git a/sys/arm64/rockchip/rk805reg.h b/sys/arm64/rockchip/rk805reg.h index db489d77c26e..b1f4481a5b68 100644 --- a/sys/arm64/rockchip/rk805reg.h +++ b/sys/arm64/rockchip/rk805reg.h @@ -1,98 +1,123 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _RK805REG_H_ #define _RK805REG_H_ +/* + * The RTC registers are the same in both RK805 and RK808. + * Note that the code assumes that RK805_RTC_SECS is 0 + */ +#define RK805_RTC_SECS 0x00 +#define RK805_RTC_SECS_MASK 0x7f +#define RK805_RTC_MINUTES 0x01 +#define RK805_RTC_MINUTES_MASK 0x7f +#define RK805_RTC_HOURS 0x02 +#define RK805_RTC_HOURS_MASK 0x3f +#define RK805_RTC_HOURS_PM 0x80 +#define RK805_RTC_DAYS 0x03 +#define RK805_RTC_DAYS_MASK 0x3f +#define RK805_RTC_MONTHS 0x04 +#define RK805_RTC_MONTHS_MASK 0x1f +#define RK805_RTC_YEARS 0x05 +#define RK805_RTC_WEEKS 0x06 /* day of week */ +#define RK805_RTC_WEEKS_MASK 0x07 + +#define RK805_RTC_CTRL 0x10 +#define RK805_RTC_CTRL_STOP (1 << 0) +#define RK805_RTC_AMPM_MODE (1 << 3) +#define RK805_RTC_GET_TIME (1 << 6) +#define RK805_RTC_READSEL (1 << 7) + #define RK805_CHIP_NAME 0x17 #define RK805_CHIP_VER 0x18 #define RK805_OTP_VER 0x19 #define RK805_DCDC_EN 0x23 #define RK808_LDO_EN 0x24 #define RK805_SLEEP_DCDC_EN 0x25 #define RK805_SLEEP_LDO_EN 0x26 #define RK805_LDO_EN 0x27 #define RK805_SLEEP_LDO_LP_EN 0x2A #define RK805_DCDC1_CONFIG 0x2E #define RK805_DCDC1_ON_VSEL 0x2F #define RK805_DCDC1_SLEEP_VSEL 0x30 #define RK805_DCDC2_CONFIG 0x32 #define RK805_DCDC2_ON_VSEL 0x33 #define RK805_DCDC2_SLEEP_VSEL 0x34 #define RK805_DCDC3_CONFIG 0x36 #define RK805_DCDC4_CONFIG 0x37 #define RK805_DCDC4_ON_VSEL 0x38 #define RK805_DCDC4_SLEEP_VSEL 0x39 #define RK805_LDO1_ON_VSEL 0x3B #define RK805_LDO1_SLEEP_VSEL 0x3C #define RK805_LDO2_ON_VSEL 0x3D #define RK805_LDO2_SLEEP_VSEL 0x3E #define RK805_LDO3_ON_VSEL 0x3F #define RK805_LDO3_SLEEP_VSEL 0x40 #define RK808_LDO4_ON_VSEL 0x41 #define RK808_LDO4_SLEEP_VSEL 0x42 #define RK808_LDO5_ON_VSEL 0x43 #define RK808_LDO5_SLEEP_VSEL 0x44 #define RK808_LDO6_ON_VSEL 0x45 #define RK808_LDO6_SLEEP_VSEL 0x46 #define RK808_LDO7_ON_VSEL 0x47 #define RK808_LDO7_SLEEP_VSEL 0x48 #define RK808_LDO8_ON_VSEL 0x49 #define RK808_LDO8_SLEEP_VSEL 0x4A enum rk805_regulator { RK805_DCDC1 = 0, RK805_DCDC2, RK805_DCDC3, RK805_DCDC4, RK805_LDO1, RK805_LDO2, RK805_LDO3, }; enum rk808_regulator { RK808_DCDC1 = 0, RK808_DCDC2, RK808_DCDC3, RK808_DCDC4, RK808_LDO1, RK808_LDO2, RK808_LDO3, RK808_LDO4, RK808_LDO5, RK808_LDO6, RK808_LDO7, RK808_LDO8, RK808_SWITCH1, RK808_SWITCH2, }; #endif /* _RK805REG_H_ */