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);
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to