blob: ca08f94a368d0652d3334d15587008721117824b [file] [log] [blame]
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +01001// 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
Axel Lin5358db52019-01-30 17:07:21 +08008#include <linux/of.h>
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +01009#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)
Axel Lin3df42352019-03-25 21:55:57 +080023#define MAX77651_REGULATOR_V_SBB1_MASK GENMASK(5, 2)
24#define MAX77651_REGULATOR_V_SBB1_RANGE_MASK GENMASK(1, 0)
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +010025
26#define MAX77650_REGULATOR_AD_MASK BIT(3)
27#define MAX77650_REGULATOR_AD_DISABLED 0x00
28#define MAX77650_REGULATOR_AD_ENABLED BIT(3)
29
30#define MAX77650_REGULATOR_CURR_LIM_MASK GENMASK(7, 6)
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +010031
32enum {
33 MAX77650_REGULATOR_ID_LDO = 0,
34 MAX77650_REGULATOR_ID_SBB0,
35 MAX77650_REGULATOR_ID_SBB1,
36 MAX77650_REGULATOR_ID_SBB2,
37 MAX77650_REGULATOR_NUM_REGULATORS,
38};
39
40struct max77650_regulator_desc {
41 struct regulator_desc desc;
42 unsigned int regA;
43 unsigned int regB;
44};
45
Nathan Chancellor59dec1f2019-05-22 18:26:29 -070046static struct max77650_regulator_desc max77651_SBB1_desc;
47
Axel Lin3df42352019-03-25 21:55:57 +080048static const unsigned int max77651_sbb1_volt_range_sel[] = {
49 0x0, 0x1, 0x2, 0x3
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +010050};
51
Matti Vaittinen60ab7f42020-05-08 18:43:36 +030052static const struct linear_range max77651_sbb1_volt_ranges[] = {
Axel Lin3df42352019-03-25 21:55:57 +080053 /* range index 0 */
54 REGULATOR_LINEAR_RANGE(2400000, 0x00, 0x0f, 50000),
55 /* range index 1 */
56 REGULATOR_LINEAR_RANGE(3200000, 0x00, 0x0f, 50000),
57 /* range index 2 */
58 REGULATOR_LINEAR_RANGE(4000000, 0x00, 0x0f, 50000),
59 /* range index 3 */
60 REGULATOR_LINEAR_RANGE(4800000, 0x00, 0x09, 50000),
61};
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +010062
Axel Lin6c98ac2a2019-02-28 21:40:18 +080063static const unsigned int max77650_current_limit_table[] = {
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +010064 1000000, 866000, 707000, 500000,
65};
66
67static int max77650_regulator_is_enabled(struct regulator_dev *rdev)
68{
69 struct max77650_regulator_desc *rdesc;
70 struct regmap *map;
71 int val, rv, en;
72
73 rdesc = rdev_get_drvdata(rdev);
74 map = rdev_get_regmap(rdev);
75
76 rv = regmap_read(map, rdesc->regB, &val);
77 if (rv)
78 return rv;
79
80 en = MAX77650_REGULATOR_EN_CTRL_BITS(val);
81
82 return en != MAX77650_REGULATOR_DISABLED;
83}
84
85static int max77650_regulator_enable(struct regulator_dev *rdev)
86{
87 struct max77650_regulator_desc *rdesc;
88 struct regmap *map;
89
90 rdesc = rdev_get_drvdata(rdev);
91 map = rdev_get_regmap(rdev);
92
93 return regmap_update_bits(map, rdesc->regB,
94 MAX77650_REGULATOR_EN_CTRL_MASK,
95 MAX77650_REGULATOR_ENABLED);
96}
97
98static int max77650_regulator_disable(struct regulator_dev *rdev)
99{
100 struct max77650_regulator_desc *rdesc;
101 struct regmap *map;
102
103 rdesc = rdev_get_drvdata(rdev);
104 map = rdev_get_regmap(rdev);
105
106 return regmap_update_bits(map, rdesc->regB,
107 MAX77650_REGULATOR_EN_CTRL_MASK,
108 MAX77650_REGULATOR_DISABLED);
109}
110
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100111static const struct regulator_ops max77650_regulator_LDO_ops = {
112 .is_enabled = max77650_regulator_is_enabled,
113 .enable = max77650_regulator_enable,
114 .disable = max77650_regulator_disable,
115 .list_voltage = regulator_list_voltage_linear,
116 .map_voltage = regulator_map_voltage_linear,
117 .get_voltage_sel = regulator_get_voltage_sel_regmap,
Bartosz Golaszewski3c7577d2019-07-03 18:10:35 +0200118 .set_voltage_sel = regulator_set_voltage_sel_regmap,
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100119 .set_active_discharge = regulator_set_active_discharge_regmap,
120};
121
122static const struct regulator_ops max77650_regulator_SBB_ops = {
123 .is_enabled = max77650_regulator_is_enabled,
124 .enable = max77650_regulator_enable,
125 .disable = max77650_regulator_disable,
126 .list_voltage = regulator_list_voltage_linear,
127 .map_voltage = regulator_map_voltage_linear,
128 .get_voltage_sel = regulator_get_voltage_sel_regmap,
Bartosz Golaszewski3c7577d2019-07-03 18:10:35 +0200129 .set_voltage_sel = regulator_set_voltage_sel_regmap,
Axel Lin6c98ac2a2019-02-28 21:40:18 +0800130 .get_current_limit = regulator_get_current_limit_regmap,
131 .set_current_limit = regulator_set_current_limit_regmap,
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100132 .set_active_discharge = regulator_set_active_discharge_regmap,
133};
134
Axel Lin3df42352019-03-25 21:55:57 +0800135/* Special case for max77651 SBB1 - pickable linear-range voltage mapping. */
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100136static const struct regulator_ops max77651_SBB1_regulator_ops = {
137 .is_enabled = max77650_regulator_is_enabled,
138 .enable = max77650_regulator_enable,
139 .disable = max77650_regulator_disable,
Axel Lin3df42352019-03-25 21:55:57 +0800140 .list_voltage = regulator_list_voltage_pickable_linear_range,
141 .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
Bartosz Golaszewski3c7577d2019-07-03 18:10:35 +0200142 .set_voltage_sel = regulator_set_voltage_sel_pickable_regmap,
Axel Lin6c98ac2a2019-02-28 21:40:18 +0800143 .get_current_limit = regulator_get_current_limit_regmap,
144 .set_current_limit = regulator_set_current_limit_regmap,
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100145 .set_active_discharge = regulator_set_active_discharge_regmap,
146};
147
148static struct max77650_regulator_desc max77650_LDO_desc = {
149 .desc = {
150 .name = "ldo",
151 .of_match = of_match_ptr("ldo"),
152 .regulators_node = of_match_ptr("regulators"),
153 .supply_name = "in-ldo",
154 .id = MAX77650_REGULATOR_ID_LDO,
155 .ops = &max77650_regulator_LDO_ops,
156 .min_uV = 1350000,
157 .uV_step = 12500,
158 .n_voltages = 128,
Bartosz Golaszewski3c7577d2019-07-03 18:10:35 +0200159 .vsel_step = 1,
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100160 .vsel_mask = MAX77650_REGULATOR_V_LDO_MASK,
161 .vsel_reg = MAX77650_REG_CNFG_LDO_A,
162 .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
163 .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED,
164 .active_discharge_mask = MAX77650_REGULATOR_AD_MASK,
165 .active_discharge_reg = MAX77650_REG_CNFG_LDO_B,
166 .enable_time = 100,
167 .type = REGULATOR_VOLTAGE,
Axel Lin721efb52019-02-20 09:53:28 +0800168 .owner = THIS_MODULE,
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100169 },
170 .regA = MAX77650_REG_CNFG_LDO_A,
171 .regB = MAX77650_REG_CNFG_LDO_B,
172};
173
174static struct max77650_regulator_desc max77650_SBB0_desc = {
175 .desc = {
176 .name = "sbb0",
177 .of_match = of_match_ptr("sbb0"),
178 .regulators_node = of_match_ptr("regulators"),
179 .supply_name = "in-sbb0",
180 .id = MAX77650_REGULATOR_ID_SBB0,
181 .ops = &max77650_regulator_SBB_ops,
182 .min_uV = 800000,
183 .uV_step = 25000,
184 .n_voltages = 64,
Bartosz Golaszewski3c7577d2019-07-03 18:10:35 +0200185 .vsel_step = 1,
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100186 .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK,
187 .vsel_reg = MAX77650_REG_CNFG_SBB0_A,
188 .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
189 .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED,
190 .active_discharge_mask = MAX77650_REGULATOR_AD_MASK,
191 .active_discharge_reg = MAX77650_REG_CNFG_SBB0_B,
192 .enable_time = 100,
193 .type = REGULATOR_VOLTAGE,
Axel Lin721efb52019-02-20 09:53:28 +0800194 .owner = THIS_MODULE,
Axel Lin6c98ac2a2019-02-28 21:40:18 +0800195 .csel_reg = MAX77650_REG_CNFG_SBB0_A,
196 .csel_mask = MAX77650_REGULATOR_CURR_LIM_MASK,
197 .curr_table = max77650_current_limit_table,
198 .n_current_limits = ARRAY_SIZE(max77650_current_limit_table),
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100199 },
200 .regA = MAX77650_REG_CNFG_SBB0_A,
201 .regB = MAX77650_REG_CNFG_SBB0_B,
202};
203
204static struct max77650_regulator_desc max77650_SBB1_desc = {
205 .desc = {
206 .name = "sbb1",
207 .of_match = of_match_ptr("sbb1"),
208 .regulators_node = of_match_ptr("regulators"),
209 .supply_name = "in-sbb1",
210 .id = MAX77650_REGULATOR_ID_SBB1,
211 .ops = &max77650_regulator_SBB_ops,
212 .min_uV = 800000,
213 .uV_step = 12500,
214 .n_voltages = 64,
Bartosz Golaszewski3c7577d2019-07-03 18:10:35 +0200215 .vsel_step = 1,
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100216 .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK,
217 .vsel_reg = MAX77650_REG_CNFG_SBB1_A,
218 .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
219 .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED,
220 .active_discharge_mask = MAX77650_REGULATOR_AD_MASK,
221 .active_discharge_reg = MAX77650_REG_CNFG_SBB1_B,
222 .enable_time = 100,
223 .type = REGULATOR_VOLTAGE,
Axel Lin721efb52019-02-20 09:53:28 +0800224 .owner = THIS_MODULE,
Axel Lin6c98ac2a2019-02-28 21:40:18 +0800225 .csel_reg = MAX77650_REG_CNFG_SBB1_A,
226 .csel_mask = MAX77650_REGULATOR_CURR_LIM_MASK,
227 .curr_table = max77650_current_limit_table,
228 .n_current_limits = ARRAY_SIZE(max77650_current_limit_table),
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100229 },
230 .regA = MAX77650_REG_CNFG_SBB1_A,
231 .regB = MAX77650_REG_CNFG_SBB1_B,
232};
233
234static struct max77650_regulator_desc max77651_SBB1_desc = {
235 .desc = {
236 .name = "sbb1",
237 .of_match = of_match_ptr("sbb1"),
238 .regulators_node = of_match_ptr("regulators"),
239 .supply_name = "in-sbb1",
240 .id = MAX77650_REGULATOR_ID_SBB1,
241 .ops = &max77651_SBB1_regulator_ops,
Axel Lin3df42352019-03-25 21:55:57 +0800242 .linear_range_selectors = max77651_sbb1_volt_range_sel,
243 .linear_ranges = max77651_sbb1_volt_ranges,
244 .n_linear_ranges = ARRAY_SIZE(max77651_sbb1_volt_ranges),
245 .n_voltages = 58,
Bartosz Golaszewski3c7577d2019-07-03 18:10:35 +0200246 .vsel_step = 1,
Axel Lin3df42352019-03-25 21:55:57 +0800247 .vsel_range_mask = MAX77651_REGULATOR_V_SBB1_RANGE_MASK,
248 .vsel_range_reg = MAX77650_REG_CNFG_SBB1_A,
249 .vsel_mask = MAX77651_REGULATOR_V_SBB1_MASK,
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100250 .vsel_reg = MAX77650_REG_CNFG_SBB1_A,
251 .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
252 .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED,
253 .active_discharge_mask = MAX77650_REGULATOR_AD_MASK,
254 .active_discharge_reg = MAX77650_REG_CNFG_SBB1_B,
255 .enable_time = 100,
256 .type = REGULATOR_VOLTAGE,
Axel Lin721efb52019-02-20 09:53:28 +0800257 .owner = THIS_MODULE,
Axel Lin6c98ac2a2019-02-28 21:40:18 +0800258 .csel_reg = MAX77650_REG_CNFG_SBB1_A,
259 .csel_mask = MAX77650_REGULATOR_CURR_LIM_MASK,
260 .curr_table = max77650_current_limit_table,
261 .n_current_limits = ARRAY_SIZE(max77650_current_limit_table),
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100262 },
263 .regA = MAX77650_REG_CNFG_SBB1_A,
264 .regB = MAX77650_REG_CNFG_SBB1_B,
265};
266
267static struct max77650_regulator_desc max77650_SBB2_desc = {
268 .desc = {
269 .name = "sbb2",
270 .of_match = of_match_ptr("sbb2"),
271 .regulators_node = of_match_ptr("regulators"),
272 .supply_name = "in-sbb0",
273 .id = MAX77650_REGULATOR_ID_SBB2,
274 .ops = &max77650_regulator_SBB_ops,
275 .min_uV = 800000,
276 .uV_step = 50000,
277 .n_voltages = 64,
Bartosz Golaszewski3c7577d2019-07-03 18:10:35 +0200278 .vsel_step = 1,
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100279 .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK,
280 .vsel_reg = MAX77650_REG_CNFG_SBB2_A,
281 .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
282 .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED,
283 .active_discharge_mask = MAX77650_REGULATOR_AD_MASK,
284 .active_discharge_reg = MAX77650_REG_CNFG_SBB2_B,
285 .enable_time = 100,
286 .type = REGULATOR_VOLTAGE,
Axel Lin721efb52019-02-20 09:53:28 +0800287 .owner = THIS_MODULE,
Axel Lin6c98ac2a2019-02-28 21:40:18 +0800288 .csel_reg = MAX77650_REG_CNFG_SBB2_A,
289 .csel_mask = MAX77650_REGULATOR_CURR_LIM_MASK,
290 .curr_table = max77650_current_limit_table,
291 .n_current_limits = ARRAY_SIZE(max77650_current_limit_table),
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100292 },
293 .regA = MAX77650_REG_CNFG_SBB2_A,
294 .regB = MAX77650_REG_CNFG_SBB2_B,
295};
296
297static struct max77650_regulator_desc max77651_SBB2_desc = {
298 .desc = {
299 .name = "sbb2",
300 .of_match = of_match_ptr("sbb2"),
301 .regulators_node = of_match_ptr("regulators"),
302 .supply_name = "in-sbb0",
303 .id = MAX77650_REGULATOR_ID_SBB2,
304 .ops = &max77650_regulator_SBB_ops,
305 .min_uV = 2400000,
306 .uV_step = 50000,
307 .n_voltages = 64,
Bartosz Golaszewski3c7577d2019-07-03 18:10:35 +0200308 .vsel_step = 1,
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100309 .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK,
310 .vsel_reg = MAX77650_REG_CNFG_SBB2_A,
311 .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED,
312 .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED,
313 .active_discharge_mask = MAX77650_REGULATOR_AD_MASK,
314 .active_discharge_reg = MAX77650_REG_CNFG_SBB2_B,
315 .enable_time = 100,
316 .type = REGULATOR_VOLTAGE,
Axel Lin721efb52019-02-20 09:53:28 +0800317 .owner = THIS_MODULE,
Axel Lin6c98ac2a2019-02-28 21:40:18 +0800318 .csel_reg = MAX77650_REG_CNFG_SBB2_A,
319 .csel_mask = MAX77650_REGULATOR_CURR_LIM_MASK,
320 .curr_table = max77650_current_limit_table,
321 .n_current_limits = ARRAY_SIZE(max77650_current_limit_table),
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100322 },
323 .regA = MAX77650_REG_CNFG_SBB2_A,
324 .regB = MAX77650_REG_CNFG_SBB2_B,
325};
326
327static int max77650_regulator_probe(struct platform_device *pdev)
328{
329 struct max77650_regulator_desc **rdescs;
330 struct max77650_regulator_desc *rdesc;
331 struct regulator_config config = { };
332 struct device *dev, *parent;
333 struct regulator_dev *rdev;
334 struct regmap *map;
335 unsigned int val;
336 int i, rv;
337
338 dev = &pdev->dev;
339 parent = dev->parent;
340
341 if (!dev->of_node)
342 dev->of_node = parent->of_node;
343
344 rdescs = devm_kcalloc(dev, MAX77650_REGULATOR_NUM_REGULATORS,
345 sizeof(*rdescs), GFP_KERNEL);
346 if (!rdescs)
347 return -ENOMEM;
348
349 map = dev_get_regmap(parent, NULL);
350 if (!map)
351 return -ENODEV;
352
353 rv = regmap_read(map, MAX77650_REG_CID, &val);
354 if (rv)
355 return rv;
356
357 rdescs[MAX77650_REGULATOR_ID_LDO] = &max77650_LDO_desc;
358 rdescs[MAX77650_REGULATOR_ID_SBB0] = &max77650_SBB0_desc;
359
360 switch (MAX77650_CID_BITS(val)) {
361 case MAX77650_CID_77650A:
362 case MAX77650_CID_77650C:
363 rdescs[MAX77650_REGULATOR_ID_SBB1] = &max77650_SBB1_desc;
364 rdescs[MAX77650_REGULATOR_ID_SBB2] = &max77650_SBB2_desc;
365 break;
366 case MAX77650_CID_77651A:
367 case MAX77650_CID_77651B:
368 rdescs[MAX77650_REGULATOR_ID_SBB1] = &max77651_SBB1_desc;
369 rdescs[MAX77650_REGULATOR_ID_SBB2] = &max77651_SBB2_desc;
370 break;
371 default:
372 return -ENODEV;
373 }
374
375 config.dev = parent;
376
377 for (i = 0; i < MAX77650_REGULATOR_NUM_REGULATORS; i++) {
378 rdesc = rdescs[i];
379 config.driver_data = rdesc;
380
381 rdev = devm_regulator_register(dev, &rdesc->desc, &config);
382 if (IS_ERR(rdev))
383 return PTR_ERR(rdev);
384 }
385
386 return 0;
387}
388
Bartosz Golaszewski100a2112019-12-10 11:07:25 +0100389static const struct of_device_id max77650_regulator_of_match[] = {
390 { .compatible = "maxim,max77650-regulator" },
391 { }
392};
393MODULE_DEVICE_TABLE(of, max77650_regulator_of_match);
394
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100395static struct platform_driver max77650_regulator_driver = {
396 .driver = {
397 .name = "max77650-regulator",
Bartosz Golaszewski100a2112019-12-10 11:07:25 +0100398 .of_match_table = max77650_regulator_of_match,
Bartosz Golaszewskibcc61f12019-01-29 14:35:40 +0100399 },
400 .probe = max77650_regulator_probe,
401};
402module_platform_driver(max77650_regulator_driver);
403
404MODULE_DESCRIPTION("MAXIM 77650/77651 regulator driver");
405MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
406MODULE_LICENSE("GPL v2");
Bartosz Golaszewskiba2bf342019-07-03 10:48:49 +0200407MODULE_ALIAS("platform:max77650-regulator");