aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Zabel <p.zabel@pengutronix.de>2014-02-11 08:43:44 -0500
committerMark Brown <broonie@linaro.org>2014-02-14 15:30:47 -0500
commit605ebd35f059eb7dc087c4b5def1a8ce80acec55 (patch)
tree32e5ada5936e28d09247d6c303ac57ddc26c1188
parent38dbfb59d1175ef458d006556061adeaa8751b72 (diff)
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>
-rw-r--r--drivers/regulator/anatop-regulator.c76
1 files changed, 74 insertions, 2 deletions
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index 862e63e451d0..dff120a38e40 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -34,6 +34,8 @@
34#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */ 34#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */
35#define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */ 35#define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */
36 36
37#define LDO_POWER_GATE 0x00
38
37struct anatop_regulator { 39struct anatop_regulator {
38 const char *name; 40 const char *name;
39 u32 control_reg; 41 u32 control_reg;
@@ -48,6 +50,7 @@ struct anatop_regulator {
48 int max_voltage; 50 int max_voltage;
49 struct regulator_desc rdesc; 51 struct regulator_desc rdesc;
50 struct regulator_init_data *initdata; 52 struct regulator_init_data *initdata;
53 int sel;
51}; 54};
52 55
53static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg, 56static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg,
@@ -97,14 +100,68 @@ static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg)
97 return regulator_get_voltage_sel_regmap(reg); 100 return regulator_get_voltage_sel_regmap(reg);
98} 101}
99 102
103static int anatop_regmap_enable(struct regulator_dev *reg)
104{
105 struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
106
107 return regulator_set_voltage_sel_regmap(reg, anatop_reg->sel);
108}
109
110static int anatop_regmap_disable(struct regulator_dev *reg)
111{
112 return regulator_set_voltage_sel_regmap(reg, LDO_POWER_GATE);
113}
114
115static int anatop_regmap_is_enabled(struct regulator_dev *reg)
116{
117 return regulator_get_voltage_sel_regmap(reg) != LDO_POWER_GATE;
118}
119
120static int anatop_regmap_core_set_voltage_sel(struct regulator_dev *reg,
121 unsigned selector)
122{
123 struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
124 int ret;
125
126 if (!anatop_regmap_is_enabled(reg)) {
127 anatop_reg->sel = selector;
128 return 0;
129 }
130
131 ret = regulator_set_voltage_sel_regmap(reg, selector);
132 if (!ret)
133 anatop_reg->sel = selector;
134 return ret;
135}
136
137static int anatop_regmap_core_get_voltage_sel(struct regulator_dev *reg)
138{
139 struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
140
141 if (!anatop_regmap_is_enabled(reg))
142 return anatop_reg->sel;
143
144 return regulator_get_voltage_sel_regmap(reg);
145}
146
100static struct regulator_ops anatop_rops = { 147static struct regulator_ops anatop_rops = {
101 .set_voltage_sel = anatop_regmap_set_voltage_sel, 148 .set_voltage_sel = anatop_regmap_set_voltage_sel,
102 .set_voltage_time_sel = anatop_regmap_set_voltage_time_sel,
103 .get_voltage_sel = anatop_regmap_get_voltage_sel, 149 .get_voltage_sel = anatop_regmap_get_voltage_sel,
104 .list_voltage = regulator_list_voltage_linear, 150 .list_voltage = regulator_list_voltage_linear,
105 .map_voltage = regulator_map_voltage_linear, 151 .map_voltage = regulator_map_voltage_linear,
106}; 152};
107 153
154static struct regulator_ops anatop_core_rops = {
155 .enable = anatop_regmap_enable,
156 .disable = anatop_regmap_disable,
157 .is_enabled = anatop_regmap_is_enabled,
158 .set_voltage_sel = anatop_regmap_core_set_voltage_sel,
159 .set_voltage_time_sel = anatop_regmap_set_voltage_time_sel,
160 .get_voltage_sel = anatop_regmap_core_get_voltage_sel,
161 .list_voltage = regulator_list_voltage_linear,
162 .map_voltage = regulator_map_voltage_linear,
163};
164
108static int anatop_regulator_probe(struct platform_device *pdev) 165static int anatop_regulator_probe(struct platform_device *pdev)
109{ 166{
110 struct device *dev = &pdev->dev; 167 struct device *dev = &pdev->dev;
@@ -116,6 +173,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
116 struct regulator_init_data *initdata; 173 struct regulator_init_data *initdata;
117 struct regulator_config config = { }; 174 struct regulator_config config = { };
118 int ret = 0; 175 int ret = 0;
176 u32 val;
119 177
120 initdata = of_get_regulator_init_data(dev, np); 178 initdata = of_get_regulator_init_data(dev, np);
121 sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL); 179 sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL);
@@ -125,7 +183,6 @@ static int anatop_regulator_probe(struct platform_device *pdev)
125 sreg->name = of_get_property(np, "regulator-name", NULL); 183 sreg->name = of_get_property(np, "regulator-name", NULL);
126 rdesc = &sreg->rdesc; 184 rdesc = &sreg->rdesc;
127 rdesc->name = sreg->name; 185 rdesc->name = sreg->name;
128 rdesc->ops = &anatop_rops;
129 rdesc->type = REGULATOR_VOLTAGE; 186 rdesc->type = REGULATOR_VOLTAGE;
130 rdesc->owner = THIS_MODULE; 187 rdesc->owner = THIS_MODULE;
131 188
@@ -197,6 +254,21 @@ static int anatop_regulator_probe(struct platform_device *pdev)
197 config.of_node = pdev->dev.of_node; 254 config.of_node = pdev->dev.of_node;
198 config.regmap = sreg->anatop; 255 config.regmap = sreg->anatop;
199 256
257 /* Only core regulators have the ramp up delay configuration. */
258 if (sreg->control_reg && sreg->delay_bit_width) {
259 rdesc->ops = &anatop_core_rops;
260
261 ret = regmap_read(config.regmap, rdesc->vsel_reg, &val);
262 if (ret) {
263 dev_err(dev, "failed to read initial state\n");
264 return ret;
265 }
266
267 sreg->sel = (val & rdesc->vsel_mask) >> sreg->vol_bit_shift;
268 } else {
269 rdesc->ops = &anatop_rops;
270 }
271
200 /* register regulator */ 272 /* register regulator */
201 rdev = devm_regulator_register(dev, rdesc, &config); 273 rdev = devm_regulator_register(dev, rdesc, &config);
202 if (IS_ERR(rdev)) { 274 if (IS_ERR(rdev)) {