From 774ffdd63d18a0d87e2a110caccfd63f81ed3292 Mon Sep 17 00:00:00 2001 From: jmcneill Date: Sat, 7 Oct 2017 18:22:06 +0000 Subject: [PATCH] Hook axp20x into fdt regulator api --- sys/dev/i2c/axp20x.c | 156 +++++++++++++++++++++++++++++++++++++++- sys/dev/i2c/axp20xvar.h | 3 +- sys/dev/i2c/files.i2c | 6 +- 3 files changed, 160 insertions(+), 5 deletions(-) diff --git a/sys/dev/i2c/axp20x.c b/sys/dev/i2c/axp20x.c index ac6002988cc7..78a79af95644 100644 --- a/sys/dev/i2c/axp20x.c +++ b/sys/dev/i2c/axp20x.c @@ -1,4 +1,4 @@ -/* $NetBSD: axp20x.c,v 1.7 2017/08/29 10:10:54 jmcneill Exp $ */ +/* $NetBSD: axp20x.c,v 1.8 2017/10/07 18:22:06 jmcneill Exp $ */ /*- * Copyright (c) 2014-2017 Jared McNeill @@ -29,7 +29,7 @@ #include "opt_fdt.h" #include -__KERNEL_RCSID(0, "$NetBSD: axp20x.c,v 1.7 2017/08/29 10:10:54 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: axp20x.c,v 1.8 2017/10/07 18:22:06 jmcneill Exp $"); #include #include @@ -632,6 +632,31 @@ axp20x_set_dcdc(device_t dev, int dcdc, int mvolt, bool poll) } } +int +axp20x_get_dcdc(device_t dev, int dcdc, int *pmvolt, bool poll) +{ + struct axp20x_softc *sc = device_private(dev); + uint8_t reg; + int error; + + switch (dcdc) { + case AXP20X_DCDC2: + error = axp20x_read(sc, AXP_DCDC2, ®, 1, poll ? I2C_F_POLL : 0); + if (error != 0) + return error; + *pmvolt = __SHIFTOUT(reg, AXP_DCDC2_VOLT_MASK) * 25 + 700; + return 0; + case AXP20X_DCDC3: + error = axp20x_read(sc, AXP_DCDC3, ®, 1, poll ? I2C_F_POLL : 0); + if (error != 0) + return error; + *pmvolt = __SHIFTOUT(reg, AXP_DCDC3_VOLT_MASK) * 25 + 700; + return 0; + default: + return EINVAL; + } +} + void axp20x_poweroff(device_t dev) { @@ -643,6 +668,122 @@ axp20x_poweroff(device_t dev) } #ifdef FDT +static const struct axp20xregdef { + const char *name; + int dcdc; +} axp20x_regdefs[] = { + { "dcdc2", AXP20X_DCDC2 }, + { "dcdc3", AXP20X_DCDC3 }, +}; + +struct axp20xreg_softc { + device_t sc_dev; + int sc_phandle; + const struct axp20xregdef *sc_regdef; +}; + +struct axp20xreg_attach_args { + int reg_phandle; +}; + +static int +axp20xreg_acquire(device_t dev) +{ + return 0; +} + +static void +axp20xreg_release(device_t dev) +{ +} + +static int +axp20xreg_enable(device_t dev, bool enable) +{ + /* TODO */ + return enable ? 0 : EINVAL; +} + +static int +axp20xreg_set_voltage(device_t dev, u_int min_uvol, u_int max_uvol) +{ + struct axp20xreg_softc * const sc = device_private(dev); + + return axp20x_set_dcdc(device_parent(dev), sc->sc_regdef->dcdc, min_uvol / 1000, true); +} + +static int +axp20xreg_get_voltage(device_t dev, u_int *puvol) +{ + struct axp20xreg_softc * const sc = device_private(dev); + int mvol, error; + + error = axp20x_get_dcdc(device_parent(dev), sc->sc_regdef->dcdc, &mvol, true); + if (error != 0) + return error; + + *puvol = mvol * 1000; + return 0; +} + +static struct fdtbus_regulator_controller_func axp20xreg_funcs = { + .acquire = axp20xreg_acquire, + .release = axp20xreg_release, + .enable = axp20xreg_enable, + .set_voltage = axp20xreg_set_voltage, + .get_voltage = axp20xreg_get_voltage, +}; + +static const struct axp20xregdef * +axp20xreg_lookup(int phandle) +{ + const char *name; + int n; + + name = fdtbus_get_string(phandle, "name"); + if (name == NULL) + return NULL; + + for (n = 0; n < __arraycount(axp20x_regdefs); n++) + if (strcmp(name, axp20x_regdefs[n].name) == 0) + return &axp20x_regdefs[n]; + + return NULL; +} + +static int +axp20xreg_match(device_t parent, cfdata_t match, void *aux) +{ + const struct axp20xreg_attach_args *reg = aux; + + return axp20xreg_lookup(reg->reg_phandle) != NULL; +} + +static void +axp20xreg_attach(device_t parent, device_t self, void *aux) +{ + struct axp20xreg_softc * const sc = device_private(self); + const struct axp20xreg_attach_args *reg = aux; + const char *regulator_name; + + sc->sc_dev = self; + sc->sc_phandle = reg->reg_phandle; + sc->sc_regdef = axp20xreg_lookup(reg->reg_phandle); + + regulator_name = fdtbus_get_string(reg->reg_phandle, "regulator-name"); + + aprint_naive("\n"); + if (regulator_name) + aprint_normal(": %s (%s)\n", sc->sc_regdef->name, regulator_name); + else + aprint_normal(": %s\n", sc->sc_regdef->name); + + fdtbus_register_regulator_controller(self, sc->sc_phandle, &axp20xreg_funcs); +} + +CFATTACH_DECL_NEW(axp20xreg, sizeof(struct axp20xreg_softc), + axp20xreg_match, axp20xreg_attach, NULL, NULL); + static void axp20x_fdt_poweroff(device_t dev) { @@ -657,7 +798,18 @@ static struct fdtbus_power_controller_func axp20x_fdt_power_funcs = { static void axp20x_fdt_attach(struct axp20x_softc *sc) { + int regulators_phandle, child; + fdtbus_register_power_controller(sc->sc_dev, sc->sc_phandle, &axp20x_fdt_power_funcs); + + regulators_phandle = of_find_firstchild_byname(sc->sc_phandle, "regulators"); + if (regulators_phandle == -1) + return; + + for (child = OF_child(regulators_phandle); child; child = OF_peer(child)) { + struct axp20xreg_attach_args reg = { .reg_phandle = child }; + config_found(sc->sc_dev, ®, NULL); + } } #endif /* FDT */ diff --git a/sys/dev/i2c/axp20xvar.h b/sys/dev/i2c/axp20xvar.h index cfd77f87bd62..704f61277d69 100644 --- a/sys/dev/i2c/axp20xvar.h +++ b/sys/dev/i2c/axp20xvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: axp20xvar.h,v 1.2 2017/08/29 10:10:54 jmcneill Exp $ */ +/* $NetBSD: axp20xvar.h,v 1.3 2017/10/07 18:22:06 jmcneill Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. @@ -31,6 +31,7 @@ #define AXP20X_DCDC3 3 int axp20x_set_dcdc(device_t, int, int, bool); +int axp20x_get_dcdc(device_t, int, int *, bool); void axp20x_poweroff(device_t); #endif /* _DEV_I2C_AXP20XVAR_H_ */ diff --git a/sys/dev/i2c/files.i2c b/sys/dev/i2c/files.i2c index c3541fee5fb2..f0c9acf04f70 100644 --- a/sys/dev/i2c/files.i2c +++ b/sys/dev/i2c/files.i2c @@ -1,4 +1,4 @@ -# $NetBSD: files.i2c,v 1.77 2017/10/02 22:48:02 jmcneill Exp $ +# $NetBSD: files.i2c,v 1.78 2017/10/07 18:22:06 jmcneill Exp $ obsolete defflag opt_i2cbus.h I2C_SCAN define i2cbus { } @@ -222,8 +222,10 @@ attach mpl115a at iic file dev/i2c/mpl115a.c mpl115a # AXP20x Power Management Unit -device axp20x: sysmon_envsys +device axp20x { }: sysmon_envsys +device axp20xreg: axp20x attach axp20x at iic +attach axp20xreg at axp20x file dev/i2c/axp20x.c axp20x needs-flag # AXP22x Power Management Unit