Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

regulator: anatop: Add bypass support to digital LDOs

The ARM, PU, and SOC LDOs in the i.MX6 PMU can operate
in bypass mode. This allows to use external switching
regulators for cpu voltage scaling.

Since bypass and power gating modes are not configured
with their own bits, but via the voltage target bitfield,
store bypass state to be restored when reenabling the
regulator.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Mark Brown <broonie@linaro.org>

authored by

Philipp Zabel and committed by
Mark Brown
d38018f2 605ebd35

+42 -3
+42 -3
drivers/regulator/anatop-regulator.c
··· 35 35 #define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */ 36 36 37 37 #define LDO_POWER_GATE 0x00 38 + #define LDO_FET_FULL_ON 0x1f 38 39 39 40 struct anatop_regulator { 40 41 const char *name; ··· 51 50 int max_voltage; 52 51 struct regulator_desc rdesc; 53 52 struct regulator_init_data *initdata; 53 + bool bypass; 54 54 int sel; 55 55 }; 56 56 ··· 105 103 static int anatop_regmap_enable(struct regulator_dev *reg) 106 104 { 107 105 struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); 106 + int sel; 108 107 109 - return regulator_set_voltage_sel_regmap(reg, anatop_reg->sel); 108 + sel = anatop_reg->bypass ? LDO_FET_FULL_ON : anatop_reg->sel; 109 + return regulator_set_voltage_sel_regmap(reg, sel); 110 110 } 111 111 112 112 static int anatop_regmap_disable(struct regulator_dev *reg) ··· 127 123 struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); 128 124 int ret; 129 125 130 - if (!anatop_regmap_is_enabled(reg)) { 126 + if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg)) { 131 127 anatop_reg->sel = selector; 132 128 return 0; 133 129 } ··· 142 138 { 143 139 struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); 144 140 145 - if (!anatop_regmap_is_enabled(reg)) 141 + if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg)) 146 142 return anatop_reg->sel; 147 143 148 144 return regulator_get_voltage_sel_regmap(reg); 145 + } 146 + 147 + static int anatop_regmap_get_bypass(struct regulator_dev *reg, bool *enable) 148 + { 149 + struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); 150 + int sel; 151 + 152 + sel = regulator_get_voltage_sel_regmap(reg); 153 + if (sel == LDO_FET_FULL_ON) 154 + WARN_ON(!anatop_reg->bypass); 155 + else if (sel != LDO_POWER_GATE) 156 + WARN_ON(anatop_reg->bypass); 157 + 158 + *enable = anatop_reg->bypass; 159 + return 0; 160 + } 161 + 162 + static int anatop_regmap_set_bypass(struct regulator_dev *reg, bool enable) 163 + { 164 + struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); 165 + int sel; 166 + 167 + if (enable == anatop_reg->bypass) 168 + return 0; 169 + 170 + sel = enable ? LDO_FET_FULL_ON : anatop_reg->sel; 171 + anatop_reg->bypass = enable; 172 + 173 + return regulator_set_voltage_sel_regmap(reg, sel); 149 174 } 150 175 151 176 static struct regulator_ops anatop_rops = { ··· 193 160 .get_voltage_sel = anatop_regmap_core_get_voltage_sel, 194 161 .list_voltage = regulator_list_voltage_linear, 195 162 .map_voltage = regulator_map_voltage_linear, 163 + .get_bypass = anatop_regmap_get_bypass, 164 + .set_bypass = anatop_regmap_set_bypass, 196 165 }; 197 166 198 167 static int anatop_regulator_probe(struct platform_device *pdev) ··· 300 265 } 301 266 302 267 sreg->sel = (val & rdesc->vsel_mask) >> sreg->vol_bit_shift; 268 + if (sreg->sel == LDO_FET_FULL_ON) { 269 + sreg->sel = 0; 270 + sreg->bypass = true; 271 + } 303 272 } else { 304 273 rdesc->ops = &anatop_rops; 305 274 }