blob: 8df1abcf7885cb38fdf0054586902773acb54128 [file] [log] [blame]
Martin Fuzzey7ae22d82020-01-14 15:56:17 +00001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018 Flowbird
4 * Martin Fuzzey <martin.fuzzey@flowbird.group>
5 */
6
7#include <common.h>
8#include <dm.h>
Simon Glasscd93d622020-05-10 11:40:13 -06009#include <linux/bitops.h>
Martin Fuzzey7ae22d82020-01-14 15:56:17 +000010#include <power/da9063_pmic.h>
11#include <power/pmic.h>
12#include <power/regulator.h>
13
14#define DA9063_BUCK_EN 0x01
15#define DA9063_LDO_EN 0x01
16#define DA9063_VBUCK_MASK 0x7F
17#define DA9063_BUCK_SL 0x80
18#define DA9063_LDO_SL 0x80
19
20#define DA9063_VLDO1_MASK 0x3F
21#define DA9063_VLDO2_MASK 0x3F
22#define DA9063_VLDO3_MASK 0x7F
23#define DA9063_VLDO4_MASK 0x7F
24#define DA9063_VLDO5_MASK 0x3F
25#define DA9063_VLDO6_MASK 0x3F
26#define DA9063_VLDO7_MASK 0x3F
27#define DA9063_VLDO8_MASK 0x3F
28#define DA9063_VLDO9_MASK 0x3F
29#define DA9063_VLDO10_MASK 0x3F
30#define DA9063_VLDO11_MASK 0x3F
31
32#define DA9063_BUCK_MODE_MASK 0xC0
33#define DA9063_BUCK_MODE_MANUAL 0x00
34#define DA9063_BUCK_MODE_SLEEP 0x40
35#define DA9063_BUCK_MODE_SYNC 0x80
36#define DA9063_BUCK_MODE_AUTO 0xC0
37
38#define DA9063_BIO_ILIM_MASK 0x0F
39#define DA9063_BMEM_ILIM_MASK 0xF0
40#define DA9063_BPRO_ILIM_MASK 0x0F
41#define DA9063_BPERI_ILIM_MASK 0xF0
42#define DA9063_BCORE1_ILIM_MASK 0x0F
43#define DA9063_BCORE2_ILIM_MASK 0xF0
44
45struct da9063_reg_info {
46 uint min_uV;
47 uint step_uV;
48 uint max_uV;
49 uint min_uA;
50 uint step_uA;
51 uint max_uA;
52 uint en_reg;
53 uint vsel_reg;
54 uint mode_reg;
55 uint ilim_reg;
56 u8 en_mask;
57 u8 vsel_mask;
58 u8 ilim_mask;
59 const char *dt_node_name;
60 const int *current_limits;
61};
62
63struct da9063_priv {
64 const struct da9063_reg_info *reg_info;
65};
66
67static struct dm_regulator_mode da9063_ldo_modes[] = {
68 { .id = DA9063_LDOMODE_SLEEP,
69 .register_value = DA9063_LDO_SL, .name = "SLEEP" },
70 { .id = DA9063_LDOMODE_NORMAL,
71 .register_value = 0, .name = "NORMAL" },
72};
73
74#define DA9063_LDO(regl_name, min_mV, step_mV, max_mV) \
75 .min_uV = (min_mV) * 1000, \
76 .step_uV = (step_mV) * 1000, \
77 .max_uV = (max_mV) * 1000, \
78 .en_reg = DA9063_REG_##regl_name##_CONT, \
79 .en_mask = DA9063_LDO_EN, \
80 .vsel_reg = DA9063_REG_V##regl_name##_A, \
81 .vsel_mask = DA9063_V##regl_name##_MASK, \
82 .mode_reg = DA9063_REG_V##regl_name##_A \
83
84/* This array is directly indexed so must stay in numerical order */
85static const struct da9063_reg_info da9063_ldo_info[] = {
86 { DA9063_LDO(LDO1, 600, 20, 1860) },
87 { DA9063_LDO(LDO2, 600, 20, 1860) },
88 { DA9063_LDO(LDO3, 900, 20, 3440) },
89 { DA9063_LDO(LDO4, 900, 20, 3440) },
90 { DA9063_LDO(LDO5, 900, 50, 3600) },
91 { DA9063_LDO(LDO6, 900, 50, 3600) },
92 { DA9063_LDO(LDO7, 900, 50, 3600) },
93 { DA9063_LDO(LDO8, 900, 50, 3600) },
94 { DA9063_LDO(LDO9, 950, 50, 3600) },
95 { DA9063_LDO(LDO10, 900, 50, 3600) },
96 { DA9063_LDO(LDO11, 900, 50, 3600) },
97};
98
99static struct dm_regulator_mode da9063_buck_modes[] = {
100 { .id = DA9063_BUCKMODE_SLEEP,
101 .register_value = DA9063_BUCK_MODE_SLEEP, .name = "SLEEP" },
102 { .id = DA9063_BUCKMODE_SYNC,
103 .register_value = DA9063_BUCK_MODE_SYNC, .name = "SYNC" },
104 { .id = DA9063_BUCKMODE_AUTO,
105 .register_value = DA9063_BUCK_MODE_AUTO, .name = "AUTO" },
106};
107
108#define DA9063_BUCK(regl_name, dt_name, \
109 min_mV, step_mV, max_mV, \
110 min_mA, step_mA, max_mA, _ilim_reg) \
111 .dt_node_name = dt_name, \
112 .min_uV = (min_mV) * 1000, \
113 .step_uV = (step_mV) * 1000, \
114 .max_uV = (max_mV) * 1000, \
115 .min_uA = (min_mA) * 1000, \
116 .step_uA = (step_mA) * 1000, \
117 .max_uA = (max_mA) * 1000, \
118 .en_reg = DA9063_REG_##regl_name##_CONT, \
119 .en_mask = DA9063_BUCK_EN, \
120 .vsel_reg = DA9063_REG_V##regl_name##_A, \
121 .vsel_mask = DA9063_VBUCK_MASK, \
122 .mode_reg = DA9063_REG_##regl_name##_CFG, \
123 .ilim_reg = DA9063_REG_BUCK_ILIM_##_ilim_reg, \
124 .ilim_mask = DA9063_##regl_name##_ILIM_MASK
125
126static const struct da9063_reg_info da9063_buck_info[] = {
127 /* mV mA */
128 { DA9063_BUCK(BCORE1, "bcore1", 300, 10, 1570, 500, 100, 2000, C) },
129 { DA9063_BUCK(BCORE2, "bcore2", 300, 10, 1570, 500, 100, 2000, C) },
130 { DA9063_BUCK(BPRO, "bpro", 530, 10, 1800, 500, 100, 2000, B) },
131 { DA9063_BUCK(BMEM, "bmem", 800, 20, 3340, 1500, 100, 3000, A) },
132 { DA9063_BUCK(BIO, "bio", 800, 20, 3340, 1500, 100, 3000, A) },
133 { DA9063_BUCK(BPERI, "bperi", 800, 20, 3340, 1500, 100, 3000, B) },
134};
135
136static int da9063_get_enable(struct udevice *dev)
137{
Simon Glass0fd3d912020-12-22 19:30:28 -0700138 const struct da9063_priv *priv = dev_get_priv(dev);
Martin Fuzzey7ae22d82020-01-14 15:56:17 +0000139 const struct da9063_reg_info *info = priv->reg_info;
140 int ret;
141
142 ret = pmic_reg_read(dev->parent, info->en_reg);
143 if (ret < 0)
144 return ret;
145
146 return ret & info->en_mask ? true : false;
147}
148
149static int da9063_set_enable(struct udevice *dev, bool enable)
150{
Simon Glass0fd3d912020-12-22 19:30:28 -0700151 const struct da9063_priv *priv = dev_get_priv(dev);
Martin Fuzzey7ae22d82020-01-14 15:56:17 +0000152 const struct da9063_reg_info *info = priv->reg_info;
153
154 return pmic_clrsetbits(dev->parent, info->en_reg,
155 info->en_mask, enable ? info->en_mask : 0);
156}
157
158static int da9063_get_voltage(struct udevice *dev)
159{
Simon Glass0fd3d912020-12-22 19:30:28 -0700160 const struct da9063_priv *priv = dev_get_priv(dev);
Martin Fuzzey7ae22d82020-01-14 15:56:17 +0000161 const struct da9063_reg_info *info = priv->reg_info;
162 int ret;
163
164 ret = pmic_reg_read(dev->parent, info->vsel_reg);
165 if (ret < 0)
166 return ret;
167
168 return info->min_uV + (ret & info->vsel_mask) * info->step_uV;
169}
170
171static int da9063_set_voltage(struct udevice *dev, int uV)
172{
Simon Glass0fd3d912020-12-22 19:30:28 -0700173 const struct da9063_priv *priv = dev_get_priv(dev);
Martin Fuzzey7ae22d82020-01-14 15:56:17 +0000174 const struct da9063_reg_info *info = priv->reg_info;
175 uint sel;
176
177 if (uV < info->min_uV || uV > info->max_uV)
178 return -EINVAL;
179
180 sel = (uV - info->min_uV) / info->step_uV;
181
182 return pmic_clrsetbits(dev->parent, info->vsel_reg,
183 info->vsel_mask, sel);
184}
185
186static const struct dm_regulator_mode
187 *da9063_find_mode_by_id(int id,
188 const struct dm_regulator_mode *modes,
189 uint mode_count)
190{
191 for (; mode_count; mode_count--) {
192 if (modes->id == id)
193 return modes;
194 modes++;
195 }
196 return NULL;
197}
198
199static int ldo_get_mode(struct udevice *dev)
200{
Simon Glass0fd3d912020-12-22 19:30:28 -0700201 const struct da9063_priv *priv = dev_get_priv(dev);
Martin Fuzzey7ae22d82020-01-14 15:56:17 +0000202 const struct da9063_reg_info *info = priv->reg_info;
203 int val;
204
205 val = pmic_reg_read(dev->parent, info->mode_reg);
206 if (val < 0)
207 return val;
208
209 if (val & DA9063_LDO_SL)
210 return DA9063_LDOMODE_SLEEP;
211 else
212 return DA9063_LDOMODE_NORMAL;
213}
214
215static int ldo_set_mode(struct udevice *dev, int mode_id)
216{
Simon Glass0fd3d912020-12-22 19:30:28 -0700217 const struct da9063_priv *priv = dev_get_priv(dev);
Martin Fuzzey7ae22d82020-01-14 15:56:17 +0000218 const struct da9063_reg_info *info = priv->reg_info;
219 const struct dm_regulator_mode *mode;
220
221 mode = da9063_find_mode_by_id(mode_id,
222 da9063_ldo_modes,
223 ARRAY_SIZE(da9063_ldo_modes));
224 if (!mode)
225 return -EINVAL;
226
227 return pmic_clrsetbits(dev->parent, info->mode_reg,
228 DA9063_LDO_SL, mode->register_value);
229}
230
231static int buck_get_mode(struct udevice *dev)
232{
Simon Glass0fd3d912020-12-22 19:30:28 -0700233 const struct da9063_priv *priv = dev_get_priv(dev);
Martin Fuzzey7ae22d82020-01-14 15:56:17 +0000234 const struct da9063_reg_info *info = priv->reg_info;
235 int i;
236 int val;
237
238 val = pmic_reg_read(dev->parent, info->mode_reg);
239 if (val < 0)
240 return val;
241
242 val &= DA9063_BUCK_MODE_MASK;
243 if (val == DA9063_BUCK_MODE_MANUAL) {
244 val = pmic_reg_read(dev->parent, info->vsel_reg);
245 if (val < 0)
246 return val;
247
248 if (val & DA9063_BUCK_SL)
249 return DA9063_BUCKMODE_SLEEP;
250 else
251 return DA9063_BUCKMODE_SYNC;
252 }
253
254 for (i = 0; i < ARRAY_SIZE(da9063_buck_modes); i++) {
255 if (da9063_buck_modes[i].register_value == val)
256 return da9063_buck_modes[i].id;
257 }
258
259 return -EINVAL;
260}
261
262static int buck_set_mode(struct udevice *dev, int mode_id)
263{
Simon Glass0fd3d912020-12-22 19:30:28 -0700264 const struct da9063_priv *priv = dev_get_priv(dev);
Martin Fuzzey7ae22d82020-01-14 15:56:17 +0000265 const struct da9063_reg_info *info = priv->reg_info;
266 const struct dm_regulator_mode *mode;
267
268 mode = da9063_find_mode_by_id(mode_id,
269 da9063_buck_modes,
270 ARRAY_SIZE(da9063_buck_modes));
271 if (!mode)
272 return -EINVAL;
273
274 return pmic_clrsetbits(dev->parent, info->mode_reg,
275 DA9063_BUCK_MODE_MASK, mode->register_value);
276}
277
278static int buck_get_current_limit(struct udevice *dev)
279{
Simon Glass0fd3d912020-12-22 19:30:28 -0700280 const struct da9063_priv *priv = dev_get_priv(dev);
Martin Fuzzey7ae22d82020-01-14 15:56:17 +0000281 const struct da9063_reg_info *info = priv->reg_info;
282 int val;
283
284 val = pmic_reg_read(dev->parent, info->ilim_reg);
285 if (val < 0)
286 return val;
287
288 val &= info->ilim_mask;
289 val >>= (ffs(info->ilim_mask) - 1);
290
291 return info->min_uA + val * info->step_uA;
292}
293
294static int buck_set_current_limit(struct udevice *dev, int uA)
295{
Simon Glass0fd3d912020-12-22 19:30:28 -0700296 const struct da9063_priv *priv = dev_get_priv(dev);
Martin Fuzzey7ae22d82020-01-14 15:56:17 +0000297 const struct da9063_reg_info *info = priv->reg_info;
298 int val;
299
300 if (uA < info->min_uA || uA > info->max_uA)
301 return -EINVAL;
302
303 val = (uA - info->min_uA) / info->step_uA;
304 val <<= (ffs(info->ilim_mask) - 1);
305
306 return pmic_clrsetbits(dev->parent, info->ilim_reg,
307 info->ilim_mask, val);
308}
309
310static int da9063_ldo_probe(struct udevice *dev)
311{
Simon Glasscaa4daa2020-12-03 16:55:18 -0700312 struct dm_regulator_uclass_plat *uc_pdata;
Simon Glass0fd3d912020-12-22 19:30:28 -0700313 struct da9063_priv *priv = dev_get_priv(dev);
Martin Fuzzey7ae22d82020-01-14 15:56:17 +0000314
315 /* LDOs are named numerically in DT so can directly index */
316 if (dev->driver_data < 1 ||
317 dev->driver_data > ARRAY_SIZE(da9063_ldo_info))
318 return -EINVAL;
319 priv->reg_info = &da9063_ldo_info[dev->driver_data - 1];
320
Simon Glasscaa4daa2020-12-03 16:55:18 -0700321 uc_pdata = dev_get_uclass_plat(dev);
Martin Fuzzey7ae22d82020-01-14 15:56:17 +0000322 uc_pdata->type = REGULATOR_TYPE_LDO;
323 uc_pdata->mode = da9063_ldo_modes;
324 uc_pdata->mode_count = ARRAY_SIZE(da9063_ldo_modes);
325
326 return 0;
327}
328
329static int da9063_buck_probe(struct udevice *dev)
330{
Simon Glasscaa4daa2020-12-03 16:55:18 -0700331 struct dm_regulator_uclass_plat *uc_pdata;
Simon Glass0fd3d912020-12-22 19:30:28 -0700332 struct da9063_priv *priv = dev_get_priv(dev);
Martin Fuzzey7ae22d82020-01-14 15:56:17 +0000333 int i;
334
335 /* Bucks have names rather than numbers so need to match with DT */
336 for (i = 0; i < ARRAY_SIZE(da9063_buck_info); i++) {
337 const struct da9063_reg_info *info = &da9063_buck_info[i];
338
339 if (!strcmp(info->dt_node_name, dev->name)) {
340 priv->reg_info = info;
341 break;
342 }
343 }
344 if (!priv->reg_info)
345 return -ENODEV;
346
Simon Glasscaa4daa2020-12-03 16:55:18 -0700347 uc_pdata = dev_get_uclass_plat(dev);
Martin Fuzzey7ae22d82020-01-14 15:56:17 +0000348 uc_pdata->type = REGULATOR_TYPE_BUCK;
349 uc_pdata->mode = da9063_buck_modes;
350 uc_pdata->mode_count = ARRAY_SIZE(da9063_buck_modes);
351
352 return 0;
353}
354
355static const struct dm_regulator_ops da9063_ldo_ops = {
356 .get_value = da9063_get_voltage,
357 .set_value = da9063_set_voltage,
358 .get_enable = da9063_get_enable,
359 .set_enable = da9063_set_enable,
360 .get_mode = ldo_get_mode,
361 .set_mode = ldo_set_mode,
362};
363
364U_BOOT_DRIVER(da9063_ldo) = {
365 .name = DA9063_LDO_DRIVER,
366 .id = UCLASS_REGULATOR,
367 .ops = &da9063_ldo_ops,
368 .probe = da9063_ldo_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700369 .priv_auto = sizeof(struct da9063_priv),
Martin Fuzzey7ae22d82020-01-14 15:56:17 +0000370};
371
372static const struct dm_regulator_ops da9063_buck_ops = {
373 .get_value = da9063_get_voltage,
374 .set_value = da9063_set_voltage,
375 .get_enable = da9063_get_enable,
376 .set_enable = da9063_set_enable,
377 .get_mode = buck_get_mode,
378 .set_mode = buck_set_mode,
379 .get_current = buck_get_current_limit,
380 .set_current = buck_set_current_limit,
381};
382
383U_BOOT_DRIVER(da9063_buck) = {
384 .name = DA9063_BUCK_DRIVER,
385 .id = UCLASS_REGULATOR,
386 .ops = &da9063_buck_ops,
387 .probe = da9063_buck_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700388 .priv_auto = sizeof(struct da9063_priv),
Martin Fuzzey7ae22d82020-01-14 15:56:17 +0000389};