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