Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 1 Sep 2016 21:19:11 +0000 (UTC)
From:      Jared McNeill <jmcneill@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r305246 - head/sys/arm/allwinner
Message-ID:  <201609012119.u81LJBWo063222@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201609012119.u81LJBWo063222>