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