1// SPDX-License-Identifier: GPL-2.0
2//
3// regulator driver for the PF1550
4//
5// Copyright (C) 2016 Freescale Semiconductor, Inc.
6// Robin Gong <yibin.gong@freescale.com>
7//
8// Portions Copyright (c) 2025 Savoir-faire Linux Inc.
9// Samuel Kayode <samuel.kayode@savoirfairelinux.com>
10//
11
12#include <linux/err.h>
13#include <linux/interrupt.h>
14#include <linux/mfd/pf1550.h>
15#include <linux/module.h>
16#include <linux/platform_device.h>
17#include <linux/regulator/driver.h>
18#include <linux/regulator/machine.h>
19
20#define PF1550_REGULATOR_IRQ_NR 11
21#define PF1550_MAX_REGULATOR 7
22
23struct pf1550_desc {
24 struct regulator_desc desc;
25 unsigned char stby_reg;
26 unsigned char stby_mask;
27 unsigned char stby_enable_reg;
28 unsigned char stby_enable_mask;
29};
30
31struct pf1550_regulator_info {
32 struct device *dev;
33 const struct pf1550_ddata *pf1550;
34 struct pf1550_desc regulator_descs[PF1550_MAX_REGULATOR];
35 struct regulator_dev *rdevs[PF1550_MAX_REGULATOR];
36};
37
38static const int pf1550_sw12_volts[] = {
39 1100000, 1200000, 1350000, 1500000, 1800000, 2500000, 3000000, 3300000,
40};
41
42static const int pf1550_ldo13_volts[] = {
43 750000, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000,
44 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
45 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
46 2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
47};
48
49static int pf1550_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
50{
51 int id = rdev_get_id(rdev);
52 unsigned int ramp_bits = 0;
53 int ret;
54
55 if (id > PF1550_VREFDDR)
56 return -EACCES;
57
58 if (ramp_delay < 0 || ramp_delay > 6250)
59 return -EINVAL;
60
61 ramp_delay = 6250 / ramp_delay;
62 ramp_bits = ramp_delay >> 1;
63
64 ret = regmap_update_bits(map: rdev->regmap, reg: rdev->desc->vsel_reg + 4, mask: 0x10,
65 val: ramp_bits << 4);
66 if (ret < 0)
67 dev_err(&rdev->dev, "ramp failed, err %d\n", ret);
68
69 return ret;
70}
71
72static int pf1550_set_suspend_enable(struct regulator_dev *rdev)
73{
74 const struct pf1550_desc *desc = container_of_const(rdev->desc,
75 struct pf1550_desc,
76 desc);
77 unsigned int val = desc->stby_enable_mask;
78
79 return regmap_update_bits(map: rdev->regmap, reg: desc->stby_enable_reg,
80 mask: desc->stby_enable_mask, val);
81}
82
83static int pf1550_set_suspend_disable(struct regulator_dev *rdev)
84{
85 const struct pf1550_desc *desc = container_of_const(rdev->desc,
86 struct pf1550_desc,
87 desc);
88
89 return regmap_update_bits(map: rdev->regmap, reg: desc->stby_enable_reg,
90 mask: desc->stby_enable_mask, val: 0);
91}
92
93static int pf1550_buck_set_table_suspend_voltage(struct regulator_dev *rdev,
94 int uV)
95{
96 const struct pf1550_desc *desc = container_of_const(rdev->desc,
97 struct pf1550_desc,
98 desc);
99 int ret;
100
101 ret = regulator_map_voltage_ascend(rdev, min_uV: uV, max_uV: uV);
102 if (ret < 0) {
103 dev_err(rdev_get_dev(rdev), "failed to map %i uV\n", uV);
104 return ret;
105 }
106
107 return regmap_update_bits(map: rdev->regmap, reg: desc->stby_reg,
108 mask: desc->stby_mask, val: ret);
109}
110
111static int pf1550_buck_set_linear_suspend_voltage(struct regulator_dev *rdev,
112 int uV)
113{
114 const struct pf1550_desc *desc = container_of_const(rdev->desc,
115 struct pf1550_desc,
116 desc);
117 int ret;
118
119 ret = regulator_map_voltage_linear(rdev, min_uV: uV, max_uV: uV);
120 if (ret < 0) {
121 dev_err(rdev_get_dev(rdev), "failed to map %i uV\n", uV);
122 return ret;
123 }
124
125 return regmap_update_bits(map: rdev->regmap, reg: desc->stby_reg,
126 mask: desc->stby_mask, val: ret);
127}
128
129static const struct regulator_ops pf1550_sw1_ops = {
130 .enable = regulator_enable_regmap,
131 .disable = regulator_disable_regmap,
132 .set_suspend_enable = pf1550_set_suspend_enable,
133 .set_suspend_disable = pf1550_set_suspend_disable,
134 .is_enabled = regulator_is_enabled_regmap,
135 .list_voltage = regulator_list_voltage_table,
136 .set_voltage_sel = regulator_set_voltage_sel_regmap,
137 .get_voltage_sel = regulator_get_voltage_sel_regmap,
138 .set_voltage_time_sel = regulator_set_voltage_time_sel,
139 .set_suspend_voltage = pf1550_buck_set_table_suspend_voltage,
140 .map_voltage = regulator_map_voltage_ascend,
141 .set_ramp_delay = pf1550_set_ramp_delay,
142};
143
144static const struct regulator_ops pf1550_sw2_ops = {
145 .enable = regulator_enable_regmap,
146 .disable = regulator_disable_regmap,
147 .set_suspend_enable = pf1550_set_suspend_enable,
148 .set_suspend_disable = pf1550_set_suspend_disable,
149 .is_enabled = regulator_is_enabled_regmap,
150 .list_voltage = regulator_list_voltage_linear,
151 .set_voltage_sel = regulator_set_voltage_sel_regmap,
152 .get_voltage_sel = regulator_get_voltage_sel_regmap,
153 .set_voltage_time_sel = regulator_set_voltage_time_sel,
154 .set_suspend_voltage = pf1550_buck_set_linear_suspend_voltage,
155 .map_voltage = regulator_map_voltage_linear,
156 .set_ramp_delay = pf1550_set_ramp_delay,
157};
158
159static const struct regulator_ops pf1550_ldo1_ops = {
160 .enable = regulator_enable_regmap,
161 .disable = regulator_disable_regmap,
162 .set_suspend_enable = pf1550_set_suspend_enable,
163 .set_suspend_disable = pf1550_set_suspend_disable,
164 .is_enabled = regulator_is_enabled_regmap,
165 .list_voltage = regulator_list_voltage_table,
166 .map_voltage = regulator_map_voltage_ascend,
167 .set_voltage_sel = regulator_set_voltage_sel_regmap,
168 .get_voltage_sel = regulator_get_voltage_sel_regmap,
169};
170
171static const struct regulator_ops pf1550_ldo2_ops = {
172 .enable = regulator_enable_regmap,
173 .disable = regulator_disable_regmap,
174 .set_suspend_enable = pf1550_set_suspend_enable,
175 .set_suspend_disable = pf1550_set_suspend_disable,
176 .is_enabled = regulator_is_enabled_regmap,
177 .list_voltage = regulator_list_voltage_linear,
178 .set_voltage_sel = regulator_set_voltage_sel_regmap,
179 .get_voltage_sel = regulator_get_voltage_sel_regmap,
180 .map_voltage = regulator_map_voltage_linear,
181};
182
183static const struct regulator_ops pf1550_fixed_ops = {
184 .enable = regulator_enable_regmap,
185 .disable = regulator_disable_regmap,
186 .set_suspend_enable = pf1550_set_suspend_enable,
187 .set_suspend_disable = pf1550_set_suspend_disable,
188 .is_enabled = regulator_is_enabled_regmap,
189 .list_voltage = regulator_list_voltage_linear,
190};
191
192#define PF_VREF(_chip, match, _name, voltage) { \
193 .desc = { \
194 .name = #_name, \
195 .of_match = of_match_ptr(match), \
196 .regulators_node = of_match_ptr("regulators"), \
197 .n_voltages = 1, \
198 .ops = &pf1550_fixed_ops, \
199 .type = REGULATOR_VOLTAGE, \
200 .id = _chip ## _ ## _name, \
201 .owner = THIS_MODULE, \
202 .min_uV = (voltage), \
203 .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
204 .enable_mask = 0x1, \
205 }, \
206 .stby_enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
207 .stby_enable_mask = 0x2, \
208}
209
210#define PF_SW(_chip, match, _name, min, max, mask, step) { \
211 .desc = { \
212 .name = #_name, \
213 .of_match = of_match_ptr(match), \
214 .regulators_node = of_match_ptr("regulators"), \
215 .n_voltages = ((max) - (min)) / (step) + 1, \
216 .ops = &pf1550_sw2_ops, \
217 .type = REGULATOR_VOLTAGE, \
218 .id = _chip ## _ ## _name, \
219 .owner = THIS_MODULE, \
220 .min_uV = (min), \
221 .uV_step = (step), \
222 .linear_min_sel = 0, \
223 .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \
224 .vsel_mask = (mask), \
225 .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
226 .enable_mask = 0x1, \
227 }, \
228 .stby_reg = _chip ## _PMIC_REG_ ## _name ## _STBY_VOLT, \
229 .stby_mask = (mask), \
230 .stby_enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
231 .stby_enable_mask = 0x2, \
232}
233
234#define PF_LDO1(_chip, match, _name, mask, voltages) { \
235 .desc = { \
236 .name = #_name, \
237 .of_match = of_match_ptr(match), \
238 .regulators_node = of_match_ptr("regulators"), \
239 .n_voltages = ARRAY_SIZE(voltages), \
240 .ops = &pf1550_ldo1_ops, \
241 .type = REGULATOR_VOLTAGE, \
242 .id = _chip ## _ ## _name, \
243 .owner = THIS_MODULE, \
244 .volt_table = voltages, \
245 .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \
246 .vsel_mask = (mask), \
247 .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
248 .enable_mask = 0x1, \
249 }, \
250 .stby_enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
251 .stby_enable_mask = 0x2, \
252}
253
254#define PF_LDO2(_chip, match, _name, mask, min, max, step) { \
255 .desc = { \
256 .name = #_name, \
257 .of_match = of_match_ptr(match), \
258 .regulators_node = of_match_ptr("regulators"), \
259 .n_voltages = ((max) - (min)) / (step) + 1, \
260 .ops = &pf1550_ldo2_ops, \
261 .type = REGULATOR_VOLTAGE, \
262 .id = _chip ## _ ## _name, \
263 .owner = THIS_MODULE, \
264 .min_uV = (min), \
265 .uV_step = (step), \
266 .linear_min_sel = 0, \
267 .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \
268 .vsel_mask = (mask), \
269 .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
270 .enable_mask = 0x1, \
271 }, \
272 .stby_enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
273 .stby_enable_mask = 0x2, \
274}
275
276static struct pf1550_desc pf1550_regulators[] = {
277 PF_SW(PF1550, "sw1", SW1, 600000, 1387500, 0x3f, 12500),
278 PF_SW(PF1550, "sw2", SW2, 600000, 1387500, 0x3f, 12500),
279 PF_SW(PF1550, "sw3", SW3, 1800000, 3300000, 0xf, 100000),
280 PF_VREF(PF1550, "vrefddr", VREFDDR, 1200000),
281 PF_LDO1(PF1550, "ldo1", LDO1, 0x1f, pf1550_ldo13_volts),
282 PF_LDO2(PF1550, "ldo2", LDO2, 0xf, 1800000, 3300000, 100000),
283 PF_LDO1(PF1550, "ldo3", LDO3, 0x1f, pf1550_ldo13_volts),
284};
285
286static irqreturn_t pf1550_regulator_irq_handler(int irq, void *data)
287{
288 struct pf1550_regulator_info *info = data;
289 struct device *dev = info->dev;
290 struct platform_device *pdev = to_platform_device(dev);
291 int i, irq_type = -1;
292 unsigned int event;
293
294 for (i = 0; i < PF1550_REGULATOR_IRQ_NR; i++)
295 if (irq == platform_get_irq(pdev, i))
296 irq_type = i;
297
298 switch (irq_type) {
299 /* The _LS interrupts indicate over-current event. The _HS interrupts
300 * which are more accurate and can detect catastrophic faults, issue
301 * an error event. The current limit FAULT interrupt is similar to the
302 * _HS'
303 */
304 case PF1550_PMIC_IRQ_SW1_LS:
305 case PF1550_PMIC_IRQ_SW2_LS:
306 case PF1550_PMIC_IRQ_SW3_LS:
307 event = REGULATOR_EVENT_OVER_CURRENT_WARN;
308 for (i = 0; i < PF1550_MAX_REGULATOR; i++)
309 if (!strcmp(rdev_get_name(rdev: info->rdevs[i]), "SW3"))
310 regulator_notifier_call_chain(rdev: info->rdevs[i],
311 event, NULL);
312 break;
313 case PF1550_PMIC_IRQ_SW1_HS:
314 case PF1550_PMIC_IRQ_SW2_HS:
315 case PF1550_PMIC_IRQ_SW3_HS:
316 event = REGULATOR_EVENT_OVER_CURRENT;
317 for (i = 0; i < PF1550_MAX_REGULATOR; i++)
318 if (!strcmp(rdev_get_name(rdev: info->rdevs[i]), "SW3"))
319 regulator_notifier_call_chain(rdev: info->rdevs[i],
320 event, NULL);
321 break;
322 case PF1550_PMIC_IRQ_LDO1_FAULT:
323 case PF1550_PMIC_IRQ_LDO2_FAULT:
324 case PF1550_PMIC_IRQ_LDO3_FAULT:
325 event = REGULATOR_EVENT_OVER_CURRENT;
326 for (i = 0; i < PF1550_MAX_REGULATOR; i++)
327 if (!strcmp(rdev_get_name(rdev: info->rdevs[i]), "LDO3"))
328 regulator_notifier_call_chain(rdev: info->rdevs[i],
329 event, NULL);
330 break;
331 case PF1550_PMIC_IRQ_TEMP_110:
332 case PF1550_PMIC_IRQ_TEMP_125:
333 event = REGULATOR_EVENT_OVER_TEMP;
334 for (i = 0; i < PF1550_MAX_REGULATOR; i++)
335 regulator_notifier_call_chain(rdev: info->rdevs[i],
336 event, NULL);
337 break;
338 default:
339 dev_err(dev, "regulator interrupt: irq %d occurred\n",
340 irq_type);
341 }
342
343 return IRQ_HANDLED;
344}
345
346static int pf1550_regulator_probe(struct platform_device *pdev)
347{
348 const struct pf1550_ddata *pf1550 = dev_get_drvdata(dev: pdev->dev.parent);
349 struct regulator_config config = { };
350 struct pf1550_regulator_info *info;
351 int i, irq = -1, ret = 0;
352
353 info = devm_kzalloc(dev: &pdev->dev, size: sizeof(*info), GFP_KERNEL);
354 if (!info)
355 return -ENOMEM;
356
357 config.regmap = dev_get_regmap(dev: pf1550->dev, NULL);
358 if (!config.regmap)
359 return dev_err_probe(dev: &pdev->dev, err: -ENODEV,
360 fmt: "failed to get parent regmap\n");
361
362 config.dev = pf1550->dev;
363 config.regmap = pf1550->regmap;
364 info->dev = &pdev->dev;
365 info->pf1550 = pf1550;
366
367 memcpy(info->regulator_descs, pf1550_regulators,
368 sizeof(info->regulator_descs));
369
370 for (i = 0; i < ARRAY_SIZE(pf1550_regulators); i++) {
371 struct regulator_desc *desc;
372
373 desc = &info->regulator_descs[i].desc;
374
375 if ((desc->id == PF1550_SW2 && !pf1550->dvs2_enable) ||
376 (desc->id == PF1550_SW1 && !pf1550->dvs1_enable)) {
377 /* OTP_SW2_DVS_ENB == 1? or OTP_SW1_DVS_ENB == 1? */
378 desc->volt_table = pf1550_sw12_volts;
379 desc->n_voltages = ARRAY_SIZE(pf1550_sw12_volts);
380 desc->ops = &pf1550_sw1_ops;
381 }
382
383 info->rdevs[i] = devm_regulator_register(dev: &pdev->dev, regulator_desc: desc,
384 config: &config);
385 if (IS_ERR(ptr: info->rdevs[i]))
386 return dev_err_probe(dev: &pdev->dev,
387 err: PTR_ERR(ptr: info->rdevs[i]),
388 fmt: "failed to initialize regulator-%d\n",
389 i);
390 }
391
392 platform_set_drvdata(pdev, data: info);
393
394 for (i = 0; i < PF1550_REGULATOR_IRQ_NR; i++) {
395 irq = platform_get_irq(pdev, i);
396 if (irq < 0)
397 return irq;
398
399 ret = devm_request_threaded_irq(dev: &pdev->dev, irq, NULL,
400 thread_fn: pf1550_regulator_irq_handler,
401 IRQF_NO_SUSPEND,
402 devname: "pf1550-regulator", dev_id: info);
403 if (ret)
404 return dev_err_probe(dev: &pdev->dev, err: ret,
405 fmt: "failed: irq request (IRQ: %d)\n",
406 i);
407 }
408
409 return 0;
410}
411
412static const struct platform_device_id pf1550_regulator_id[] = {
413 { "pf1550-regulator", },
414 { /* sentinel */ }
415};
416MODULE_DEVICE_TABLE(platform, pf1550_regulator_id);
417
418static struct platform_driver pf1550_regulator_driver = {
419 .driver = {
420 .name = "pf1550-regulator",
421 },
422 .probe = pf1550_regulator_probe,
423 .id_table = pf1550_regulator_id,
424};
425module_platform_driver(pf1550_regulator_driver);
426
427MODULE_DESCRIPTION("NXP PF1550 regulator driver");
428MODULE_AUTHOR("Robin Gong <yibin.gong@freescale.com>");
429MODULE_LICENSE("GPL");
430

source code of linux/drivers/regulator/pf1550-regulator.c