1 // SPDX-License-Identifier: GPL-2.0+
3 // pv88080-regulator.c - Regulator device driver for PV88080
4 // Copyright (C) 2016 Powerventure Semiconductor Ltd.
8 #include <linux/module.h>
10 #include <linux/init.h>
11 #include <linux/slab.h>
12 #include <linux/regulator/driver.h>
13 #include <linux/regulator/machine.h>
14 #include <linux/regmap.h>
15 #include <linux/irq.h>
16 #include <linux/interrupt.h>
17 #include <linux/regulator/of_regulator.h>
18 #include "pv88080-regulator.h"
20 #define PV88080_MAX_REGULATORS 4
22 /* PV88080 REGULATOR IDs */
36 struct pv88080_regulator
{
37 struct regulator_desc desc
;
38 unsigned int mode_reg
;
45 struct regmap
*regmap
;
46 struct regulator_dev
*rdev
[PV88080_MAX_REGULATORS
];
48 const struct pv88080_compatible_regmap
*regmap_config
;
51 struct pv88080_buck_voltage
{
57 struct pv88080_buck_regmap
{
63 int buck_vdac_range_reg
;
64 int buck_vrange_gain_reg
;
71 struct pv88080_compatible_regmap
{
73 struct pv88080_buck_regmap buck_regmap
[PV88080_MAX_REGULATORS
-1];
75 int hvbuck_enable_reg
;
77 int hvbuck_enable_mask
;
81 static const struct regmap_config pv88080_regmap_config
= {
86 /* Current limits array (in uA) for BUCK1, BUCK2, BUCK3.
87 * Entry indexes corresponds to register values.
90 static const unsigned int pv88080_buck1_limits
[] = {
91 3230000, 5130000, 6960000, 8790000
94 static const unsigned int pv88080_buck23_limits
[] = {
95 1496000, 2393000, 3291000, 4189000
98 static const struct pv88080_buck_voltage pv88080_buck_vol
[2] = {
111 static const struct pv88080_compatible_regmap pv88080_aa_regs
= {
114 .buck_enable_reg
= PV88080AA_REG_BUCK1_CONF0
,
115 .buck_vsel_reg
= PV88080AA_REG_BUCK1_CONF0
,
116 .buck_mode_reg
= PV88080AA_REG_BUCK1_CONF1
,
117 .buck_limit_reg
= PV88080AA_REG_BUCK1_CONF1
,
118 .buck_vdac_range_reg
= PV88080AA_REG_BUCK1_CONF2
,
119 .buck_vrange_gain_reg
= PV88080AA_REG_BUCK1_CONF5
,
120 .buck_enable_mask
= PV88080_BUCK1_EN
,
121 .buck_vsel_mask
= PV88080_VBUCK1_MASK
,
122 .buck_limit_mask
= PV88080_BUCK1_ILIM_MASK
,
126 .buck_enable_reg
= PV88080AA_REG_BUCK2_CONF0
,
127 .buck_vsel_reg
= PV88080AA_REG_BUCK2_CONF0
,
128 .buck_mode_reg
= PV88080AA_REG_BUCK2_CONF1
,
129 .buck_limit_reg
= PV88080AA_REG_BUCK2_CONF1
,
130 .buck_vdac_range_reg
= PV88080AA_REG_BUCK2_CONF2
,
131 .buck_vrange_gain_reg
= PV88080AA_REG_BUCK2_CONF5
,
132 .buck_enable_mask
= PV88080_BUCK2_EN
,
133 .buck_vsel_mask
= PV88080_VBUCK2_MASK
,
134 .buck_limit_mask
= PV88080_BUCK2_ILIM_MASK
,
138 .buck_enable_reg
= PV88080AA_REG_BUCK3_CONF0
,
139 .buck_vsel_reg
= PV88080AA_REG_BUCK3_CONF0
,
140 .buck_mode_reg
= PV88080AA_REG_BUCK3_CONF1
,
141 .buck_limit_reg
= PV88080AA_REG_BUCK3_CONF1
,
142 .buck_vdac_range_reg
= PV88080AA_REG_BUCK3_CONF2
,
143 .buck_vrange_gain_reg
= PV88080AA_REG_BUCK3_CONF5
,
144 .buck_enable_mask
= PV88080_BUCK3_EN
,
145 .buck_vsel_mask
= PV88080_VBUCK3_MASK
,
146 .buck_limit_mask
= PV88080_BUCK3_ILIM_MASK
,
149 .hvbuck_enable_reg
= PV88080AA_REG_HVBUCK_CONF2
,
150 .hvbuck_vsel_reg
= PV88080AA_REG_HVBUCK_CONF1
,
151 .hvbuck_enable_mask
= PV88080_HVBUCK_EN
,
152 .hvbuck_vsel_mask
= PV88080_VHVBUCK_MASK
,
155 static const struct pv88080_compatible_regmap pv88080_ba_regs
= {
158 .buck_enable_reg
= PV88080BA_REG_BUCK1_CONF0
,
159 .buck_vsel_reg
= PV88080BA_REG_BUCK1_CONF0
,
160 .buck_mode_reg
= PV88080BA_REG_BUCK1_CONF1
,
161 .buck_limit_reg
= PV88080BA_REG_BUCK1_CONF1
,
162 .buck_vdac_range_reg
= PV88080BA_REG_BUCK1_CONF2
,
163 .buck_vrange_gain_reg
= PV88080BA_REG_BUCK1_CONF5
,
164 .buck_enable_mask
= PV88080_BUCK1_EN
,
165 .buck_vsel_mask
= PV88080_VBUCK1_MASK
,
166 .buck_limit_mask
= PV88080_BUCK1_ILIM_MASK
,
170 .buck_enable_reg
= PV88080BA_REG_BUCK2_CONF0
,
171 .buck_vsel_reg
= PV88080BA_REG_BUCK2_CONF0
,
172 .buck_mode_reg
= PV88080BA_REG_BUCK2_CONF1
,
173 .buck_limit_reg
= PV88080BA_REG_BUCK2_CONF1
,
174 .buck_vdac_range_reg
= PV88080BA_REG_BUCK2_CONF2
,
175 .buck_vrange_gain_reg
= PV88080BA_REG_BUCK2_CONF5
,
176 .buck_enable_mask
= PV88080_BUCK2_EN
,
177 .buck_vsel_mask
= PV88080_VBUCK2_MASK
,
178 .buck_limit_mask
= PV88080_BUCK2_ILIM_MASK
,
182 .buck_enable_reg
= PV88080BA_REG_BUCK3_CONF0
,
183 .buck_vsel_reg
= PV88080BA_REG_BUCK3_CONF0
,
184 .buck_mode_reg
= PV88080BA_REG_BUCK3_CONF1
,
185 .buck_limit_reg
= PV88080BA_REG_BUCK3_CONF1
,
186 .buck_vdac_range_reg
= PV88080BA_REG_BUCK3_CONF2
,
187 .buck_vrange_gain_reg
= PV88080BA_REG_BUCK3_CONF5
,
188 .buck_enable_mask
= PV88080_BUCK3_EN
,
189 .buck_vsel_mask
= PV88080_VBUCK3_MASK
,
190 .buck_limit_mask
= PV88080_BUCK3_ILIM_MASK
,
193 .hvbuck_enable_reg
= PV88080BA_REG_HVBUCK_CONF2
,
194 .hvbuck_vsel_reg
= PV88080BA_REG_HVBUCK_CONF1
,
195 .hvbuck_enable_mask
= PV88080_HVBUCK_EN
,
196 .hvbuck_vsel_mask
= PV88080_VHVBUCK_MASK
,
200 static const struct of_device_id pv88080_dt_ids
[] = {
201 { .compatible
= "pvs,pv88080", .data
= (void *)TYPE_PV88080_AA
},
202 { .compatible
= "pvs,pv88080-aa", .data
= (void *)TYPE_PV88080_AA
},
203 { .compatible
= "pvs,pv88080-ba", .data
= (void *)TYPE_PV88080_BA
},
206 MODULE_DEVICE_TABLE(of
, pv88080_dt_ids
);
209 static unsigned int pv88080_buck_get_mode(struct regulator_dev
*rdev
)
211 struct pv88080_regulator
*info
= rdev_get_drvdata(rdev
);
215 ret
= regmap_read(rdev
->regmap
, info
->mode_reg
, &data
);
219 switch (data
& PV88080_BUCK1_MODE_MASK
) {
220 case PV88080_BUCK_MODE_SYNC
:
221 mode
= REGULATOR_MODE_FAST
;
223 case PV88080_BUCK_MODE_AUTO
:
224 mode
= REGULATOR_MODE_NORMAL
;
226 case PV88080_BUCK_MODE_SLEEP
:
227 mode
= REGULATOR_MODE_STANDBY
;
236 static int pv88080_buck_set_mode(struct regulator_dev
*rdev
,
239 struct pv88080_regulator
*info
= rdev_get_drvdata(rdev
);
243 case REGULATOR_MODE_FAST
:
244 val
= PV88080_BUCK_MODE_SYNC
;
246 case REGULATOR_MODE_NORMAL
:
247 val
= PV88080_BUCK_MODE_AUTO
;
249 case REGULATOR_MODE_STANDBY
:
250 val
= PV88080_BUCK_MODE_SLEEP
;
256 return regmap_update_bits(rdev
->regmap
, info
->mode_reg
,
257 PV88080_BUCK1_MODE_MASK
, val
);
260 static const struct regulator_ops pv88080_buck_ops
= {
261 .get_mode
= pv88080_buck_get_mode
,
262 .set_mode
= pv88080_buck_set_mode
,
263 .enable
= regulator_enable_regmap
,
264 .disable
= regulator_disable_regmap
,
265 .is_enabled
= regulator_is_enabled_regmap
,
266 .set_voltage_sel
= regulator_set_voltage_sel_regmap
,
267 .get_voltage_sel
= regulator_get_voltage_sel_regmap
,
268 .list_voltage
= regulator_list_voltage_linear
,
269 .set_current_limit
= regulator_set_current_limit_regmap
,
270 .get_current_limit
= regulator_get_current_limit_regmap
,
273 static const struct regulator_ops pv88080_hvbuck_ops
= {
274 .enable
= regulator_enable_regmap
,
275 .disable
= regulator_disable_regmap
,
276 .is_enabled
= regulator_is_enabled_regmap
,
277 .set_voltage_sel
= regulator_set_voltage_sel_regmap
,
278 .get_voltage_sel
= regulator_get_voltage_sel_regmap
,
279 .list_voltage
= regulator_list_voltage_linear
,
282 #define PV88080_BUCK(chip, regl_name, min, step, max, limits_array) \
285 .id = chip##_ID_##regl_name,\
286 .name = __stringify(chip##_##regl_name),\
287 .of_match = of_match_ptr(#regl_name),\
288 .regulators_node = of_match_ptr("regulators"),\
289 .type = REGULATOR_VOLTAGE,\
290 .owner = THIS_MODULE,\
291 .ops = &pv88080_buck_ops,\
294 .n_voltages = ((max) - (min))/(step) + 1, \
295 .curr_table = limits_array, \
296 .n_current_limits = ARRAY_SIZE(limits_array), \
300 #define PV88080_HVBUCK(chip, regl_name, min, step, max) \
303 .id = chip##_ID_##regl_name,\
304 .name = __stringify(chip##_##regl_name),\
305 .of_match = of_match_ptr(#regl_name),\
306 .regulators_node = of_match_ptr("regulators"),\
307 .type = REGULATOR_VOLTAGE,\
308 .owner = THIS_MODULE,\
309 .ops = &pv88080_hvbuck_ops,\
312 .n_voltages = ((max) - (min))/(step) + 1, \
316 static struct pv88080_regulator pv88080_regulator_info
[] = {
317 PV88080_BUCK(PV88080
, BUCK1
, 600000, 6250, 1393750,
318 pv88080_buck1_limits
),
319 PV88080_BUCK(PV88080
, BUCK2
, 600000, 6250, 1393750,
320 pv88080_buck23_limits
),
321 PV88080_BUCK(PV88080
, BUCK3
, 600000, 6250, 1393750,
322 pv88080_buck23_limits
),
323 PV88080_HVBUCK(PV88080
, HVBUCK
, 0, 5000, 1275000),
326 static irqreturn_t
pv88080_irq_handler(int irq
, void *data
)
328 struct pv88080
*chip
= data
;
329 int i
, reg_val
, err
, ret
= IRQ_NONE
;
331 err
= regmap_read(chip
->regmap
, PV88080_REG_EVENT_A
, ®_val
);
335 if (reg_val
& PV88080_E_VDD_FLT
) {
336 for (i
= 0; i
< PV88080_MAX_REGULATORS
; i
++) {
337 if (chip
->rdev
[i
] != NULL
)
338 regulator_notifier_call_chain(chip
->rdev
[i
],
339 REGULATOR_EVENT_UNDER_VOLTAGE
,
343 err
= regmap_write(chip
->regmap
, PV88080_REG_EVENT_A
,
351 if (reg_val
& PV88080_E_OVER_TEMP
) {
352 for (i
= 0; i
< PV88080_MAX_REGULATORS
; i
++) {
353 if (chip
->rdev
[i
] != NULL
)
354 regulator_notifier_call_chain(chip
->rdev
[i
],
355 REGULATOR_EVENT_OVER_TEMP
,
359 err
= regmap_write(chip
->regmap
, PV88080_REG_EVENT_A
,
360 PV88080_E_OVER_TEMP
);
370 dev_err(chip
->dev
, "I2C error : %d\n", err
);
375 * I2C driver interface functions
377 static int pv88080_i2c_probe(struct i2c_client
*i2c
,
378 const struct i2c_device_id
*id
)
380 struct regulator_init_data
*init_data
= dev_get_platdata(&i2c
->dev
);
381 struct pv88080
*chip
;
382 const struct pv88080_compatible_regmap
*regmap_config
;
383 const struct of_device_id
*match
;
384 struct regulator_config config
= { };
386 unsigned int conf2
, conf5
;
388 chip
= devm_kzalloc(&i2c
->dev
, sizeof(struct pv88080
), GFP_KERNEL
);
392 chip
->dev
= &i2c
->dev
;
393 chip
->regmap
= devm_regmap_init_i2c(i2c
, &pv88080_regmap_config
);
394 if (IS_ERR(chip
->regmap
)) {
395 error
= PTR_ERR(chip
->regmap
);
396 dev_err(chip
->dev
, "Failed to allocate register map: %d\n",
401 if (i2c
->dev
.of_node
) {
402 match
= of_match_node(pv88080_dt_ids
, i2c
->dev
.of_node
);
404 dev_err(chip
->dev
, "Failed to get of_match_node\n");
407 chip
->type
= (unsigned long)match
->data
;
409 chip
->type
= id
->driver_data
;
412 i2c_set_clientdata(i2c
, chip
);
415 ret
= regmap_write(chip
->regmap
, PV88080_REG_MASK_A
, 0xFF);
418 "Failed to mask A reg: %d\n", ret
);
421 ret
= regmap_write(chip
->regmap
, PV88080_REG_MASK_B
, 0xFF);
424 "Failed to mask B reg: %d\n", ret
);
427 ret
= regmap_write(chip
->regmap
, PV88080_REG_MASK_C
, 0xFF);
430 "Failed to mask C reg: %d\n", ret
);
434 ret
= devm_request_threaded_irq(&i2c
->dev
, i2c
->irq
, NULL
,
436 IRQF_TRIGGER_LOW
|IRQF_ONESHOT
,
439 dev_err(chip
->dev
, "Failed to request IRQ: %d\n",
444 ret
= regmap_update_bits(chip
->regmap
, PV88080_REG_MASK_A
,
445 PV88080_M_VDD_FLT
| PV88080_M_OVER_TEMP
, 0);
448 "Failed to update mask reg: %d\n", ret
);
452 dev_warn(chip
->dev
, "No IRQ configured\n");
455 switch (chip
->type
) {
456 case TYPE_PV88080_AA
:
457 chip
->regmap_config
= &pv88080_aa_regs
;
459 case TYPE_PV88080_BA
:
460 chip
->regmap_config
= &pv88080_ba_regs
;
464 regmap_config
= chip
->regmap_config
;
465 config
.dev
= chip
->dev
;
466 config
.regmap
= chip
->regmap
;
468 /* Registeration for BUCK1, 2, 3 */
469 for (i
= 0; i
< PV88080_MAX_REGULATORS
-1; i
++) {
471 config
.init_data
= &init_data
[i
];
473 pv88080_regulator_info
[i
].desc
.csel_reg
474 = regmap_config
->buck_regmap
[i
].buck_limit_reg
;
475 pv88080_regulator_info
[i
].desc
.csel_mask
476 = regmap_config
->buck_regmap
[i
].buck_limit_mask
;
477 pv88080_regulator_info
[i
].mode_reg
478 = regmap_config
->buck_regmap
[i
].buck_mode_reg
;
479 pv88080_regulator_info
[i
].conf2
480 = regmap_config
->buck_regmap
[i
].buck_vdac_range_reg
;
481 pv88080_regulator_info
[i
].conf5
482 = regmap_config
->buck_regmap
[i
].buck_vrange_gain_reg
;
483 pv88080_regulator_info
[i
].desc
.enable_reg
484 = regmap_config
->buck_regmap
[i
].buck_enable_reg
;
485 pv88080_regulator_info
[i
].desc
.enable_mask
486 = regmap_config
->buck_regmap
[i
].buck_enable_mask
;
487 pv88080_regulator_info
[i
].desc
.vsel_reg
488 = regmap_config
->buck_regmap
[i
].buck_vsel_reg
;
489 pv88080_regulator_info
[i
].desc
.vsel_mask
490 = regmap_config
->buck_regmap
[i
].buck_vsel_mask
;
492 ret
= regmap_read(chip
->regmap
,
493 pv88080_regulator_info
[i
].conf2
, &conf2
);
496 conf2
= ((conf2
>> PV88080_BUCK_VDAC_RANGE_SHIFT
) &
497 PV88080_BUCK_VDAC_RANGE_MASK
);
499 ret
= regmap_read(chip
->regmap
,
500 pv88080_regulator_info
[i
].conf5
, &conf5
);
503 conf5
= ((conf5
>> PV88080_BUCK_VRANGE_GAIN_SHIFT
) &
504 PV88080_BUCK_VRANGE_GAIN_MASK
);
506 pv88080_regulator_info
[i
].desc
.min_uV
=
507 pv88080_buck_vol
[conf2
].min_uV
* (conf5
+1);
508 pv88080_regulator_info
[i
].desc
.uV_step
=
509 pv88080_buck_vol
[conf2
].uV_step
* (conf5
+1);
510 pv88080_regulator_info
[i
].desc
.n_voltages
=
511 ((pv88080_buck_vol
[conf2
].max_uV
* (conf5
+1))
512 - (pv88080_regulator_info
[i
].desc
.min_uV
))
513 /(pv88080_regulator_info
[i
].desc
.uV_step
) + 1;
515 config
.driver_data
= (void *)&pv88080_regulator_info
[i
];
516 chip
->rdev
[i
] = devm_regulator_register(chip
->dev
,
517 &pv88080_regulator_info
[i
].desc
, &config
);
518 if (IS_ERR(chip
->rdev
[i
])) {
520 "Failed to register PV88080 regulator\n");
521 return PTR_ERR(chip
->rdev
[i
]);
525 pv88080_regulator_info
[PV88080_ID_HVBUCK
].desc
.enable_reg
526 = regmap_config
->hvbuck_enable_reg
;
527 pv88080_regulator_info
[PV88080_ID_HVBUCK
].desc
.enable_mask
528 = regmap_config
->hvbuck_enable_mask
;
529 pv88080_regulator_info
[PV88080_ID_HVBUCK
].desc
.vsel_reg
530 = regmap_config
->hvbuck_vsel_reg
;
531 pv88080_regulator_info
[PV88080_ID_HVBUCK
].desc
.vsel_mask
532 = regmap_config
->hvbuck_vsel_mask
;
534 /* Registeration for HVBUCK */
536 config
.init_data
= &init_data
[PV88080_ID_HVBUCK
];
538 config
.driver_data
= (void *)&pv88080_regulator_info
[PV88080_ID_HVBUCK
];
539 chip
->rdev
[PV88080_ID_HVBUCK
] = devm_regulator_register(chip
->dev
,
540 &pv88080_regulator_info
[PV88080_ID_HVBUCK
].desc
, &config
);
541 if (IS_ERR(chip
->rdev
[PV88080_ID_HVBUCK
])) {
542 dev_err(chip
->dev
, "Failed to register PV88080 regulator\n");
543 return PTR_ERR(chip
->rdev
[PV88080_ID_HVBUCK
]);
549 static const struct i2c_device_id pv88080_i2c_id
[] = {
550 { "pv88080", TYPE_PV88080_AA
},
551 { "pv88080-aa", TYPE_PV88080_AA
},
552 { "pv88080-ba", TYPE_PV88080_BA
},
555 MODULE_DEVICE_TABLE(i2c
, pv88080_i2c_id
);
557 static struct i2c_driver pv88080_regulator_driver
= {
560 .of_match_table
= of_match_ptr(pv88080_dt_ids
),
562 .probe
= pv88080_i2c_probe
,
563 .id_table
= pv88080_i2c_id
,
566 module_i2c_driver(pv88080_regulator_driver
);
568 MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");
569 MODULE_DESCRIPTION("Regulator device driver for Powerventure PV88080");
570 MODULE_LICENSE("GPL");