]>
Commit | Line | Data |
---|---|---|
237868c9 PF |
1 | /* |
2 | * Copyright 2017 NXP | |
3 | * | |
4 | * Peng Fan <peng.fan@nxp.com> | |
5 | * | |
6 | * SPDX-License-Identifier: GPL-2.0+ | |
7 | */ | |
8 | ||
8fa46350 PF |
9 | #include <common.h> |
10 | #include <fdtdec.h> | |
11 | #include <errno.h> | |
12 | #include <dm.h> | |
13 | #include <i2c.h> | |
14 | #include <power/pmic.h> | |
15 | #include <power/regulator.h> | |
16 | #include <power/pfuze100_pmic.h> | |
17 | ||
18 | /** | |
19 | * struct pfuze100_regulator_desc - regulator descriptor | |
20 | * | |
21 | * @name: Identify name for the regulator. | |
22 | * @type: Indicates the regulator type. | |
23 | * @uV_step: Voltage increase for each selector. | |
24 | * @vsel_reg: Register for adjust regulator voltage for normal. | |
25 | * @vsel_mask: Mask bit for setting regulator voltage for normal. | |
26 | * @stby_reg: Register for adjust regulator voltage for standby. | |
27 | * @stby_mask: Mask bit for setting regulator voltage for standby. | |
28 | * @volt_table: Voltage mapping table (if table based mapping). | |
29 | * @voltage: Current voltage for REGULATOR_TYPE_FIXED type regulator. | |
30 | */ | |
31 | struct pfuze100_regulator_desc { | |
32 | char *name; | |
33 | enum regulator_type type; | |
34 | unsigned int uV_step; | |
35 | unsigned int vsel_reg; | |
36 | unsigned int vsel_mask; | |
37 | unsigned int stby_reg; | |
38 | unsigned int stby_mask; | |
39 | unsigned int *volt_table; | |
40 | unsigned int voltage; | |
41 | }; | |
42 | ||
43 | /** | |
44 | * struct pfuze100_regulator_platdata - platform data for pfuze100 | |
45 | * | |
46 | * @desc: Points the description entry of one regulator of pfuze100 | |
47 | */ | |
48 | struct pfuze100_regulator_platdata { | |
49 | struct pfuze100_regulator_desc *desc; | |
50 | }; | |
51 | ||
52 | #define PFUZE100_FIXED_REG(_name, base, vol) \ | |
53 | { \ | |
54 | .name = #_name, \ | |
55 | .type = REGULATOR_TYPE_FIXED, \ | |
56 | .voltage = (vol), \ | |
57 | } | |
58 | ||
59 | #define PFUZE100_SW_REG(_name, base, step) \ | |
60 | { \ | |
61 | .name = #_name, \ | |
62 | .type = REGULATOR_TYPE_BUCK, \ | |
63 | .uV_step = (step), \ | |
64 | .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ | |
65 | .vsel_mask = 0x3F, \ | |
66 | .stby_reg = (base) + PFUZE100_STBY_OFFSET, \ | |
67 | .stby_mask = 0x3F, \ | |
68 | } | |
69 | ||
70 | #define PFUZE100_SWB_REG(_name, base, mask, step, voltages) \ | |
71 | { \ | |
72 | .name = #_name, \ | |
73 | .type = REGULATOR_TYPE_BUCK, \ | |
74 | .uV_step = (step), \ | |
75 | .vsel_reg = (base), \ | |
76 | .vsel_mask = (mask), \ | |
77 | .volt_table = (voltages), \ | |
78 | } | |
79 | ||
80 | #define PFUZE100_SNVS_REG(_name, base, mask, voltages) \ | |
81 | { \ | |
82 | .name = #_name, \ | |
83 | .type = REGULATOR_TYPE_OTHER, \ | |
84 | .vsel_reg = (base), \ | |
85 | .vsel_mask = (mask), \ | |
86 | .volt_table = (voltages), \ | |
87 | } | |
88 | ||
89 | #define PFUZE100_VGEN_REG(_name, base, step) \ | |
90 | { \ | |
91 | .name = #_name, \ | |
92 | .type = REGULATOR_TYPE_LDO, \ | |
93 | .uV_step = (step), \ | |
94 | .vsel_reg = (base), \ | |
95 | .vsel_mask = 0xF, \ | |
96 | .stby_reg = (base), \ | |
97 | .stby_mask = 0x20, \ | |
98 | } | |
99 | ||
100 | #define PFUZE3000_VCC_REG(_name, base, step) \ | |
101 | { \ | |
102 | .name = #_name, \ | |
103 | .type = REGULATOR_TYPE_LDO, \ | |
104 | .uV_step = (step), \ | |
105 | .vsel_reg = (base), \ | |
106 | .vsel_mask = 0x3, \ | |
107 | .stby_reg = (base), \ | |
108 | .stby_mask = 0x20, \ | |
109 | } | |
110 | ||
111 | #define PFUZE3000_SW1_REG(_name, base, step) \ | |
112 | { \ | |
113 | .name = #_name, \ | |
114 | .type = REGULATOR_TYPE_BUCK, \ | |
115 | .uV_step = (step), \ | |
116 | .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ | |
117 | .vsel_mask = 0x1F, \ | |
118 | .stby_reg = (base) + PFUZE100_STBY_OFFSET, \ | |
119 | .stby_mask = 0x1F, \ | |
120 | } | |
121 | ||
122 | #define PFUZE3000_SW2_REG(_name, base, step) \ | |
123 | { \ | |
124 | .name = #_name, \ | |
125 | .type = REGULATOR_TYPE_BUCK, \ | |
126 | .uV_step = (step), \ | |
127 | .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ | |
128 | .vsel_mask = 0x7, \ | |
129 | .stby_reg = (base) + PFUZE100_STBY_OFFSET, \ | |
130 | .stby_mask = 0x7, \ | |
131 | } | |
132 | ||
133 | #define PFUZE3000_SW3_REG(_name, base, step) \ | |
134 | { \ | |
135 | .name = #_name, \ | |
136 | .type = REGULATOR_TYPE_BUCK, \ | |
137 | .uV_step = (step), \ | |
138 | .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ | |
139 | .vsel_mask = 0xF, \ | |
140 | .stby_reg = (base) + PFUZE100_STBY_OFFSET, \ | |
141 | .stby_mask = 0xF, \ | |
142 | } | |
143 | ||
144 | static unsigned int pfuze100_swbst[] = { | |
145 | 5000000, 5050000, 5100000, 5150000 | |
146 | }; | |
147 | ||
148 | static unsigned int pfuze100_vsnvs[] = { | |
149 | 1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000, -1 | |
150 | }; | |
151 | ||
152 | static unsigned int pfuze3000_vsnvs[] = { | |
153 | -1, -1, -1, -1, -1, -1, 3000000, -1 | |
154 | }; | |
155 | ||
156 | static unsigned int pfuze3000_sw2lo[] = { | |
157 | 1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000 | |
158 | }; | |
159 | ||
160 | /* PFUZE100 */ | |
161 | static struct pfuze100_regulator_desc pfuze100_regulators[] = { | |
162 | PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000), | |
163 | PFUZE100_SW_REG(sw1c, PFUZE100_SW1CVOL, 25000), | |
164 | PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000), | |
165 | PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000), | |
166 | PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000), | |
167 | PFUZE100_SW_REG(sw4, PFUZE100_SW4VOL, 25000), | |
168 | PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst), | |
169 | PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), | |
170 | PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000), | |
171 | PFUZE100_VGEN_REG(vgen1, PFUZE100_VGEN1VOL, 50000), | |
172 | PFUZE100_VGEN_REG(vgen2, PFUZE100_VGEN2VOL, 50000), | |
173 | PFUZE100_VGEN_REG(vgen3, PFUZE100_VGEN3VOL, 100000), | |
174 | PFUZE100_VGEN_REG(vgen4, PFUZE100_VGEN4VOL, 100000), | |
175 | PFUZE100_VGEN_REG(vgen5, PFUZE100_VGEN5VOL, 100000), | |
176 | PFUZE100_VGEN_REG(vgen6, PFUZE100_VGEN6VOL, 100000), | |
177 | }; | |
178 | ||
179 | /* PFUZE200 */ | |
180 | static struct pfuze100_regulator_desc pfuze200_regulators[] = { | |
181 | PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000), | |
182 | PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000), | |
183 | PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000), | |
184 | PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000), | |
185 | PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst), | |
186 | PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), | |
187 | PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000), | |
188 | PFUZE100_VGEN_REG(vgen1, PFUZE100_VGEN1VOL, 50000), | |
189 | PFUZE100_VGEN_REG(vgen2, PFUZE100_VGEN2VOL, 50000), | |
190 | PFUZE100_VGEN_REG(vgen3, PFUZE100_VGEN3VOL, 100000), | |
191 | PFUZE100_VGEN_REG(vgen4, PFUZE100_VGEN4VOL, 100000), | |
192 | PFUZE100_VGEN_REG(vgen5, PFUZE100_VGEN5VOL, 100000), | |
193 | PFUZE100_VGEN_REG(vgen6, PFUZE100_VGEN6VOL, 100000), | |
194 | }; | |
195 | ||
196 | /* PFUZE3000 */ | |
197 | static struct pfuze100_regulator_desc pfuze3000_regulators[] = { | |
198 | PFUZE3000_SW1_REG(sw1a, PFUZE100_SW1ABVOL, 25000), | |
199 | PFUZE3000_SW1_REG(sw1b, PFUZE100_SW1CVOL, 25000), | |
200 | PFUZE100_SWB_REG(sw2, PFUZE100_SW2VOL, 0x7, 50000, pfuze3000_sw2lo), | |
201 | PFUZE3000_SW3_REG(sw3, PFUZE100_SW3AVOL, 50000), | |
202 | PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst), | |
203 | PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze3000_vsnvs), | |
204 | PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000), | |
205 | PFUZE100_VGEN_REG(vldo1, PFUZE100_VGEN1VOL, 100000), | |
206 | PFUZE100_VGEN_REG(vldo2, PFUZE100_VGEN2VOL, 50000), | |
207 | PFUZE3000_VCC_REG(vccsd, PFUZE100_VGEN3VOL, 150000), | |
208 | PFUZE3000_VCC_REG(v33, PFUZE100_VGEN4VOL, 150000), | |
209 | PFUZE100_VGEN_REG(vldo3, PFUZE100_VGEN5VOL, 100000), | |
210 | PFUZE100_VGEN_REG(vldo4, PFUZE100_VGEN6VOL, 100000), | |
211 | }; | |
212 | ||
213 | #define MODE(_id, _val, _name) { \ | |
214 | .id = _id, \ | |
215 | .register_value = _val, \ | |
216 | .name = _name, \ | |
217 | } | |
218 | ||
219 | /* SWx Buck regulator mode */ | |
220 | static struct dm_regulator_mode pfuze_sw_modes[] = { | |
221 | MODE(OFF_OFF, OFF_OFF, "OFF_OFF"), | |
222 | MODE(PWM_OFF, PWM_OFF, "PWM_OFF"), | |
223 | MODE(PFM_OFF, PFM_OFF, "PFM_OFF"), | |
224 | MODE(APS_OFF, APS_OFF, "APS_OFF"), | |
225 | MODE(PWM_PWM, PWM_PWM, "PWM_PWM"), | |
226 | MODE(PWM_APS, PWM_APS, "PWM_APS"), | |
227 | MODE(APS_APS, APS_APS, "APS_APS"), | |
228 | MODE(APS_PFM, APS_PFM, "APS_PFM"), | |
229 | MODE(PWM_PFM, PWM_PFM, "PWM_PFM"), | |
230 | }; | |
231 | ||
232 | /* Boost Buck regulator mode for normal operation */ | |
233 | static struct dm_regulator_mode pfuze_swbst_modes[] = { | |
234 | MODE(SWBST_MODE_OFF, SWBST_MODE_OFF , "SWBST_MODE_OFF"), | |
235 | MODE(SWBST_MODE_PFM, SWBST_MODE_PFM, "SWBST_MODE_PFM"), | |
236 | MODE(SWBST_MODE_AUTO, SWBST_MODE_AUTO, "SWBST_MODE_AUTO"), | |
237 | MODE(SWBST_MODE_APS, SWBST_MODE_APS, "SWBST_MODE_APS"), | |
238 | }; | |
239 | ||
240 | /* VGENx LDO regulator mode for normal operation */ | |
241 | static struct dm_regulator_mode pfuze_ldo_modes[] = { | |
242 | MODE(LDO_MODE_OFF, LDO_MODE_OFF, "LDO_MODE_OFF"), | |
243 | MODE(LDO_MODE_ON, LDO_MODE_ON, "LDO_MODE_ON"), | |
244 | }; | |
245 | ||
246 | static struct pfuze100_regulator_desc *se_desc(struct pfuze100_regulator_desc *desc, | |
247 | int size, | |
248 | const char *name) | |
249 | { | |
250 | int i; | |
251 | ||
252 | for (i = 0; i < size; desc++) { | |
253 | if (!strcmp(desc->name, name)) | |
254 | return desc; | |
255 | continue; | |
256 | } | |
257 | ||
258 | return NULL; | |
259 | } | |
260 | ||
261 | static int pfuze100_regulator_probe(struct udevice *dev) | |
262 | { | |
263 | struct dm_regulator_uclass_platdata *uc_pdata; | |
264 | struct pfuze100_regulator_platdata *plat = dev_get_platdata(dev); | |
265 | struct pfuze100_regulator_desc *desc; | |
266 | ||
267 | switch (dev_get_driver_data(dev_get_parent(dev))) { | |
268 | case PFUZE100: | |
269 | desc = se_desc(pfuze100_regulators, | |
270 | ARRAY_SIZE(pfuze100_regulators), | |
271 | dev->name); | |
272 | break; | |
273 | case PFUZE200: | |
274 | desc = se_desc(pfuze200_regulators, | |
275 | ARRAY_SIZE(pfuze200_regulators), | |
276 | dev->name); | |
277 | break; | |
278 | case PFUZE3000: | |
279 | desc = se_desc(pfuze3000_regulators, | |
280 | ARRAY_SIZE(pfuze3000_regulators), | |
281 | dev->name); | |
282 | break; | |
283 | default: | |
284 | debug("Unsupported PFUZE\n"); | |
285 | return -EINVAL; | |
286 | } | |
287 | if (!desc) { | |
288 | debug("Do not support regulator %s\n", dev->name); | |
289 | return -EINVAL; | |
290 | } | |
291 | ||
292 | plat->desc = desc; | |
293 | uc_pdata = dev_get_uclass_platdata(dev); | |
294 | ||
295 | uc_pdata->type = desc->type; | |
296 | if (uc_pdata->type == REGULATOR_TYPE_BUCK) { | |
297 | if (!strcmp(dev->name, "swbst")) { | |
298 | uc_pdata->mode = pfuze_swbst_modes; | |
299 | uc_pdata->mode_count = ARRAY_SIZE(pfuze_swbst_modes); | |
300 | } else { | |
301 | uc_pdata->mode = pfuze_sw_modes; | |
302 | uc_pdata->mode_count = ARRAY_SIZE(pfuze_sw_modes); | |
303 | } | |
304 | } else if (uc_pdata->type == REGULATOR_TYPE_LDO) { | |
305 | uc_pdata->mode = pfuze_ldo_modes; | |
306 | uc_pdata->mode_count = ARRAY_SIZE(pfuze_ldo_modes); | |
307 | } else { | |
308 | uc_pdata->mode = NULL; | |
309 | uc_pdata->mode_count = 0; | |
310 | } | |
311 | ||
312 | return 0; | |
313 | } | |
314 | ||
315 | static int pfuze100_regulator_mode(struct udevice *dev, int op, int *opmode) | |
316 | { | |
fcdb5319 | 317 | int val; |
8fa46350 PF |
318 | struct pfuze100_regulator_platdata *plat = dev_get_platdata(dev); |
319 | struct pfuze100_regulator_desc *desc = plat->desc; | |
320 | ||
321 | if (op == PMIC_OP_GET) { | |
322 | if (desc->type == REGULATOR_TYPE_BUCK) { | |
323 | if (!strcmp(dev->name, "swbst")) { | |
324 | val = pmic_reg_read(dev->parent, | |
325 | desc->vsel_reg); | |
326 | if (val < 0) | |
327 | return val; | |
328 | ||
329 | val &= SWBST_MODE_MASK; | |
330 | val >>= SWBST_MODE_SHIFT; | |
331 | *opmode = val; | |
332 | ||
333 | return 0; | |
334 | } | |
335 | val = pmic_reg_read(dev->parent, | |
336 | desc->vsel_reg + | |
337 | PFUZE100_MODE_OFFSET); | |
338 | if (val < 0) | |
339 | return val; | |
340 | ||
341 | val &= SW_MODE_MASK; | |
342 | val >>= SW_MODE_SHIFT; | |
343 | *opmode = val; | |
344 | ||
345 | return 0; | |
346 | ||
347 | } else if (desc->type == REGULATOR_TYPE_LDO) { | |
348 | val = pmic_reg_read(dev->parent, desc->vsel_reg); | |
349 | if (val < 0) | |
350 | return val; | |
351 | ||
352 | val &= LDO_MODE_MASK; | |
353 | val >>= LDO_MODE_SHIFT; | |
354 | *opmode = val; | |
355 | ||
356 | return 0; | |
357 | } else { | |
358 | return -EINVAL; | |
359 | } | |
360 | } | |
361 | ||
362 | if (desc->type == REGULATOR_TYPE_BUCK) { | |
363 | if (!strcmp(dev->name, "swbst")) | |
364 | return pmic_clrsetbits(dev->parent, desc->vsel_reg, | |
365 | SWBST_MODE_MASK, | |
366 | *opmode << SWBST_MODE_SHIFT); | |
367 | ||
368 | val = pmic_clrsetbits(dev->parent, | |
369 | desc->vsel_reg + PFUZE100_MODE_OFFSET, | |
370 | SW_MODE_MASK, | |
371 | *opmode << SW_MODE_SHIFT); | |
372 | ||
373 | } else if (desc->type == REGULATOR_TYPE_LDO) { | |
374 | val = pmic_clrsetbits(dev->parent, desc->vsel_reg, | |
375 | LDO_MODE_MASK, | |
376 | *opmode << LDO_MODE_SHIFT); | |
377 | return val; | |
378 | } else { | |
379 | return -EINVAL; | |
380 | } | |
381 | ||
382 | return 0; | |
383 | } | |
384 | ||
385 | static int pfuze100_regulator_enable(struct udevice *dev, int op, bool *enable) | |
386 | { | |
fcdb5319 | 387 | int val; |
8fa46350 PF |
388 | int ret, on_off; |
389 | struct dm_regulator_uclass_platdata *uc_pdata = | |
390 | dev_get_uclass_platdata(dev); | |
391 | ||
392 | if (op == PMIC_OP_GET) { | |
393 | if (!strcmp(dev->name, "vrefddr")) { | |
394 | val = pmic_reg_read(dev->parent, PFUZE100_VREFDDRCON); | |
395 | if (val < 0) | |
396 | return val; | |
397 | ||
398 | if (val & VREFDDRCON_EN) | |
399 | *enable = true; | |
400 | else | |
401 | *enable = false; | |
402 | return 0; | |
403 | } | |
404 | ret = pfuze100_regulator_mode(dev, op, &on_off); | |
405 | if (ret) | |
406 | return ret; | |
407 | switch (on_off) { | |
408 | /* OFF_OFF, SWBST_MODE_OFF, LDO_MODE_OFF have same value */ | |
409 | case OFF_OFF: | |
410 | *enable = false; | |
411 | break; | |
412 | default: | |
413 | *enable = true; | |
414 | break; | |
415 | } | |
416 | } else if (op == PMIC_OP_SET) { | |
417 | if (!strcmp(dev->name, "vrefddr")) { | |
418 | val = pmic_reg_read(dev->parent, PFUZE100_VREFDDRCON); | |
419 | if (val < 0) | |
420 | return val; | |
421 | ||
422 | if (val & VREFDDRCON_EN) | |
423 | return 0; | |
424 | val |= VREFDDRCON_EN; | |
425 | ||
426 | return pmic_reg_write(dev->parent, PFUZE100_VREFDDRCON, | |
427 | val); | |
428 | } | |
429 | ||
430 | if (uc_pdata->type == REGULATOR_TYPE_LDO) { | |
431 | on_off = *enable ? LDO_MODE_ON : LDO_MODE_OFF; | |
432 | } else if (uc_pdata->type == REGULATOR_TYPE_BUCK) { | |
433 | if (!strcmp(dev->name, "swbst")) | |
434 | on_off = *enable ? SWBST_MODE_AUTO : | |
435 | SWBST_MODE_OFF; | |
436 | else | |
437 | on_off = *enable ? APS_PFM : OFF_OFF; | |
438 | } else { | |
439 | return -EINVAL; | |
440 | } | |
441 | ||
442 | return pfuze100_regulator_mode(dev, op, &on_off); | |
443 | } | |
444 | ||
445 | return 0; | |
446 | } | |
447 | ||
448 | static int pfuze100_regulator_val(struct udevice *dev, int op, int *uV) | |
449 | { | |
450 | int i; | |
fcdb5319 | 451 | int val; |
8fa46350 PF |
452 | struct pfuze100_regulator_platdata *plat = dev_get_platdata(dev); |
453 | struct pfuze100_regulator_desc *desc = plat->desc; | |
454 | struct dm_regulator_uclass_platdata *uc_pdata = | |
455 | dev_get_uclass_platdata(dev); | |
456 | ||
457 | if (op == PMIC_OP_GET) { | |
458 | *uV = 0; | |
459 | if (uc_pdata->type == REGULATOR_TYPE_FIXED) { | |
460 | *uV = desc->voltage; | |
461 | } else if (desc->volt_table) { | |
462 | val = pmic_reg_read(dev->parent, desc->vsel_reg); | |
463 | if (val < 0) | |
464 | return val; | |
465 | val &= desc->vsel_mask; | |
466 | *uV = desc->volt_table[val]; | |
467 | } else { | |
468 | if (uc_pdata->min_uV < 0) { | |
469 | debug("Need to provide min_uV in dts.\n"); | |
470 | return -EINVAL; | |
471 | } | |
472 | val = pmic_reg_read(dev->parent, desc->vsel_reg); | |
473 | if (val < 0) | |
474 | return val; | |
475 | val &= desc->vsel_mask; | |
476 | *uV = uc_pdata->min_uV + (int)val * desc->uV_step; | |
477 | } | |
478 | ||
479 | return 0; | |
480 | } | |
481 | ||
482 | if (uc_pdata->type == REGULATOR_TYPE_FIXED) { | |
483 | debug("Set voltage for REGULATOR_TYPE_FIXED regulator\n"); | |
484 | return -EINVAL; | |
485 | } else if (desc->volt_table) { | |
486 | for (i = 0; i < desc->vsel_mask; i++) { | |
487 | if (*uV == desc->volt_table[i]) | |
488 | break; | |
489 | } | |
490 | if (i == desc->vsel_mask) { | |
491 | debug("Unsupported voltage %u\n", *uV); | |
492 | return -EINVAL; | |
493 | } | |
494 | ||
495 | return pmic_clrsetbits(dev->parent, desc->vsel_reg, | |
496 | desc->vsel_mask, i); | |
497 | } else { | |
498 | if (uc_pdata->min_uV < 0) { | |
499 | debug("Need to provide min_uV in dts.\n"); | |
500 | return -EINVAL; | |
501 | } | |
502 | return pmic_clrsetbits(dev->parent, desc->vsel_reg, | |
503 | desc->vsel_mask, | |
504 | (*uV - uc_pdata->min_uV) / desc->uV_step); | |
505 | } | |
506 | ||
507 | return 0; | |
508 | } | |
509 | ||
510 | static int pfuze100_regulator_get_value(struct udevice *dev) | |
511 | { | |
512 | int uV; | |
513 | int ret; | |
514 | ||
515 | ret = pfuze100_regulator_val(dev, PMIC_OP_GET, &uV); | |
516 | if (ret) | |
517 | return ret; | |
518 | ||
519 | return uV; | |
520 | } | |
521 | ||
522 | static int pfuze100_regulator_set_value(struct udevice *dev, int uV) | |
523 | { | |
524 | return pfuze100_regulator_val(dev, PMIC_OP_SET, &uV); | |
525 | } | |
526 | ||
117daa82 | 527 | static int pfuze100_regulator_get_enable(struct udevice *dev) |
8fa46350 PF |
528 | { |
529 | int ret; | |
530 | bool enable = false; | |
531 | ||
532 | ret = pfuze100_regulator_enable(dev, PMIC_OP_GET, &enable); | |
533 | if (ret) | |
534 | return ret; | |
535 | ||
536 | return enable; | |
537 | } | |
538 | ||
539 | static int pfuze100_regulator_set_enable(struct udevice *dev, bool enable) | |
540 | { | |
541 | return pfuze100_regulator_enable(dev, PMIC_OP_SET, &enable); | |
542 | } | |
543 | ||
544 | static int pfuze100_regulator_get_mode(struct udevice *dev) | |
545 | { | |
546 | int mode; | |
547 | int ret; | |
548 | ||
549 | ret = pfuze100_regulator_mode(dev, PMIC_OP_GET, &mode); | |
550 | if (ret) | |
551 | return ret; | |
552 | ||
553 | return mode; | |
554 | } | |
555 | ||
556 | static int pfuze100_regulator_set_mode(struct udevice *dev, int mode) | |
557 | { | |
558 | return pfuze100_regulator_mode(dev, PMIC_OP_SET, &mode); | |
559 | } | |
560 | ||
561 | static const struct dm_regulator_ops pfuze100_regulator_ops = { | |
562 | .get_value = pfuze100_regulator_get_value, | |
563 | .set_value = pfuze100_regulator_set_value, | |
564 | .get_enable = pfuze100_regulator_get_enable, | |
565 | .set_enable = pfuze100_regulator_set_enable, | |
566 | .get_mode = pfuze100_regulator_get_mode, | |
567 | .set_mode = pfuze100_regulator_set_mode, | |
568 | }; | |
569 | ||
570 | U_BOOT_DRIVER(pfuze100_regulator) = { | |
571 | .name = "pfuze100_regulator", | |
572 | .id = UCLASS_REGULATOR, | |
573 | .ops = &pfuze100_regulator_ops, | |
574 | .probe = pfuze100_regulator_probe, | |
575 | .platdata_auto_alloc_size = sizeof(struct pfuze100_regulator_platdata), | |
576 | }; |