]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/nvidia/as3722_regulators.c
arm: clean up empty lines in .c and .h files
[FreeBSD/FreeBSD.git] / sys / arm / nvidia / as3722_regulators.c
1 /*-
2  * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bus.h>
33 #include <sys/gpio.h>
34 #include <sys/kernel.h>
35 #include <sys/module.h>
36 #include <sys/malloc.h>
37 #include <sys/rman.h>
38 #include <sys/sx.h>
39
40 #include <machine/bus.h>
41
42 #include <dev/extres/regulator/regulator.h>
43 #include <dev/gpio/gpiobusvar.h>
44
45 #include <gnu/dts/include/dt-bindings/mfd/as3722.h>
46
47 #include "as3722.h"
48
49 MALLOC_DEFINE(M_AS3722_REG, "AS3722 regulator", "AS3722 power regulator");
50
51 #define DIV_ROUND_UP(n,d) howmany(n, d)
52
53 enum as3722_reg_id {
54         AS3722_REG_ID_SD0,
55         AS3722_REG_ID_SD1,
56         AS3722_REG_ID_SD2,
57         AS3722_REG_ID_SD3,
58         AS3722_REG_ID_SD4,
59         AS3722_REG_ID_SD5,
60         AS3722_REG_ID_SD6,
61         AS3722_REG_ID_LDO0,
62         AS3722_REG_ID_LDO1,
63         AS3722_REG_ID_LDO2,
64         AS3722_REG_ID_LDO3,
65         AS3722_REG_ID_LDO4,
66         AS3722_REG_ID_LDO5,
67         AS3722_REG_ID_LDO6,
68         AS3722_REG_ID_LDO7,
69         AS3722_REG_ID_LDO9,
70         AS3722_REG_ID_LDO10,
71         AS3722_REG_ID_LDO11,
72 };
73
74 /* Regulator HW definition. */
75 struct reg_def {
76         intptr_t                id;             /* ID */
77         char                    *name;          /* Regulator name */
78         char                    *supply_name;   /* Source property name */
79         uint8_t                 volt_reg;
80         uint8_t                 volt_vsel_mask;
81         uint8_t                 enable_reg;
82         uint8_t                 enable_mask;
83         uint8_t                 ext_enable_reg;
84         uint8_t                 ext_enable_mask;
85         struct regulator_range  *ranges;
86         int                     nranges;
87 };
88
89 struct as3722_reg_sc {
90         struct regnode          *regnode;
91         struct as3722_softc     *base_sc;
92         struct reg_def          *def;
93         phandle_t               xref;
94
95         struct regnode_std_param *param;
96         int                     ext_control;
97         int                     enable_tracking;
98
99         int                     enable_usec;
100 };
101
102 static struct regulator_range as3722_sd016_ranges[] = {
103         REG_RANGE_INIT(0x00, 0x00,       0,     0),
104         REG_RANGE_INIT(0x01, 0x5A,  610000, 10000),
105 };
106
107 static struct regulator_range as3722_sd0_lv_ranges[] = {
108         REG_RANGE_INIT(0x00, 0x00,       0,     0),
109         REG_RANGE_INIT(0x01, 0x6E,  410000, 10000),
110 };
111
112 static struct regulator_range as3722_sd_ranges[] = {
113         REG_RANGE_INIT(0x00, 0x00,       0,     0),
114         REG_RANGE_INIT(0x01, 0x40,  612500, 12500),
115         REG_RANGE_INIT(0x41, 0x70, 1425000, 25000),
116         REG_RANGE_INIT(0x71, 0x7F, 2650000, 50000),
117 };
118
119 static struct regulator_range as3722_ldo3_ranges[] = {
120         REG_RANGE_INIT(0x00, 0x00,       0,     0),
121         REG_RANGE_INIT(0x01, 0x2D,  620000, 20000),
122 };
123
124 static struct regulator_range as3722_ldo_ranges[] = {
125         REG_RANGE_INIT(0x00, 0x00,       0,     0),
126         REG_RANGE_INIT(0x01, 0x24,  825000, 25000),
127         REG_RANGE_INIT(0x40, 0x7F, 1725000, 25000),
128 };
129
130 static struct reg_def as3722s_def[] = {
131         {
132                 .id = AS3722_REG_ID_SD0,
133                 .name = "sd0",
134                 .volt_reg = AS3722_SD0_VOLTAGE,
135                 .volt_vsel_mask = AS3722_SD_VSEL_MASK,
136                 .enable_reg = AS3722_SD_CONTROL,
137                 .enable_mask = AS3722_SDN_CTRL(0),
138                 .ext_enable_reg = AS3722_ENABLE_CTRL1,
139                 .ext_enable_mask = AS3722_SD0_EXT_ENABLE_MASK,
140                 .ranges = as3722_sd016_ranges,
141                 .nranges = nitems(as3722_sd016_ranges),
142         },
143         {
144                 .id = AS3722_REG_ID_SD1,
145                 .name = "sd1",
146                 .volt_reg = AS3722_SD1_VOLTAGE,
147                 .volt_vsel_mask = AS3722_SD_VSEL_MASK,
148                 .enable_reg = AS3722_SD_CONTROL,
149                 .enable_mask = AS3722_SDN_CTRL(1),
150                 .ext_enable_reg = AS3722_ENABLE_CTRL1,
151                 .ext_enable_mask = AS3722_SD1_EXT_ENABLE_MASK,
152                 .ranges = as3722_sd_ranges,
153                 .nranges = nitems(as3722_sd_ranges),
154         },
155         {
156                 .id = AS3722_REG_ID_SD2,
157                 .name = "sd2",
158                 .supply_name = "vsup-sd2",
159                 .volt_reg = AS3722_SD2_VOLTAGE,
160                 .volt_vsel_mask = AS3722_SD_VSEL_MASK,
161                 .enable_reg = AS3722_SD_CONTROL,
162                 .enable_mask = AS3722_SDN_CTRL(2),
163                 .ext_enable_reg = AS3722_ENABLE_CTRL1,
164                 .ext_enable_mask = AS3722_SD2_EXT_ENABLE_MASK,
165                 .ranges = as3722_sd_ranges,
166                 .nranges = nitems(as3722_sd_ranges),
167         },
168         {
169                 .id = AS3722_REG_ID_SD3,
170                 .name = "sd3",
171                 .supply_name = "vsup-sd3",
172                 .volt_reg = AS3722_SD3_VOLTAGE,
173                 .volt_vsel_mask = AS3722_SD_VSEL_MASK,
174                 .enable_reg = AS3722_SD_CONTROL,
175                 .enable_mask = AS3722_SDN_CTRL(3),
176                 .ext_enable_reg = AS3722_ENABLE_CTRL1,
177                 .ext_enable_mask = AS3722_SD3_EXT_ENABLE_MASK,
178                 .ranges = as3722_sd_ranges,
179                 .nranges = nitems(as3722_sd_ranges),
180         },
181         {
182                 .id = AS3722_REG_ID_SD4,
183                 .name = "sd4",
184                 .supply_name = "vsup-sd4",
185                 .volt_reg = AS3722_SD4_VOLTAGE,
186                 .volt_vsel_mask = AS3722_SD_VSEL_MASK,
187                 .enable_reg = AS3722_SD_CONTROL,
188                 .enable_mask = AS3722_SDN_CTRL(4),
189                 .ext_enable_reg = AS3722_ENABLE_CTRL2,
190                 .ext_enable_mask = AS3722_SD4_EXT_ENABLE_MASK,
191                 .ranges = as3722_sd_ranges,
192                 .nranges = nitems(as3722_sd_ranges),
193         },
194         {
195                 .id = AS3722_REG_ID_SD5,
196                 .name = "sd5",
197                 .supply_name = "vsup-sd5",
198                 .volt_reg = AS3722_SD5_VOLTAGE,
199                 .volt_vsel_mask = AS3722_SD_VSEL_MASK,
200                 .enable_reg = AS3722_SD_CONTROL,
201                 .enable_mask = AS3722_SDN_CTRL(5),
202                 .ext_enable_reg = AS3722_ENABLE_CTRL2,
203                 .ext_enable_mask = AS3722_SD5_EXT_ENABLE_MASK,
204                 .ranges = as3722_sd_ranges,
205                 .nranges = nitems(as3722_sd_ranges),
206         },
207         {
208                 .id = AS3722_REG_ID_SD6,
209                 .name = "sd6",
210                 .volt_reg = AS3722_SD6_VOLTAGE,
211                 .volt_vsel_mask = AS3722_SD_VSEL_MASK,
212                 .enable_reg = AS3722_SD_CONTROL,
213                 .enable_mask = AS3722_SDN_CTRL(6),
214                 .ext_enable_reg = AS3722_ENABLE_CTRL2,
215                 .ext_enable_mask = AS3722_SD6_EXT_ENABLE_MASK,
216                 .ranges = as3722_sd016_ranges,
217                 .nranges = nitems(as3722_sd016_ranges),
218         },
219         {
220                 .id = AS3722_REG_ID_LDO0,
221                 .name = "ldo0",
222                 .supply_name = "vin-ldo0",
223                 .volt_reg = AS3722_LDO0_VOLTAGE,
224                 .volt_vsel_mask = AS3722_LDO0_VSEL_MASK,
225                 .enable_reg = AS3722_LDO_CONTROL0,
226                 .enable_mask = AS3722_LDO0_CTRL,
227                 .ext_enable_reg = AS3722_ENABLE_CTRL3,
228                 .ext_enable_mask = AS3722_LDO0_EXT_ENABLE_MASK,
229                 .ranges = as3722_ldo_ranges,
230                 .nranges = nitems(as3722_ldo_ranges),
231         },
232         {
233                 .id = AS3722_REG_ID_LDO1,
234                 .name = "ldo1",
235                 .supply_name = "vin-ldo1-6",
236                 .volt_reg = AS3722_LDO1_VOLTAGE,
237                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
238                 .enable_reg = AS3722_LDO_CONTROL0,
239                 .enable_mask = AS3722_LDO1_CTRL,
240                 .ext_enable_reg = AS3722_ENABLE_CTRL3,
241                 .ext_enable_mask = AS3722_LDO1_EXT_ENABLE_MASK,
242                 .ranges = as3722_ldo_ranges,
243                 .nranges = nitems(as3722_ldo_ranges),
244         },
245         {
246                 .id = AS3722_REG_ID_LDO2,
247                 .name = "ldo2",
248                 .supply_name = "vin-ldo2-5-7",
249                 .volt_reg = AS3722_LDO2_VOLTAGE,
250                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
251                 .enable_reg = AS3722_LDO_CONTROL0,
252                 .enable_mask = AS3722_LDO2_CTRL,
253                 .ext_enable_reg = AS3722_ENABLE_CTRL3,
254                 .ext_enable_mask = AS3722_LDO2_EXT_ENABLE_MASK,
255                 .ranges = as3722_ldo_ranges,
256                 .nranges = nitems(as3722_ldo_ranges),
257         },
258         {
259                 .id = AS3722_REG_ID_LDO3,
260                 .name = "ldo3",
261                 .supply_name = "vin-ldo3-4",
262                 .volt_reg = AS3722_LDO3_VOLTAGE,
263                 .volt_vsel_mask = AS3722_LDO3_VSEL_MASK,
264                 .enable_reg = AS3722_LDO_CONTROL0,
265                 .enable_mask = AS3722_LDO3_CTRL,
266                 .ext_enable_reg = AS3722_ENABLE_CTRL3,
267                 .ext_enable_mask = AS3722_LDO3_EXT_ENABLE_MASK,
268                 .ranges = as3722_ldo3_ranges,
269                 .nranges = nitems(as3722_ldo3_ranges),
270         },
271         {
272                 .id = AS3722_REG_ID_LDO4,
273                 .name = "ldo4",
274                 .supply_name = "vin-ldo3-4",
275                 .volt_reg = AS3722_LDO4_VOLTAGE,
276                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
277                 .enable_reg = AS3722_LDO_CONTROL0,
278                 .enable_mask = AS3722_LDO4_CTRL,
279                 .ext_enable_reg = AS3722_ENABLE_CTRL4,
280                 .ext_enable_mask = AS3722_LDO4_EXT_ENABLE_MASK,
281                 .ranges = as3722_ldo_ranges,
282                 .nranges = nitems(as3722_ldo_ranges),
283         },
284         {
285                 .id = AS3722_REG_ID_LDO5,
286                 .name = "ldo5",
287                 .supply_name = "vin-ldo2-5-7",
288                 .volt_reg = AS3722_LDO5_VOLTAGE,
289                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
290                 .enable_reg = AS3722_LDO_CONTROL0,
291                 .enable_mask = AS3722_LDO5_CTRL,
292                 .ext_enable_reg = AS3722_ENABLE_CTRL4,
293                 .ext_enable_mask = AS3722_LDO5_EXT_ENABLE_MASK,
294                 .ranges = as3722_ldo_ranges,
295                 .nranges = nitems(as3722_ldo_ranges),
296         },
297         {
298                 .id = AS3722_REG_ID_LDO6,
299                 .name = "ldo6",
300                 .supply_name = "vin-ldo1-6",
301                 .volt_reg = AS3722_LDO6_VOLTAGE,
302                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
303                 .enable_reg = AS3722_LDO_CONTROL0,
304                 .enable_mask = AS3722_LDO6_CTRL,
305                 .ext_enable_reg = AS3722_ENABLE_CTRL4,
306                 .ext_enable_mask = AS3722_LDO6_EXT_ENABLE_MASK,
307                 .ranges = as3722_ldo_ranges,
308                 .nranges = nitems(as3722_ldo_ranges),
309         },
310         {
311                 .id = AS3722_REG_ID_LDO7,
312                 .name = "ldo7",
313                 .supply_name = "vin-ldo2-5-7",
314                 .volt_reg = AS3722_LDO7_VOLTAGE,
315                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
316                 .enable_reg = AS3722_LDO_CONTROL0,
317                 .enable_mask = AS3722_LDO7_CTRL,
318                 .ext_enable_reg = AS3722_ENABLE_CTRL4,
319                 .ext_enable_mask = AS3722_LDO7_EXT_ENABLE_MASK,
320                 .ranges = as3722_ldo_ranges,
321                 .nranges = nitems(as3722_ldo_ranges),
322         },
323         {
324                 .id = AS3722_REG_ID_LDO9,
325                 .name = "ldo9",
326                 .supply_name = "vin-ldo9-10",
327                 .volt_reg = AS3722_LDO9_VOLTAGE,
328                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
329                 .enable_reg = AS3722_LDO_CONTROL1,
330                 .enable_mask = AS3722_LDO9_CTRL,
331                 .ext_enable_reg = AS3722_ENABLE_CTRL5,
332                 .ext_enable_mask = AS3722_LDO9_EXT_ENABLE_MASK,
333                 .ranges = as3722_ldo_ranges,
334                 .nranges = nitems(as3722_ldo_ranges),
335         },
336         {
337                 .id = AS3722_REG_ID_LDO10,
338                 .name = "ldo10",
339                 .supply_name = "vin-ldo9-10",
340                 .volt_reg = AS3722_LDO10_VOLTAGE,
341                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
342                 .enable_reg = AS3722_LDO_CONTROL1,
343                 .enable_mask = AS3722_LDO10_CTRL,
344                 .ext_enable_reg = AS3722_ENABLE_CTRL5,
345                 .ext_enable_mask = AS3722_LDO10_EXT_ENABLE_MASK,
346                 .ranges = as3722_ldo_ranges,
347                 .nranges = nitems(as3722_ldo_ranges),
348         },
349         {
350                 .id = AS3722_REG_ID_LDO11,
351                 .name = "ldo11",
352                 .supply_name = "vin-ldo11",
353                 .volt_reg = AS3722_LDO11_VOLTAGE,
354                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
355                 .enable_reg = AS3722_LDO_CONTROL1,
356                 .enable_mask = AS3722_LDO11_CTRL,
357                 .ext_enable_reg = AS3722_ENABLE_CTRL5,
358                 .ext_enable_mask = AS3722_LDO11_EXT_ENABLE_MASK,
359                 .ranges = as3722_ldo_ranges,
360                 .nranges = nitems(as3722_ldo_ranges),
361         },
362 };
363
364 struct as3722_regnode_init_def {
365         struct regnode_init_def reg_init_def;
366         int                     ext_control;
367         int                     enable_tracking;
368 };
369
370 static int as3722_regnode_init(struct regnode *regnode);
371 static int as3722_regnode_enable(struct regnode *regnode, bool enable,
372     int *udelay);
373 static int as3722_regnode_set_volt(struct regnode *regnode, int min_uvolt,
374     int max_uvolt, int *udelay);
375 static int as3722_regnode_get_volt(struct regnode *regnode, int *uvolt);
376 static regnode_method_t as3722_regnode_methods[] = {
377         /* Regulator interface */
378         REGNODEMETHOD(regnode_init,             as3722_regnode_init),
379         REGNODEMETHOD(regnode_enable,           as3722_regnode_enable),
380         REGNODEMETHOD(regnode_set_voltage,      as3722_regnode_set_volt),
381         REGNODEMETHOD(regnode_get_voltage,      as3722_regnode_get_volt),
382         REGNODEMETHOD_END
383 };
384 DEFINE_CLASS_1(as3722_regnode, as3722_regnode_class, as3722_regnode_methods,
385    sizeof(struct as3722_reg_sc), regnode_class);
386
387 static int
388 as3722_read_sel(struct as3722_reg_sc *sc, uint8_t *sel)
389 {
390         int rv;
391
392         rv = RD1(sc->base_sc, sc->def->volt_reg, sel);
393         if (rv != 0)
394                 return (rv);
395         *sel &= sc->def->volt_vsel_mask;
396         *sel >>= ffs(sc->def->volt_vsel_mask) - 1;
397         return (0);
398 }
399
400 static int
401 as3722_write_sel(struct as3722_reg_sc *sc, uint8_t sel)
402 {
403         int rv;
404
405         sel <<= ffs(sc->def->volt_vsel_mask) - 1;
406         sel &= sc->def->volt_vsel_mask;
407
408         rv = RM1(sc->base_sc, sc->def->volt_reg,
409             sc->def->volt_vsel_mask, sel);
410         if (rv != 0)
411                 return (rv);
412         return (rv);
413 }
414
415 static bool
416 as3722_sd0_is_low_voltage(struct as3722_reg_sc *sc)
417 {
418         uint8_t val;
419         int rv;
420
421         rv = RD1(sc->base_sc, AS3722_FUSE7, &val);
422         if (rv != 0)
423                 return (rv);
424         return (val & AS3722_FUSE7_SD0_LOW_VOLTAGE ? true : false);
425 }
426
427 static int
428 as3722_reg_extreg_setup(struct as3722_reg_sc *sc, int ext_pwr_ctrl)
429 {
430         uint8_t val;
431         int rv;
432
433         val =  ext_pwr_ctrl << (ffs(sc->def->ext_enable_mask) - 1);
434         rv = RM1(sc->base_sc, sc->def->ext_enable_reg,
435             sc->def->ext_enable_mask, val);
436         return (rv);
437 }
438
439 static int
440 as3722_reg_enable(struct as3722_reg_sc *sc)
441 {
442         int rv;
443
444         rv = RM1(sc->base_sc, sc->def->enable_reg,
445             sc->def->enable_mask, sc->def->enable_mask);
446         return (rv);
447 }
448
449 static int
450 as3722_reg_disable(struct as3722_reg_sc *sc)
451 {
452         int rv;
453
454         rv = RM1(sc->base_sc, sc->def->enable_reg,
455             sc->def->enable_mask, 0);
456         return (rv);
457 }
458
459 static int
460 as3722_regnode_init(struct regnode *regnode)
461 {
462         struct as3722_reg_sc *sc;
463         int rv;
464
465         sc = regnode_get_softc(regnode);
466
467         sc->enable_usec = 500;
468         if (sc->def->id == AS3722_REG_ID_SD0) {
469                 if (as3722_sd0_is_low_voltage(sc)) {
470                         sc->def->ranges = as3722_sd0_lv_ranges;
471                         sc->def->nranges = nitems(as3722_sd0_lv_ranges);
472                 }
473                 sc->enable_usec = 600;
474         } else if (sc->def->id == AS3722_REG_ID_LDO3) {
475                 if (sc->enable_tracking) {
476                         rv = RM1(sc->base_sc, sc->def->volt_reg,
477                             AS3722_LDO3_MODE_MASK,
478                             AS3722_LDO3_MODE_PMOS_TRACKING);
479                         if (rv < 0) {
480                                 device_printf(sc->base_sc->dev,
481                                         "LDO3 tracking failed: %d\n", rv);
482                                 return (rv);
483                         }
484                 }
485         }
486
487         if (sc->ext_control) {
488                 rv = as3722_reg_enable(sc);
489                 if (rv < 0) {
490                         device_printf(sc->base_sc->dev,
491                                 "Failed to enable %s regulator: %d\n",
492                                 sc->def->name, rv);
493                         return (rv);
494                 }
495                 rv = as3722_reg_extreg_setup(sc, sc->ext_control);
496                 if (rv < 0) {
497                         device_printf(sc->base_sc->dev,
498                                 "%s ext control failed: %d", sc->def->name, rv);
499                         return (rv);
500                 }
501         }
502         return (0);
503 }
504
505 static void
506 as3722_fdt_parse(struct as3722_softc *sc, phandle_t node, struct reg_def *def,
507 struct as3722_regnode_init_def *init_def)
508 {
509         int rv;
510         phandle_t parent, supply_node;
511         char prop_name[64]; /* Maximum OFW property name length. */
512
513         rv = regulator_parse_ofw_stdparam(sc->dev, node,
514             &init_def->reg_init_def);
515
516         rv = OF_getencprop(node, "ams,ext-control", &init_def->ext_control,
517             sizeof(init_def->ext_control));
518         if (rv <= 0)
519                 init_def->ext_control = 0;
520         if (init_def->ext_control > 3) {
521                 device_printf(sc->dev,
522                     "Invalid value for ams,ext-control property: %d\n",
523                     init_def->ext_control);
524                 init_def->ext_control = 0;
525         }
526         if (OF_hasprop(node, "ams,enable-tracking"))
527                 init_def->enable_tracking = 1;
528
529         /* Get parent supply. */
530         if (def->supply_name == NULL)
531                  return;
532
533         parent = OF_parent(node);
534         snprintf(prop_name, sizeof(prop_name), "%s-supply",
535             def->supply_name);
536         rv = OF_getencprop(parent, prop_name, &supply_node,
537             sizeof(supply_node));
538         if (rv <= 0)
539                 return;
540         supply_node = OF_node_from_xref(supply_node);
541         rv = OF_getprop_alloc(supply_node, "regulator-name",
542             (void **)&init_def->reg_init_def.parent_name);
543         if (rv <= 0)
544                 init_def->reg_init_def.parent_name = NULL;
545 }
546
547 static struct as3722_reg_sc *
548 as3722_attach(struct as3722_softc *sc, phandle_t node, struct reg_def *def)
549 {
550         struct as3722_reg_sc *reg_sc;
551         struct as3722_regnode_init_def init_def;
552         struct regnode *regnode;
553
554         bzero(&init_def, sizeof(init_def));
555
556         as3722_fdt_parse(sc, node, def, &init_def);
557         init_def.reg_init_def.id = def->id;
558         init_def.reg_init_def.ofw_node = node;
559         regnode = regnode_create(sc->dev, &as3722_regnode_class,
560             &init_def.reg_init_def);
561         if (regnode == NULL) {
562                 device_printf(sc->dev, "Cannot create regulator.\n");
563                 return (NULL);
564         }
565         reg_sc = regnode_get_softc(regnode);
566
567         /* Init regulator softc. */
568         reg_sc->regnode = regnode;
569         reg_sc->base_sc = sc;
570         reg_sc->def = def;
571         reg_sc->xref = OF_xref_from_node(node);
572
573         reg_sc->param = regnode_get_stdparam(regnode);
574         reg_sc->ext_control = init_def.ext_control;
575         reg_sc->enable_tracking = init_def.enable_tracking;
576
577         regnode_register(regnode);
578         if (bootverbose) {
579                 int volt, rv;
580                 regnode_topo_slock();
581                 rv = regnode_get_voltage(regnode, &volt);
582                 if (rv == ENODEV) {
583                         device_printf(sc->dev,
584                            " Regulator %s: parent doesn't exist yet.\n",
585                            regnode_get_name(regnode));
586                 } else if (rv != 0) {
587                         device_printf(sc->dev,
588                            " Regulator %s: voltage: INVALID!!!\n",
589                            regnode_get_name(regnode));
590                 } else {
591                         device_printf(sc->dev,
592                             " Regulator %s: voltage: %d uV\n",
593                             regnode_get_name(regnode), volt);
594                 }
595                 regnode_topo_unlock();
596         }
597
598         return (reg_sc);
599 }
600
601 int
602 as3722_regulator_attach(struct as3722_softc *sc, phandle_t node)
603 {
604         struct as3722_reg_sc *reg;
605         phandle_t child, rnode;
606         int i;
607
608         rnode = ofw_bus_find_child(node, "regulators");
609         if (rnode <= 0) {
610                 device_printf(sc->dev, " Cannot find regulators subnode\n");
611                 return (ENXIO);
612         }
613
614         sc->nregs = nitems(as3722s_def);
615         sc->regs = malloc(sizeof(struct as3722_reg_sc *) * sc->nregs,
616             M_AS3722_REG, M_WAITOK | M_ZERO);
617
618         /* Attach all known regulators if exist in DT. */
619         for (i = 0; i < sc->nregs; i++) {
620                 child = ofw_bus_find_child(rnode, as3722s_def[i].name);
621                 if (child == 0) {
622                         if (bootverbose)
623                                 device_printf(sc->dev,
624                                     "Regulator %s missing in DT\n",
625                                     as3722s_def[i].name);
626                         continue;
627                 }
628                 reg = as3722_attach(sc, child, as3722s_def + i);
629                 if (reg == NULL) {
630                         device_printf(sc->dev, "Cannot attach regulator: %s\n",
631                             as3722s_def[i].name);
632                         return (ENXIO);
633                 }
634                 sc->regs[i] = reg;
635         }
636         return (0);
637 }
638
639 int
640 as3722_regulator_map(device_t dev, phandle_t xref, int ncells,
641     pcell_t *cells, int *num)
642 {
643         struct as3722_softc *sc;
644         int i;
645
646         sc = device_get_softc(dev);
647         for (i = 0; i < sc->nregs; i++) {
648                 if (sc->regs[i] == NULL)
649                         continue;
650                 if (sc->regs[i]->xref == xref) {
651                         *num = sc->regs[i]->def->id;
652                         return (0);
653                 }
654         }
655         return (ENXIO);
656 }
657
658 static int
659 as3722_regnode_enable(struct regnode *regnode, bool val, int *udelay)
660 {
661         struct as3722_reg_sc *sc;
662         int rv;
663
664         sc = regnode_get_softc(regnode);
665
666         if (val)
667                 rv = as3722_reg_enable(sc);
668         else
669                 rv = as3722_reg_disable(sc);
670         *udelay = sc->enable_usec;
671         return (rv);
672 }
673
674 static int
675 as3722_regnode_set_volt(struct regnode *regnode, int min_uvolt, int max_uvolt,
676     int *udelay)
677 {
678         struct as3722_reg_sc *sc;
679         uint8_t sel;
680         int rv;
681
682         sc = regnode_get_softc(regnode);
683
684         *udelay = 0;
685         rv = regulator_range_volt_to_sel8(sc->def->ranges, sc->def->nranges,
686             min_uvolt, max_uvolt, &sel);
687         if (rv != 0)
688                 return (rv);
689         rv = as3722_write_sel(sc, sel);
690         return (rv);
691
692 }
693
694 static int
695 as3722_regnode_get_volt(struct regnode *regnode, int *uvolt)
696 {
697         struct as3722_reg_sc *sc;
698         uint8_t sel;
699         int rv;
700
701         sc = regnode_get_softc(regnode);
702         rv = as3722_read_sel(sc, &sel);
703         if (rv != 0)
704                 return (rv);
705
706         /* LDO6 have bypass. */
707         if (sc->def->id == AS3722_REG_ID_LDO6 && sel == AS3722_LDO6_SEL_BYPASS)
708                 return (ENOENT);
709         rv = regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges,
710             sel, uvolt);
711         return (rv);
712 }