Date: Wed, 28 Nov 2018 13:53:44 +0000 (UTC) From: Emmanuel Vadot <manu@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r341142 - in head/sys: arm64/rockchip conf modules/rockchip modules/rockchip/rk805 Message-ID: <201811281353.wASDriwE000969@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: manu Date: Wed Nov 28 13:53:43 2018 New Revision: 341142 URL: https://svnweb.freebsd.org/changeset/base/341142 Log: Add RK805 PMIC Support RK805 is the companion PMIC for RK3328 SoC. Add a driver for it with most of it's regulators supported. MFC after: 1 month Added: head/sys/arm64/rockchip/rk805.c (contents, props changed) head/sys/arm64/rockchip/rk805reg.h (contents, props changed) head/sys/modules/rockchip/rk805/ head/sys/modules/rockchip/rk805/Makefile (contents, props changed) Modified: head/sys/conf/files.arm64 head/sys/modules/rockchip/Makefile Added: head/sys/arm64/rockchip/rk805.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/arm64/rockchip/rk805.c Wed Nov 28 13:53:43 2018 (r341142) @@ -0,0 +1,422 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.org> + * All rights reserved. + * + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/rman.h> +#include <machine/bus.h> + +#include <dev/iicbus/iiconf.h> +#include <dev/iicbus/iicbus.h> + +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include <dev/extres/regulator/regulator.h> + +#include <arm64/rockchip/rk805reg.h> + +#include "regdev_if.h" + +MALLOC_DEFINE(M_RK805_REG, "RK805 regulator", "RK805 power regulator"); + +static struct ofw_compat_data compat_data[] = { + {"rockchip,rk805", 1}, + {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 rk805_softc { + device_t dev; + struct mtx mtx; + struct resource * res[1]; + void * intrcookie; + struct intr_config_hook intr_hook; + + struct rk805_reg_sc **regs; + int nregs; +}; + +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, + }, +}; + +static int +rk805_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size) +{ + + return (iicdev_readfrom(dev, reg, data, size, IIC_INTRWAIT)); +} + +static int +rk805_write(device_t dev, uint8_t reg, uint8_t data) +{ + struct iic_msg msg; + uint8_t buf[2]; + + buf[0] = reg; + buf[1] = data; + msg.slave = iicbus_get_addr(dev); + msg.flags = IIC_M_WR; + msg.buf = buf; + msg.len = sizeof(buf); + + return (iicbus_transfer_excl(dev, &msg, 1, IIC_INTRWAIT)); +} + +static int +rk805_regnode_init(struct regnode *regnode) +{ + return (0); +} + +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); + + 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); + + *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_set_voltage(struct regnode *regnode, int min_uvolt, + int max_uvolt, int *udelay) +{ + struct rk805_reg_sc *sc; + uint8_t val; + + sc = regnode_get_softc(regnode); + + if (!sc->def->voltage_step) + return (ENXIO); + + 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); + + *udelay = 0; + + 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_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); + + 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_set_voltage, rk805_regnode_set_voltage), + REGNODEMETHOD(regnode_get_voltage, rk805_regnode_get_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; + + if (bootverbose) { + err = rk805_read(dev, 0x17, data, 1); + if (err != 0) { + device_printf(dev, "Cannot read chip name reg\n"); + return; + } + err = rk805_read(dev, 0x18, 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); + } + + config_intrhook_disestablish(&sc->intr_hook); +} + +static int +rk805_attach(device_t dev) +{ + struct rk805_softc *sc; + struct rk805_reg_sc *reg; + struct rk805_regdef *regdefs; + 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->regs = malloc(sizeof(struct rk805_reg_sc *) * sc->nregs, + M_RK805_REG, M_WAITOK | M_ZERO); + + regdefs = rk805_regdefs; + sc->nregs = nitems(rk805_regdefs); + + 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; + reg = rk805_reg_attach(dev, child, ®defs[i]); + if (reg == NULL) { + device_printf(dev, + "cannot attach regulator %s\n", + regdefs[i].name); + continue; + } + sc->regs[i] = reg; + 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 device_method_t rk805_methods[] = { + DEVMETHOD(device_probe, rk805_probe), + DEVMETHOD(device_attach, rk805_attach), + DEVMETHOD(device_detach, rk805_detach), + + 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); Added: head/sys/arm64/rockchip/rk805reg.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/arm64/rockchip/rk805reg.h Wed Nov 28 13:53:43 2018 (r341142) @@ -0,0 +1,72 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.org> + * All rights reserved. + * + * 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_ + +#define RK805_CHIP_NAME 0x17 +#define RK805_CHIP_VER 0x18 +#define RK805_OTP_VER 0x19 + +#define RK805_DCDC_EN 0x23 +#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 + +enum rk805_regulator { + RK805_DCDC1, + RK805_DCDC2, + RK805_DCDC3, + RK805_DCDC4, + RK805_LDO1, + RK805_LDO2, + RK805_LDO3, +}; + +#endif /* _RK805REG_H_ */ Modified: head/sys/conf/files.arm64 ============================================================================== --- head/sys/conf/files.arm64 Wed Nov 28 13:25:22 2018 (r341141) +++ head/sys/conf/files.arm64 Wed Nov 28 13:53:43 2018 (r341142) @@ -253,6 +253,7 @@ cddl/dev/dtrace/aarch64/dtrace_subr.c optional dtrac cddl/dev/fbt/aarch64/fbt_isa.c optional dtrace_fbt | dtraceall compile-with "${FBT_C}" arm64/rockchip/rk_i2c.c optional rk_i2c fdt soc_rockchip_rk3328 +arm64/rockchip/rk805.c optional rk805 fdt soc_rockchip_rk3328 arm64/rockchip/rk_grf.c optional fdt soc_rockchip_rk3328 arm64/rockchip/rk_pinctrl.c optional fdt soc_rockchip_rk3328 arm64/rockchip/rk_gpio.c optional fdt soc_rockchip_rk3328 Modified: head/sys/modules/rockchip/Makefile ============================================================================== --- head/sys/modules/rockchip/Makefile Wed Nov 28 13:25:22 2018 (r341141) +++ head/sys/modules/rockchip/Makefile Wed Nov 28 13:53:43 2018 (r341142) @@ -3,5 +3,6 @@ SUBDIR = \ rk_i2c \ + rk805 .include <bsd.subdir.mk> Added: head/sys/modules/rockchip/rk805/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/modules/rockchip/rk805/Makefile Wed Nov 28 13:53:43 2018 (r341142) @@ -0,0 +1,17 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/arm64/rockchip + +KMOD= rk805 +SRCS= rk805.c + +SRCS+= \ + bus_if.h \ + device_if.h \ + iicbus_if.h \ + regnode_if.h \ + regdev_if.h \ + ofw_bus_if.h \ + opt_platform.h \ + +.include <bsd.kmod.mk>
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201811281353.wASDriwE000969>