Hook axp20x into fdt regulator api

This commit is contained in:
jmcneill 2017-10-07 18:22:06 +00:00
parent 8342fe3404
commit 774ffdd63d
3 changed files with 160 additions and 5 deletions

View File

@ -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 <jmcneill@invisible.ca>
@ -29,7 +29,7 @@
#include "opt_fdt.h"
#include <sys/cdefs.h>
__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 <sys/param.h>
#include <sys/systm.h>
@ -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, &reg, 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, &reg, 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, &reg, NULL);
}
}
#endif /* FDT */

View File

@ -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_ */

View File

@ -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