blob: a80176bdf8ec0fec414352bf50965da83fd1a500 [file] [log] [blame]
Axel Lin0ae3b062019-05-03 13:36:36 +08001// SPDX-License-Identifier: GPL-2.0+
2//
3// pv88090-regulator.c - Regulator device driver for PV88090
4// Copyright (C) 2015 Powerventure Semiconductor Ltd.
James Banc90456e2015-12-08 10:57:29 +09005
6#include <linux/err.h>
James Banc90456e2015-12-08 10:57:29 +09007#include <linux/i2c.h>
8#include <linux/module.h>
9#include <linux/init.h>
10#include <linux/slab.h>
11#include <linux/regulator/driver.h>
12#include <linux/regulator/machine.h>
13#include <linux/regmap.h>
14#include <linux/irq.h>
15#include <linux/interrupt.h>
16#include <linux/regulator/of_regulator.h>
James Banc90456e2015-12-08 10:57:29 +090017#include "pv88090-regulator.h"
18
19#define PV88090_MAX_REGULATORS 5
20
21/* PV88090 REGULATOR IDs */
22enum {
23 /* BUCKs */
24 PV88090_ID_BUCK1,
25 PV88090_ID_BUCK2,
26 PV88090_ID_BUCK3,
27
28 /* LDOs */
29 PV88090_ID_LDO1,
30 PV88090_ID_LDO2,
31};
32
33struct pv88090_regulator {
34 struct regulator_desc desc;
James Banc90456e2015-12-08 10:57:29 +090035 unsigned int conf;
36 unsigned int conf2;
37};
38
39struct pv88090 {
40 struct device *dev;
41 struct regmap *regmap;
42 struct regulator_dev *rdev[PV88090_MAX_REGULATORS];
43};
44
45struct pv88090_buck_voltage {
46 int min_uV;
47 int max_uV;
48 int uV_step;
49};
50
51static const struct regmap_config pv88090_regmap_config = {
52 .reg_bits = 8,
53 .val_bits = 8,
54};
55
56/* Current limits array (in uA) for BUCK1, BUCK2, BUCK3.
57 * Entry indexes corresponds to register values.
58 */
59
Axel Linf4afd052019-02-28 21:40:21 +080060static const unsigned int pv88090_buck1_limits[] = {
James Banc90456e2015-12-08 10:57:29 +090061 220000, 440000, 660000, 880000, 1100000, 1320000, 1540000, 1760000,
62 1980000, 2200000, 2420000, 2640000, 2860000, 3080000, 3300000, 3520000,
63 3740000, 3960000, 4180000, 4400000, 4620000, 4840000, 5060000, 5280000,
64 5500000, 5720000, 5940000, 6160000, 6380000, 6600000, 6820000, 7040000
65};
66
Axel Linf4afd052019-02-28 21:40:21 +080067static const unsigned int pv88090_buck23_limits[] = {
James Banc90456e2015-12-08 10:57:29 +090068 1496000, 2393000, 3291000, 4189000
69};
70
71static const struct pv88090_buck_voltage pv88090_buck_vol[3] = {
72 {
73 .min_uV = 600000,
74 .max_uV = 1393750,
75 .uV_step = 6250,
76 },
77
78 {
79 .min_uV = 1400000,
80 .max_uV = 2193750,
81 .uV_step = 6250,
82 },
83 {
84 .min_uV = 1250000,
85 .max_uV = 2837500,
86 .uV_step = 12500,
87 },
88};
89
90static unsigned int pv88090_buck_get_mode(struct regulator_dev *rdev)
91{
92 struct pv88090_regulator *info = rdev_get_drvdata(rdev);
93 unsigned int data;
94 int ret, mode = 0;
95
96 ret = regmap_read(rdev->regmap, info->conf, &data);
97 if (ret < 0)
98 return ret;
99
100 switch (data & PV88090_BUCK1_MODE_MASK) {
101 case PV88090_BUCK_MODE_SYNC:
102 mode = REGULATOR_MODE_FAST;
103 break;
104 case PV88090_BUCK_MODE_AUTO:
105 mode = REGULATOR_MODE_NORMAL;
106 break;
107 case PV88090_BUCK_MODE_SLEEP:
108 mode = REGULATOR_MODE_STANDBY;
109 break;
110 }
111
112 return mode;
113}
114
115static int pv88090_buck_set_mode(struct regulator_dev *rdev,
116 unsigned int mode)
117{
118 struct pv88090_regulator *info = rdev_get_drvdata(rdev);
119 int val = 0;
120
121 switch (mode) {
122 case REGULATOR_MODE_FAST:
123 val = PV88090_BUCK_MODE_SYNC;
124 break;
125 case REGULATOR_MODE_NORMAL:
126 val = PV88090_BUCK_MODE_AUTO;
127 break;
128 case REGULATOR_MODE_STANDBY:
129 val = PV88090_BUCK_MODE_SLEEP;
130 break;
131 default:
132 return -EINVAL;
133 }
134
135 return regmap_update_bits(rdev->regmap, info->conf,
136 PV88090_BUCK1_MODE_MASK, val);
137}
138
Bhumika Goyal36fe20c2017-01-28 20:45:39 +0530139static const struct regulator_ops pv88090_buck_ops = {
James Banc90456e2015-12-08 10:57:29 +0900140 .get_mode = pv88090_buck_get_mode,
141 .set_mode = pv88090_buck_set_mode,
142 .enable = regulator_enable_regmap,
143 .disable = regulator_disable_regmap,
144 .is_enabled = regulator_is_enabled_regmap,
145 .set_voltage_sel = regulator_set_voltage_sel_regmap,
146 .get_voltage_sel = regulator_get_voltage_sel_regmap,
147 .list_voltage = regulator_list_voltage_linear,
Axel Linf4afd052019-02-28 21:40:21 +0800148 .set_current_limit = regulator_set_current_limit_regmap,
149 .get_current_limit = regulator_get_current_limit_regmap,
James Banc90456e2015-12-08 10:57:29 +0900150};
151
Bhumika Goyal36fe20c2017-01-28 20:45:39 +0530152static const struct regulator_ops pv88090_ldo_ops = {
James Banc90456e2015-12-08 10:57:29 +0900153 .enable = regulator_enable_regmap,
154 .disable = regulator_disable_regmap,
155 .is_enabled = regulator_is_enabled_regmap,
156 .set_voltage_sel = regulator_set_voltage_sel_regmap,
157 .get_voltage_sel = regulator_get_voltage_sel_regmap,
158 .list_voltage = regulator_list_voltage_linear,
159};
160
161#define PV88090_BUCK(chip, regl_name, min, step, max, limits_array) \
162{\
163 .desc = {\
164 .id = chip##_ID_##regl_name,\
165 .name = __stringify(chip##_##regl_name),\
166 .of_match = of_match_ptr(#regl_name),\
167 .regulators_node = of_match_ptr("regulators"),\
168 .type = REGULATOR_VOLTAGE,\
169 .owner = THIS_MODULE,\
170 .ops = &pv88090_buck_ops,\
171 .min_uV = min, \
172 .uV_step = step, \
173 .n_voltages = ((max) - (min))/(step) + 1, \
174 .enable_reg = PV88090_REG_##regl_name##_CONF0, \
175 .enable_mask = PV88090_##regl_name##_EN, \
176 .vsel_reg = PV88090_REG_##regl_name##_CONF0, \
177 .vsel_mask = PV88090_V##regl_name##_MASK, \
Axel Linf4afd052019-02-28 21:40:21 +0800178 .curr_table = limits_array, \
179 .n_current_limits = ARRAY_SIZE(limits_array), \
180 .csel_reg = PV88090_REG_##regl_name##_CONF1, \
181 .csel_mask = PV88090_##regl_name##_ILIM_MASK, \
James Banc90456e2015-12-08 10:57:29 +0900182 },\
James Banc90456e2015-12-08 10:57:29 +0900183 .conf = PV88090_REG_##regl_name##_CONF1, \
184 .conf2 = PV88090_REG_##regl_name##_CONF2, \
185}
186
187#define PV88090_LDO(chip, regl_name, min, step, max) \
188{\
189 .desc = {\
190 .id = chip##_ID_##regl_name,\
191 .name = __stringify(chip##_##regl_name),\
192 .of_match = of_match_ptr(#regl_name),\
193 .regulators_node = of_match_ptr("regulators"),\
194 .type = REGULATOR_VOLTAGE,\
195 .owner = THIS_MODULE,\
196 .ops = &pv88090_ldo_ops,\
197 .min_uV = min, \
198 .uV_step = step, \
199 .n_voltages = ((max) - (min))/(step) + 1, \
200 .enable_reg = PV88090_REG_##regl_name##_CONT, \
201 .enable_mask = PV88090_##regl_name##_EN, \
202 .vsel_reg = PV88090_REG_##regl_name##_CONT, \
203 .vsel_mask = PV88090_V##regl_name##_MASK, \
204 },\
205}
206
207static struct pv88090_regulator pv88090_regulator_info[] = {
208 PV88090_BUCK(PV88090, BUCK1, 600000, 6250, 1393750,
209 pv88090_buck1_limits),
210 PV88090_BUCK(PV88090, BUCK2, 600000, 6250, 1393750,
211 pv88090_buck23_limits),
212 PV88090_BUCK(PV88090, BUCK3, 600000, 6250, 1393750,
213 pv88090_buck23_limits),
214 PV88090_LDO(PV88090, LDO1, 1200000, 50000, 4350000),
215 PV88090_LDO(PV88090, LDO2, 650000, 25000, 2225000),
216};
217
218static irqreturn_t pv88090_irq_handler(int irq, void *data)
219{
220 struct pv88090 *chip = data;
221 int i, reg_val, err, ret = IRQ_NONE;
222
223 err = regmap_read(chip->regmap, PV88090_REG_EVENT_A, &reg_val);
224 if (err < 0)
225 goto error_i2c;
226
227 if (reg_val & PV88090_E_VDD_FLT) {
228 for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
Michał Mirosławe9c142b02020-08-10 06:33:32 +0200229 if (chip->rdev[i] != NULL)
James Banc90456e2015-12-08 10:57:29 +0900230 regulator_notifier_call_chain(chip->rdev[i],
231 REGULATOR_EVENT_UNDER_VOLTAGE,
232 NULL);
James Banc90456e2015-12-08 10:57:29 +0900233 }
234
James Ban623f7b92016-03-07 16:08:20 +0900235 err = regmap_write(chip->regmap, PV88090_REG_EVENT_A,
236 PV88090_E_VDD_FLT);
James Banc90456e2015-12-08 10:57:29 +0900237 if (err < 0)
238 goto error_i2c;
239
240 ret = IRQ_HANDLED;
241 }
242
243 if (reg_val & PV88090_E_OVER_TEMP) {
244 for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
Michał Mirosławe9c142b02020-08-10 06:33:32 +0200245 if (chip->rdev[i] != NULL)
James Banc90456e2015-12-08 10:57:29 +0900246 regulator_notifier_call_chain(chip->rdev[i],
247 REGULATOR_EVENT_OVER_TEMP,
248 NULL);
James Banc90456e2015-12-08 10:57:29 +0900249 }
250
James Ban623f7b92016-03-07 16:08:20 +0900251 err = regmap_write(chip->regmap, PV88090_REG_EVENT_A,
252 PV88090_E_OVER_TEMP);
James Banc90456e2015-12-08 10:57:29 +0900253 if (err < 0)
254 goto error_i2c;
255
256 ret = IRQ_HANDLED;
257 }
258
259 return ret;
260
261error_i2c:
262 dev_err(chip->dev, "I2C error : %d\n", err);
263 return IRQ_NONE;
264}
265
266/*
267 * I2C driver interface functions
268 */
Axel Lin77e29592020-01-09 23:58:08 +0800269static int pv88090_i2c_probe(struct i2c_client *i2c)
James Banc90456e2015-12-08 10:57:29 +0900270{
271 struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev);
272 struct pv88090 *chip;
273 struct regulator_config config = { };
274 int error, i, ret = 0;
275 unsigned int conf2, range, index;
276
277 chip = devm_kzalloc(&i2c->dev, sizeof(struct pv88090), GFP_KERNEL);
278 if (!chip)
279 return -ENOMEM;
280
281 chip->dev = &i2c->dev;
282 chip->regmap = devm_regmap_init_i2c(i2c, &pv88090_regmap_config);
283 if (IS_ERR(chip->regmap)) {
284 error = PTR_ERR(chip->regmap);
285 dev_err(chip->dev, "Failed to allocate register map: %d\n",
286 error);
287 return error;
288 }
289
290 i2c_set_clientdata(i2c, chip);
291
292 if (i2c->irq != 0) {
293 ret = regmap_write(chip->regmap, PV88090_REG_MASK_A, 0xFF);
294 if (ret < 0) {
295 dev_err(chip->dev,
296 "Failed to mask A reg: %d\n", ret);
297 return ret;
298 }
299
300 ret = regmap_write(chip->regmap, PV88090_REG_MASK_B, 0xFF);
301 if (ret < 0) {
302 dev_err(chip->dev,
303 "Failed to mask B reg: %d\n", ret);
304 return ret;
305 }
306
Axel Linecee9882015-12-10 18:11:58 +0800307 ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
James Banc90456e2015-12-08 10:57:29 +0900308 pv88090_irq_handler,
309 IRQF_TRIGGER_LOW|IRQF_ONESHOT,
310 "pv88090", chip);
311 if (ret != 0) {
312 dev_err(chip->dev, "Failed to request IRQ: %d\n",
313 i2c->irq);
314 return ret;
315 }
316
317 ret = regmap_update_bits(chip->regmap, PV88090_REG_MASK_A,
318 PV88090_M_VDD_FLT | PV88090_M_OVER_TEMP, 0);
319 if (ret < 0) {
320 dev_err(chip->dev,
321 "Failed to update mask reg: %d\n", ret);
322 return ret;
323 }
324
325 } else {
326 dev_warn(chip->dev, "No IRQ configured\n");
327 }
328
329 config.dev = chip->dev;
330 config.regmap = chip->regmap;
331
332 for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
333 if (init_data)
334 config.init_data = &init_data[i];
335
336 if (i == PV88090_ID_BUCK2 || i == PV88090_ID_BUCK3) {
337 ret = regmap_read(chip->regmap,
338 pv88090_regulator_info[i].conf2, &conf2);
339 if (ret < 0)
340 return ret;
341
Dan Carpenterd761c902015-12-12 15:38:43 +0300342 conf2 = (conf2 >> PV88090_BUCK_VDAC_RANGE_SHIFT) &
343 PV88090_BUCK_VDAC_RANGE_MASK;
James Banc90456e2015-12-08 10:57:29 +0900344
345 ret = regmap_read(chip->regmap,
346 PV88090_REG_BUCK_FOLD_RANGE, &range);
347 if (ret < 0)
348 return ret;
349
Dan Carpenterd761c902015-12-12 15:38:43 +0300350 range = (range >>
Eric Jeong8986a112017-08-30 17:54:27 +0900351 (PV88090_BUCK_VRANGE_GAIN_SHIFT + i - 1)) &
352 PV88090_BUCK_VRANGE_GAIN_MASK;
James Banc90456e2015-12-08 10:57:29 +0900353 index = ((range << 1) | conf2);
Eric Jeong8986a112017-08-30 17:54:27 +0900354 if (index > PV88090_ID_BUCK3) {
355 dev_err(chip->dev,
356 "Invalid index(%d)\n", index);
357 return -EINVAL;
358 }
James Banc90456e2015-12-08 10:57:29 +0900359
360 pv88090_regulator_info[i].desc.min_uV
361 = pv88090_buck_vol[index].min_uV;
362 pv88090_regulator_info[i].desc.uV_step
363 = pv88090_buck_vol[index].uV_step;
364 pv88090_regulator_info[i].desc.n_voltages
365 = ((pv88090_buck_vol[index].max_uV)
366 - (pv88090_buck_vol[index].min_uV))
367 /(pv88090_buck_vol[index].uV_step) + 1;
368 }
369
370 config.driver_data = (void *)&pv88090_regulator_info[i];
371 chip->rdev[i] = devm_regulator_register(chip->dev,
372 &pv88090_regulator_info[i].desc, &config);
373 if (IS_ERR(chip->rdev[i])) {
374 dev_err(chip->dev,
375 "Failed to register PV88090 regulator\n");
376 return PTR_ERR(chip->rdev[i]);
377 }
378 }
379
380 return 0;
381}
382
383static const struct i2c_device_id pv88090_i2c_id[] = {
384 {"pv88090", 0},
385 {},
386};
387MODULE_DEVICE_TABLE(i2c, pv88090_i2c_id);
388
389#ifdef CONFIG_OF
390static const struct of_device_id pv88090_dt_ids[] = {
391 { .compatible = "pvs,pv88090", .data = &pv88090_i2c_id[0] },
392 {},
393};
394MODULE_DEVICE_TABLE(of, pv88090_dt_ids);
395#endif
396
397static struct i2c_driver pv88090_regulator_driver = {
398 .driver = {
399 .name = "pv88090",
400 .of_match_table = of_match_ptr(pv88090_dt_ids),
401 },
Axel Lin77e29592020-01-09 23:58:08 +0800402 .probe_new = pv88090_i2c_probe,
James Banc90456e2015-12-08 10:57:29 +0900403 .id_table = pv88090_i2c_id,
404};
405
406module_i2c_driver(pv88090_regulator_driver);
407
408MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");
409MODULE_DESCRIPTION("Regulator device driver for Powerventure PV88090");
410MODULE_LICENSE("GPL");