regulator: anatop: Add bypass support to digital LDOs
[firefly-linux-kernel-4.4.55.git] / drivers / regulator / anatop-regulator.c
index dff120a38e404d680f6cb368e941f50d529a0b9c..38e8122c4b09d351cab212e0011eaaed095a5a01 100644 (file)
@@ -35,6 +35,7 @@
 #define LDO_RAMP_UP_FREQ_IN_MHZ         24 /* cycle based on 24M OSC */
 
 #define LDO_POWER_GATE                 0x00
+#define LDO_FET_FULL_ON                        0x1f
 
 struct anatop_regulator {
        const char *name;
@@ -50,6 +51,7 @@ struct anatop_regulator {
        int max_voltage;
        struct regulator_desc rdesc;
        struct regulator_init_data *initdata;
+       bool bypass;
        int sel;
 };
 
@@ -103,8 +105,10 @@ static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg)
 static int anatop_regmap_enable(struct regulator_dev *reg)
 {
        struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+       int sel;
 
-       return regulator_set_voltage_sel_regmap(reg, anatop_reg->sel);
+       sel = anatop_reg->bypass ? LDO_FET_FULL_ON : anatop_reg->sel;
+       return regulator_set_voltage_sel_regmap(reg, sel);
 }
 
 static int anatop_regmap_disable(struct regulator_dev *reg)
@@ -123,7 +127,7 @@ static int anatop_regmap_core_set_voltage_sel(struct regulator_dev *reg,
        struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
        int ret;
 
-       if (!anatop_regmap_is_enabled(reg)) {
+       if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg)) {
                anatop_reg->sel = selector;
                return 0;
        }
@@ -138,12 +142,41 @@ static int anatop_regmap_core_get_voltage_sel(struct regulator_dev *reg)
 {
        struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
 
-       if (!anatop_regmap_is_enabled(reg))
+       if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg))
                return anatop_reg->sel;
 
        return regulator_get_voltage_sel_regmap(reg);
 }
 
+static int anatop_regmap_get_bypass(struct regulator_dev *reg, bool *enable)
+{
+       struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+       int sel;
+
+       sel = regulator_get_voltage_sel_regmap(reg);
+       if (sel == LDO_FET_FULL_ON)
+               WARN_ON(!anatop_reg->bypass);
+       else if (sel != LDO_POWER_GATE)
+               WARN_ON(anatop_reg->bypass);
+
+       *enable = anatop_reg->bypass;
+       return 0;
+}
+
+static int anatop_regmap_set_bypass(struct regulator_dev *reg, bool enable)
+{
+       struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+       int sel;
+
+       if (enable == anatop_reg->bypass)
+               return 0;
+
+       sel = enable ? LDO_FET_FULL_ON : anatop_reg->sel;
+       anatop_reg->bypass = enable;
+
+       return regulator_set_voltage_sel_regmap(reg, sel);
+}
+
 static struct regulator_ops anatop_rops = {
        .set_voltage_sel = anatop_regmap_set_voltage_sel,
        .get_voltage_sel = anatop_regmap_get_voltage_sel,
@@ -160,6 +193,8 @@ static struct regulator_ops anatop_core_rops = {
        .get_voltage_sel = anatop_regmap_core_get_voltage_sel,
        .list_voltage = regulator_list_voltage_linear,
        .map_voltage = regulator_map_voltage_linear,
+       .get_bypass = anatop_regmap_get_bypass,
+       .set_bypass = anatop_regmap_set_bypass,
 };
 
 static int anatop_regulator_probe(struct platform_device *pdev)
@@ -265,6 +300,10 @@ static int anatop_regulator_probe(struct platform_device *pdev)
                }
 
                sreg->sel = (val & rdesc->vsel_mask) >> sreg->vol_bit_shift;
+               if (sreg->sel == LDO_FET_FULL_ON) {
+                       sreg->sel = 0;
+                       sreg->bypass = true;
+               }
        } else {
                rdesc->ops = &anatop_rops;
        }