Skip to content

Commit 9bcbaba

Browse files
M-Vaittinenbroonie
authored andcommitted
regulator: bd718x7: remove voltage change restriction from BD71847 LDOs
The BD71837 had a HW "feature" where changing the regulator output voltages of other regulators but bucks 1-4 might cause spikes if regulators were enabled. Thus SW prohibit voltage changes for other regulators except for bucks 1-4 when regulator is enabled. The HW colleagues did inadvertly fix this issue for BD71847 and BD71850. The power-good detection for LDOs can still cause false alarms if LDO voltage is changed upwards when LDO is enabled. Allow LDO voltage changes and disabe the power-good monioring for the duration of the LDO voltage change and enable it after LDO voltage has stabilized. ROHM HW colleagues measured the safety limit of 1000uS for guaranteeing the voltage has stabilized. Let's use that for starters and add confiurable stabilization wait-time later if needed. Signed-off-by: Matti Vaittinen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 4f43adc commit 9bcbaba

File tree

1 file changed

+158
-12
lines changed

1 file changed

+158
-12
lines changed

drivers/regulator/bd718x7-regulator.c

Lines changed: 158 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,13 @@ static int bd718xx_buck1234_set_ramp_delay(struct regulator_dev *rdev,
6262
* is changed. Hence we return -EBUSY for these if voltage is changed
6363
* when BUCK/LDO is enabled.
6464
*
65-
* The LDO operation for BD71847 and BD71850 is icurrently unknown.
66-
* It's safer to still assume they can't be changed when enabled.
65+
* On BD71847, BD71850, ... The LDO voltage can be changed when LDO is
66+
* enabled. But if voltage is increased the LDO power-good monitoring
67+
* must be disabled for the duration of changing + 1mS to ensure voltage
68+
* has reached the higher level before HW does next under voltage detection
69+
* cycle.
6770
*/
68-
static int bd718xx_set_voltage_sel_restricted(struct regulator_dev *rdev,
71+
static int bd71837_set_voltage_sel_restricted(struct regulator_dev *rdev,
6972
unsigned int sel)
7073
{
7174
if (regulator_is_enabled_regmap(rdev))
@@ -74,8 +77,123 @@ static int bd718xx_set_voltage_sel_restricted(struct regulator_dev *rdev,
7477
return regulator_set_voltage_sel_regmap(rdev, sel);
7578
}
7679

80+
static void voltage_change_done(struct regulator_dev *rdev, unsigned int sel,
81+
unsigned int *mask)
82+
{
83+
int ret;
84+
85+
if (*mask) {
86+
/*
87+
* Let's allow scheduling as we use I2C anyways. We just need to
88+
* guarantee minimum of 1ms sleep - it shouldn't matter if we
89+
* exceed it due to the scheduling.
90+
*/
91+
msleep(1);
92+
/*
93+
* Note for next hacker. The PWRGOOD should not be masked on
94+
* BD71847 so we will just unconditionally enable detection
95+
* when voltage is set.
96+
* If someone want's to disable PWRGOOD he must implement
97+
* caching and restoring the old value here. I am not
98+
* aware of such use-cases so for the sake of the simplicity
99+
* we just always enable PWRGOOD here.
100+
*/
101+
ret = regmap_update_bits(rdev->regmap, BD718XX_REG_MVRFLTMASK2,
102+
*mask, 0);
103+
if (ret)
104+
dev_err(&rdev->dev,
105+
"Failed to re-enable voltage monitoring (%d)\n",
106+
ret);
107+
}
108+
}
109+
110+
static int voltage_change_prepare(struct regulator_dev *rdev, unsigned int sel,
111+
unsigned int *mask)
112+
{
113+
int ret;
114+
115+
*mask = 0;
116+
if (regulator_is_enabled_regmap(rdev)) {
117+
int now, new;
118+
119+
now = rdev->desc->ops->get_voltage_sel(rdev);
120+
if (now < 0)
121+
return now;
122+
123+
now = rdev->desc->ops->list_voltage(rdev, now);
124+
if (now < 0)
125+
return now;
126+
127+
new = rdev->desc->ops->list_voltage(rdev, sel);
128+
if (new < 0)
129+
return new;
130+
131+
/*
132+
* If we increase LDO voltage when LDO is enabled we need to
133+
* disable the power-good detection until voltage has reached
134+
* the new level. According to HW colleagues the maximum time
135+
* it takes is 1000us. I assume that on systems with light load
136+
* this might be less - and we could probably use DT to give
137+
* system specific delay value if performance matters.
138+
*
139+
* Well, knowing we use I2C here and can add scheduling delays
140+
* I don't think it is worth the hassle and I just add fixed
141+
* 1ms sleep here (and allow scheduling). If this turns out to
142+
* be a problem we can change it to delay and make the delay
143+
* time configurable.
144+
*/
145+
if (new > now) {
146+
int ldo_offset = rdev->desc->id - BD718XX_LDO1;
147+
148+
*mask = BD718XX_LDO1_VRMON80 << ldo_offset;
149+
ret = regmap_update_bits(rdev->regmap,
150+
BD718XX_REG_MVRFLTMASK2,
151+
*mask, *mask);
152+
if (ret) {
153+
dev_err(&rdev->dev,
154+
"Failed to stop voltage monitoring\n");
155+
return ret;
156+
}
157+
}
158+
}
159+
160+
return 0;
161+
}
162+
163+
static int bd718xx_set_voltage_sel_restricted(struct regulator_dev *rdev,
164+
unsigned int sel)
165+
{
166+
int ret;
167+
int mask;
168+
169+
ret = voltage_change_prepare(rdev, sel, &mask);
170+
if (ret)
171+
return ret;
172+
173+
ret = regulator_set_voltage_sel_regmap(rdev, sel);
174+
voltage_change_done(rdev, sel, &mask);
175+
176+
return ret;
177+
}
178+
77179
static int bd718xx_set_voltage_sel_pickable_restricted(
78180
struct regulator_dev *rdev, unsigned int sel)
181+
{
182+
int ret;
183+
int mask;
184+
185+
ret = voltage_change_prepare(rdev, sel, &mask);
186+
if (ret)
187+
return ret;
188+
189+
ret = regulator_set_voltage_sel_pickable_regmap(rdev, sel);
190+
voltage_change_done(rdev, sel, &mask);
191+
192+
return ret;
193+
}
194+
195+
static int bd71837_set_voltage_sel_pickable_restricted(
196+
struct regulator_dev *rdev, unsigned int sel)
79197
{
80198
if (regulator_is_enabled_regmap(rdev))
81199
return -EBUSY;
@@ -90,6 +208,16 @@ static const struct regulator_ops bd718xx_pickable_range_ldo_ops = {
90208
.list_voltage = regulator_list_voltage_pickable_linear_range,
91209
.set_voltage_sel = bd718xx_set_voltage_sel_pickable_restricted,
92210
.get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
211+
212+
};
213+
214+
static const struct regulator_ops bd71837_pickable_range_ldo_ops = {
215+
.enable = regulator_enable_regmap,
216+
.disable = regulator_disable_regmap,
217+
.is_enabled = regulator_is_enabled_regmap,
218+
.list_voltage = regulator_list_voltage_pickable_linear_range,
219+
.set_voltage_sel = bd71837_set_voltage_sel_pickable_restricted,
220+
.get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
93221
};
94222

95223
static const struct regulator_ops bd718xx_pickable_range_buck_ops = {
@@ -107,11 +235,20 @@ static const struct regulator_ops bd71837_pickable_range_buck_ops = {
107235
.disable = regulator_disable_regmap,
108236
.is_enabled = regulator_is_enabled_regmap,
109237
.list_voltage = regulator_list_voltage_pickable_linear_range,
110-
.set_voltage_sel = bd718xx_set_voltage_sel_pickable_restricted,
238+
.set_voltage_sel = bd71837_set_voltage_sel_pickable_restricted,
111239
.get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
112240
.set_voltage_time_sel = regulator_set_voltage_time_sel,
113241
};
114242

243+
static const struct regulator_ops bd71837_ldo_regulator_ops = {
244+
.enable = regulator_enable_regmap,
245+
.disable = regulator_disable_regmap,
246+
.is_enabled = regulator_is_enabled_regmap,
247+
.list_voltage = regulator_list_voltage_linear_range,
248+
.set_voltage_sel = bd71837_set_voltage_sel_restricted,
249+
.get_voltage_sel = regulator_get_voltage_sel_regmap,
250+
};
251+
115252
static const struct regulator_ops bd718xx_ldo_regulator_ops = {
116253
.enable = regulator_enable_regmap,
117254
.disable = regulator_disable_regmap,
@@ -121,6 +258,15 @@ static const struct regulator_ops bd718xx_ldo_regulator_ops = {
121258
.get_voltage_sel = regulator_get_voltage_sel_regmap,
122259
};
123260

261+
static const struct regulator_ops bd71837_ldo_regulator_nolinear_ops = {
262+
.enable = regulator_enable_regmap,
263+
.disable = regulator_disable_regmap,
264+
.is_enabled = regulator_is_enabled_regmap,
265+
.list_voltage = regulator_list_voltage_table,
266+
.set_voltage_sel = bd71837_set_voltage_sel_restricted,
267+
.get_voltage_sel = regulator_get_voltage_sel_regmap,
268+
};
269+
124270
static const struct regulator_ops bd718xx_ldo_regulator_nolinear_ops = {
125271
.enable = regulator_enable_regmap,
126272
.disable = regulator_disable_regmap,
@@ -145,7 +291,7 @@ static const struct regulator_ops bd71837_buck_regulator_ops = {
145291
.disable = regulator_disable_regmap,
146292
.is_enabled = regulator_is_enabled_regmap,
147293
.list_voltage = regulator_list_voltage_linear_range,
148-
.set_voltage_sel = bd718xx_set_voltage_sel_restricted,
294+
.set_voltage_sel = bd71837_set_voltage_sel_restricted,
149295
.get_voltage_sel = regulator_get_voltage_sel_regmap,
150296
.set_voltage_time_sel = regulator_set_voltage_time_sel,
151297
};
@@ -938,7 +1084,7 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
9381084
.of_match = of_match_ptr("LDO1"),
9391085
.regulators_node = of_match_ptr("regulators"),
9401086
.id = BD718XX_LDO1,
941-
.ops = &bd718xx_pickable_range_ldo_ops,
1087+
.ops = &bd71837_pickable_range_ldo_ops,
9421088
.type = REGULATOR_VOLTAGE,
9431089
.n_voltages = BD718XX_LDO1_VOLTAGE_NUM,
9441090
.linear_ranges = bd718xx_ldo1_volts,
@@ -964,7 +1110,7 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
9641110
.of_match = of_match_ptr("LDO2"),
9651111
.regulators_node = of_match_ptr("regulators"),
9661112
.id = BD718XX_LDO2,
967-
.ops = &bd718xx_ldo_regulator_nolinear_ops,
1113+
.ops = &bd71837_ldo_regulator_nolinear_ops,
9681114
.type = REGULATOR_VOLTAGE,
9691115
.volt_table = &ldo_2_volts[0],
9701116
.vsel_reg = BD718XX_REG_LDO2_VOLT,
@@ -986,7 +1132,7 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
9861132
.of_match = of_match_ptr("LDO3"),
9871133
.regulators_node = of_match_ptr("regulators"),
9881134
.id = BD718XX_LDO3,
989-
.ops = &bd718xx_ldo_regulator_ops,
1135+
.ops = &bd71837_ldo_regulator_ops,
9901136
.type = REGULATOR_VOLTAGE,
9911137
.n_voltages = BD718XX_LDO3_VOLTAGE_NUM,
9921138
.linear_ranges = bd718xx_ldo3_volts,
@@ -1009,7 +1155,7 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
10091155
.of_match = of_match_ptr("LDO4"),
10101156
.regulators_node = of_match_ptr("regulators"),
10111157
.id = BD718XX_LDO4,
1012-
.ops = &bd718xx_ldo_regulator_ops,
1158+
.ops = &bd71837_ldo_regulator_ops,
10131159
.type = REGULATOR_VOLTAGE,
10141160
.n_voltages = BD718XX_LDO4_VOLTAGE_NUM,
10151161
.linear_ranges = bd718xx_ldo4_volts,
@@ -1032,7 +1178,7 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
10321178
.of_match = of_match_ptr("LDO5"),
10331179
.regulators_node = of_match_ptr("regulators"),
10341180
.id = BD718XX_LDO5,
1035-
.ops = &bd718xx_ldo_regulator_ops,
1181+
.ops = &bd71837_ldo_regulator_ops,
10361182
.type = REGULATOR_VOLTAGE,
10371183
.n_voltages = BD71837_LDO5_VOLTAGE_NUM,
10381184
.linear_ranges = bd71837_ldo5_volts,
@@ -1059,7 +1205,7 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
10591205
.of_match = of_match_ptr("LDO6"),
10601206
.regulators_node = of_match_ptr("regulators"),
10611207
.id = BD718XX_LDO6,
1062-
.ops = &bd718xx_ldo_regulator_ops,
1208+
.ops = &bd71837_ldo_regulator_ops,
10631209
.type = REGULATOR_VOLTAGE,
10641210
.n_voltages = BD718XX_LDO6_VOLTAGE_NUM,
10651211
.linear_ranges = bd718xx_ldo6_volts,
@@ -1086,7 +1232,7 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
10861232
.of_match = of_match_ptr("LDO7"),
10871233
.regulators_node = of_match_ptr("regulators"),
10881234
.id = BD718XX_LDO7,
1089-
.ops = &bd718xx_ldo_regulator_ops,
1235+
.ops = &bd71837_ldo_regulator_ops,
10901236
.type = REGULATOR_VOLTAGE,
10911237
.n_voltages = BD71837_LDO7_VOLTAGE_NUM,
10921238
.linear_ranges = bd71837_ldo7_volts,

0 commit comments

Comments
 (0)