blob: b1d0d97ae935684c5f2640c63e9d9ad2134d963b [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++) {
229 if (chip->rdev[i] != NULL) {
Steve Twiss275513b2019-02-26 15:46:55 +0000230 regulator_lock(chip->rdev[i]);
James Banc90456e2015-12-08 10:57:29 +0900231 regulator_notifier_call_chain(chip->rdev[i],
232 REGULATOR_EVENT_UNDER_VOLTAGE,
233 NULL);
Steve Twiss275513b2019-02-26 15:46:55 +0000234 regulator_unlock(chip->rdev[i]);
James Banc90456e2015-12-08 10:57:29 +0900235 }
236 }
237
James Ban623f7b92016-03-07 16:08:20 +0900238 err = regmap_write(chip->regmap, PV88090_REG_EVENT_A,
239 PV88090_E_VDD_FLT);
James Banc90456e2015-12-08 10:57:29 +0900240 if (err < 0)
241 goto error_i2c;
242
243 ret = IRQ_HANDLED;
244 }
245
246 if (reg_val & PV88090_E_OVER_TEMP) {
247 for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
248 if (chip->rdev[i] != NULL) {
Steve Twiss275513b2019-02-26 15:46:55 +0000249 regulator_lock(chip->rdev[i]);
James Banc90456e2015-12-08 10:57:29 +0900250 regulator_notifier_call_chain(chip->rdev[i],
251 REGULATOR_EVENT_OVER_TEMP,
252 NULL);
Steve Twiss275513b2019-02-26 15:46:55 +0000253 regulator_unlock(chip->rdev[i]);
James Banc90456e2015-12-08 10:57:29 +0900254 }
255 }
256
James Ban623f7b92016-03-07 16:08:20 +0900257 err = regmap_write(chip->regmap, PV88090_REG_EVENT_A,
258 PV88090_E_OVER_TEMP);
James Banc90456e2015-12-08 10:57:29 +0900259 if (err < 0)
260 goto error_i2c;
261
262 ret = IRQ_HANDLED;
263 }
264
265 return ret;
266
267error_i2c:
268 dev_err(chip->dev, "I2C error : %d\n", err);
269 return IRQ_NONE;
270}
271
272/*
273 * I2C driver interface functions
274 */
275static int pv88090_i2c_probe(struct i2c_client *i2c,
276 const struct i2c_device_id *id)
277{
278 struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev);
279 struct pv88090 *chip;
280 struct regulator_config config = { };
281 int error, i, ret = 0;
282 unsigned int conf2, range, index;
283
284 chip = devm_kzalloc(&i2c->dev, sizeof(struct pv88090), GFP_KERNEL);
285 if (!chip)
286 return -ENOMEM;
287
288 chip->dev = &i2c->dev;
289 chip->regmap = devm_regmap_init_i2c(i2c, &pv88090_regmap_config);
290 if (IS_ERR(chip->regmap)) {
291 error = PTR_ERR(chip->regmap);
292 dev_err(chip->dev, "Failed to allocate register map: %d\n",
293 error);
294 return error;
295 }
296
297 i2c_set_clientdata(i2c, chip);
298
299 if (i2c->irq != 0) {
300 ret = regmap_write(chip->regmap, PV88090_REG_MASK_A, 0xFF);
301 if (ret < 0) {
302 dev_err(chip->dev,
303 "Failed to mask A reg: %d\n", ret);
304 return ret;
305 }
306
307 ret = regmap_write(chip->regmap, PV88090_REG_MASK_B, 0xFF);
308 if (ret < 0) {
309 dev_err(chip->dev,
310 "Failed to mask B reg: %d\n", ret);
311 return ret;
312 }
313
Axel Linecee9882015-12-10 18:11:58 +0800314 ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
James Banc90456e2015-12-08 10:57:29 +0900315 pv88090_irq_handler,
316 IRQF_TRIGGER_LOW|IRQF_ONESHOT,
317 "pv88090", chip);
318 if (ret != 0) {
319 dev_err(chip->dev, "Failed to request IRQ: %d\n",
320 i2c->irq);
321 return ret;
322 }
323
324 ret = regmap_update_bits(chip->regmap, PV88090_REG_MASK_A,
325 PV88090_M_VDD_FLT | PV88090_M_OVER_TEMP, 0);
326 if (ret < 0) {
327 dev_err(chip->dev,
328 "Failed to update mask reg: %d\n", ret);
329 return ret;
330 }
331
332 } else {
333 dev_warn(chip->dev, "No IRQ configured\n");
334 }
335
336 config.dev = chip->dev;
337 config.regmap = chip->regmap;
338
339 for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
340 if (init_data)
341 config.init_data = &init_data[i];
342
343 if (i == PV88090_ID_BUCK2 || i == PV88090_ID_BUCK3) {
344 ret = regmap_read(chip->regmap,
345 pv88090_regulator_info[i].conf2, &conf2);
346 if (ret < 0)
347 return ret;
348
Dan Carpenterd761c902015-12-12 15:38:43 +0300349 conf2 = (conf2 >> PV88090_BUCK_VDAC_RANGE_SHIFT) &
350 PV88090_BUCK_VDAC_RANGE_MASK;
James Banc90456e2015-12-08 10:57:29 +0900351
352 ret = regmap_read(chip->regmap,
353 PV88090_REG_BUCK_FOLD_RANGE, &range);
354 if (ret < 0)
355 return ret;
356
Dan Carpenterd761c902015-12-12 15:38:43 +0300357 range = (range >>
Eric Jeong8986a112017-08-30 17:54:27 +0900358 (PV88090_BUCK_VRANGE_GAIN_SHIFT + i - 1)) &
359 PV88090_BUCK_VRANGE_GAIN_MASK;
James Banc90456e2015-12-08 10:57:29 +0900360 index = ((range << 1) | conf2);
Eric Jeong8986a112017-08-30 17:54:27 +0900361 if (index > PV88090_ID_BUCK3) {
362 dev_err(chip->dev,
363 "Invalid index(%d)\n", index);
364 return -EINVAL;
365 }
James Banc90456e2015-12-08 10:57:29 +0900366
367 pv88090_regulator_info[i].desc.min_uV
368 = pv88090_buck_vol[index].min_uV;
369 pv88090_regulator_info[i].desc.uV_step
370 = pv88090_buck_vol[index].uV_step;
371 pv88090_regulator_info[i].desc.n_voltages
372 = ((pv88090_buck_vol[index].max_uV)
373 - (pv88090_buck_vol[index].min_uV))
374 /(pv88090_buck_vol[index].uV_step) + 1;
375 }
376
377 config.driver_data = (void *)&pv88090_regulator_info[i];
378 chip->rdev[i] = devm_regulator_register(chip->dev,
379 &pv88090_regulator_info[i].desc, &config);
380 if (IS_ERR(chip->rdev[i])) {
381 dev_err(chip->dev,
382 "Failed to register PV88090 regulator\n");
383 return PTR_ERR(chip->rdev[i]);
384 }
385 }
386
387 return 0;
388}
389
390static const struct i2c_device_id pv88090_i2c_id[] = {
391 {"pv88090", 0},
392 {},
393};
394MODULE_DEVICE_TABLE(i2c, pv88090_i2c_id);
395
396#ifdef CONFIG_OF
397static const struct of_device_id pv88090_dt_ids[] = {
398 { .compatible = "pvs,pv88090", .data = &pv88090_i2c_id[0] },
399 {},
400};
401MODULE_DEVICE_TABLE(of, pv88090_dt_ids);
402#endif
403
404static struct i2c_driver pv88090_regulator_driver = {
405 .driver = {
406 .name = "pv88090",
407 .of_match_table = of_match_ptr(pv88090_dt_ids),
408 },
409 .probe = pv88090_i2c_probe,
410 .id_table = pv88090_i2c_id,
411};
412
413module_i2c_driver(pv88090_regulator_driver);
414
415MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");
416MODULE_DESCRIPTION("Regulator device driver for Powerventure PV88090");
417MODULE_LICENSE("GPL");