regulator: lp873x: Convert to use regulator_set/get_current_limit_regmap
[linux-2.6-block.git] / drivers / regulator / max77650-regulator.c
CommitLineData
bcc61f1c
BG
1// SPDX-License-Identifier: GPL-2.0
2//
3// Copyright (C) 2018 BayLibre SAS
4// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
5//
6// Regulator driver for MAXIM 77650/77651 charger/power-supply.
7
5358db54 8#include <linux/of.h>
bcc61f1c
BG
9#include <linux/mfd/max77650.h>
10#include <linux/module.h>
11#include <linux/platform_device.h>
12#include <linux/regmap.h>
13#include <linux/regulator/driver.h>
14
15#define MAX77650_REGULATOR_EN_CTRL_MASK GENMASK(3, 0)
16#define MAX77650_REGULATOR_EN_CTRL_BITS(_reg) \
17 ((_reg) & MAX77650_REGULATOR_EN_CTRL_MASK)
18#define MAX77650_REGULATOR_ENABLED GENMASK(2, 1)
19#define MAX77650_REGULATOR_DISABLED BIT(2)
20
21#define MAX77650_REGULATOR_V_LDO_MASK GENMASK(6, 0)
22#define MAX77650_REGULATOR_V_SBB_MASK GENMASK(5, 0)
23
24#define MAX77650_REGULATOR_AD_MASK BIT(3)
25#define MAX77650_REGULATOR_AD_DISABLED 0x00
26#define MAX77650_REGULATOR_AD_ENABLED BIT(3)
27
28#define MAX77650_REGULATOR_CURR_LIM_MASK GENMASK(7, 6)
29#define MAX77650_REGULATOR_CURR_LIM_BITS(_reg) \
30 (((_reg) & MAX77650_REGULATOR_CURR_LIM_MASK) >> 6)
31#define MAX77650_REGULATOR_CURR_LIM_SHIFT(_val) ((_val) << 6)
32
33enum {
34 MAX77650_REGULATOR_ID_LDO = 0,
35 MAX77650_REGULATOR_ID_SBB0,
36 MAX77650_REGULATOR_ID_SBB1,
37 MAX77650_REGULATOR_ID_SBB2,
38 MAX77650_REGULATOR_NUM_REGULATORS,
39};
40
41struct max77650_regulator_desc {
42 struct regulator_desc desc;
43 unsigned int regA;
44 unsigned int regB;
45};
46
47static const u32 max77651_sbb1_regulator_volt_table[] = {
48 2400000, 3200000, 4000000, 4800000,
49 2450000, 3250000, 4050000, 4850000,
50 2500000, 3300000, 4100000, 4900000,
51 2550000, 3350000, 4150000, 4950000,
52 2600000, 3400000, 4200000, 5000000,
53 2650000, 3450000, 4250000, 5050000,
54 2700000, 3500000, 4300000, 5100000,
55 2750000, 3550000, 4350000, 5150000,
56 2800000, 3600000, 4400000, 5200000,
57 2850000, 3650000, 4450000, 5250000,
58 2900000, 3700000, 4500000, 0,
59 2950000, 3750000, 4550000, 0,
60 3000000, 3800000, 4600000, 0,
61 3050000, 3850000, 4650000, 0,
62 3100000, 3900000, 4700000, 0,
63 3150000, 3950000, 4750000, 0,
64};
65
66#define MAX77651_REGULATOR_SBB1_SEL_DEC(_val) \
67 (((_val & 0x3c) >> 2) | ((_val & 0x03) << 4))
68#define MAX77651_REGULATOR_SBB1_SEL_ENC(_val) \
69 (((_val & 0x30) >> 4) | ((_val & 0x0f) << 2))
70
71#define MAX77650_REGULATOR_SBB1_SEL_DECR(_val) \
72 do { \
73 _val = MAX77651_REGULATOR_SBB1_SEL_DEC(_val); \
74 _val--; \
75 _val = MAX77651_REGULATOR_SBB1_SEL_ENC(_val); \
76 } while (0)
77
78#define MAX77650_REGULATOR_SBB1_SEL_INCR(_val) \
79 do { \
80 _val = MAX77651_REGULATOR_SBB1_SEL_DEC(_val); \
81 _val++; \
82 _val = MAX77651_REGULATOR_SBB1_SEL_ENC(_val); \
83 } while (0)
84
85static const int max77650_current_limit_table[] = {
86 1000000, 866000, 707000, 500000,
87};
88
89static int max77650_regulator_is_enabled(struct regulator_dev *rdev)
90{
91 struct max77650_regulator_desc *rdesc;
92 struct regmap *map;
93 int val, rv, en;
94
95 rdesc = rdev_get_drvdata(rdev);
96 map = rdev_get_regmap(rdev);
97
98 rv = regmap_read(map, rdesc->regB, &val);
99 if (rv)
100 return rv;
101
102 en = MAX77650_REGULATOR_EN_CTRL_BITS(val);
103
104 return en != MAX77650_REGULATOR_DISABLED;
105}
106
107static int max77650_regulator_enable(struct regulator_dev *rdev)
108{
109 struct max77650_regulator_desc *rdesc;
110 struct regmap *map;
111
112 rdesc = rdev_get_drvdata(rdev);
113 map = rdev_get_regmap(rdev);
114
115 return regmap_update_bits(map, rdesc->regB,
116 MAX77650_REGULATOR_EN_CTRL_MASK,
117 MAX77650_REGULATOR_ENABLED);
118}
119
120static int max77650_regulator_disable(struct regulator_dev *rdev)
121{
122 struct max77650_regulator_desc *rdesc;
123 struct regmap *map;
124
125 rdesc = rdev_get_drvdata(rdev);
126 map = rdev_get_regmap(rdev);
127
128 return regmap_update_bits(map, rdesc->regB,
129 MAX77650_REGULATOR_EN_CTRL_MASK,
130 MAX77650_REGULATOR_DISABLED);
131}
132
133static int max77650_regulator_set_voltage_sel(struct regulator_dev *rdev,
134 unsigned int sel)
135{
136 int rv = 0, curr, diff;
137 bool ascending;
138
139 /*
140 * If the regulator is disabled, we can program the desired
141 * voltage right away.
142 */
143 if (!max77650_regulator_is_enabled(rdev))
144 return regulator_set_voltage_sel_regmap(rdev, sel);
145
146 /*
147 * Otherwise we need to manually ramp the output voltage up/down
148 * one step at a time.
149 */
150
151 curr = regulator_get_voltage_sel_regmap(rdev);
152 if (curr < 0)
153 return curr;
154
155 diff = curr - sel;
156 if (diff == 0)
157 return 0; /* Already there. */
158 else if (diff > 0)
159 ascending = false;
160 else
161 ascending = true;
162
163 /*
164 * Make sure we'll get to the right voltage and break the loop even if
165 * the selector equals 0.
166 */
167 for (ascending ? curr++ : curr--;; ascending ? curr++ : curr--) {
168 rv = regulator_set_voltage_sel_regmap(rdev, curr);
169 if (rv)
170 return rv;
171
172 if (curr == sel)
173 break;
174 }
175
176 return 0;
177}
178
179/*
180 * Special case: non-linear voltage table for max77651 SBB1 - software
181 * must ensure the voltage is ramped in 50mV increments.
182 */
183static int max77651_regulator_sbb1_set_voltage_sel(struct regulator_dev *rdev,
184 unsigned int sel)
185{
186 int rv = 0, curr, vcurr, vdest, vdiff;
187
188 /*
189 * If the regulator is disabled, we can program the desired
190 * voltage right away.
191 */
192 if (!max77650_regulator_is_enabled(rdev))
193 return regulator_set_voltage_sel_regmap(rdev, sel);
194
195 curr = regulator_get_voltage_sel_regmap(rdev);
196 if (curr < 0)
197 return curr;
198
199 if (curr == sel)
200 return 0; /* Already there. */
201
202 vcurr = max77651_sbb1_regulator_volt_table[curr];
203 vdest = max77651_sbb1_regulator_volt_table[sel];
204 vdiff = vcurr - vdest;
205
206 for (;;) {
207 if (vdiff > 0)
208 MAX77650_REGULATOR_SBB1_SEL_DECR(curr);
209 else
210 MAX77650_REGULATOR_SBB1_SEL_INCR(curr);
211
212 rv = regulator_set_voltage_sel_regmap(rdev, curr);
213 if (rv)
214 return rv;
215
216 if (curr == sel)
217 break;
218 };
219
220 return 0;
221}
222
223static int max77650_regulator_get_current_limit(struct regulator_dev *rdev)
224{
225 struct max77650_regulator_desc *rdesc;
226 struct regmap *map;
227 int val, rv, limit;
228
229 rdesc = rdev_get_drvdata(rdev);
230 map = rdev_get_regmap(rdev);
231
232 rv = regmap_read(map, rdesc->regA, &val);
233 if (rv)
234 return rv;
235
236 limit = MAX77650_REGULATOR_CURR_LIM_BITS(val);
237
238 return max77650_current_limit_table[limit];
239}
240
241static int max77650_regulator_set_current_limit(struct regulator_dev *rdev,
242 int min_uA, int max_uA)
243{
244 struct max77650_regulator_desc *rdesc;
245 struct regmap *map;
d3d1a6a7 246 int i, limit;
bcc61f1c
BG
247
248 rdesc = rdev_get_drvdata(rdev);
249 map = rdev_get_regmap(rdev);
250
251 for (i = 0; i < ARRAY_SIZE(max77650_current_limit_table); i++) {
252 limit = max77650_current_limit_table[i];
253
254 if (limit >= min_uA && limit <= max_uA) {
d3d1a6a7 255 return regmap_update_bits(map, rdesc->regA,
bcc61f1c
BG
256 MAX77650_REGULATOR_CURR_LIM_MASK,
257 MAX77650_REGULATOR_CURR_LIM_SHIFT(i));
bcc61f1c
BG
258 }
259 }
260
261 return -EINVAL;
262}
263
264static const struct regulator_ops max77650_regulator_LDO_ops = {
265 .is_enabled = max77650_regulator_is_enabled,
266 .enable = max77650_regulator_enable,
267 .disable = max77650_regulator_disable,
268 .list_voltage = regulator_list_voltage_linear,
269 .map_voltage = regulator_map_voltage_linear,
270 .get_voltage_sel = regulator_get_voltage_sel_regmap,
271 .set_voltage_sel = max77650_regulator_set_voltage_sel,
272 .set_active_discharge = regulator_set_active_discharge_regmap,
273};
274
275static const struct regulator_ops max77650_regulator_SBB_ops = {
276 .is_enabled = max77650_regulator_is_enabled,
277 .enable = max77650_regulator_enable,
278 .disable = max77650_regulator_disable,
279 .list_voltage = regulator_list_voltage_linear,
280 .map_voltage = regulator_map_voltage_linear,
281 .get_voltage_sel = regulator_get_voltage_sel_regmap,
282 .set_voltage_sel = max77650_regulator_set_voltage_sel,
283 .get_current_limit = max77650_regulator_get_current_limit,
284 .set_current_limit = max77650_regulator_set_current_limit,
285 .set_active_discharge = regulator_set_active_discharge_regmap,
286};
287
288/* Special case for max77651 SBB1 - non-linear voltage mapping. */
289static const struct regulator_ops max77651_SBB1_regulator_ops = {
290 .is_enabled = max77650_regulator_is_enabled,
291 .enable = max77650_regulator_enable,
292 .disable = max77650_regulator_disable,
293 .list_voltage = regulator_list_voltage_table,
294 .get_voltage_sel = regulator_get_voltage_sel_regmap,
295 .set_voltage_sel = max77651_regulator_sbb1_set_voltage_sel,
296 .get_current_limit = max77650_regulator_get_current_limit,
297 .set_current_limit = max77650_regulator_set_current_limit,
298 .set_active_discharge = regulator_set_active_discharge_regmap,
299};
300
301static struct max77650_regulator_desc max77650_LDO_desc = {
302 .desc = {
303 .name = "ldo",
304 .of_match = of_match_ptr("ldo"),
305 .regulators_node = of_match_ptr("regulators"),
306 .supply_name = "in-ldo",
307 .id = MAX77650_REGULATOR_ID_LDO,
308 .ops = &max77650_regulator_LDO_ops,
309 .min_uV = 1350000,
310 .uV_step = 12500,
311 .n_voltages = 128,
312 .vsel_mask = MAX77650_REGULATOR_V_LDO_MASK,
313 .vsel_reg = MAX77650_REG_CNFG_LDO_A,
314 .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
315 .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED,
316 .active_discharge_mask = MAX77650_REGULATOR_AD_MASK,
317 .active_discharge_reg = MAX77650_REG_CNFG_LDO_B,
318 .enable_time = 100,
319 .type = REGULATOR_VOLTAGE,
721efb50 320 .owner = THIS_MODULE,
bcc61f1c
BG
321 },
322 .regA = MAX77650_REG_CNFG_LDO_A,
323 .regB = MAX77650_REG_CNFG_LDO_B,
324};
325
326static struct max77650_regulator_desc max77650_SBB0_desc = {
327 .desc = {
328 .name = "sbb0",
329 .of_match = of_match_ptr("sbb0"),
330 .regulators_node = of_match_ptr("regulators"),
331 .supply_name = "in-sbb0",
332 .id = MAX77650_REGULATOR_ID_SBB0,
333 .ops = &max77650_regulator_SBB_ops,
334 .min_uV = 800000,
335 .uV_step = 25000,
336 .n_voltages = 64,
337 .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK,
338 .vsel_reg = MAX77650_REG_CNFG_SBB0_A,
339 .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
340 .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED,
341 .active_discharge_mask = MAX77650_REGULATOR_AD_MASK,
342 .active_discharge_reg = MAX77650_REG_CNFG_SBB0_B,
343 .enable_time = 100,
344 .type = REGULATOR_VOLTAGE,
721efb50 345 .owner = THIS_MODULE,
bcc61f1c
BG
346 },
347 .regA = MAX77650_REG_CNFG_SBB0_A,
348 .regB = MAX77650_REG_CNFG_SBB0_B,
349};
350
351static struct max77650_regulator_desc max77650_SBB1_desc = {
352 .desc = {
353 .name = "sbb1",
354 .of_match = of_match_ptr("sbb1"),
355 .regulators_node = of_match_ptr("regulators"),
356 .supply_name = "in-sbb1",
357 .id = MAX77650_REGULATOR_ID_SBB1,
358 .ops = &max77650_regulator_SBB_ops,
359 .min_uV = 800000,
360 .uV_step = 12500,
361 .n_voltages = 64,
362 .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK,
363 .vsel_reg = MAX77650_REG_CNFG_SBB1_A,
364 .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
365 .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED,
366 .active_discharge_mask = MAX77650_REGULATOR_AD_MASK,
367 .active_discharge_reg = MAX77650_REG_CNFG_SBB1_B,
368 .enable_time = 100,
369 .type = REGULATOR_VOLTAGE,
721efb50 370 .owner = THIS_MODULE,
bcc61f1c
BG
371 },
372 .regA = MAX77650_REG_CNFG_SBB1_A,
373 .regB = MAX77650_REG_CNFG_SBB1_B,
374};
375
376static struct max77650_regulator_desc max77651_SBB1_desc = {
377 .desc = {
378 .name = "sbb1",
379 .of_match = of_match_ptr("sbb1"),
380 .regulators_node = of_match_ptr("regulators"),
381 .supply_name = "in-sbb1",
382 .id = MAX77650_REGULATOR_ID_SBB1,
383 .ops = &max77651_SBB1_regulator_ops,
384 .volt_table = max77651_sbb1_regulator_volt_table,
385 .n_voltages = ARRAY_SIZE(max77651_sbb1_regulator_volt_table),
386 .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK,
387 .vsel_reg = MAX77650_REG_CNFG_SBB1_A,
388 .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
389 .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED,
390 .active_discharge_mask = MAX77650_REGULATOR_AD_MASK,
391 .active_discharge_reg = MAX77650_REG_CNFG_SBB1_B,
392 .enable_time = 100,
393 .type = REGULATOR_VOLTAGE,
721efb50 394 .owner = THIS_MODULE,
bcc61f1c
BG
395 },
396 .regA = MAX77650_REG_CNFG_SBB1_A,
397 .regB = MAX77650_REG_CNFG_SBB1_B,
398};
399
400static struct max77650_regulator_desc max77650_SBB2_desc = {
401 .desc = {
402 .name = "sbb2",
403 .of_match = of_match_ptr("sbb2"),
404 .regulators_node = of_match_ptr("regulators"),
405 .supply_name = "in-sbb0",
406 .id = MAX77650_REGULATOR_ID_SBB2,
407 .ops = &max77650_regulator_SBB_ops,
408 .min_uV = 800000,
409 .uV_step = 50000,
410 .n_voltages = 64,
411 .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK,
412 .vsel_reg = MAX77650_REG_CNFG_SBB2_A,
413 .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
414 .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED,
415 .active_discharge_mask = MAX77650_REGULATOR_AD_MASK,
416 .active_discharge_reg = MAX77650_REG_CNFG_SBB2_B,
417 .enable_time = 100,
418 .type = REGULATOR_VOLTAGE,
721efb50 419 .owner = THIS_MODULE,
bcc61f1c
BG
420 },
421 .regA = MAX77650_REG_CNFG_SBB2_A,
422 .regB = MAX77650_REG_CNFG_SBB2_B,
423};
424
425static struct max77650_regulator_desc max77651_SBB2_desc = {
426 .desc = {
427 .name = "sbb2",
428 .of_match = of_match_ptr("sbb2"),
429 .regulators_node = of_match_ptr("regulators"),
430 .supply_name = "in-sbb0",
431 .id = MAX77650_REGULATOR_ID_SBB2,
432 .ops = &max77650_regulator_SBB_ops,
433 .min_uV = 2400000,
434 .uV_step = 50000,
435 .n_voltages = 64,
436 .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK,
437 .vsel_reg = MAX77650_REG_CNFG_SBB2_A,
438 .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
439 .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED,
440 .active_discharge_mask = MAX77650_REGULATOR_AD_MASK,
441 .active_discharge_reg = MAX77650_REG_CNFG_SBB2_B,
442 .enable_time = 100,
443 .type = REGULATOR_VOLTAGE,
721efb50 444 .owner = THIS_MODULE,
bcc61f1c
BG
445 },
446 .regA = MAX77650_REG_CNFG_SBB2_A,
447 .regB = MAX77650_REG_CNFG_SBB2_B,
448};
449
450static int max77650_regulator_probe(struct platform_device *pdev)
451{
452 struct max77650_regulator_desc **rdescs;
453 struct max77650_regulator_desc *rdesc;
454 struct regulator_config config = { };
455 struct device *dev, *parent;
456 struct regulator_dev *rdev;
457 struct regmap *map;
458 unsigned int val;
459 int i, rv;
460
461 dev = &pdev->dev;
462 parent = dev->parent;
463
464 if (!dev->of_node)
465 dev->of_node = parent->of_node;
466
467 rdescs = devm_kcalloc(dev, MAX77650_REGULATOR_NUM_REGULATORS,
468 sizeof(*rdescs), GFP_KERNEL);
469 if (!rdescs)
470 return -ENOMEM;
471
472 map = dev_get_regmap(parent, NULL);
473 if (!map)
474 return -ENODEV;
475
476 rv = regmap_read(map, MAX77650_REG_CID, &val);
477 if (rv)
478 return rv;
479
480 rdescs[MAX77650_REGULATOR_ID_LDO] = &max77650_LDO_desc;
481 rdescs[MAX77650_REGULATOR_ID_SBB0] = &max77650_SBB0_desc;
482
483 switch (MAX77650_CID_BITS(val)) {
484 case MAX77650_CID_77650A:
485 case MAX77650_CID_77650C:
486 rdescs[MAX77650_REGULATOR_ID_SBB1] = &max77650_SBB1_desc;
487 rdescs[MAX77650_REGULATOR_ID_SBB2] = &max77650_SBB2_desc;
488 break;
489 case MAX77650_CID_77651A:
490 case MAX77650_CID_77651B:
491 rdescs[MAX77650_REGULATOR_ID_SBB1] = &max77651_SBB1_desc;
492 rdescs[MAX77650_REGULATOR_ID_SBB2] = &max77651_SBB2_desc;
493 break;
494 default:
495 return -ENODEV;
496 }
497
498 config.dev = parent;
499
500 for (i = 0; i < MAX77650_REGULATOR_NUM_REGULATORS; i++) {
501 rdesc = rdescs[i];
502 config.driver_data = rdesc;
503
504 rdev = devm_regulator_register(dev, &rdesc->desc, &config);
505 if (IS_ERR(rdev))
506 return PTR_ERR(rdev);
507 }
508
509 return 0;
510}
511
512static struct platform_driver max77650_regulator_driver = {
513 .driver = {
514 .name = "max77650-regulator",
515 },
516 .probe = max77650_regulator_probe,
517};
518module_platform_driver(max77650_regulator_driver);
519
520MODULE_DESCRIPTION("MAXIM 77650/77651 regulator driver");
521MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
522MODULE_LICENSE("GPL v2");