1e9034789SMichal Meloun /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3e9034789SMichal Meloun  *
4e9034789SMichal Meloun  * Copyright 2020 Michal Meloun <mmel@FreeBSD.org>
5e9034789SMichal Meloun  *
6e9034789SMichal Meloun  * Redistribution and use in source and binary forms, with or without
7e9034789SMichal Meloun  * modification, are permitted provided that the following conditions
8e9034789SMichal Meloun  * are met:
9e9034789SMichal Meloun  * 1. Redistributions of source code must retain the above copyright
10e9034789SMichal Meloun  *    notice, this list of conditions and the following disclaimer.
11e9034789SMichal Meloun  * 2. Redistributions in binary form must reproduce the above copyright
12e9034789SMichal Meloun  *    notice, this list of conditions and the following disclaimer in the
13e9034789SMichal Meloun  *    documentation and/or other materials provided with the distribution.
14e9034789SMichal Meloun  *
15e9034789SMichal Meloun  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16e9034789SMichal Meloun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17e9034789SMichal Meloun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18e9034789SMichal Meloun  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19e9034789SMichal Meloun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20e9034789SMichal Meloun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21e9034789SMichal Meloun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22e9034789SMichal Meloun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23e9034789SMichal Meloun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24e9034789SMichal Meloun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25e9034789SMichal Meloun  * SUCH DAMAGE.
26e9034789SMichal Meloun  */
27e9034789SMichal Meloun 
28e9034789SMichal Meloun #include <sys/param.h>
29e9034789SMichal Meloun #include <sys/systm.h>
30e9034789SMichal Meloun #include <sys/bus.h>
31e9034789SMichal Meloun #include <sys/gpio.h>
32e9034789SMichal Meloun #include <sys/kernel.h>
33e9034789SMichal Meloun #include <sys/module.h>
34e9034789SMichal Meloun #include <sys/malloc.h>
35e9034789SMichal Meloun #include <sys/rman.h>
36e9034789SMichal Meloun #include <sys/sx.h>
37e9034789SMichal Meloun 
38e9034789SMichal Meloun #include <machine/bus.h>
39e9034789SMichal Meloun 
40*b2f0caf1SEmmanuel Vadot #include <dev/regulator/regulator.h>
41e9034789SMichal Meloun #include <dev/gpio/gpiobusvar.h>
42e9034789SMichal Meloun 
43c38fe878SEmmanuel Vadot #include <dt-bindings/mfd/max77620.h>
44e9034789SMichal Meloun 
45e9034789SMichal Meloun #include "max77620.h"
46e9034789SMichal Meloun 
47e9034789SMichal Meloun MALLOC_DEFINE(M_MAX77620_REG, "MAX77620 regulator", "MAX77620 power regulator");
48e9034789SMichal Meloun 
49e9034789SMichal Meloun #define	DIV_ROUND_UP(n,d) howmany(n, d)
50e9034789SMichal Meloun 
51e9034789SMichal Meloun enum max77620_reg_id {
52e9034789SMichal Meloun 	MAX77620_REG_ID_SD0,
53e9034789SMichal Meloun 	MAX77620_REG_ID_SD1,
54e9034789SMichal Meloun 	MAX77620_REG_ID_SD2,
55e9034789SMichal Meloun 	MAX77620_REG_ID_SD3,
56e9034789SMichal Meloun 	MAX77620_REG_ID_LDO0,
57e9034789SMichal Meloun 	MAX77620_REG_ID_LDO1,
58e9034789SMichal Meloun 	MAX77620_REG_ID_LDO2,
59e9034789SMichal Meloun 	MAX77620_REG_ID_LDO3,
60e9034789SMichal Meloun 	MAX77620_REG_ID_LDO4,
61e9034789SMichal Meloun 	MAX77620_REG_ID_LDO5,
62e9034789SMichal Meloun 	MAX77620_REG_ID_LDO6,
63e9034789SMichal Meloun 	MAX77620_REG_ID_LDO7,
64e9034789SMichal Meloun 	MAX77620_REG_ID_LDO8,
65e9034789SMichal Meloun };
66e9034789SMichal Meloun 
67e9034789SMichal Meloun /* Initial configuration. */
68e9034789SMichal Meloun struct max77620_regnode_init_def {
69e9034789SMichal Meloun 	struct regnode_init_def	reg_init_def;
70e9034789SMichal Meloun 	int active_fps_src;
71e9034789SMichal Meloun 	int active_fps_pu_slot;
72e9034789SMichal Meloun 	int active_fps_pd_slot;
73e9034789SMichal Meloun 	int suspend_fps_src;
74e9034789SMichal Meloun 	int suspend_fps_pu_slot;
75e9034789SMichal Meloun 	int suspend_fps_pd_slot;
76e9034789SMichal Meloun 	int ramp_rate_setting;
77e9034789SMichal Meloun };
78e9034789SMichal Meloun 
79e9034789SMichal Meloun /* Regulator HW definition. */
80e9034789SMichal Meloun struct reg_def {
81e9034789SMichal Meloun 	intptr_t		id;		/* ID */
82e9034789SMichal Meloun 	char			*name;		/* Regulator name */
83e9034789SMichal Meloun 	char			*supply_name;	/* Source property name */
84e9034789SMichal Meloun 	bool 			is_sd_reg; 	/* SD or LDO regulator? */
85e9034789SMichal Meloun 	uint8_t			volt_reg;
86e9034789SMichal Meloun 	uint8_t			volt_vsel_mask;
87e9034789SMichal Meloun 	uint8_t			cfg_reg;
88e9034789SMichal Meloun 	uint8_t			fps_reg;
89e9034789SMichal Meloun 	uint8_t			pwr_mode_reg;
90e9034789SMichal Meloun 	uint8_t			pwr_mode_mask;
91e9034789SMichal Meloun 	uint8_t			pwr_mode_shift;
92e9034789SMichal Meloun 	struct regulator_range	*ranges;
93e9034789SMichal Meloun 	int			nranges;
94e9034789SMichal Meloun };
95e9034789SMichal Meloun 
96e9034789SMichal Meloun struct max77620_reg_sc {
97e9034789SMichal Meloun 	struct regnode		*regnode;
98e9034789SMichal Meloun 	struct max77620_softc	*base_sc;
99e9034789SMichal Meloun 	struct reg_def		*def;
100e9034789SMichal Meloun 	phandle_t		xref;
101e9034789SMichal Meloun 
102e9034789SMichal Meloun 	struct regnode_std_param *param;
103e9034789SMichal Meloun 	/* Configured values */
104e9034789SMichal Meloun 	int			active_fps_src;
105e9034789SMichal Meloun 	int			active_fps_pu_slot;
106e9034789SMichal Meloun 	int			active_fps_pd_slot;
107e9034789SMichal Meloun 	int			suspend_fps_src;
108e9034789SMichal Meloun 	int			suspend_fps_pu_slot;
109e9034789SMichal Meloun 	int			suspend_fps_pd_slot;
110e9034789SMichal Meloun 	int			ramp_rate_setting;
111e9034789SMichal Meloun 	int			enable_usec;
112e9034789SMichal Meloun 	uint8_t			enable_pwr_mode;
113e9034789SMichal Meloun 
114e9034789SMichal Meloun 	/* Cached values */
115e9034789SMichal Meloun 	uint8_t			fps_src;
116e9034789SMichal Meloun 	uint8_t			pwr_mode;
117e9034789SMichal Meloun 	int			pwr_ramp_delay;
118e9034789SMichal Meloun };
119e9034789SMichal Meloun 
120e9034789SMichal Meloun static struct regulator_range max77620_sd0_ranges[] = {
121e9034789SMichal Meloun 	REG_RANGE_INIT(0, 64, 600000, 12500),  /* 0.6V - 1.4V / 12.5mV */
122e9034789SMichal Meloun };
123e9034789SMichal Meloun 
124e9034789SMichal Meloun static struct regulator_range max77620_sd1_ranges[] = {
125e9034789SMichal Meloun 	REG_RANGE_INIT(0, 76, 600000, 12500),  /* 0.6V - 1.55V / 12.5mV */
126e9034789SMichal Meloun };
127e9034789SMichal Meloun 
128e9034789SMichal Meloun static struct regulator_range max77620_sdx_ranges[] = {
129e9034789SMichal Meloun 	REG_RANGE_INIT(0, 255, 600000, 12500),  /* 0.6V - 3.7875V / 12.5mV */
130e9034789SMichal Meloun };
131e9034789SMichal Meloun 
132e9034789SMichal Meloun static struct regulator_range max77620_ldo0_1_ranges[] = {
133e9034789SMichal Meloun 	REG_RANGE_INIT(0, 63, 800000, 25000),  /* 0.8V - 2.375V / 25mV */
134e9034789SMichal Meloun };
135e9034789SMichal Meloun 
136e9034789SMichal Meloun static struct regulator_range max77620_ldo4_ranges[] = {
137e9034789SMichal Meloun 	REG_RANGE_INIT(0, 63, 800000, 12500),  /* 0.8V - 1.5875V / 12.5mV */
138e9034789SMichal Meloun };
139e9034789SMichal Meloun 
140e9034789SMichal Meloun static struct regulator_range max77620_ldox_ranges[] = {
141e9034789SMichal Meloun 	REG_RANGE_INIT(0, 63, 800000, 50000),  /* 0.8V - 3.95V / 50mV */
142e9034789SMichal Meloun };
143e9034789SMichal Meloun 
144e9034789SMichal Meloun static struct reg_def max77620s_def[] = {
145e9034789SMichal Meloun 	{
146e9034789SMichal Meloun 		.id = MAX77620_REG_ID_SD0,
147e9034789SMichal Meloun 		.name = "sd0",
148e9034789SMichal Meloun 		.supply_name = "in-sd0",
149e9034789SMichal Meloun 		.is_sd_reg = true,
150e9034789SMichal Meloun 		.volt_reg = MAX77620_REG_SD0,
151e9034789SMichal Meloun 		.volt_vsel_mask = MAX77620_SD0_VSEL_MASK,
152e9034789SMichal Meloun 		.cfg_reg = MAX77620_REG_CFG_SD0,
153e9034789SMichal Meloun 		.fps_reg = MAX77620_REG_FPS_SD0,
154e9034789SMichal Meloun 		.pwr_mode_reg = MAX77620_REG_CFG_SD0,
155e9034789SMichal Meloun 		.pwr_mode_mask = MAX77620_SD_POWER_MODE_MASK,
156e9034789SMichal Meloun 		.pwr_mode_shift = MAX77620_SD_POWER_MODE_SHIFT,
157e9034789SMichal Meloun 		.ranges = max77620_sd0_ranges,
158e9034789SMichal Meloun 		.nranges = nitems(max77620_sd0_ranges),
159e9034789SMichal Meloun 	},
160e9034789SMichal Meloun 	{
161e9034789SMichal Meloun 		.id = MAX77620_REG_ID_SD1,
162e9034789SMichal Meloun 		.name = "sd1",
163e9034789SMichal Meloun 		.supply_name = "in-sd1",
164e9034789SMichal Meloun 		.is_sd_reg = true,
165e9034789SMichal Meloun 		.volt_reg = MAX77620_REG_SD1,
166e9034789SMichal Meloun 		.volt_vsel_mask = MAX77620_SD1_VSEL_MASK,
167e9034789SMichal Meloun 		.cfg_reg = MAX77620_REG_CFG_SD1,
168e9034789SMichal Meloun 		.fps_reg = MAX77620_REG_FPS_SD1,
169e9034789SMichal Meloun 		.pwr_mode_reg = MAX77620_REG_CFG_SD1,
170e9034789SMichal Meloun 		.pwr_mode_mask = MAX77620_SD_POWER_MODE_MASK,
171e9034789SMichal Meloun 		.pwr_mode_shift = MAX77620_SD_POWER_MODE_SHIFT,
172e9034789SMichal Meloun 		.ranges = max77620_sd1_ranges,
173e9034789SMichal Meloun 		.nranges = nitems(max77620_sd1_ranges),
174e9034789SMichal Meloun 	},
175e9034789SMichal Meloun 	{
176e9034789SMichal Meloun 		.id = MAX77620_REG_ID_SD2,
177e9034789SMichal Meloun 		.name = "sd2",
178e9034789SMichal Meloun 		.supply_name = "in-sd2",
179e9034789SMichal Meloun 		.is_sd_reg = true,
180e9034789SMichal Meloun 		.volt_reg = MAX77620_REG_SD2,
181e9034789SMichal Meloun 		.volt_vsel_mask = MAX77620_SDX_VSEL_MASK,
182e9034789SMichal Meloun 		.cfg_reg = MAX77620_REG_CFG_SD2,
183e9034789SMichal Meloun 		.fps_reg = MAX77620_REG_FPS_SD2,
184e9034789SMichal Meloun 		.pwr_mode_reg = MAX77620_REG_CFG_SD2,
185e9034789SMichal Meloun 		.pwr_mode_mask = MAX77620_SD_POWER_MODE_MASK,
186e9034789SMichal Meloun 		.pwr_mode_shift = MAX77620_SD_POWER_MODE_SHIFT,
187e9034789SMichal Meloun 		.ranges = max77620_sdx_ranges,
188e9034789SMichal Meloun 		.nranges = nitems(max77620_sdx_ranges),
189e9034789SMichal Meloun 	},
190e9034789SMichal Meloun 	{
191e9034789SMichal Meloun 		.id = MAX77620_REG_ID_SD3,
192e9034789SMichal Meloun 		.name = "sd3",
193e9034789SMichal Meloun 		.supply_name = "in-sd3",
194e9034789SMichal Meloun 		.is_sd_reg = true,
195e9034789SMichal Meloun 		.volt_reg = MAX77620_REG_SD3,
196e9034789SMichal Meloun 		.volt_vsel_mask = MAX77620_SDX_VSEL_MASK,
197e9034789SMichal Meloun 		.cfg_reg = MAX77620_REG_CFG_SD3,
198e9034789SMichal Meloun 		.fps_reg = MAX77620_REG_FPS_SD3,
199e9034789SMichal Meloun 		.pwr_mode_reg = MAX77620_REG_CFG_SD3,
200e9034789SMichal Meloun 		.pwr_mode_mask = MAX77620_SD_POWER_MODE_MASK,
201e9034789SMichal Meloun 		.pwr_mode_shift = MAX77620_SD_POWER_MODE_SHIFT,
202e9034789SMichal Meloun 		.ranges = max77620_sdx_ranges,
203e9034789SMichal Meloun 		.nranges = nitems(max77620_sdx_ranges),
204e9034789SMichal Meloun 	},
205e9034789SMichal Meloun 	{
206e9034789SMichal Meloun 		.id = MAX77620_REG_ID_LDO0,
207e9034789SMichal Meloun 		.name = "ldo0",
208e9034789SMichal Meloun 		.supply_name = "vin-ldo0-1",
209e9034789SMichal Meloun 		.volt_reg = MAX77620_REG_CFG_LDO0,
210e9034789SMichal Meloun 		.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,
211e9034789SMichal Meloun 		.is_sd_reg = false,
212e9034789SMichal Meloun 		.cfg_reg = MAX77620_REG_CFG2_LDO0,
213e9034789SMichal Meloun 		.fps_reg = MAX77620_REG_FPS_LDO0,
214e9034789SMichal Meloun 		.pwr_mode_reg = MAX77620_REG_CFG_LDO0,
215e9034789SMichal Meloun 		.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,
216e9034789SMichal Meloun 		.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,
217e9034789SMichal Meloun 		.ranges = max77620_ldo0_1_ranges,
218e9034789SMichal Meloun 		.nranges = nitems(max77620_ldo0_1_ranges),
219e9034789SMichal Meloun 	},
220e9034789SMichal Meloun 	{
221e9034789SMichal Meloun 		.id = MAX77620_REG_ID_LDO1,
222e9034789SMichal Meloun 		.name = "ldo1",
223e9034789SMichal Meloun 		.supply_name = "in-ldo0-1",
224e9034789SMichal Meloun 		.is_sd_reg = false,
225e9034789SMichal Meloun 		.volt_reg = MAX77620_REG_CFG_LDO1,
226e9034789SMichal Meloun 		.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,
227e9034789SMichal Meloun 		.cfg_reg = MAX77620_REG_CFG2_LDO1,
228e9034789SMichal Meloun 		.fps_reg = MAX77620_REG_FPS_LDO1,
229e9034789SMichal Meloun 		.pwr_mode_reg = MAX77620_REG_CFG_LDO1,
230e9034789SMichal Meloun 		.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,
231e9034789SMichal Meloun 		.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,
232e9034789SMichal Meloun 		.ranges = max77620_ldo0_1_ranges,
233e9034789SMichal Meloun 		.nranges = nitems(max77620_ldo0_1_ranges),
234e9034789SMichal Meloun 	},
235e9034789SMichal Meloun 	{
236e9034789SMichal Meloun 		.id = MAX77620_REG_ID_LDO2,
237e9034789SMichal Meloun 		.name = "ldo2",
238e9034789SMichal Meloun 		.supply_name = "in-ldo2",
239e9034789SMichal Meloun 		.is_sd_reg = false,
240e9034789SMichal Meloun 		.volt_reg = MAX77620_REG_CFG_LDO2,
241e9034789SMichal Meloun 		.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,
242e9034789SMichal Meloun 		.cfg_reg = MAX77620_REG_CFG2_LDO2,
243e9034789SMichal Meloun 		.fps_reg = MAX77620_REG_FPS_LDO2,
244e9034789SMichal Meloun 		.pwr_mode_reg = MAX77620_REG_CFG_LDO2,
245e9034789SMichal Meloun 		.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,
246e9034789SMichal Meloun 		.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,
247e9034789SMichal Meloun 		.ranges = max77620_ldox_ranges,
248e9034789SMichal Meloun 		.nranges = nitems(max77620_ldox_ranges),
249e9034789SMichal Meloun 	},
250e9034789SMichal Meloun 	{
251e9034789SMichal Meloun 		.id = MAX77620_REG_ID_LDO3,
252e9034789SMichal Meloun 		.name = "ldo3",
253e9034789SMichal Meloun 		.supply_name = "in-ldo3-5",
254e9034789SMichal Meloun 		.is_sd_reg = false,
255e9034789SMichal Meloun 		.volt_reg = MAX77620_REG_CFG_LDO3,
256e9034789SMichal Meloun 		.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,
257e9034789SMichal Meloun 		.cfg_reg = MAX77620_REG_CFG2_LDO3,
258e9034789SMichal Meloun 		.fps_reg = MAX77620_REG_FPS_LDO3,
259e9034789SMichal Meloun 		.pwr_mode_reg = MAX77620_REG_CFG_LDO3,
260e9034789SMichal Meloun 		.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,
261e9034789SMichal Meloun 		.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,
262e9034789SMichal Meloun 		.ranges = max77620_ldox_ranges,
263e9034789SMichal Meloun 		.nranges = nitems(max77620_ldox_ranges),
264e9034789SMichal Meloun 	},
265e9034789SMichal Meloun 	{
266e9034789SMichal Meloun 		.id = MAX77620_REG_ID_LDO4,
267e9034789SMichal Meloun 		.name = "ldo4",
268e9034789SMichal Meloun 		.supply_name = "in-ldo4-6",
269e9034789SMichal Meloun 		.is_sd_reg = false,
270e9034789SMichal Meloun 		.volt_reg = MAX77620_REG_CFG_LDO4,
271e9034789SMichal Meloun 		.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,
272e9034789SMichal Meloun 		.cfg_reg = MAX77620_REG_CFG2_LDO4,
273e9034789SMichal Meloun 		.fps_reg = MAX77620_REG_FPS_LDO4,
274e9034789SMichal Meloun 		.pwr_mode_reg = MAX77620_REG_CFG_LDO4,
275e9034789SMichal Meloun 		.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,
276e9034789SMichal Meloun 		.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,
277e9034789SMichal Meloun 		.ranges = max77620_ldo4_ranges,
278e9034789SMichal Meloun 		.nranges = nitems(max77620_ldo4_ranges),
279e9034789SMichal Meloun 	},
280e9034789SMichal Meloun 	{
281e9034789SMichal Meloun 		.id = MAX77620_REG_ID_LDO5,
282e9034789SMichal Meloun 		.name = "ldo5",
283e9034789SMichal Meloun 		.supply_name = "in-ldo3-5",
284e9034789SMichal Meloun 		.is_sd_reg = false,
285e9034789SMichal Meloun 		.volt_reg = MAX77620_REG_CFG_LDO5,
286e9034789SMichal Meloun 		.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,
287e9034789SMichal Meloun 		.cfg_reg = MAX77620_REG_CFG2_LDO5,
288e9034789SMichal Meloun 		.fps_reg = MAX77620_REG_FPS_LDO5,
289e9034789SMichal Meloun 		.pwr_mode_reg = MAX77620_REG_CFG_LDO5,
290e9034789SMichal Meloun 		.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,
291e9034789SMichal Meloun 		.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,
292e9034789SMichal Meloun 		.ranges = max77620_ldox_ranges,
293e9034789SMichal Meloun 		.nranges = nitems(max77620_ldox_ranges),
294e9034789SMichal Meloun 	},
295e9034789SMichal Meloun 	{
296e9034789SMichal Meloun 		.id = MAX77620_REG_ID_LDO6,
297e9034789SMichal Meloun 		.name = "ldo6",
298e9034789SMichal Meloun 		.supply_name = "in-ldo4-6",
299e9034789SMichal Meloun 		.is_sd_reg = false,
300e9034789SMichal Meloun 		.volt_reg = MAX77620_REG_CFG_LDO6,
301e9034789SMichal Meloun 		.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,
302e9034789SMichal Meloun 		.cfg_reg = MAX77620_REG_CFG2_LDO6,
303e9034789SMichal Meloun 		.fps_reg = MAX77620_REG_FPS_LDO6,
304e9034789SMichal Meloun 		.pwr_mode_reg = MAX77620_REG_CFG_LDO6,
305e9034789SMichal Meloun 		.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,
306e9034789SMichal Meloun 		.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,
307e9034789SMichal Meloun 		.ranges = max77620_ldox_ranges,
308e9034789SMichal Meloun 		.nranges = nitems(max77620_ldox_ranges),
309e9034789SMichal Meloun 	},
310e9034789SMichal Meloun 	{
311e9034789SMichal Meloun 		.id = MAX77620_REG_ID_LDO7,
312e9034789SMichal Meloun 		.name = "ldo7",
313e9034789SMichal Meloun 		.supply_name = "in-ldo7-8",
314e9034789SMichal Meloun 		.is_sd_reg = false,
315e9034789SMichal Meloun 		.volt_reg = MAX77620_REG_CFG_LDO7,
316e9034789SMichal Meloun 		.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,
317e9034789SMichal Meloun 		.cfg_reg = MAX77620_REG_CFG2_LDO7,
318e9034789SMichal Meloun 		.fps_reg = MAX77620_REG_FPS_LDO7,
319e9034789SMichal Meloun 		.pwr_mode_reg = MAX77620_REG_CFG_LDO7,
320e9034789SMichal Meloun 		.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,
321e9034789SMichal Meloun 		.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,
322e9034789SMichal Meloun 		.ranges = max77620_ldox_ranges,
323e9034789SMichal Meloun 		.nranges = nitems(max77620_ldox_ranges),
324e9034789SMichal Meloun 	},
325e9034789SMichal Meloun 	{
326e9034789SMichal Meloun 		.id = MAX77620_REG_ID_LDO8,
327e9034789SMichal Meloun 		.name = "ldo8",
328e9034789SMichal Meloun 		.supply_name = "in-ldo7-8",
329e9034789SMichal Meloun 		.is_sd_reg = false,
330e9034789SMichal Meloun 		.volt_reg = MAX77620_REG_CFG_LDO8,
331e9034789SMichal Meloun 		.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,
332e9034789SMichal Meloun 		.cfg_reg = MAX77620_REG_CFG2_LDO8,
333e9034789SMichal Meloun 		.fps_reg = MAX77620_REG_FPS_LDO8,
334e9034789SMichal Meloun 		.pwr_mode_reg = MAX77620_REG_CFG_LDO8,
335e9034789SMichal Meloun 		.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,
336e9034789SMichal Meloun 		.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,
337e9034789SMichal Meloun 		.ranges = max77620_ldox_ranges,
338e9034789SMichal Meloun 		.nranges = nitems(max77620_ldox_ranges),
339e9034789SMichal Meloun 	},
340e9034789SMichal Meloun };
341e9034789SMichal Meloun 
342e9034789SMichal Meloun 
343e9034789SMichal Meloun static int max77620_regnode_init(struct regnode *regnode);
344e9034789SMichal Meloun static int max77620_regnode_enable(struct regnode *regnode, bool enable,
345e9034789SMichal Meloun     int *udelay);
346e9034789SMichal Meloun static int max77620_regnode_set_volt(struct regnode *regnode, int min_uvolt,
347e9034789SMichal Meloun     int max_uvolt, int *udelay);
348e9034789SMichal Meloun static int max77620_regnode_get_volt(struct regnode *regnode, int *uvolt);
349e9034789SMichal Meloun static regnode_method_t max77620_regnode_methods[] = {
350e9034789SMichal Meloun 	/* Regulator interface */
351e9034789SMichal Meloun 	REGNODEMETHOD(regnode_init,		max77620_regnode_init),
352e9034789SMichal Meloun 	REGNODEMETHOD(regnode_enable,		max77620_regnode_enable),
353e9034789SMichal Meloun 	REGNODEMETHOD(regnode_set_voltage,	max77620_regnode_set_volt),
354e9034789SMichal Meloun 	REGNODEMETHOD(regnode_get_voltage,	max77620_regnode_get_volt),
355e9034789SMichal Meloun 	REGNODEMETHOD_END
356e9034789SMichal Meloun };
357e9034789SMichal Meloun DEFINE_CLASS_1(max77620_regnode, max77620_regnode_class, max77620_regnode_methods,
358e9034789SMichal Meloun    sizeof(struct max77620_reg_sc), regnode_class);
359e9034789SMichal Meloun 
360e9034789SMichal Meloun static int
max77620_get_sel(struct max77620_reg_sc * sc,uint8_t * sel)361e9034789SMichal Meloun max77620_get_sel(struct max77620_reg_sc *sc, uint8_t *sel)
362e9034789SMichal Meloun {
363e9034789SMichal Meloun 	int rv;
364e9034789SMichal Meloun 
365e9034789SMichal Meloun 	rv = RD1(sc->base_sc, sc->def->volt_reg, sel);
366e9034789SMichal Meloun 	if (rv != 0) {
367e9034789SMichal Meloun 		printf("%s: cannot read volatge selector: %d\n",
368e9034789SMichal Meloun 		    regnode_get_name(sc->regnode), rv);
369e9034789SMichal Meloun 		return (rv);
370e9034789SMichal Meloun 	}
371e9034789SMichal Meloun 	*sel &= sc->def->volt_vsel_mask;
372e9034789SMichal Meloun 	*sel >>= ffs(sc->def->volt_vsel_mask) - 1;
373e9034789SMichal Meloun 	return (0);
374e9034789SMichal Meloun }
375e9034789SMichal Meloun 
376e9034789SMichal Meloun static int
max77620_set_sel(struct max77620_reg_sc * sc,uint8_t sel)377e9034789SMichal Meloun max77620_set_sel(struct max77620_reg_sc *sc, uint8_t sel)
378e9034789SMichal Meloun {
379e9034789SMichal Meloun 	int rv;
380e9034789SMichal Meloun 
381e9034789SMichal Meloun 	sel <<= ffs(sc->def->volt_vsel_mask) - 1;
382e9034789SMichal Meloun 	sel &= sc->def->volt_vsel_mask;
383e9034789SMichal Meloun 
384e9034789SMichal Meloun 	rv = RM1(sc->base_sc, sc->def->volt_reg,
385e9034789SMichal Meloun 	    sc->def->volt_vsel_mask, sel);
386e9034789SMichal Meloun 	if (rv != 0) {
387e9034789SMichal Meloun 		printf("%s: cannot set volatge selector: %d\n",
388e9034789SMichal Meloun 		    regnode_get_name(sc->regnode), rv);
389e9034789SMichal Meloun 		return (rv);
390e9034789SMichal Meloun 	}
391e9034789SMichal Meloun 	return (rv);
392e9034789SMichal Meloun }
393e9034789SMichal Meloun 
394e9034789SMichal Meloun static int
max77620_get_fps_src(struct max77620_reg_sc * sc,uint8_t * fps_src)395e9034789SMichal Meloun max77620_get_fps_src(struct max77620_reg_sc *sc, uint8_t *fps_src)
396e9034789SMichal Meloun {
397e9034789SMichal Meloun 	uint8_t val;
398e9034789SMichal Meloun 	int rv;
399e9034789SMichal Meloun 
400e9034789SMichal Meloun 	rv = RD1(sc->base_sc, sc->def->fps_reg, &val);
401e9034789SMichal Meloun 	if (rv != 0)
402e9034789SMichal Meloun 		return (rv);
403e9034789SMichal Meloun 
404e9034789SMichal Meloun 	*fps_src  = (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT;
405e9034789SMichal Meloun 	return (0);
406e9034789SMichal Meloun }
407e9034789SMichal Meloun 
408e9034789SMichal Meloun static int
max77620_set_fps_src(struct max77620_reg_sc * sc,uint8_t fps_src)409e9034789SMichal Meloun max77620_set_fps_src(struct max77620_reg_sc *sc, uint8_t fps_src)
410e9034789SMichal Meloun {
411e9034789SMichal Meloun 	int rv;
412e9034789SMichal Meloun 
413e9034789SMichal Meloun 	rv = RM1(sc->base_sc, sc->def->fps_reg, MAX77620_FPS_SRC_MASK,
414e9034789SMichal Meloun 	    fps_src << MAX77620_FPS_SRC_SHIFT);
415e9034789SMichal Meloun 	if (rv != 0)
416e9034789SMichal Meloun 		return (rv);
417e9034789SMichal Meloun 	sc->fps_src = fps_src;
418e9034789SMichal Meloun 	return (0);
419e9034789SMichal Meloun }
420e9034789SMichal Meloun 
421e9034789SMichal Meloun static int
max77620_set_fps_slots(struct max77620_reg_sc * sc,bool suspend)422e9034789SMichal Meloun max77620_set_fps_slots(struct max77620_reg_sc *sc, bool suspend)
423e9034789SMichal Meloun {
424e9034789SMichal Meloun 	uint8_t mask, val;
425e9034789SMichal Meloun 	int pu_slot, pd_slot, rv;
426e9034789SMichal Meloun 
427e9034789SMichal Meloun 	if (suspend) {
428e9034789SMichal Meloun 		pu_slot = sc->suspend_fps_pu_slot;
429e9034789SMichal Meloun 		pd_slot = sc->suspend_fps_pd_slot;
430e9034789SMichal Meloun 	} else {
431e9034789SMichal Meloun 		pu_slot = sc->active_fps_pu_slot;
432e9034789SMichal Meloun 		pd_slot = sc->active_fps_pd_slot;
433e9034789SMichal Meloun 	}
434e9034789SMichal Meloun 
435e9034789SMichal Meloun 	mask = 0;
436e9034789SMichal Meloun 	val = 0;
437e9034789SMichal Meloun 	if (pu_slot >= 0) {
438e9034789SMichal Meloun 		mask |= MAX77620_FPS_PU_PERIOD_MASK;
439e9034789SMichal Meloun 		val |= ((uint8_t)pu_slot << MAX77620_FPS_PU_PERIOD_SHIFT) &
440e9034789SMichal Meloun 		    MAX77620_FPS_PU_PERIOD_MASK;
441e9034789SMichal Meloun 	}
442e9034789SMichal Meloun 	if (pd_slot >= 0) {
443e9034789SMichal Meloun 		mask |= MAX77620_FPS_PD_PERIOD_MASK;
444e9034789SMichal Meloun 		val |= ((uint8_t)pd_slot << MAX77620_FPS_PD_PERIOD_SHIFT) &
445e9034789SMichal Meloun 		    MAX77620_FPS_PD_PERIOD_MASK;
446e9034789SMichal Meloun 	}
447e9034789SMichal Meloun 
448e9034789SMichal Meloun 	rv = RM1(sc->base_sc, sc->def->fps_reg, mask, val);
449e9034789SMichal Meloun 	if (rv != 0)
450e9034789SMichal Meloun 		return (rv);
451e9034789SMichal Meloun 	return (0);
452e9034789SMichal Meloun }
453e9034789SMichal Meloun 
454e9034789SMichal Meloun static int
max77620_get_pwr_mode(struct max77620_reg_sc * sc,uint8_t * pwr_mode)455e9034789SMichal Meloun max77620_get_pwr_mode(struct max77620_reg_sc *sc, uint8_t *pwr_mode)
456e9034789SMichal Meloun {
457e9034789SMichal Meloun 	uint8_t val;
458e9034789SMichal Meloun 	int rv;
459e9034789SMichal Meloun 
460e9034789SMichal Meloun 	rv = RD1(sc->base_sc, sc->def->pwr_mode_reg, &val);
461e9034789SMichal Meloun 	if (rv != 0)
462e9034789SMichal Meloun 		return (rv);
463e9034789SMichal Meloun 
464e9034789SMichal Meloun 	*pwr_mode  = (val & sc->def->pwr_mode_mask) >> sc->def->pwr_mode_shift;
465e9034789SMichal Meloun 	return (0);
466e9034789SMichal Meloun }
467e9034789SMichal Meloun 
468e9034789SMichal Meloun static int
max77620_set_pwr_mode(struct max77620_reg_sc * sc,uint8_t pwr_mode)469e9034789SMichal Meloun max77620_set_pwr_mode(struct max77620_reg_sc *sc, uint8_t pwr_mode)
470e9034789SMichal Meloun {
471e9034789SMichal Meloun 	int rv;
472e9034789SMichal Meloun 
473e9034789SMichal Meloun 	rv = RM1(sc->base_sc, sc->def->pwr_mode_reg, sc->def->pwr_mode_shift,
474e9034789SMichal Meloun 	    pwr_mode << sc->def->pwr_mode_shift);
475e9034789SMichal Meloun 	if (rv != 0)
476e9034789SMichal Meloun 		return (rv);
477e9034789SMichal Meloun 	sc->pwr_mode = pwr_mode;
478e9034789SMichal Meloun 	return (0);
479e9034789SMichal Meloun }
480e9034789SMichal Meloun 
481e9034789SMichal Meloun static int
max77620_get_pwr_ramp_delay(struct max77620_reg_sc * sc,int * rate)482e9034789SMichal Meloun max77620_get_pwr_ramp_delay(struct max77620_reg_sc *sc, int *rate)
483e9034789SMichal Meloun {
484e9034789SMichal Meloun 	uint8_t val;
485e9034789SMichal Meloun 	int rv;
486e9034789SMichal Meloun 
487e9034789SMichal Meloun 	rv = RD1(sc->base_sc, sc->def->cfg_reg, &val);
488e9034789SMichal Meloun 	if (rv != 0)
489e9034789SMichal Meloun 		return (rv);
490e9034789SMichal Meloun 
491e9034789SMichal Meloun 	if (sc->def->is_sd_reg) {
492e9034789SMichal Meloun 		val = (val & MAX77620_SD_SR_MASK) >> MAX77620_SD_SR_SHIFT;
493e9034789SMichal Meloun 		if (val == 0)
494e9034789SMichal Meloun 			*rate = 13750;
495e9034789SMichal Meloun 		else if (val == 1)
496e9034789SMichal Meloun 			*rate = 27500;
497e9034789SMichal Meloun 		else if (val == 2)
498e9034789SMichal Meloun 			*rate = 55000;
499e9034789SMichal Meloun 		else
500e9034789SMichal Meloun 			*rate = 100000;
501e9034789SMichal Meloun 	} else {
502e9034789SMichal Meloun 		val = (val & MAX77620_LDO_SLEW_RATE_MASK) >>
503e9034789SMichal Meloun 		    MAX77620_LDO_SLEW_RATE_SHIFT;
504e9034789SMichal Meloun 		if (val == 0)
505e9034789SMichal Meloun 			*rate = 100000;
506e9034789SMichal Meloun 		else
507e9034789SMichal Meloun 			*rate = 5000;
508e9034789SMichal Meloun 	}
509e9034789SMichal Meloun 	sc->pwr_ramp_delay = *rate;
510e9034789SMichal Meloun 	return (0);
511e9034789SMichal Meloun }
512e9034789SMichal Meloun 
513e9034789SMichal Meloun static int
max77620_set_pwr_ramp_delay(struct max77620_reg_sc * sc,int rate)514e9034789SMichal Meloun max77620_set_pwr_ramp_delay(struct max77620_reg_sc *sc, int rate)
515e9034789SMichal Meloun {
516e9034789SMichal Meloun 	uint8_t val, mask;
517e9034789SMichal Meloun 	int rv;
518e9034789SMichal Meloun 
519e9034789SMichal Meloun 	if (sc->def->is_sd_reg) {
520e9034789SMichal Meloun 		if (rate <= 13750)
521e9034789SMichal Meloun 			val = 0;
522e9034789SMichal Meloun 		else if (rate <= 27500)
523e9034789SMichal Meloun 			val = 1;
524e9034789SMichal Meloun 		else if (rate <= 55000)
525e9034789SMichal Meloun 			val = 2;
526e9034789SMichal Meloun 		else
527e9034789SMichal Meloun 			val = 3;
528e9034789SMichal Meloun 		val <<= MAX77620_SD_SR_SHIFT;
529e9034789SMichal Meloun 		mask = MAX77620_SD_SR_MASK;
530e9034789SMichal Meloun 	} else {
531e9034789SMichal Meloun 		if (rate <= 5000)
532e9034789SMichal Meloun 			val = 1;
533e9034789SMichal Meloun 		else
534e9034789SMichal Meloun 			val = 0;
535e9034789SMichal Meloun 		val <<= MAX77620_LDO_SLEW_RATE_SHIFT;
536e9034789SMichal Meloun 		mask = MAX77620_LDO_SLEW_RATE_MASK;
537e9034789SMichal Meloun 	}
538e9034789SMichal Meloun 	rv = RM1(sc->base_sc, sc->def->cfg_reg, mask, val);
539e9034789SMichal Meloun 	if (rv != 0)
540e9034789SMichal Meloun 		return (rv);
541e9034789SMichal Meloun 	return (0);
542e9034789SMichal Meloun }
543e9034789SMichal Meloun 
544e9034789SMichal Meloun static int
max77620_regnode_init(struct regnode * regnode)545e9034789SMichal Meloun max77620_regnode_init(struct regnode *regnode)
546e9034789SMichal Meloun {
547e9034789SMichal Meloun 	struct max77620_reg_sc *sc;
548e9034789SMichal Meloun 	uint8_t val;
549e9034789SMichal Meloun 	int intval, rv;
550e9034789SMichal Meloun 
551e9034789SMichal Meloun 	sc = regnode_get_softc(regnode);
552e9034789SMichal Meloun 	sc->enable_usec = 500;
553e9034789SMichal Meloun 	sc->enable_pwr_mode = MAX77620_POWER_MODE_NORMAL;
554e9034789SMichal Meloun #if 0
555e9034789SMichal Meloun {
556e9034789SMichal Meloun uint8_t val1, val2, val3;
557e9034789SMichal Meloun RD1(sc->base_sc, sc->def->volt_reg, &val1);
558e9034789SMichal Meloun RD1(sc->base_sc, sc->def->cfg_reg, &val2);
559e9034789SMichal Meloun RD1(sc->base_sc, sc->def->fps_reg, &val3);
560e9034789SMichal Meloun printf("%s: Volt: 0x%02X, CFG: 0x%02X, FPS: 0x%02X\n", regnode_get_name(sc->regnode), val1, val2, val3);
561e9034789SMichal Meloun }
562e9034789SMichal Meloun #endif
563e9034789SMichal Meloun 	/* Get current power mode */
564e9034789SMichal Meloun 	rv = max77620_get_pwr_mode(sc, &val);
565e9034789SMichal Meloun 	if (rv != 0) {
566e9034789SMichal Meloun 		printf("%s: cannot read current power mode: %d\n",
567e9034789SMichal Meloun 		    regnode_get_name(sc->regnode), rv);
568e9034789SMichal Meloun 		return (rv);
569e9034789SMichal Meloun 	}
570e9034789SMichal Meloun 	sc->pwr_mode = val;
571e9034789SMichal Meloun 
572e9034789SMichal Meloun 	/* Get current power ramp delay */
573e9034789SMichal Meloun 	rv = max77620_get_pwr_ramp_delay(sc, &intval);
574e9034789SMichal Meloun 	if (rv != 0) {
575e9034789SMichal Meloun 		printf("%s: cannot read current power mode: %d\n",
576e9034789SMichal Meloun 		    regnode_get_name(sc->regnode), rv);
577e9034789SMichal Meloun 		return (rv);
578e9034789SMichal Meloun 	}
579e9034789SMichal Meloun 	sc->pwr_ramp_delay = intval;
580e9034789SMichal Meloun 
581e9034789SMichal Meloun 	/* Get FPS source if is not specified. */
582e9034789SMichal Meloun 	if (sc->active_fps_src == -1) {
583e9034789SMichal Meloun 		rv = max77620_get_fps_src(sc, &val);
584e9034789SMichal Meloun 		if (rv != 0) {
585e9034789SMichal Meloun 			printf("%s: cannot read current FPS source: %d\n",
586e9034789SMichal Meloun 			    regnode_get_name(sc->regnode), rv);
587e9034789SMichal Meloun 			return (rv);
588e9034789SMichal Meloun 		}
589e9034789SMichal Meloun 		sc->active_fps_src = val;
590e9034789SMichal Meloun 	}
591e9034789SMichal Meloun 
592e9034789SMichal Meloun 	/* Configure power mode non-FPS controlled regulators. */
593e9034789SMichal Meloun 	if (sc->active_fps_src != MAX77620_FPS_SRC_NONE ||
594e9034789SMichal Meloun 	    (sc->pwr_mode != MAX77620_POWER_MODE_DISABLE &&
595e9034789SMichal Meloun 	    sc->pwr_mode != sc->enable_pwr_mode)) {
596e9034789SMichal Meloun 		rv = max77620_set_pwr_mode(sc, (uint8_t)sc->enable_pwr_mode);
597e9034789SMichal Meloun 		if (rv != 0) {
598e9034789SMichal Meloun 			printf("%s: cannot set power mode: %d\n",
599e9034789SMichal Meloun 			    regnode_get_name(sc->regnode), rv);
600e9034789SMichal Meloun 			return (rv);
601e9034789SMichal Meloun 		}
602e9034789SMichal Meloun 	}
603e9034789SMichal Meloun 
604e9034789SMichal Meloun 	/* Set FPS source. */
605e9034789SMichal Meloun 	rv = max77620_set_fps_src(sc, sc->active_fps_src);
606e9034789SMichal Meloun 	if (rv != 0) {
607e9034789SMichal Meloun 		printf("%s: cannot setup FPS source: %d\n",
608e9034789SMichal Meloun 		    regnode_get_name(sc->regnode), rv);
609e9034789SMichal Meloun 		return (rv);
610e9034789SMichal Meloun 	}
611e9034789SMichal Meloun 	/* Set FPS slots. */
612e9034789SMichal Meloun 	rv = max77620_set_fps_slots(sc, false);
613e9034789SMichal Meloun 	if (rv != 0) {
614e9034789SMichal Meloun 		printf("%s: cannot setup power slots: %d\n",
615e9034789SMichal Meloun 		    regnode_get_name(sc->regnode), rv);
616e9034789SMichal Meloun 		return (rv);
617e9034789SMichal Meloun 	}
618e9034789SMichal Meloun 	/* Setup power ramp . */
619e9034789SMichal Meloun 	if (sc->ramp_rate_setting != -1) {
620e9034789SMichal Meloun 		rv = max77620_set_pwr_ramp_delay(sc, sc->pwr_ramp_delay);
621e9034789SMichal Meloun 		if (rv != 0) {
622e9034789SMichal Meloun 			printf("%s: cannot set power ramp delay: %d\n",
623e9034789SMichal Meloun 			    regnode_get_name(sc->regnode), rv);
624e9034789SMichal Meloun 			return (rv);
625e9034789SMichal Meloun 		}
626e9034789SMichal Meloun 	}
627e9034789SMichal Meloun 
628e9034789SMichal Meloun 	return (0);
629e9034789SMichal Meloun }
630e9034789SMichal Meloun 
631e9034789SMichal Meloun static void
max77620_fdt_parse(struct max77620_softc * sc,phandle_t node,struct reg_def * def,struct max77620_regnode_init_def * init_def)632e9034789SMichal Meloun max77620_fdt_parse(struct max77620_softc *sc, phandle_t node, struct reg_def *def,
633e9034789SMichal Meloun struct max77620_regnode_init_def *init_def)
634e9034789SMichal Meloun {
635e9034789SMichal Meloun 	int rv;
636e9034789SMichal Meloun 	phandle_t parent, supply_node;
637e9034789SMichal Meloun 	char prop_name[64]; /* Maximum OFW property name length. */
638e9034789SMichal Meloun 
639e9034789SMichal Meloun 	rv = regulator_parse_ofw_stdparam(sc->dev, node,
640e9034789SMichal Meloun 	    &init_def->reg_init_def);
641e9034789SMichal Meloun 
642e9034789SMichal Meloun 	rv = OF_getencprop(node, "maxim,active-fps-source",
643e9034789SMichal Meloun 	    &init_def->active_fps_src, sizeof(init_def->active_fps_src));
644e9034789SMichal Meloun 	if (rv <= 0)
645e9034789SMichal Meloun 		init_def->active_fps_src = MAX77620_FPS_SRC_DEF;
646e9034789SMichal Meloun 
647e9034789SMichal Meloun 	rv = OF_getencprop(node, "maxim,active-fps-power-up-slot",
648e9034789SMichal Meloun 	    &init_def->active_fps_pu_slot, sizeof(init_def->active_fps_pu_slot));
649e9034789SMichal Meloun 	if (rv <= 0)
650e9034789SMichal Meloun 		init_def->active_fps_pu_slot = -1;
651e9034789SMichal Meloun 
652e9034789SMichal Meloun 	rv = OF_getencprop(node, "maxim,active-fps-power-down-slot",
653e9034789SMichal Meloun 	    &init_def->active_fps_pd_slot, sizeof(init_def->active_fps_pd_slot));
654e9034789SMichal Meloun 	if (rv <= 0)
655e9034789SMichal Meloun 		init_def->active_fps_pd_slot = -1;
656e9034789SMichal Meloun 
657e9034789SMichal Meloun 	rv = OF_getencprop(node, "maxim,suspend-fps-source",
658e9034789SMichal Meloun 	    &init_def->suspend_fps_src, sizeof(init_def->suspend_fps_src));
659e9034789SMichal Meloun 	if (rv <= 0)
660e9034789SMichal Meloun 		init_def->suspend_fps_src = -1;
661e9034789SMichal Meloun 
662e9034789SMichal Meloun 	rv = OF_getencprop(node, "maxim,suspend-fps-power-up-slot",
663e9034789SMichal Meloun 	    &init_def->suspend_fps_pu_slot, sizeof(init_def->suspend_fps_pu_slot));
664e9034789SMichal Meloun 	if (rv <= 0)
665e9034789SMichal Meloun 		init_def->suspend_fps_pu_slot = -1;
666e9034789SMichal Meloun 
667e9034789SMichal Meloun 	rv = OF_getencprop(node, "maxim,suspend-fps-power-down-slot",
668e9034789SMichal Meloun 	    &init_def->suspend_fps_pd_slot, sizeof(init_def->suspend_fps_pd_slot));
669e9034789SMichal Meloun 	if (rv <= 0)
670e9034789SMichal Meloun 		init_def->suspend_fps_pd_slot = -1;
671e9034789SMichal Meloun 
672e9034789SMichal Meloun 	rv = OF_getencprop(node, "maxim,ramp-rate-setting",
673e9034789SMichal Meloun 	    &init_def->ramp_rate_setting, sizeof(init_def->ramp_rate_setting));
674e9034789SMichal Meloun 	if (rv <= 0)
675e9034789SMichal Meloun 		init_def->ramp_rate_setting = -1;
676e9034789SMichal Meloun 
677e9034789SMichal Meloun 	/* Get parent supply. */
678e9034789SMichal Meloun 	if (def->supply_name == NULL)
679e9034789SMichal Meloun 		 return;
680e9034789SMichal Meloun 
681e9034789SMichal Meloun 	parent = OF_parent(node);
682e9034789SMichal Meloun 	snprintf(prop_name, sizeof(prop_name), "%s-supply",
683e9034789SMichal Meloun 	    def->supply_name);
684e9034789SMichal Meloun 	rv = OF_getencprop(parent, prop_name, &supply_node,
685e9034789SMichal Meloun 	    sizeof(supply_node));
686e9034789SMichal Meloun 	if (rv <= 0)
687e9034789SMichal Meloun 		return;
688e9034789SMichal Meloun 	supply_node = OF_node_from_xref(supply_node);
689e9034789SMichal Meloun 	rv = OF_getprop_alloc(supply_node, "regulator-name",
690e9034789SMichal Meloun 	    (void **)&init_def->reg_init_def.parent_name);
691e9034789SMichal Meloun 	if (rv <= 0)
692e9034789SMichal Meloun 		init_def->reg_init_def.parent_name = NULL;
693e9034789SMichal Meloun }
694e9034789SMichal Meloun 
695e9034789SMichal Meloun static struct max77620_reg_sc *
max77620_attach(struct max77620_softc * sc,phandle_t node,struct reg_def * def)696e9034789SMichal Meloun max77620_attach(struct max77620_softc *sc, phandle_t node, struct reg_def *def)
697e9034789SMichal Meloun {
698e9034789SMichal Meloun 	struct max77620_reg_sc *reg_sc;
699e9034789SMichal Meloun 	struct max77620_regnode_init_def init_def;
700e9034789SMichal Meloun 	struct regnode *regnode;
701e9034789SMichal Meloun 
702e9034789SMichal Meloun 	bzero(&init_def, sizeof(init_def));
703e9034789SMichal Meloun 
704e9034789SMichal Meloun 	max77620_fdt_parse(sc, node, def, &init_def);
705e9034789SMichal Meloun 	init_def.reg_init_def.id = def->id;
706e9034789SMichal Meloun 	init_def.reg_init_def.ofw_node = node;
707e9034789SMichal Meloun 	regnode = regnode_create(sc->dev, &max77620_regnode_class,
708e9034789SMichal Meloun 	    &init_def.reg_init_def);
709e9034789SMichal Meloun 	if (regnode == NULL) {
710e9034789SMichal Meloun 		device_printf(sc->dev, "Cannot create regulator.\n");
711e9034789SMichal Meloun 		return (NULL);
712e9034789SMichal Meloun 	}
713e9034789SMichal Meloun 	reg_sc = regnode_get_softc(regnode);
714e9034789SMichal Meloun 
715e9034789SMichal Meloun 	/* Init regulator softc. */
716e9034789SMichal Meloun 	reg_sc->regnode = regnode;
717e9034789SMichal Meloun 	reg_sc->base_sc = sc;
718e9034789SMichal Meloun 	reg_sc->def = def;
719e9034789SMichal Meloun 	reg_sc->xref = OF_xref_from_node(node);
720e9034789SMichal Meloun 	reg_sc->param = regnode_get_stdparam(regnode);
721e9034789SMichal Meloun 	reg_sc->active_fps_src = init_def.active_fps_src;
722e9034789SMichal Meloun 	reg_sc->active_fps_pu_slot = init_def.active_fps_pu_slot;
723e9034789SMichal Meloun 	reg_sc->active_fps_pd_slot = init_def.active_fps_pd_slot;
724e9034789SMichal Meloun 	reg_sc->suspend_fps_src = init_def.suspend_fps_src;
725e9034789SMichal Meloun 	reg_sc->suspend_fps_pu_slot = init_def.suspend_fps_pu_slot;
726e9034789SMichal Meloun 	reg_sc->suspend_fps_pd_slot = init_def.suspend_fps_pd_slot;
727e9034789SMichal Meloun 	reg_sc->ramp_rate_setting = init_def.ramp_rate_setting;
728e9034789SMichal Meloun 
729e9034789SMichal Meloun 	regnode_register(regnode);
730e9034789SMichal Meloun 	if (bootverbose) {
731e9034789SMichal Meloun 		int volt, rv;
732e9034789SMichal Meloun 		regnode_topo_slock();
733e9034789SMichal Meloun 		rv = regnode_get_voltage(regnode, &volt);
734e9034789SMichal Meloun 		if (rv == ENODEV) {
735e9034789SMichal Meloun 			device_printf(sc->dev,
736e9034789SMichal Meloun 			   " Regulator %s: parent doesn't exist yet.\n",
737e9034789SMichal Meloun 			   regnode_get_name(regnode));
738e9034789SMichal Meloun 		} else if (rv != 0) {
739e9034789SMichal Meloun 			device_printf(sc->dev,
740e9034789SMichal Meloun 			   " Regulator %s: voltage: INVALID!!!\n",
741e9034789SMichal Meloun 			   regnode_get_name(regnode));
742e9034789SMichal Meloun 		} else {
743e9034789SMichal Meloun 			device_printf(sc->dev,
744e9034789SMichal Meloun 			    " Regulator %s: voltage: %d uV\n",
745e9034789SMichal Meloun 			    regnode_get_name(regnode), volt);
746e9034789SMichal Meloun 			device_printf(sc->dev,
747e9034789SMichal Meloun 			    "  FPS source: %d, mode: %d, ramp delay: %d\n",
748e9034789SMichal Meloun 			    reg_sc->fps_src, reg_sc->pwr_mode,
749e9034789SMichal Meloun 			    reg_sc->pwr_ramp_delay);
750e9034789SMichal Meloun 		}
751e9034789SMichal Meloun 		regnode_topo_unlock();
752e9034789SMichal Meloun 	}
753e9034789SMichal Meloun 
754e9034789SMichal Meloun 	return (reg_sc);
755e9034789SMichal Meloun }
756e9034789SMichal Meloun 
757e9034789SMichal Meloun int
max77620_regulator_attach(struct max77620_softc * sc,phandle_t node)758e9034789SMichal Meloun max77620_regulator_attach(struct max77620_softc *sc, phandle_t node)
759e9034789SMichal Meloun {
760e9034789SMichal Meloun 	struct max77620_reg_sc *reg;
761e9034789SMichal Meloun 	phandle_t child, rnode;
762e9034789SMichal Meloun 	int i;
763e9034789SMichal Meloun 
764e9034789SMichal Meloun 	rnode = ofw_bus_find_child(node, "regulators");
765e9034789SMichal Meloun 	if (rnode <= 0) {
766e9034789SMichal Meloun 		device_printf(sc->dev, " Cannot find regulators subnode\n");
767e9034789SMichal Meloun 		return (ENXIO);
768e9034789SMichal Meloun 	}
769e9034789SMichal Meloun 
770e9034789SMichal Meloun 	sc->nregs = nitems(max77620s_def);
771e9034789SMichal Meloun 	sc->regs = malloc(sizeof(struct max77620_reg_sc *) * sc->nregs,
772e9034789SMichal Meloun 	    M_MAX77620_REG, M_WAITOK | M_ZERO);
773e9034789SMichal Meloun 
774e9034789SMichal Meloun 
775e9034789SMichal Meloun 	/* Attach all known regulators if exist in DT. */
776e9034789SMichal Meloun 	for (i = 0; i < sc->nregs; i++) {
777e9034789SMichal Meloun 		child = ofw_bus_find_child(rnode, max77620s_def[i].name);
778e9034789SMichal Meloun 		if (child == 0) {
779e9034789SMichal Meloun 			if (bootverbose)
780e9034789SMichal Meloun 				device_printf(sc->dev,
781e9034789SMichal Meloun 				    "Regulator %s missing in DT\n",
782e9034789SMichal Meloun 				    max77620s_def[i].name);
783e9034789SMichal Meloun 			continue;
784e9034789SMichal Meloun 		}
785e9034789SMichal Meloun 		if (ofw_bus_node_status_okay(child) == 0)
786e9034789SMichal Meloun 			continue;
787e9034789SMichal Meloun 		reg = max77620_attach(sc, child, max77620s_def + i);
788e9034789SMichal Meloun 		if (reg == NULL) {
789e9034789SMichal Meloun 			device_printf(sc->dev, "Cannot attach regulator: %s\n",
790e9034789SMichal Meloun 			    max77620s_def[i].name);
791e9034789SMichal Meloun 			return (ENXIO);
792e9034789SMichal Meloun 		}
793e9034789SMichal Meloun 		sc->regs[i] = reg;
794e9034789SMichal Meloun 	}
795e9034789SMichal Meloun 	return (0);
796e9034789SMichal Meloun }
797e9034789SMichal Meloun 
798e9034789SMichal Meloun int
max77620_regulator_map(device_t dev,phandle_t xref,int ncells,pcell_t * cells,intptr_t * num)799e9034789SMichal Meloun max77620_regulator_map(device_t dev, phandle_t xref, int ncells,
800e9034789SMichal Meloun     pcell_t *cells, intptr_t *num)
801e9034789SMichal Meloun {
802e9034789SMichal Meloun 	struct max77620_softc *sc;
803e9034789SMichal Meloun 	int i;
804e9034789SMichal Meloun 
805e9034789SMichal Meloun 	sc = device_get_softc(dev);
806e9034789SMichal Meloun 	for (i = 0; i < sc->nregs; i++) {
807e9034789SMichal Meloun 		if (sc->regs[i] == NULL)
808e9034789SMichal Meloun 			continue;
809e9034789SMichal Meloun 		if (sc->regs[i]->xref == xref) {
810e9034789SMichal Meloun 			*num = sc->regs[i]->def->id;
811e9034789SMichal Meloun 			return (0);
812e9034789SMichal Meloun 		}
813e9034789SMichal Meloun 	}
814e9034789SMichal Meloun 
815e9034789SMichal Meloun 	return (ENXIO);
816e9034789SMichal Meloun }
817e9034789SMichal Meloun 
818e9034789SMichal Meloun static int
max77620_regnode_enable(struct regnode * regnode,bool val,int * udelay)819e9034789SMichal Meloun max77620_regnode_enable(struct regnode *regnode, bool val, int *udelay)
820e9034789SMichal Meloun {
821e9034789SMichal Meloun 
822e9034789SMichal Meloun 	struct max77620_reg_sc *sc;
823e9034789SMichal Meloun 	uint8_t mode;
824e9034789SMichal Meloun 	int rv;
825e9034789SMichal Meloun 
826e9034789SMichal Meloun 	sc = regnode_get_softc(regnode);
827e9034789SMichal Meloun 
828e9034789SMichal Meloun 	if (sc->active_fps_src != MAX77620_FPS_SRC_NONE) {
829e9034789SMichal Meloun 		*udelay = 0;
830e9034789SMichal Meloun 		return (0);
831e9034789SMichal Meloun 	}
832e9034789SMichal Meloun 
833e9034789SMichal Meloun 	if (val)
834e9034789SMichal Meloun 		mode = sc->enable_pwr_mode;
835e9034789SMichal Meloun 	else
836e9034789SMichal Meloun 		mode = MAX77620_POWER_MODE_DISABLE;
837e9034789SMichal Meloun 
838e9034789SMichal Meloun 	rv = max77620_set_pwr_mode(sc, mode);
839e9034789SMichal Meloun 	if (rv != 0) {
840e9034789SMichal Meloun 		printf("%s: cannot set power mode: %d\n",
841e9034789SMichal Meloun 		    regnode_get_name(sc->regnode), rv);
842e9034789SMichal Meloun 		return (rv);
843e9034789SMichal Meloun 	}
844e9034789SMichal Meloun 
845e9034789SMichal Meloun 	*udelay = sc->enable_usec;
846e9034789SMichal Meloun 	return (0);
847e9034789SMichal Meloun }
848e9034789SMichal Meloun 
849e9034789SMichal Meloun static int
max77620_regnode_set_volt(struct regnode * regnode,int min_uvolt,int max_uvolt,int * udelay)850e9034789SMichal Meloun max77620_regnode_set_volt(struct regnode *regnode, int min_uvolt, int max_uvolt,
851e9034789SMichal Meloun     int *udelay)
852e9034789SMichal Meloun {
853e9034789SMichal Meloun 	struct max77620_reg_sc *sc;
854e9034789SMichal Meloun 	uint8_t sel;
855e9034789SMichal Meloun 	int rv;
856e9034789SMichal Meloun 
857e9034789SMichal Meloun 	sc = regnode_get_softc(regnode);
858e9034789SMichal Meloun 
859e9034789SMichal Meloun 	*udelay = 0;
860e9034789SMichal Meloun 	rv = regulator_range_volt_to_sel8(sc->def->ranges, sc->def->nranges,
861e9034789SMichal Meloun 	    min_uvolt, max_uvolt, &sel);
862e9034789SMichal Meloun 	if (rv != 0)
863e9034789SMichal Meloun 		return (rv);
864e9034789SMichal Meloun 	rv = max77620_set_sel(sc, sel);
865e9034789SMichal Meloun 	return (rv);
866e9034789SMichal Meloun }
867e9034789SMichal Meloun 
868e9034789SMichal Meloun static int
max77620_regnode_get_volt(struct regnode * regnode,int * uvolt)869e9034789SMichal Meloun max77620_regnode_get_volt(struct regnode *regnode, int *uvolt)
870e9034789SMichal Meloun {
871e9034789SMichal Meloun 
872e9034789SMichal Meloun 	struct max77620_reg_sc *sc;
873e9034789SMichal Meloun 	uint8_t sel;
874e9034789SMichal Meloun 	int rv;
875e9034789SMichal Meloun 
876e9034789SMichal Meloun 	sc = regnode_get_softc(regnode);
877e9034789SMichal Meloun 	rv = max77620_get_sel(sc, &sel);
878e9034789SMichal Meloun 	if (rv != 0)
879e9034789SMichal Meloun 		return (rv);
880e9034789SMichal Meloun 
881e9034789SMichal Meloun 	rv = regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges,
882e9034789SMichal Meloun 	    sel, uvolt);
883e9034789SMichal Meloun 	return (rv);
884e9034789SMichal Meloun 	return(0);
885e9034789SMichal Meloun }
886