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