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

regulator: anatop: Add power gating support to digital LDOs

The ARM, PU, and SOC LDOs in the i.MX6 PMU can completely gate
their power output. Since power gating is configured by writing
zero to the voltage target bitfield,, store a copy of the
voltage selector 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
605ebd35 38dbfb59

+74 -2
+74 -2
drivers/regulator/anatop-regulator.c
··· 34 34 #define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */ 35 35 #define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */ 36 36 37 + #define LDO_POWER_GATE 0x00 38 + 37 39 struct anatop_regulator { 38 40 const char *name; 39 41 u32 control_reg; ··· 50 48 int max_voltage; 51 49 struct regulator_desc rdesc; 52 50 struct regulator_init_data *initdata; 51 + int sel; 53 52 }; 54 53 55 54 static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg, ··· 100 97 return regulator_get_voltage_sel_regmap(reg); 101 98 } 102 99 100 + static int anatop_regmap_enable(struct regulator_dev *reg) 101 + { 102 + struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); 103 + 104 + return regulator_set_voltage_sel_regmap(reg, anatop_reg->sel); 105 + } 106 + 107 + static int anatop_regmap_disable(struct regulator_dev *reg) 108 + { 109 + return regulator_set_voltage_sel_regmap(reg, LDO_POWER_GATE); 110 + } 111 + 112 + static int anatop_regmap_is_enabled(struct regulator_dev *reg) 113 + { 114 + return regulator_get_voltage_sel_regmap(reg) != LDO_POWER_GATE; 115 + } 116 + 117 + static int anatop_regmap_core_set_voltage_sel(struct regulator_dev *reg, 118 + unsigned selector) 119 + { 120 + struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); 121 + int ret; 122 + 123 + if (!anatop_regmap_is_enabled(reg)) { 124 + anatop_reg->sel = selector; 125 + return 0; 126 + } 127 + 128 + ret = regulator_set_voltage_sel_regmap(reg, selector); 129 + if (!ret) 130 + anatop_reg->sel = selector; 131 + return ret; 132 + } 133 + 134 + static int anatop_regmap_core_get_voltage_sel(struct regulator_dev *reg) 135 + { 136 + struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); 137 + 138 + if (!anatop_regmap_is_enabled(reg)) 139 + return anatop_reg->sel; 140 + 141 + return regulator_get_voltage_sel_regmap(reg); 142 + } 143 + 103 144 static struct regulator_ops anatop_rops = { 104 145 .set_voltage_sel = anatop_regmap_set_voltage_sel, 105 - .set_voltage_time_sel = anatop_regmap_set_voltage_time_sel, 106 146 .get_voltage_sel = anatop_regmap_get_voltage_sel, 147 + .list_voltage = regulator_list_voltage_linear, 148 + .map_voltage = regulator_map_voltage_linear, 149 + }; 150 + 151 + static struct regulator_ops anatop_core_rops = { 152 + .enable = anatop_regmap_enable, 153 + .disable = anatop_regmap_disable, 154 + .is_enabled = anatop_regmap_is_enabled, 155 + .set_voltage_sel = anatop_regmap_core_set_voltage_sel, 156 + .set_voltage_time_sel = anatop_regmap_set_voltage_time_sel, 157 + .get_voltage_sel = anatop_regmap_core_get_voltage_sel, 107 158 .list_voltage = regulator_list_voltage_linear, 108 159 .map_voltage = regulator_map_voltage_linear, 109 160 }; ··· 173 116 struct regulator_init_data *initdata; 174 117 struct regulator_config config = { }; 175 118 int ret = 0; 119 + u32 val; 176 120 177 121 initdata = of_get_regulator_init_data(dev, np); 178 122 sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL); ··· 183 125 sreg->name = of_get_property(np, "regulator-name", NULL); 184 126 rdesc = &sreg->rdesc; 185 127 rdesc->name = sreg->name; 186 - rdesc->ops = &anatop_rops; 187 128 rdesc->type = REGULATOR_VOLTAGE; 188 129 rdesc->owner = THIS_MODULE; 189 130 ··· 253 196 config.driver_data = sreg; 254 197 config.of_node = pdev->dev.of_node; 255 198 config.regmap = sreg->anatop; 199 + 200 + /* Only core regulators have the ramp up delay configuration. */ 201 + if (sreg->control_reg && sreg->delay_bit_width) { 202 + rdesc->ops = &anatop_core_rops; 203 + 204 + ret = regmap_read(config.regmap, rdesc->vsel_reg, &val); 205 + if (ret) { 206 + dev_err(dev, "failed to read initial state\n"); 207 + return ret; 208 + } 209 + 210 + sreg->sel = (val & rdesc->vsel_mask) >> sreg->vol_bit_shift; 211 + } else { 212 + rdesc->ops = &anatop_rops; 213 + } 256 214 257 215 /* register regulator */ 258 216 rdev = devm_regulator_register(dev, rdesc, &config);