diff --git a/sys/dev/iicbus/pmic/rockchip/rk805.c b/sys/dev/iicbus/pmic/rockchip/rk805.c index e8752a3a7bef..b3182d4909a6 100644 --- a/sys/dev/iicbus/pmic/rockchip/rk805.c +++ b/sys/dev/iicbus/pmic/rockchip/rk805.c @@ -1,200 +1,202 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018-2021 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 #include static struct ofw_compat_data compat_data[] = { {"rockchip,rk805", RK805}, {NULL, 0} }; static struct rk8xx_regdef rk805_regdefs[] = { { .id = RK805_BUCK1, .name = "DCDC_REG1", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x11, .voltage_reg = RK805_BUCK1_ON_VSEL, .voltage_mask = 0x3F, .voltage_min = 712500, .voltage_max = 1450000, .voltage_step = 12500, .voltage_nstep = 64, }, { .id = RK805_BUCK2, .name = "DCDC_REG2", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x22, .voltage_reg = RK805_BUCK2_ON_VSEL, .voltage_mask = 0x3F, .voltage_min = 712500, .voltage_max = 1450000, .voltage_step = 12500, .voltage_nstep = 64, }, { .id = RK805_BUCK3, .name = "DCDC_REG3", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x44, }, { .id = RK805_BUCK4, .name = "DCDC_REG4", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x88, .voltage_reg = RK805_BUCK4_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 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 int rk805_attach(device_t dev) { struct rk8xx_softc *sc; sc = device_get_softc(dev); sc->dev = dev; sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; sc->regdefs = rk805_regdefs; sc->nregs = nitems(rk805_regdefs); sc->rtc_regs.secs = RK805_RTC_SECS; sc->rtc_regs.secs_mask = RK805_RTC_SECS_MASK; sc->rtc_regs.minutes = RK805_RTC_MINUTES; sc->rtc_regs.minutes_mask = RK805_RTC_MINUTES_MASK; sc->rtc_regs.hours = RK805_RTC_HOURS; sc->rtc_regs.hours_mask = RK805_RTC_HOURS_MASK; sc->rtc_regs.days = RK805_RTC_DAYS; sc->rtc_regs.days_mask = RK805_RTC_DAYS_MASK; sc->rtc_regs.months = RK805_RTC_MONTHS; sc->rtc_regs.months_mask = RK805_RTC_MONTHS_MASK; sc->rtc_regs.years = RK805_RTC_YEARS; sc->rtc_regs.weeks = RK805_RTC_WEEKS_MASK; sc->rtc_regs.ctrl = RK805_RTC_CTRL; sc->rtc_regs.ctrl_stop_mask = RK805_RTC_CTRL_STOP; sc->rtc_regs.ctrl_ampm_mask = RK805_RTC_AMPM_MODE; sc->rtc_regs.ctrl_gettime_mask = RK805_RTC_GET_TIME; sc->rtc_regs.ctrl_readsel_mask = RK805_RTC_READSEL; + sc->dev_ctrl.dev_ctrl_reg = RK805_DEV_CTRL; + sc->dev_ctrl.pwr_off_mask = RK805_DEV_CTRL_OFF; return (rk8xx_attach(sc)); } static device_method_t rk805_methods[] = { DEVMETHOD(device_probe, rk805_probe), DEVMETHOD(device_attach, rk805_attach), DEVMETHOD_END }; DEFINE_CLASS_1(rk805_pmu, rk805_driver, rk805_methods, sizeof(struct rk8xx_softc), rk8xx_driver); static devclass_t rk805_devclass; EARLY_DRIVER_MODULE(rk805_pmu, iicbus, rk805_driver, rk805_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); EARLY_DRIVER_MODULE(iicbus, rk805_pmu, iicbus_driver, iicbus_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); MODULE_DEPEND(rk805_pmu, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); MODULE_VERSION(rk805_pmu, 1); diff --git a/sys/dev/iicbus/pmic/rockchip/rk808.c b/sys/dev/iicbus/pmic/rockchip/rk808.c index 34d1884db088..b9214fc74b61 100644 --- a/sys/dev/iicbus/pmic/rockchip/rk808.c +++ b/sys/dev/iicbus/pmic/rockchip/rk808.c @@ -1,275 +1,277 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018-2021 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 static struct ofw_compat_data compat_data[] = { {"rockchip,rk808", RK808}, {NULL, 0} }; static struct rk8xx_regdef rk808_regdefs[] = { { .id = RK808_BUCK1, .name = "DCDC_REG1", .enable_reg = RK808_DCDC_EN, .enable_mask = 0x1, .voltage_reg = RK808_BUCK1_ON_VSEL, .voltage_mask = 0x3F, .voltage_min = 712500, .voltage_max = 1500000, .voltage_step = 12500, .voltage_nstep = 64, }, { .id = RK808_BUCK2, .name = "DCDC_REG2", .enable_reg = RK808_DCDC_EN, .enable_mask = 0x2, .voltage_reg = RK808_BUCK2_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 = RK808_BUCK3, .name = "DCDC_REG3", .enable_reg = RK808_DCDC_EN, .enable_mask = 0x4, }, { .id = RK808_BUCK4, .name = "DCDC_REG4", .enable_reg = RK808_DCDC_EN, .enable_mask = 0x8, .voltage_reg = RK808_BUCK4_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 = RK808_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 = RK808_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 = RK808_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 = RK808_DCDC_EN, .enable_mask = 0x20, .voltage_min = 3000000, .voltage_max = 3000000, }, { .id = RK808_SWITCH2, .name = "SWITCH_REG2", .enable_reg = RK808_DCDC_EN, .enable_mask = 0x40, .voltage_min = 3000000, .voltage_max = 3000000, }, }; static int rk808_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 RK808 PMIC"); return (BUS_PROBE_DEFAULT); } static int rk808_attach(device_t dev) { struct rk8xx_softc *sc; sc = device_get_softc(dev); sc->dev = dev; sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; sc->regdefs = rk808_regdefs; sc->nregs = nitems(rk808_regdefs); sc->rtc_regs.secs = RK808_RTC_SECS; sc->rtc_regs.secs_mask = RK808_RTC_SECS_MASK; sc->rtc_regs.minutes = RK808_RTC_MINUTES; sc->rtc_regs.minutes_mask = RK808_RTC_MINUTES_MASK; sc->rtc_regs.hours = RK808_RTC_HOURS; sc->rtc_regs.hours_mask = RK808_RTC_HOURS_MASK; sc->rtc_regs.days = RK808_RTC_DAYS; sc->rtc_regs.days_mask = RK808_RTC_DAYS_MASK; sc->rtc_regs.months = RK808_RTC_MONTHS; sc->rtc_regs.months_mask = RK808_RTC_MONTHS_MASK; sc->rtc_regs.years = RK808_RTC_YEARS; sc->rtc_regs.weeks = RK808_RTC_WEEKS_MASK; sc->rtc_regs.ctrl = RK808_RTC_CTRL; sc->rtc_regs.ctrl_stop_mask = RK808_RTC_CTRL_STOP; sc->rtc_regs.ctrl_ampm_mask = RK808_RTC_AMPM_MODE; sc->rtc_regs.ctrl_gettime_mask = RK808_RTC_GET_TIME; sc->rtc_regs.ctrl_readsel_mask = RK808_RTC_READSEL; + sc->dev_ctrl.dev_ctrl_reg = RK808_DEV_CTRL; + sc->dev_ctrl.pwr_off_mask = RK808_DEV_CTRL_OFF; return (rk8xx_attach(sc)); } static device_method_t rk808_methods[] = { DEVMETHOD(device_probe, rk808_probe), DEVMETHOD(device_attach, rk808_attach), DEVMETHOD_END }; DEFINE_CLASS_1(rk808_pmu, rk808_driver, rk808_methods, sizeof(struct rk8xx_softc), rk8xx_driver); static devclass_t rk808_devclass; EARLY_DRIVER_MODULE(rk808_pmu, iicbus, rk808_driver, rk808_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); EARLY_DRIVER_MODULE(iicbus, rk808_pmu, iicbus_driver, iicbus_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); MODULE_DEPEND(rk808_pmu, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); MODULE_VERSION(rk808_pmu, 1); diff --git a/sys/dev/iicbus/pmic/rockchip/rk808reg.h b/sys/dev/iicbus/pmic/rockchip/rk808reg.h index 054cac45f1d6..444b1fded12e 100644 --- a/sys/dev/iicbus/pmic/rockchip/rk808reg.h +++ b/sys/dev/iicbus/pmic/rockchip/rk808reg.h @@ -1,127 +1,131 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018-2021 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 _RK808REG_H_ #define _RK808REG_H_ /* RTC registers */ #define RK808_RTC_SECS 0x00 #define RK808_RTC_SECS_MASK 0x7f #define RK808_RTC_MINUTES 0x01 #define RK808_RTC_MINUTES_MASK 0x7f #define RK808_RTC_HOURS 0x02 #define RK808_RTC_HOURS_MASK 0x3f #define RK808_RTC_DAYS 0x03 #define RK808_RTC_DAYS_MASK 0x3f #define RK808_RTC_MONTHS 0x04 #define RK808_RTC_MONTHS_MASK 0x1f #define RK808_RTC_YEARS 0x05 #define RK808_RTC_WEEKS 0x06 /* day of week */ #define RK808_RTC_WEEKS_MASK 0x07 #define RK808_ALARM_SECONDS 0x8 #define RK808_ALARM_MINUTES 0x9 #define RK808_ALARM_HOURS 0xA #define RK808_ALARM_DAYS 0xB #define RK808_ALARM_MONTHS 0xC #define RK808_ALARM_YEARS 0xD #define RK808_RTC_CTRL 0x10 #define RK808_RTC_CTRL_STOP (1 << 0) #define RK808_RTC_AMPM_MODE (1 << 3) #define RK808_RTC_GET_TIME (1 << 6) #define RK808_RTC_READSEL (1 << 7) #define RK808_RTC_STATUS 0x11 #define RK808_RTC_INT 0x12 #define RK808_RTC_COMP_LSB 0x13 #define RK808_RTC_COMP_MSB 0x14 /* Misc registers*/ #define RK808_CLK32KOUT 0x20 #define RK808_VB_MON 0x21 #define RK808_THERMAL 0x22 /* Power channel control and monitoring registers */ #define RK808_DCDC_EN 0x23 #define RK808_LDO_EN 0x24 #define RK808_SLEEP_SET_OFF_1 0x25 #define RK808_SLEEP_SET_OFF_2 0x26 #define RK808_DCDC_UV_STS 0x27 #define RK808_DCDC_UV_ACT 0x28 #define RK808_LDO_UV_STS 0x29 #define RK808_LDO_UV_ACT 0x2A #define RK808_DCDC_PG 0x2B #define RK808_LDO_PG 0x2C #define RK808_VOUT_MON_TDB 0x2D /* Power channel configuration registers */ #define RK808_BUCK1_CONFIG 0x2E #define RK808_BUCK1_ON_VSEL 0x2F #define RK808_BUCK1_SLP_VSEL 0x30 #define RK808_BUCK2_CONFIG 0x32 #define RK808_BUCK2_ON_VSEL 0x33 #define RK808_BUCK2_SLEEP_VSEL 0x34 #define RK808_BUCK3_CONFIG 0x36 #define RK808_BUCK4_CONFIG 0x37 #define RK808_BUCK4_ON_VSEL 0x38 #define RK808_BUCK4_SLEEP_VSEL 0x39 #define RK808_DCDC_ILMAX_REG 0x90 #define RK808_LDO1_ON_VSEL 0x3B #define RK808_LDO1_SLEEP_VSEL 0x3C #define RK808_LDO2_ON_VSEL 0x3D #define RK808_LDO2_SLEEP_VSEL 0x3E #define RK808_LDO3_ON_VSEL 0x3F #define RK808_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 +#define RK808_DEV_CTRL 0x4B +#define RK808_DEV_CTRL_OFF (1 << 0) +#define RK808_DEV_CTRL_SLP (1 << 1) + enum rk808_regulator { RK808_BUCK1 = 0, RK808_BUCK2, RK808_BUCK3, RK808_BUCK4, RK808_LDO1, RK808_LDO2, RK808_LDO3, RK808_LDO4, RK808_LDO5, RK808_LDO6, RK808_LDO7, RK808_LDO8, RK808_SWITCH1, RK808_SWITCH2, }; #endif /* _RK808REG_H_ */ diff --git a/sys/dev/iicbus/pmic/rockchip/rk8xx.c b/sys/dev/iicbus/pmic/rockchip/rk8xx.c index 46f9ed24ca39..0e6839ff0152 100644 --- a/sys/dev/iicbus/pmic/rockchip/rk8xx.c +++ b/sys/dev/iicbus/pmic/rockchip/rk8xx.c @@ -1,145 +1,181 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018-2021 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 #include #include #include "clock_if.h" #include "regdev_if.h" int rk8xx_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); } int rk8xx_write(device_t dev, uint8_t reg, uint8_t *data, uint8_t size) { return (iicdev_writeto(dev, reg, data, size, IIC_INTRWAIT)); } static void rk8xx_start(void *pdev) { struct rk8xx_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 = rk8xx_read(dev, RK805_CHIP_NAME, data, 1); if (err != 0) { device_printf(dev, "Cannot read chip name reg\n"); return; } err = rk8xx_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 void +rk8xx_poweroff(void *arg, int howto) +{ + struct rk8xx_softc *sc = arg; + int error; + uint8_t val; + + if ((howto & RB_POWEROFF) == 0) + return; + + device_printf(sc->dev, "Powering off...\n"); + error = rk8xx_read(sc->dev, sc->dev_ctrl.dev_ctrl_reg, &val, 1); + if (error == 0) { + val |= sc->dev_ctrl.pwr_off_mask; + error = rk8xx_write(sc->dev, sc->dev_ctrl.dev_ctrl_reg, + &val, 1); + + /* Wait a bit for the command to take effect. */ + if (error == 0) + DELAY(100); + } + device_printf(sc->dev, "Power off failed\n"); +} + int rk8xx_attach(struct rk8xx_softc *sc) { int error; error = rk8xx_attach_clocks(sc); if (error != 0) return (error); sc->intr_hook.ich_func = rk8xx_start; sc->intr_hook.ich_arg = sc->dev; if (config_intrhook_establish(&sc->intr_hook) != 0) return (ENOMEM); rk8xx_attach_regulators(sc); + if (OF_hasprop(ofw_bus_get_node(sc->dev), + "rockchip,system-power-controller")) { + /* + * The priority is chosen to override PSCI and EFI shutdown + * methods as those two just hang without powering off on Rock64 + * at least. + */ + EVENTHANDLER_REGISTER(shutdown_final, rk8xx_poweroff, sc, + SHUTDOWN_PRI_LAST - 2); + } + return (0); } static int rk8xx_detach(device_t dev) { /* We cannot detach regulators */ return (EBUSY); } static device_method_t rk8xx_methods[] = { DEVMETHOD(device_detach, rk8xx_detach), /* regdev interface */ DEVMETHOD(regdev_map, rk8xx_map), /* Clock interface */ DEVMETHOD(clock_gettime, rk8xx_gettime), DEVMETHOD(clock_settime, rk8xx_settime), DEVMETHOD_END }; DEFINE_CLASS_0(rk8xx, rk8xx_driver, rk8xx_methods, sizeof(struct rk8xx_softc)); diff --git a/sys/dev/iicbus/pmic/rockchip/rk8xx.h b/sys/dev/iicbus/pmic/rockchip/rk8xx.h index 738209f5871e..739b57c5f0bb 100644 --- a/sys/dev/iicbus/pmic/rockchip/rk8xx.h +++ b/sys/dev/iicbus/pmic/rockchip/rk8xx.h @@ -1,122 +1,128 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2021 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. */ #ifndef _RK8XX_H_ #define _RK8XX_H_ #include #include #include enum rk_pmic_type { RK805 = 1, RK808, }; struct rk8xx_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 rk8xx_reg_sc { struct regnode *regnode; device_t base_dev; struct rk8xx_regdef *def; phandle_t xref; struct regnode_std_param *param; }; struct reg_list { TAILQ_ENTRY(reg_list) next; struct rk8xx_reg_sc *reg; }; struct rk8xx_rtc_reg { uint8_t secs; uint8_t secs_mask; uint8_t minutes; uint8_t minutes_mask; uint8_t hours; uint8_t hours_mask; uint8_t days; uint8_t days_mask; uint8_t months; uint8_t months_mask; uint8_t years; uint8_t weeks; uint8_t weeks_mask; uint8_t ctrl; uint8_t ctrl_stop_mask; uint8_t ctrl_ampm_mask; uint8_t ctrl_gettime_mask; uint8_t ctrl_readsel_mask; }; +struct rk8xx_dev_ctrl { + uint8_t dev_ctrl_reg; + uint8_t pwr_off_mask; +}; + struct rk8xx_softc { device_t dev; struct mtx mtx; struct resource * res[1]; void * intrcookie; struct intr_config_hook intr_hook; enum rk_pmic_type type; struct rk8xx_regdef *regdefs; TAILQ_HEAD(, reg_list) regs; int nregs; struct rk8xx_rtc_reg rtc_regs; + struct rk8xx_dev_ctrl dev_ctrl; }; int rk8xx_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size); int rk8xx_write(device_t dev, uint8_t reg, uint8_t *data, uint8_t size); DECLARE_CLASS(rk8xx_driver); int rk8xx_attach(struct rk8xx_softc *sc); /* rk8xx_clocks.c */ int rk8xx_attach_clocks(struct rk8xx_softc *sc); /* rk8xx_regulators.c */ void rk8xx_attach_regulators(struct rk8xx_softc *sc); int rk8xx_map(device_t dev, phandle_t xref, int ncells, pcell_t *cells, intptr_t *id); /* rk8xx_rtc.c */ int rk8xx_gettime(device_t dev, struct timespec *ts); int rk8xx_settime(device_t dev, struct timespec *ts); #endif /* _RK8XX_H_ */