svn commit: r305246 - head/sys/arm/allwinner
Jared McNeill
jmcneill at FreeBSD.org
Thu Sep 1 21:19:12 UTC 2016
Author: jmcneill
Date: Thu Sep 1 21:19:11 2016
New Revision: 305246
URL: https://svnweb.freebsd.org/changeset/base/305246
Log:
Add support for setting DCDC2 voltage.
Modified:
head/sys/arm/allwinner/axp81x.c
Modified: head/sys/arm/allwinner/axp81x.c
==============================================================================
--- head/sys/arm/allwinner/axp81x.c Thu Sep 1 21:16:29 2016 (r305245)
+++ head/sys/arm/allwinner/axp81x.c Thu Sep 1 21:19:11 2016 (r305246)
@@ -61,8 +61,13 @@ __FBSDID("$FreeBSD$");
MALLOC_DEFINE(M_AXP81X_REG, "AXP81x regulator", "AXP81x power regulator");
#define AXP_ICTYPE 0x03
+#define AXP_POWERCTL1 0x10
+#define AXP_POWERCTL1_DCDC2 (1 << 1)
#define AXP_POWERCTL2 0x12
#define AXP_POWERCTL2_DC1SW (1 << 7)
+#define AXP_VOLTCTL_DCDC2 0x21
+#define AXP_VOLTCTL_STATUS (1 << 7)
+#define AXP_VOLTCTL_MASK 0x7f
#define AXP_POWERBAT 0x32
#define AXP_POWERBAT_SHUTDOWN (1 << 7)
#define AXP_IRQEN1 0x40
@@ -109,10 +114,18 @@ struct axp81x_regdef {
char *supply_name;
uint8_t enable_reg;
uint8_t enable_mask;
+ uint8_t voltage_reg;
+ int voltage_min;
+ int voltage_max;
+ int voltage_step1;
+ int voltage_nstep1;
+ int voltage_step2;
+ int voltage_nstep2;
};
enum axp81x_reg_id {
- AXP81X_REG_ID_DC1SW
+ AXP81X_REG_ID_DC1SW,
+ AXP81X_REG_ID_DCDC2,
};
static struct axp81x_regdef axp81x_regdefs[] = {
@@ -122,6 +135,19 @@ static struct axp81x_regdef axp81x_regde
.enable_reg = AXP_POWERCTL2,
.enable_mask = AXP_POWERCTL2_DC1SW,
},
+ {
+ .id = AXP81X_REG_ID_DCDC2,
+ .name = "dcdc2",
+ .enable_reg = AXP_POWERCTL1,
+ .enable_mask = AXP_POWERCTL1_DCDC2,
+ .voltage_reg = AXP_VOLTCTL_DCDC2,
+ .voltage_min = 500,
+ .voltage_max = 1300,
+ .voltage_step1 = 10,
+ .voltage_nstep1 = 70,
+ .voltage_step2 = 20,
+ .voltage_nstep2 = 5,
+ },
};
struct axp81x_softc;
@@ -218,17 +244,82 @@ axp81x_regnode_enable(struct regnode *re
return (0);
}
+static void
+axp81x_regnode_reg_to_voltage(struct axp81x_reg_sc *sc, uint8_t val, int *uv)
+{
+ if (val < sc->def->voltage_nstep1)
+ *uv = sc->def->voltage_min + val * sc->def->voltage_step1;
+ else
+ *uv = sc->def->voltage_min +
+ (sc->def->voltage_nstep1 * sc->def->voltage_step1) +
+ ((val - sc->def->voltage_nstep1) * sc->def->voltage_step2);
+ *uv *= 1000;
+}
+
+static int
+axp81x_regnode_voltage_to_reg(struct axp81x_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 * 1000;
+
+ for (nstep = 0; nstep < sc->def->voltage_nstep1 && uvolt < min_uvolt;
+ nstep++) {
+ ++nval;
+ uvolt += (sc->def->voltage_step1 * 1000);
+ }
+ for (nstep = 0; nstep < sc->def->voltage_nstep2 && uvolt < min_uvolt;
+ nstep++) {
+ ++nval;
+ uvolt += (sc->def->voltage_step2 * 1000);
+ }
+ if (uvolt > max_uvolt)
+ return (EINVAL);
+
+ *val = nval;
+ return (0);
+}
+
static int
axp81x_regnode_set_voltage(struct regnode *regnode, int min_uvolt,
int max_uvolt, int *udelay)
{
- return (ENXIO);
+ struct axp81x_reg_sc *sc;
+ uint8_t val;
+
+ sc = regnode_get_softc(regnode);
+
+ if (!sc->def->voltage_step1 || !sc->def->voltage_step2)
+ return (ENXIO);
+
+ if (axp81x_regnode_voltage_to_reg(sc, min_uvolt, max_uvolt, &val) != 0)
+ return (ERANGE);
+
+ axp81x_write(sc->base_dev, sc->def->voltage_reg, val);
+
+ *udelay = 0;
+
+ return (0);
}
static int
axp81x_regnode_get_voltage(struct regnode *regnode, int *uvolt)
{
- return (ENXIO);
+ struct axp81x_reg_sc *sc;
+ uint8_t val;
+
+ sc = regnode_get_softc(regnode);
+
+ if (!sc->def->voltage_step1 || !sc->def->voltage_step2)
+ return (ENXIO);
+
+ axp81x_read(sc->base_dev, sc->def->voltage_reg, &val, 1);
+ axp81x_regnode_reg_to_voltage(sc, val & AXP_VOLTCTL_MASK, uvolt);
+
+ return (0);
}
static regnode_method_t axp81x_regnode_methods[] = {
@@ -519,6 +610,10 @@ axp81x_reg_attach(device_t dev, phandle_
memset(&initdef, 0, sizeof(initdef));
regulator_parse_ofw_stdparam(dev, node, &initdef);
+ if (initdef.std_param.min_uvolt == 0)
+ initdef.std_param.min_uvolt = def->voltage_min * 1000;
+ if (initdef.std_param.max_uvolt == 0)
+ initdef.std_param.max_uvolt = def->voltage_max * 1000;
initdef.id = def->id;
initdef.ofw_node = node;
regnode = regnode_create(dev, &axp81x_regnode_class, &initdef);
More information about the svn-src-all
mailing list