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