Skip to content

Commit f31f012

Browse files
committed
Fix issue when using devm_of_regulator_put_matches and
Merge series from Alina Yu <alina_yu@richtek.com>: There are two types of LDO VOUT: fixed voltage mode and adjustable voltage mode. As the fixed voltage for the LDO is outside the range of the adjustable voltage mode, the constraints for this scenario are not suitable to represent both modes. Therefore, A property is added to specify the fixed LDO VOUT. In this version, a software bug has been fixed. rtq2208_ldo_match is no longer a local variable. It prevents invalid memory access when devm_of_regulator_put_matches is called.
2 parents c1ca3e2 + 3348749 commit f31f012

2 files changed

Lines changed: 60 additions & 17 deletions

File tree

Documentation/devicetree/bindings/regulator/richtek,rtq2208.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ properties:
7575
description:
7676
regulator description for ldo[1-2].
7777

78+
properties:
79+
richtek,fixed-microvolt:
80+
description: |
81+
This property can be used to set a fixed operating voltage that lies outside
82+
the range of the regulator's adjustable mode.
83+
7884
required:
7985
- compatible
8086
- reg
@@ -177,6 +183,8 @@ examples:
177183
};
178184
};
179185
ldo1 {
186+
/* Fixed LDO VOUT */
187+
richtek,fixed-microvolt = <1200000>;
180188
regulator-min-microvolt = <1200000>;
181189
regulator-max-microvolt = <1200000>;
182190
regulator-always-on;
@@ -185,7 +193,8 @@ examples:
185193
};
186194
};
187195
ldo2 {
188-
regulator-min-microvolt = <3300000>;
196+
/* Adjustable LDO VOUT */
197+
regulator-min-microvolt = <1800000>;
189198
regulator-max-microvolt = <3300000>;
190199
regulator-always-on;
191200
regulator-state-mem {

drivers/regulator/rtq2208-regulator.c

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ static const struct regulator_ops rtq2208_regulator_buck_ops = {
219219
.set_suspend_mode = rtq2208_set_suspend_mode,
220220
};
221221

222-
static const struct regulator_ops rtq2208_regulator_ldo_ops = {
222+
static const struct regulator_ops rtq2208_regulator_ldo_fix_ops = {
223223
.enable = regulator_enable_regmap,
224224
.disable = regulator_disable_regmap,
225225
.is_enabled = regulator_is_enabled_regmap,
@@ -228,6 +228,28 @@ static const struct regulator_ops rtq2208_regulator_ldo_ops = {
228228
.set_suspend_disable = rtq2208_set_suspend_disable,
229229
};
230230

231+
static const struct regulator_ops rtq2208_regulator_ldo_adj_ops = {
232+
.enable = regulator_enable_regmap,
233+
.disable = regulator_disable_regmap,
234+
.is_enabled = regulator_is_enabled_regmap,
235+
.list_voltage = regulator_list_voltage_table,
236+
.set_voltage_sel = regulator_set_voltage_sel_regmap,
237+
.get_voltage_sel = regulator_get_voltage_sel_regmap,
238+
.set_active_discharge = regulator_set_active_discharge_regmap,
239+
.set_suspend_enable = rtq2208_set_suspend_enable,
240+
.set_suspend_disable = rtq2208_set_suspend_disable,
241+
};
242+
243+
static const unsigned int rtq2208_ldo_volt_table[] = {
244+
1800000,
245+
3300000,
246+
};
247+
248+
static struct of_regulator_match rtq2208_ldo_match[] = {
249+
{.name = "ldo2", },
250+
{.name = "ldo1", },
251+
};
252+
231253
static unsigned int rtq2208_of_map_mode(unsigned int mode)
232254
{
233255
switch (mode) {
@@ -322,13 +344,13 @@ static irqreturn_t rtq2208_irq_handler(int irqno, void *devid)
322344
return IRQ_HANDLED;
323345
}
324346

325-
static int rtq2208_of_get_fixed_voltage(struct device *dev,
326-
struct of_regulator_match *rtq2208_ldo_match, int n_fixed)
347+
static int rtq2208_of_get_ldo_dvs_ability(struct device *dev)
327348
{
328349
struct device_node *np;
329350
struct of_regulator_match *match;
330-
struct rtq2208_regulator_desc *rdesc;
351+
struct regulator_desc *desc;
331352
struct regulator_init_data *init_data;
353+
u32 fixed_uV;
332354
int ret, i;
333355

334356
if (!dev->of_node)
@@ -338,23 +360,37 @@ static int rtq2208_of_get_fixed_voltage(struct device *dev,
338360
if (!np)
339361
np = dev->of_node;
340362

341-
ret = of_regulator_match(dev, np, rtq2208_ldo_match, n_fixed);
363+
ret = of_regulator_match(dev, np, rtq2208_ldo_match, ARRAY_SIZE(rtq2208_ldo_match));
342364

343365
of_node_put(np);
344366

345367
if (ret < 0)
346368
return ret;
347369

348-
for (i = 0; i < n_fixed; i++) {
370+
for (i = 0; i < ARRAY_SIZE(rtq2208_ldo_match); i++) {
349371
match = rtq2208_ldo_match + i;
350372
init_data = match->init_data;
351-
rdesc = (struct rtq2208_regulator_desc *)match->driver_data;
373+
desc = (struct regulator_desc *)match->desc;
352374

353-
if (!init_data || !rdesc)
375+
if (!init_data || !desc)
354376
continue;
355377

356-
if (init_data->constraints.min_uV == init_data->constraints.max_uV)
357-
rdesc->desc.fixed_uV = init_data->constraints.min_uV;
378+
/* specify working fixed voltage if the propery exists */
379+
ret = of_property_read_u32(match->of_node, "richtek,fixed-microvolt", &fixed_uV);
380+
381+
if (!ret) {
382+
if (fixed_uV != init_data->constraints.min_uV ||
383+
fixed_uV != init_data->constraints.max_uV)
384+
return -EINVAL;
385+
desc->n_voltages = 1;
386+
desc->fixed_uV = fixed_uV;
387+
desc->fixed_uV = init_data->constraints.min_uV;
388+
desc->ops = &rtq2208_regulator_ldo_fix_ops;
389+
} else {
390+
desc->n_voltages = ARRAY_SIZE(rtq2208_ldo_volt_table);
391+
desc->volt_table = rtq2208_ldo_volt_table;
392+
desc->ops = &rtq2208_regulator_ldo_adj_ops;
393+
}
358394
}
359395

360396
return 0;
@@ -388,8 +424,7 @@ static const struct linear_range rtq2208_vout_range[] = {
388424
REGULATOR_LINEAR_RANGE(1310000, 181, 255, 10000),
389425
};
390426

391-
static void rtq2208_init_regulator_desc(struct rtq2208_regulator_desc *rdesc, int mtp_sel,
392-
int idx, struct of_regulator_match *rtq2208_ldo_match, int *ldo_idx)
427+
static void rtq2208_init_regulator_desc(struct rtq2208_regulator_desc *rdesc, int mtp_sel, int idx)
393428
{
394429
struct regulator_desc *desc;
395430
static const struct {
@@ -461,8 +496,7 @@ static void rtq2208_init_regulator_desc(struct rtq2208_regulator_desc *rdesc, in
461496
static int rtq2208_parse_regulator_dt_data(int n_regulator, const unsigned int *regulator_idx_table,
462497
struct rtq2208_regulator_desc *rdesc[RTQ2208_LDO_MAX], struct device *dev)
463498
{
464-
struct of_regulator_match rtq2208_ldo_match[2];
465-
int mtp_sel, ret, i, idx, ldo_idx = 0;
499+
int mtp_sel, i, idx, ret;
466500

467501
/* get mtp_sel0 or mtp_sel1 */
468502
mtp_sel = device_property_read_bool(dev, "richtek,mtp-sel-high");
@@ -474,15 +508,15 @@ static int rtq2208_parse_regulator_dt_data(int n_regulator, const unsigned int *
474508
if (!rdesc[i])
475509
return -ENOMEM;
476510

477-
rtq2208_init_regulator_desc(rdesc[i], mtp_sel, idx, rtq2208_ldo_match, &ldo_idx);
511+
rtq2208_init_regulator_desc(rdesc[i], mtp_sel, idx);
478512

479513
/* init ldo dvs ability */
480514
if (idx >= RTQ2208_LDO2)
481515
rtq2208_ldo_match[idx - RTQ2208_LDO2].desc = &rdesc[i]->desc;
482516
}
483517

484518
/* init ldo fixed_uV */
485-
ret = rtq2208_of_get_fixed_voltage(dev, rtq2208_ldo_match, ldo_idx);
519+
ret = rtq2208_of_get_ldo_dvs_ability(dev);
486520
if (ret)
487521
return dev_err_probe(dev, ret, "Failed to get ldo fixed_uV\n");
488522

0 commit comments

Comments
 (0)