1*b2f0caf1SEmmanuel Vadot /*-
2*b2f0caf1SEmmanuel Vadot * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
3*b2f0caf1SEmmanuel Vadot * All rights reserved.
4*b2f0caf1SEmmanuel Vadot *
5*b2f0caf1SEmmanuel Vadot * Redistribution and use in source and binary forms, with or without
6*b2f0caf1SEmmanuel Vadot * modification, are permitted provided that the following conditions
7*b2f0caf1SEmmanuel Vadot * are met:
8*b2f0caf1SEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright
9*b2f0caf1SEmmanuel Vadot * notice, this list of conditions and the following disclaimer.
10*b2f0caf1SEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright
11*b2f0caf1SEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the
12*b2f0caf1SEmmanuel Vadot * documentation and/or other materials provided with the distribution.
13*b2f0caf1SEmmanuel Vadot *
14*b2f0caf1SEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*b2f0caf1SEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*b2f0caf1SEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*b2f0caf1SEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*b2f0caf1SEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*b2f0caf1SEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*b2f0caf1SEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*b2f0caf1SEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*b2f0caf1SEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*b2f0caf1SEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*b2f0caf1SEmmanuel Vadot * SUCH DAMAGE.
25*b2f0caf1SEmmanuel Vadot */
26*b2f0caf1SEmmanuel Vadot
27*b2f0caf1SEmmanuel Vadot #include <sys/cdefs.h>
28*b2f0caf1SEmmanuel Vadot #include "opt_platform.h"
29*b2f0caf1SEmmanuel Vadot #include <sys/param.h>
30*b2f0caf1SEmmanuel Vadot #include <sys/conf.h>
31*b2f0caf1SEmmanuel Vadot #include <sys/bus.h>
32*b2f0caf1SEmmanuel Vadot #include <sys/kernel.h>
33*b2f0caf1SEmmanuel Vadot #include <sys/queue.h>
34*b2f0caf1SEmmanuel Vadot #include <sys/kobj.h>
35*b2f0caf1SEmmanuel Vadot #include <sys/malloc.h>
36*b2f0caf1SEmmanuel Vadot #include <sys/mutex.h>
37*b2f0caf1SEmmanuel Vadot #include <sys/limits.h>
38*b2f0caf1SEmmanuel Vadot #include <sys/lock.h>
39*b2f0caf1SEmmanuel Vadot #include <sys/sysctl.h>
40*b2f0caf1SEmmanuel Vadot #include <sys/systm.h>
41*b2f0caf1SEmmanuel Vadot #include <sys/sx.h>
42*b2f0caf1SEmmanuel Vadot
43*b2f0caf1SEmmanuel Vadot #ifdef FDT
44*b2f0caf1SEmmanuel Vadot #include <dev/fdt/fdt_common.h>
45*b2f0caf1SEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
46*b2f0caf1SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
47*b2f0caf1SEmmanuel Vadot #endif
48*b2f0caf1SEmmanuel Vadot #include <dev/regulator/regulator.h>
49*b2f0caf1SEmmanuel Vadot
50*b2f0caf1SEmmanuel Vadot #ifdef FDT
51*b2f0caf1SEmmanuel Vadot #include "regdev_if.h"
52*b2f0caf1SEmmanuel Vadot #endif
53*b2f0caf1SEmmanuel Vadot
54*b2f0caf1SEmmanuel Vadot SYSCTL_NODE(_hw, OID_AUTO, regulator, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
55*b2f0caf1SEmmanuel Vadot "Regulators");
56*b2f0caf1SEmmanuel Vadot
57*b2f0caf1SEmmanuel Vadot MALLOC_DEFINE(M_REGULATOR, "regulator", "Regulator framework");
58*b2f0caf1SEmmanuel Vadot
59*b2f0caf1SEmmanuel Vadot #define DIV_ROUND_UP(n,d) howmany(n, d)
60*b2f0caf1SEmmanuel Vadot
61*b2f0caf1SEmmanuel Vadot /* Forward declarations. */
62*b2f0caf1SEmmanuel Vadot struct regulator;
63*b2f0caf1SEmmanuel Vadot struct regnode;
64*b2f0caf1SEmmanuel Vadot
65*b2f0caf1SEmmanuel Vadot typedef TAILQ_HEAD(regnode_list, regnode) regnode_list_t;
66*b2f0caf1SEmmanuel Vadot typedef TAILQ_HEAD(regulator_list, regulator) regulator_list_t;
67*b2f0caf1SEmmanuel Vadot
68*b2f0caf1SEmmanuel Vadot /* Default regulator methods. */
69*b2f0caf1SEmmanuel Vadot static int regnode_method_init(struct regnode *regnode);
70*b2f0caf1SEmmanuel Vadot static int regnode_method_enable(struct regnode *regnode, bool enable,
71*b2f0caf1SEmmanuel Vadot int *udelay);
72*b2f0caf1SEmmanuel Vadot static int regnode_method_status(struct regnode *regnode, int *status);
73*b2f0caf1SEmmanuel Vadot static int regnode_method_set_voltage(struct regnode *regnode, int min_uvolt,
74*b2f0caf1SEmmanuel Vadot int max_uvolt, int *udelay);
75*b2f0caf1SEmmanuel Vadot static int regnode_method_get_voltage(struct regnode *regnode, int *uvolt);
76*b2f0caf1SEmmanuel Vadot static void regulator_constraint(void *dummy);
77*b2f0caf1SEmmanuel Vadot static void regulator_shutdown(void *dummy);
78*b2f0caf1SEmmanuel Vadot
79*b2f0caf1SEmmanuel Vadot /*
80*b2f0caf1SEmmanuel Vadot * Regulator controller methods.
81*b2f0caf1SEmmanuel Vadot */
82*b2f0caf1SEmmanuel Vadot static regnode_method_t regnode_methods[] = {
83*b2f0caf1SEmmanuel Vadot REGNODEMETHOD(regnode_init, regnode_method_init),
84*b2f0caf1SEmmanuel Vadot REGNODEMETHOD(regnode_enable, regnode_method_enable),
85*b2f0caf1SEmmanuel Vadot REGNODEMETHOD(regnode_status, regnode_method_status),
86*b2f0caf1SEmmanuel Vadot REGNODEMETHOD(regnode_set_voltage, regnode_method_set_voltage),
87*b2f0caf1SEmmanuel Vadot REGNODEMETHOD(regnode_get_voltage, regnode_method_get_voltage),
88*b2f0caf1SEmmanuel Vadot REGNODEMETHOD(regnode_check_voltage, regnode_method_check_voltage),
89*b2f0caf1SEmmanuel Vadot
90*b2f0caf1SEmmanuel Vadot REGNODEMETHOD_END
91*b2f0caf1SEmmanuel Vadot };
92*b2f0caf1SEmmanuel Vadot DEFINE_CLASS_0(regnode, regnode_class, regnode_methods, 0);
93*b2f0caf1SEmmanuel Vadot
94*b2f0caf1SEmmanuel Vadot /*
95*b2f0caf1SEmmanuel Vadot * Regulator node - basic element for modelling SOC and bard power supply
96*b2f0caf1SEmmanuel Vadot * chains. Its contains producer data.
97*b2f0caf1SEmmanuel Vadot */
98*b2f0caf1SEmmanuel Vadot struct regnode {
99*b2f0caf1SEmmanuel Vadot KOBJ_FIELDS;
100*b2f0caf1SEmmanuel Vadot
101*b2f0caf1SEmmanuel Vadot TAILQ_ENTRY(regnode) reglist_link; /* Global list entry */
102*b2f0caf1SEmmanuel Vadot regulator_list_t consumers_list; /* Consumers list */
103*b2f0caf1SEmmanuel Vadot
104*b2f0caf1SEmmanuel Vadot /* Cache for already resolved names */
105*b2f0caf1SEmmanuel Vadot struct regnode *parent; /* Resolved parent */
106*b2f0caf1SEmmanuel Vadot
107*b2f0caf1SEmmanuel Vadot /* Details of this device. */
108*b2f0caf1SEmmanuel Vadot const char *name; /* Globally unique name */
109*b2f0caf1SEmmanuel Vadot const char *parent_name; /* Parent name */
110*b2f0caf1SEmmanuel Vadot
111*b2f0caf1SEmmanuel Vadot device_t pdev; /* Producer device_t */
112*b2f0caf1SEmmanuel Vadot void *softc; /* Producer softc */
113*b2f0caf1SEmmanuel Vadot intptr_t id; /* Per producer unique id */
114*b2f0caf1SEmmanuel Vadot #ifdef FDT
115*b2f0caf1SEmmanuel Vadot phandle_t ofw_node; /* OFW node of regulator */
116*b2f0caf1SEmmanuel Vadot #endif
117*b2f0caf1SEmmanuel Vadot int flags; /* REGULATOR_FLAGS_ */
118*b2f0caf1SEmmanuel Vadot struct sx lock; /* Lock for this regulator */
119*b2f0caf1SEmmanuel Vadot int ref_cnt; /* Reference counter */
120*b2f0caf1SEmmanuel Vadot int enable_cnt; /* Enabled counter */
121*b2f0caf1SEmmanuel Vadot
122*b2f0caf1SEmmanuel Vadot struct regnode_std_param std_param; /* Standard parameters */
123*b2f0caf1SEmmanuel Vadot
124*b2f0caf1SEmmanuel Vadot struct sysctl_ctx_list sysctl_ctx;
125*b2f0caf1SEmmanuel Vadot };
126*b2f0caf1SEmmanuel Vadot
127*b2f0caf1SEmmanuel Vadot /*
128*b2f0caf1SEmmanuel Vadot * Per consumer data, information about how a consumer is using a regulator
129*b2f0caf1SEmmanuel Vadot * node.
130*b2f0caf1SEmmanuel Vadot * A pointer to this structure is used as a handle in the consumer interface.
131*b2f0caf1SEmmanuel Vadot */
132*b2f0caf1SEmmanuel Vadot struct regulator {
133*b2f0caf1SEmmanuel Vadot device_t cdev; /* Consumer device */
134*b2f0caf1SEmmanuel Vadot struct regnode *regnode;
135*b2f0caf1SEmmanuel Vadot TAILQ_ENTRY(regulator) link; /* Consumers list entry */
136*b2f0caf1SEmmanuel Vadot
137*b2f0caf1SEmmanuel Vadot int enable_cnt;
138*b2f0caf1SEmmanuel Vadot int min_uvolt; /* Requested uvolt range */
139*b2f0caf1SEmmanuel Vadot int max_uvolt;
140*b2f0caf1SEmmanuel Vadot };
141*b2f0caf1SEmmanuel Vadot
142*b2f0caf1SEmmanuel Vadot /*
143*b2f0caf1SEmmanuel Vadot * Regulator names must be system wide unique.
144*b2f0caf1SEmmanuel Vadot */
145*b2f0caf1SEmmanuel Vadot static regnode_list_t regnode_list = TAILQ_HEAD_INITIALIZER(regnode_list);
146*b2f0caf1SEmmanuel Vadot
147*b2f0caf1SEmmanuel Vadot static struct sx regnode_topo_lock;
148*b2f0caf1SEmmanuel Vadot SX_SYSINIT(regulator_topology, ®node_topo_lock, "Regulator topology lock");
149*b2f0caf1SEmmanuel Vadot
150*b2f0caf1SEmmanuel Vadot #define REG_TOPO_SLOCK() sx_slock(®node_topo_lock)
151*b2f0caf1SEmmanuel Vadot #define REG_TOPO_XLOCK() sx_xlock(®node_topo_lock)
152*b2f0caf1SEmmanuel Vadot #define REG_TOPO_UNLOCK() sx_unlock(®node_topo_lock)
153*b2f0caf1SEmmanuel Vadot #define REG_TOPO_ASSERT() sx_assert(®node_topo_lock, SA_LOCKED)
154*b2f0caf1SEmmanuel Vadot #define REG_TOPO_XASSERT() sx_assert(®node_topo_lock, SA_XLOCKED)
155*b2f0caf1SEmmanuel Vadot
156*b2f0caf1SEmmanuel Vadot #define REGNODE_SLOCK(_sc) sx_slock(&((_sc)->lock))
157*b2f0caf1SEmmanuel Vadot #define REGNODE_XLOCK(_sc) sx_xlock(&((_sc)->lock))
158*b2f0caf1SEmmanuel Vadot #define REGNODE_UNLOCK(_sc) sx_unlock(&((_sc)->lock))
159*b2f0caf1SEmmanuel Vadot
160*b2f0caf1SEmmanuel Vadot SYSINIT(regulator_constraint, SI_SUB_LAST, SI_ORDER_ANY, regulator_constraint,
161*b2f0caf1SEmmanuel Vadot NULL);
162*b2f0caf1SEmmanuel Vadot SYSINIT(regulator_shutdown, SI_SUB_LAST, SI_ORDER_ANY, regulator_shutdown,
163*b2f0caf1SEmmanuel Vadot NULL);
164*b2f0caf1SEmmanuel Vadot
165*b2f0caf1SEmmanuel Vadot static void
regulator_constraint(void * dummy)166*b2f0caf1SEmmanuel Vadot regulator_constraint(void *dummy)
167*b2f0caf1SEmmanuel Vadot {
168*b2f0caf1SEmmanuel Vadot struct regnode *entry;
169*b2f0caf1SEmmanuel Vadot int rv;
170*b2f0caf1SEmmanuel Vadot
171*b2f0caf1SEmmanuel Vadot REG_TOPO_SLOCK();
172*b2f0caf1SEmmanuel Vadot TAILQ_FOREACH(entry, ®node_list, reglist_link) {
173*b2f0caf1SEmmanuel Vadot rv = regnode_set_constraint(entry);
174*b2f0caf1SEmmanuel Vadot if (rv != 0 && bootverbose)
175*b2f0caf1SEmmanuel Vadot printf("regulator: setting constraint on %s failed (%d)\n",
176*b2f0caf1SEmmanuel Vadot entry->name, rv);
177*b2f0caf1SEmmanuel Vadot }
178*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
179*b2f0caf1SEmmanuel Vadot }
180*b2f0caf1SEmmanuel Vadot
181*b2f0caf1SEmmanuel Vadot /*
182*b2f0caf1SEmmanuel Vadot * Disable unused regulator
183*b2f0caf1SEmmanuel Vadot * We run this function at SI_SUB_LAST which mean that every driver that needs
184*b2f0caf1SEmmanuel Vadot * regulator should have already enable them.
185*b2f0caf1SEmmanuel Vadot * All the remaining regulators should be those left enabled by the bootloader
186*b2f0caf1SEmmanuel Vadot * or enable by default by the PMIC.
187*b2f0caf1SEmmanuel Vadot */
188*b2f0caf1SEmmanuel Vadot static void
regulator_shutdown(void * dummy)189*b2f0caf1SEmmanuel Vadot regulator_shutdown(void *dummy)
190*b2f0caf1SEmmanuel Vadot {
191*b2f0caf1SEmmanuel Vadot struct regnode *entry;
192*b2f0caf1SEmmanuel Vadot int status, ret;
193*b2f0caf1SEmmanuel Vadot int disable = 1;
194*b2f0caf1SEmmanuel Vadot
195*b2f0caf1SEmmanuel Vadot TUNABLE_INT_FETCH("hw.regulator.disable_unused", &disable);
196*b2f0caf1SEmmanuel Vadot if (!disable)
197*b2f0caf1SEmmanuel Vadot return;
198*b2f0caf1SEmmanuel Vadot REG_TOPO_SLOCK();
199*b2f0caf1SEmmanuel Vadot
200*b2f0caf1SEmmanuel Vadot if (bootverbose)
201*b2f0caf1SEmmanuel Vadot printf("regulator: shutting down unused regulators\n");
202*b2f0caf1SEmmanuel Vadot TAILQ_FOREACH(entry, ®node_list, reglist_link) {
203*b2f0caf1SEmmanuel Vadot if (!entry->std_param.always_on) {
204*b2f0caf1SEmmanuel Vadot ret = regnode_status(entry, &status);
205*b2f0caf1SEmmanuel Vadot if (ret == 0 && status == REGULATOR_STATUS_ENABLED) {
206*b2f0caf1SEmmanuel Vadot if (bootverbose)
207*b2f0caf1SEmmanuel Vadot printf("regulator: shutting down %s... ",
208*b2f0caf1SEmmanuel Vadot entry->name);
209*b2f0caf1SEmmanuel Vadot ret = regnode_stop(entry, 0);
210*b2f0caf1SEmmanuel Vadot if (bootverbose) {
211*b2f0caf1SEmmanuel Vadot /*
212*b2f0caf1SEmmanuel Vadot * Call out busy in particular, here,
213*b2f0caf1SEmmanuel Vadot * because it's not unexpected to fail
214*b2f0caf1SEmmanuel Vadot * shutdown if the regulator is simply
215*b2f0caf1SEmmanuel Vadot * in-use.
216*b2f0caf1SEmmanuel Vadot */
217*b2f0caf1SEmmanuel Vadot if (ret == EBUSY)
218*b2f0caf1SEmmanuel Vadot printf("busy\n");
219*b2f0caf1SEmmanuel Vadot else if (ret != 0)
220*b2f0caf1SEmmanuel Vadot printf("error (%d)\n", ret);
221*b2f0caf1SEmmanuel Vadot else
222*b2f0caf1SEmmanuel Vadot printf("ok\n");
223*b2f0caf1SEmmanuel Vadot }
224*b2f0caf1SEmmanuel Vadot }
225*b2f0caf1SEmmanuel Vadot }
226*b2f0caf1SEmmanuel Vadot }
227*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
228*b2f0caf1SEmmanuel Vadot }
229*b2f0caf1SEmmanuel Vadot
230*b2f0caf1SEmmanuel Vadot /*
231*b2f0caf1SEmmanuel Vadot * sysctl handler
232*b2f0caf1SEmmanuel Vadot */
233*b2f0caf1SEmmanuel Vadot static int
regnode_uvolt_sysctl(SYSCTL_HANDLER_ARGS)234*b2f0caf1SEmmanuel Vadot regnode_uvolt_sysctl(SYSCTL_HANDLER_ARGS)
235*b2f0caf1SEmmanuel Vadot {
236*b2f0caf1SEmmanuel Vadot struct regnode *regnode = arg1;
237*b2f0caf1SEmmanuel Vadot int rv, uvolt;
238*b2f0caf1SEmmanuel Vadot
239*b2f0caf1SEmmanuel Vadot if (regnode->std_param.min_uvolt == regnode->std_param.max_uvolt) {
240*b2f0caf1SEmmanuel Vadot uvolt = regnode->std_param.min_uvolt;
241*b2f0caf1SEmmanuel Vadot } else {
242*b2f0caf1SEmmanuel Vadot REG_TOPO_SLOCK();
243*b2f0caf1SEmmanuel Vadot if ((rv = regnode_get_voltage(regnode, &uvolt)) != 0) {
244*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
245*b2f0caf1SEmmanuel Vadot return (rv);
246*b2f0caf1SEmmanuel Vadot }
247*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
248*b2f0caf1SEmmanuel Vadot }
249*b2f0caf1SEmmanuel Vadot
250*b2f0caf1SEmmanuel Vadot return sysctl_handle_int(oidp, &uvolt, sizeof(uvolt), req);
251*b2f0caf1SEmmanuel Vadot }
252*b2f0caf1SEmmanuel Vadot
253*b2f0caf1SEmmanuel Vadot /* ----------------------------------------------------------------------------
254*b2f0caf1SEmmanuel Vadot *
255*b2f0caf1SEmmanuel Vadot * Default regulator methods for base class.
256*b2f0caf1SEmmanuel Vadot *
257*b2f0caf1SEmmanuel Vadot */
258*b2f0caf1SEmmanuel Vadot static int
regnode_method_init(struct regnode * regnode)259*b2f0caf1SEmmanuel Vadot regnode_method_init(struct regnode *regnode)
260*b2f0caf1SEmmanuel Vadot {
261*b2f0caf1SEmmanuel Vadot
262*b2f0caf1SEmmanuel Vadot return (0);
263*b2f0caf1SEmmanuel Vadot }
264*b2f0caf1SEmmanuel Vadot
265*b2f0caf1SEmmanuel Vadot static int
regnode_method_enable(struct regnode * regnode,bool enable,int * udelay)266*b2f0caf1SEmmanuel Vadot regnode_method_enable(struct regnode *regnode, bool enable, int *udelay)
267*b2f0caf1SEmmanuel Vadot {
268*b2f0caf1SEmmanuel Vadot
269*b2f0caf1SEmmanuel Vadot if (!enable)
270*b2f0caf1SEmmanuel Vadot return (ENXIO);
271*b2f0caf1SEmmanuel Vadot
272*b2f0caf1SEmmanuel Vadot *udelay = 0;
273*b2f0caf1SEmmanuel Vadot return (0);
274*b2f0caf1SEmmanuel Vadot }
275*b2f0caf1SEmmanuel Vadot
276*b2f0caf1SEmmanuel Vadot static int
regnode_method_status(struct regnode * regnode,int * status)277*b2f0caf1SEmmanuel Vadot regnode_method_status(struct regnode *regnode, int *status)
278*b2f0caf1SEmmanuel Vadot {
279*b2f0caf1SEmmanuel Vadot *status = REGULATOR_STATUS_ENABLED;
280*b2f0caf1SEmmanuel Vadot return (0);
281*b2f0caf1SEmmanuel Vadot }
282*b2f0caf1SEmmanuel Vadot
283*b2f0caf1SEmmanuel Vadot static int
regnode_method_set_voltage(struct regnode * regnode,int min_uvolt,int max_uvolt,int * udelay)284*b2f0caf1SEmmanuel Vadot regnode_method_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt,
285*b2f0caf1SEmmanuel Vadot int *udelay)
286*b2f0caf1SEmmanuel Vadot {
287*b2f0caf1SEmmanuel Vadot
288*b2f0caf1SEmmanuel Vadot if ((min_uvolt > regnode->std_param.max_uvolt) ||
289*b2f0caf1SEmmanuel Vadot (max_uvolt < regnode->std_param.min_uvolt))
290*b2f0caf1SEmmanuel Vadot return (ERANGE);
291*b2f0caf1SEmmanuel Vadot *udelay = 0;
292*b2f0caf1SEmmanuel Vadot return (0);
293*b2f0caf1SEmmanuel Vadot }
294*b2f0caf1SEmmanuel Vadot
295*b2f0caf1SEmmanuel Vadot static int
regnode_method_get_voltage(struct regnode * regnode,int * uvolt)296*b2f0caf1SEmmanuel Vadot regnode_method_get_voltage(struct regnode *regnode, int *uvolt)
297*b2f0caf1SEmmanuel Vadot {
298*b2f0caf1SEmmanuel Vadot
299*b2f0caf1SEmmanuel Vadot *uvolt = regnode->std_param.min_uvolt +
300*b2f0caf1SEmmanuel Vadot (regnode->std_param.max_uvolt - regnode->std_param.min_uvolt) / 2;
301*b2f0caf1SEmmanuel Vadot return (0);
302*b2f0caf1SEmmanuel Vadot }
303*b2f0caf1SEmmanuel Vadot
304*b2f0caf1SEmmanuel Vadot int
regnode_method_check_voltage(struct regnode * regnode,int uvolt)305*b2f0caf1SEmmanuel Vadot regnode_method_check_voltage(struct regnode *regnode, int uvolt)
306*b2f0caf1SEmmanuel Vadot {
307*b2f0caf1SEmmanuel Vadot
308*b2f0caf1SEmmanuel Vadot if ((uvolt > regnode->std_param.max_uvolt) ||
309*b2f0caf1SEmmanuel Vadot (uvolt < regnode->std_param.min_uvolt))
310*b2f0caf1SEmmanuel Vadot return (ERANGE);
311*b2f0caf1SEmmanuel Vadot return (0);
312*b2f0caf1SEmmanuel Vadot }
313*b2f0caf1SEmmanuel Vadot
314*b2f0caf1SEmmanuel Vadot /* ----------------------------------------------------------------------------
315*b2f0caf1SEmmanuel Vadot *
316*b2f0caf1SEmmanuel Vadot * Internal functions.
317*b2f0caf1SEmmanuel Vadot *
318*b2f0caf1SEmmanuel Vadot */
319*b2f0caf1SEmmanuel Vadot
320*b2f0caf1SEmmanuel Vadot static struct regnode *
regnode_find_by_name(const char * name)321*b2f0caf1SEmmanuel Vadot regnode_find_by_name(const char *name)
322*b2f0caf1SEmmanuel Vadot {
323*b2f0caf1SEmmanuel Vadot struct regnode *entry;
324*b2f0caf1SEmmanuel Vadot
325*b2f0caf1SEmmanuel Vadot REG_TOPO_ASSERT();
326*b2f0caf1SEmmanuel Vadot
327*b2f0caf1SEmmanuel Vadot TAILQ_FOREACH(entry, ®node_list, reglist_link) {
328*b2f0caf1SEmmanuel Vadot if (strcmp(entry->name, name) == 0)
329*b2f0caf1SEmmanuel Vadot return (entry);
330*b2f0caf1SEmmanuel Vadot }
331*b2f0caf1SEmmanuel Vadot return (NULL);
332*b2f0caf1SEmmanuel Vadot }
333*b2f0caf1SEmmanuel Vadot
334*b2f0caf1SEmmanuel Vadot static struct regnode *
regnode_find_by_id(device_t dev,intptr_t id)335*b2f0caf1SEmmanuel Vadot regnode_find_by_id(device_t dev, intptr_t id)
336*b2f0caf1SEmmanuel Vadot {
337*b2f0caf1SEmmanuel Vadot struct regnode *entry;
338*b2f0caf1SEmmanuel Vadot
339*b2f0caf1SEmmanuel Vadot REG_TOPO_ASSERT();
340*b2f0caf1SEmmanuel Vadot
341*b2f0caf1SEmmanuel Vadot TAILQ_FOREACH(entry, ®node_list, reglist_link) {
342*b2f0caf1SEmmanuel Vadot if ((entry->pdev == dev) && (entry->id == id))
343*b2f0caf1SEmmanuel Vadot return (entry);
344*b2f0caf1SEmmanuel Vadot }
345*b2f0caf1SEmmanuel Vadot
346*b2f0caf1SEmmanuel Vadot return (NULL);
347*b2f0caf1SEmmanuel Vadot }
348*b2f0caf1SEmmanuel Vadot
349*b2f0caf1SEmmanuel Vadot /*
350*b2f0caf1SEmmanuel Vadot * Create and initialize regulator object, but do not register it.
351*b2f0caf1SEmmanuel Vadot */
352*b2f0caf1SEmmanuel Vadot struct regnode *
regnode_create(device_t pdev,regnode_class_t regnode_class,struct regnode_init_def * def)353*b2f0caf1SEmmanuel Vadot regnode_create(device_t pdev, regnode_class_t regnode_class,
354*b2f0caf1SEmmanuel Vadot struct regnode_init_def *def)
355*b2f0caf1SEmmanuel Vadot {
356*b2f0caf1SEmmanuel Vadot struct regnode *regnode;
357*b2f0caf1SEmmanuel Vadot struct sysctl_oid *regnode_oid;
358*b2f0caf1SEmmanuel Vadot
359*b2f0caf1SEmmanuel Vadot KASSERT(def->name != NULL, ("regulator name is NULL"));
360*b2f0caf1SEmmanuel Vadot KASSERT(def->name[0] != '\0', ("regulator name is empty"));
361*b2f0caf1SEmmanuel Vadot
362*b2f0caf1SEmmanuel Vadot REG_TOPO_SLOCK();
363*b2f0caf1SEmmanuel Vadot if (regnode_find_by_name(def->name) != NULL)
364*b2f0caf1SEmmanuel Vadot panic("Duplicated regulator registration: %s\n", def->name);
365*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
366*b2f0caf1SEmmanuel Vadot
367*b2f0caf1SEmmanuel Vadot /* Create object and initialize it. */
368*b2f0caf1SEmmanuel Vadot regnode = malloc(sizeof(struct regnode), M_REGULATOR,
369*b2f0caf1SEmmanuel Vadot M_WAITOK | M_ZERO);
370*b2f0caf1SEmmanuel Vadot kobj_init((kobj_t)regnode, (kobj_class_t)regnode_class);
371*b2f0caf1SEmmanuel Vadot sx_init(®node->lock, "Regulator node lock");
372*b2f0caf1SEmmanuel Vadot
373*b2f0caf1SEmmanuel Vadot /* Allocate softc if required. */
374*b2f0caf1SEmmanuel Vadot if (regnode_class->size > 0) {
375*b2f0caf1SEmmanuel Vadot regnode->softc = malloc(regnode_class->size, M_REGULATOR,
376*b2f0caf1SEmmanuel Vadot M_WAITOK | M_ZERO);
377*b2f0caf1SEmmanuel Vadot }
378*b2f0caf1SEmmanuel Vadot
379*b2f0caf1SEmmanuel Vadot
380*b2f0caf1SEmmanuel Vadot /* Copy all strings unless they're flagged as static. */
381*b2f0caf1SEmmanuel Vadot if (def->flags & REGULATOR_FLAGS_STATIC) {
382*b2f0caf1SEmmanuel Vadot regnode->name = def->name;
383*b2f0caf1SEmmanuel Vadot regnode->parent_name = def->parent_name;
384*b2f0caf1SEmmanuel Vadot } else {
385*b2f0caf1SEmmanuel Vadot regnode->name = strdup(def->name, M_REGULATOR);
386*b2f0caf1SEmmanuel Vadot if (def->parent_name != NULL)
387*b2f0caf1SEmmanuel Vadot regnode->parent_name = strdup(def->parent_name,
388*b2f0caf1SEmmanuel Vadot M_REGULATOR);
389*b2f0caf1SEmmanuel Vadot }
390*b2f0caf1SEmmanuel Vadot
391*b2f0caf1SEmmanuel Vadot /* Rest of init. */
392*b2f0caf1SEmmanuel Vadot TAILQ_INIT(®node->consumers_list);
393*b2f0caf1SEmmanuel Vadot regnode->id = def->id;
394*b2f0caf1SEmmanuel Vadot regnode->pdev = pdev;
395*b2f0caf1SEmmanuel Vadot regnode->flags = def->flags;
396*b2f0caf1SEmmanuel Vadot regnode->parent = NULL;
397*b2f0caf1SEmmanuel Vadot regnode->std_param = def->std_param;
398*b2f0caf1SEmmanuel Vadot #ifdef FDT
399*b2f0caf1SEmmanuel Vadot regnode->ofw_node = def->ofw_node;
400*b2f0caf1SEmmanuel Vadot #endif
401*b2f0caf1SEmmanuel Vadot
402*b2f0caf1SEmmanuel Vadot sysctl_ctx_init(®node->sysctl_ctx);
403*b2f0caf1SEmmanuel Vadot regnode_oid = SYSCTL_ADD_NODE(®node->sysctl_ctx,
404*b2f0caf1SEmmanuel Vadot SYSCTL_STATIC_CHILDREN(_hw_regulator),
405*b2f0caf1SEmmanuel Vadot OID_AUTO, regnode->name,
406*b2f0caf1SEmmanuel Vadot CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "A regulator node");
407*b2f0caf1SEmmanuel Vadot
408*b2f0caf1SEmmanuel Vadot SYSCTL_ADD_INT(®node->sysctl_ctx,
409*b2f0caf1SEmmanuel Vadot SYSCTL_CHILDREN(regnode_oid),
410*b2f0caf1SEmmanuel Vadot OID_AUTO, "min_uvolt",
411*b2f0caf1SEmmanuel Vadot CTLFLAG_RD, ®node->std_param.min_uvolt, 0,
412*b2f0caf1SEmmanuel Vadot "Minimal voltage (in uV)");
413*b2f0caf1SEmmanuel Vadot SYSCTL_ADD_INT(®node->sysctl_ctx,
414*b2f0caf1SEmmanuel Vadot SYSCTL_CHILDREN(regnode_oid),
415*b2f0caf1SEmmanuel Vadot OID_AUTO, "max_uvolt",
416*b2f0caf1SEmmanuel Vadot CTLFLAG_RD, ®node->std_param.max_uvolt, 0,
417*b2f0caf1SEmmanuel Vadot "Maximal voltage (in uV)");
418*b2f0caf1SEmmanuel Vadot SYSCTL_ADD_INT(®node->sysctl_ctx,
419*b2f0caf1SEmmanuel Vadot SYSCTL_CHILDREN(regnode_oid),
420*b2f0caf1SEmmanuel Vadot OID_AUTO, "min_uamp",
421*b2f0caf1SEmmanuel Vadot CTLFLAG_RD, ®node->std_param.min_uamp, 0,
422*b2f0caf1SEmmanuel Vadot "Minimal amperage (in uA)");
423*b2f0caf1SEmmanuel Vadot SYSCTL_ADD_INT(®node->sysctl_ctx,
424*b2f0caf1SEmmanuel Vadot SYSCTL_CHILDREN(regnode_oid),
425*b2f0caf1SEmmanuel Vadot OID_AUTO, "max_uamp",
426*b2f0caf1SEmmanuel Vadot CTLFLAG_RD, ®node->std_param.max_uamp, 0,
427*b2f0caf1SEmmanuel Vadot "Maximal amperage (in uA)");
428*b2f0caf1SEmmanuel Vadot SYSCTL_ADD_INT(®node->sysctl_ctx,
429*b2f0caf1SEmmanuel Vadot SYSCTL_CHILDREN(regnode_oid),
430*b2f0caf1SEmmanuel Vadot OID_AUTO, "ramp_delay",
431*b2f0caf1SEmmanuel Vadot CTLFLAG_RD, ®node->std_param.ramp_delay, 0,
432*b2f0caf1SEmmanuel Vadot "Ramp delay (in uV/us)");
433*b2f0caf1SEmmanuel Vadot SYSCTL_ADD_INT(®node->sysctl_ctx,
434*b2f0caf1SEmmanuel Vadot SYSCTL_CHILDREN(regnode_oid),
435*b2f0caf1SEmmanuel Vadot OID_AUTO, "enable_delay",
436*b2f0caf1SEmmanuel Vadot CTLFLAG_RD, ®node->std_param.enable_delay, 0,
437*b2f0caf1SEmmanuel Vadot "Enable delay (in us)");
438*b2f0caf1SEmmanuel Vadot SYSCTL_ADD_INT(®node->sysctl_ctx,
439*b2f0caf1SEmmanuel Vadot SYSCTL_CHILDREN(regnode_oid),
440*b2f0caf1SEmmanuel Vadot OID_AUTO, "enable_cnt",
441*b2f0caf1SEmmanuel Vadot CTLFLAG_RD, ®node->enable_cnt, 0,
442*b2f0caf1SEmmanuel Vadot "The regulator enable counter");
443*b2f0caf1SEmmanuel Vadot SYSCTL_ADD_U8(®node->sysctl_ctx,
444*b2f0caf1SEmmanuel Vadot SYSCTL_CHILDREN(regnode_oid),
445*b2f0caf1SEmmanuel Vadot OID_AUTO, "boot_on",
446*b2f0caf1SEmmanuel Vadot CTLFLAG_RD, (uint8_t *) ®node->std_param.boot_on, 0,
447*b2f0caf1SEmmanuel Vadot "Is enabled on boot");
448*b2f0caf1SEmmanuel Vadot SYSCTL_ADD_U8(®node->sysctl_ctx,
449*b2f0caf1SEmmanuel Vadot SYSCTL_CHILDREN(regnode_oid),
450*b2f0caf1SEmmanuel Vadot OID_AUTO, "always_on",
451*b2f0caf1SEmmanuel Vadot CTLFLAG_RD, (uint8_t *)®node->std_param.always_on, 0,
452*b2f0caf1SEmmanuel Vadot "Is always enabled");
453*b2f0caf1SEmmanuel Vadot
454*b2f0caf1SEmmanuel Vadot SYSCTL_ADD_PROC(®node->sysctl_ctx,
455*b2f0caf1SEmmanuel Vadot SYSCTL_CHILDREN(regnode_oid),
456*b2f0caf1SEmmanuel Vadot OID_AUTO, "uvolt",
457*b2f0caf1SEmmanuel Vadot CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
458*b2f0caf1SEmmanuel Vadot regnode, 0, regnode_uvolt_sysctl,
459*b2f0caf1SEmmanuel Vadot "I",
460*b2f0caf1SEmmanuel Vadot "Current voltage (in uV)");
461*b2f0caf1SEmmanuel Vadot
462*b2f0caf1SEmmanuel Vadot return (regnode);
463*b2f0caf1SEmmanuel Vadot }
464*b2f0caf1SEmmanuel Vadot
465*b2f0caf1SEmmanuel Vadot /* Register regulator object. */
466*b2f0caf1SEmmanuel Vadot struct regnode *
regnode_register(struct regnode * regnode)467*b2f0caf1SEmmanuel Vadot regnode_register(struct regnode *regnode)
468*b2f0caf1SEmmanuel Vadot {
469*b2f0caf1SEmmanuel Vadot int rv;
470*b2f0caf1SEmmanuel Vadot
471*b2f0caf1SEmmanuel Vadot #ifdef FDT
472*b2f0caf1SEmmanuel Vadot if (regnode->ofw_node <= 0)
473*b2f0caf1SEmmanuel Vadot regnode->ofw_node = ofw_bus_get_node(regnode->pdev);
474*b2f0caf1SEmmanuel Vadot if (regnode->ofw_node <= 0)
475*b2f0caf1SEmmanuel Vadot return (NULL);
476*b2f0caf1SEmmanuel Vadot #endif
477*b2f0caf1SEmmanuel Vadot
478*b2f0caf1SEmmanuel Vadot rv = REGNODE_INIT(regnode);
479*b2f0caf1SEmmanuel Vadot if (rv != 0) {
480*b2f0caf1SEmmanuel Vadot printf("REGNODE_INIT failed: %d\n", rv);
481*b2f0caf1SEmmanuel Vadot return (NULL);
482*b2f0caf1SEmmanuel Vadot }
483*b2f0caf1SEmmanuel Vadot
484*b2f0caf1SEmmanuel Vadot REG_TOPO_XLOCK();
485*b2f0caf1SEmmanuel Vadot TAILQ_INSERT_TAIL(®node_list, regnode, reglist_link);
486*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
487*b2f0caf1SEmmanuel Vadot #ifdef FDT
488*b2f0caf1SEmmanuel Vadot OF_device_register_xref(OF_xref_from_node(regnode->ofw_node),
489*b2f0caf1SEmmanuel Vadot regnode->pdev);
490*b2f0caf1SEmmanuel Vadot #endif
491*b2f0caf1SEmmanuel Vadot return (regnode);
492*b2f0caf1SEmmanuel Vadot }
493*b2f0caf1SEmmanuel Vadot
494*b2f0caf1SEmmanuel Vadot static int
regnode_resolve_parent(struct regnode * regnode)495*b2f0caf1SEmmanuel Vadot regnode_resolve_parent(struct regnode *regnode)
496*b2f0caf1SEmmanuel Vadot {
497*b2f0caf1SEmmanuel Vadot
498*b2f0caf1SEmmanuel Vadot /* All ready resolved or no parent? */
499*b2f0caf1SEmmanuel Vadot if ((regnode->parent != NULL) ||
500*b2f0caf1SEmmanuel Vadot (regnode->parent_name == NULL))
501*b2f0caf1SEmmanuel Vadot return (0);
502*b2f0caf1SEmmanuel Vadot
503*b2f0caf1SEmmanuel Vadot regnode->parent = regnode_find_by_name(regnode->parent_name);
504*b2f0caf1SEmmanuel Vadot if (regnode->parent == NULL)
505*b2f0caf1SEmmanuel Vadot return (ENODEV);
506*b2f0caf1SEmmanuel Vadot return (0);
507*b2f0caf1SEmmanuel Vadot }
508*b2f0caf1SEmmanuel Vadot
509*b2f0caf1SEmmanuel Vadot static void
regnode_delay(int usec)510*b2f0caf1SEmmanuel Vadot regnode_delay(int usec)
511*b2f0caf1SEmmanuel Vadot {
512*b2f0caf1SEmmanuel Vadot int ticks;
513*b2f0caf1SEmmanuel Vadot
514*b2f0caf1SEmmanuel Vadot if (usec == 0)
515*b2f0caf1SEmmanuel Vadot return;
516*b2f0caf1SEmmanuel Vadot ticks = (usec * hz + 999999) / 1000000;
517*b2f0caf1SEmmanuel Vadot
518*b2f0caf1SEmmanuel Vadot if (cold || ticks < 2)
519*b2f0caf1SEmmanuel Vadot DELAY(usec);
520*b2f0caf1SEmmanuel Vadot else
521*b2f0caf1SEmmanuel Vadot pause("REGULATOR", ticks);
522*b2f0caf1SEmmanuel Vadot }
523*b2f0caf1SEmmanuel Vadot
524*b2f0caf1SEmmanuel Vadot /* --------------------------------------------------------------------------
525*b2f0caf1SEmmanuel Vadot *
526*b2f0caf1SEmmanuel Vadot * Regulator providers interface
527*b2f0caf1SEmmanuel Vadot *
528*b2f0caf1SEmmanuel Vadot */
529*b2f0caf1SEmmanuel Vadot
530*b2f0caf1SEmmanuel Vadot const char *
regnode_get_name(struct regnode * regnode)531*b2f0caf1SEmmanuel Vadot regnode_get_name(struct regnode *regnode)
532*b2f0caf1SEmmanuel Vadot {
533*b2f0caf1SEmmanuel Vadot
534*b2f0caf1SEmmanuel Vadot return (regnode->name);
535*b2f0caf1SEmmanuel Vadot }
536*b2f0caf1SEmmanuel Vadot
537*b2f0caf1SEmmanuel Vadot const char *
regnode_get_parent_name(struct regnode * regnode)538*b2f0caf1SEmmanuel Vadot regnode_get_parent_name(struct regnode *regnode)
539*b2f0caf1SEmmanuel Vadot {
540*b2f0caf1SEmmanuel Vadot
541*b2f0caf1SEmmanuel Vadot return (regnode->parent_name);
542*b2f0caf1SEmmanuel Vadot }
543*b2f0caf1SEmmanuel Vadot
544*b2f0caf1SEmmanuel Vadot int
regnode_get_flags(struct regnode * regnode)545*b2f0caf1SEmmanuel Vadot regnode_get_flags(struct regnode *regnode)
546*b2f0caf1SEmmanuel Vadot {
547*b2f0caf1SEmmanuel Vadot
548*b2f0caf1SEmmanuel Vadot return (regnode->flags);
549*b2f0caf1SEmmanuel Vadot }
550*b2f0caf1SEmmanuel Vadot
551*b2f0caf1SEmmanuel Vadot void *
regnode_get_softc(struct regnode * regnode)552*b2f0caf1SEmmanuel Vadot regnode_get_softc(struct regnode *regnode)
553*b2f0caf1SEmmanuel Vadot {
554*b2f0caf1SEmmanuel Vadot
555*b2f0caf1SEmmanuel Vadot return (regnode->softc);
556*b2f0caf1SEmmanuel Vadot }
557*b2f0caf1SEmmanuel Vadot
558*b2f0caf1SEmmanuel Vadot device_t
regnode_get_device(struct regnode * regnode)559*b2f0caf1SEmmanuel Vadot regnode_get_device(struct regnode *regnode)
560*b2f0caf1SEmmanuel Vadot {
561*b2f0caf1SEmmanuel Vadot
562*b2f0caf1SEmmanuel Vadot return (regnode->pdev);
563*b2f0caf1SEmmanuel Vadot }
564*b2f0caf1SEmmanuel Vadot
regnode_get_stdparam(struct regnode * regnode)565*b2f0caf1SEmmanuel Vadot struct regnode_std_param *regnode_get_stdparam(struct regnode *regnode)
566*b2f0caf1SEmmanuel Vadot {
567*b2f0caf1SEmmanuel Vadot
568*b2f0caf1SEmmanuel Vadot return (®node->std_param);
569*b2f0caf1SEmmanuel Vadot }
570*b2f0caf1SEmmanuel Vadot
regnode_topo_unlock(void)571*b2f0caf1SEmmanuel Vadot void regnode_topo_unlock(void)
572*b2f0caf1SEmmanuel Vadot {
573*b2f0caf1SEmmanuel Vadot
574*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
575*b2f0caf1SEmmanuel Vadot }
576*b2f0caf1SEmmanuel Vadot
regnode_topo_xlock(void)577*b2f0caf1SEmmanuel Vadot void regnode_topo_xlock(void)
578*b2f0caf1SEmmanuel Vadot {
579*b2f0caf1SEmmanuel Vadot
580*b2f0caf1SEmmanuel Vadot REG_TOPO_XLOCK();
581*b2f0caf1SEmmanuel Vadot }
582*b2f0caf1SEmmanuel Vadot
regnode_topo_slock(void)583*b2f0caf1SEmmanuel Vadot void regnode_topo_slock(void)
584*b2f0caf1SEmmanuel Vadot {
585*b2f0caf1SEmmanuel Vadot
586*b2f0caf1SEmmanuel Vadot REG_TOPO_SLOCK();
587*b2f0caf1SEmmanuel Vadot }
588*b2f0caf1SEmmanuel Vadot
589*b2f0caf1SEmmanuel Vadot
590*b2f0caf1SEmmanuel Vadot /* --------------------------------------------------------------------------
591*b2f0caf1SEmmanuel Vadot *
592*b2f0caf1SEmmanuel Vadot * Real consumers executive
593*b2f0caf1SEmmanuel Vadot *
594*b2f0caf1SEmmanuel Vadot */
595*b2f0caf1SEmmanuel Vadot struct regnode *
regnode_get_parent(struct regnode * regnode)596*b2f0caf1SEmmanuel Vadot regnode_get_parent(struct regnode *regnode)
597*b2f0caf1SEmmanuel Vadot {
598*b2f0caf1SEmmanuel Vadot int rv;
599*b2f0caf1SEmmanuel Vadot
600*b2f0caf1SEmmanuel Vadot REG_TOPO_ASSERT();
601*b2f0caf1SEmmanuel Vadot
602*b2f0caf1SEmmanuel Vadot rv = regnode_resolve_parent(regnode);
603*b2f0caf1SEmmanuel Vadot if (rv != 0)
604*b2f0caf1SEmmanuel Vadot return (NULL);
605*b2f0caf1SEmmanuel Vadot
606*b2f0caf1SEmmanuel Vadot return (regnode->parent);
607*b2f0caf1SEmmanuel Vadot }
608*b2f0caf1SEmmanuel Vadot
609*b2f0caf1SEmmanuel Vadot /*
610*b2f0caf1SEmmanuel Vadot * Enable regulator.
611*b2f0caf1SEmmanuel Vadot */
612*b2f0caf1SEmmanuel Vadot int
regnode_enable(struct regnode * regnode)613*b2f0caf1SEmmanuel Vadot regnode_enable(struct regnode *regnode)
614*b2f0caf1SEmmanuel Vadot {
615*b2f0caf1SEmmanuel Vadot int udelay;
616*b2f0caf1SEmmanuel Vadot int rv;
617*b2f0caf1SEmmanuel Vadot
618*b2f0caf1SEmmanuel Vadot REG_TOPO_ASSERT();
619*b2f0caf1SEmmanuel Vadot
620*b2f0caf1SEmmanuel Vadot /* Enable regulator for each node in chain, starting from source. */
621*b2f0caf1SEmmanuel Vadot rv = regnode_resolve_parent(regnode);
622*b2f0caf1SEmmanuel Vadot if (rv != 0)
623*b2f0caf1SEmmanuel Vadot return (rv);
624*b2f0caf1SEmmanuel Vadot if (regnode->parent != NULL) {
625*b2f0caf1SEmmanuel Vadot rv = regnode_enable(regnode->parent);
626*b2f0caf1SEmmanuel Vadot if (rv != 0)
627*b2f0caf1SEmmanuel Vadot return (rv);
628*b2f0caf1SEmmanuel Vadot }
629*b2f0caf1SEmmanuel Vadot
630*b2f0caf1SEmmanuel Vadot /* Handle this node. */
631*b2f0caf1SEmmanuel Vadot REGNODE_XLOCK(regnode);
632*b2f0caf1SEmmanuel Vadot if (regnode->enable_cnt == 0) {
633*b2f0caf1SEmmanuel Vadot rv = REGNODE_ENABLE(regnode, true, &udelay);
634*b2f0caf1SEmmanuel Vadot if (rv != 0) {
635*b2f0caf1SEmmanuel Vadot REGNODE_UNLOCK(regnode);
636*b2f0caf1SEmmanuel Vadot return (rv);
637*b2f0caf1SEmmanuel Vadot }
638*b2f0caf1SEmmanuel Vadot regnode_delay(udelay);
639*b2f0caf1SEmmanuel Vadot }
640*b2f0caf1SEmmanuel Vadot regnode->enable_cnt++;
641*b2f0caf1SEmmanuel Vadot REGNODE_UNLOCK(regnode);
642*b2f0caf1SEmmanuel Vadot return (0);
643*b2f0caf1SEmmanuel Vadot }
644*b2f0caf1SEmmanuel Vadot
645*b2f0caf1SEmmanuel Vadot /*
646*b2f0caf1SEmmanuel Vadot * Disable regulator.
647*b2f0caf1SEmmanuel Vadot */
648*b2f0caf1SEmmanuel Vadot int
regnode_disable(struct regnode * regnode)649*b2f0caf1SEmmanuel Vadot regnode_disable(struct regnode *regnode)
650*b2f0caf1SEmmanuel Vadot {
651*b2f0caf1SEmmanuel Vadot int udelay;
652*b2f0caf1SEmmanuel Vadot int rv;
653*b2f0caf1SEmmanuel Vadot
654*b2f0caf1SEmmanuel Vadot REG_TOPO_ASSERT();
655*b2f0caf1SEmmanuel Vadot rv = 0;
656*b2f0caf1SEmmanuel Vadot
657*b2f0caf1SEmmanuel Vadot REGNODE_XLOCK(regnode);
658*b2f0caf1SEmmanuel Vadot /* Disable regulator for each node in chain, starting from consumer. */
659*b2f0caf1SEmmanuel Vadot if (regnode->enable_cnt == 1 &&
660*b2f0caf1SEmmanuel Vadot (regnode->flags & REGULATOR_FLAGS_NOT_DISABLE) == 0 &&
661*b2f0caf1SEmmanuel Vadot !regnode->std_param.always_on) {
662*b2f0caf1SEmmanuel Vadot rv = REGNODE_ENABLE(regnode, false, &udelay);
663*b2f0caf1SEmmanuel Vadot if (rv != 0) {
664*b2f0caf1SEmmanuel Vadot REGNODE_UNLOCK(regnode);
665*b2f0caf1SEmmanuel Vadot return (rv);
666*b2f0caf1SEmmanuel Vadot }
667*b2f0caf1SEmmanuel Vadot regnode_delay(udelay);
668*b2f0caf1SEmmanuel Vadot }
669*b2f0caf1SEmmanuel Vadot regnode->enable_cnt--;
670*b2f0caf1SEmmanuel Vadot REGNODE_UNLOCK(regnode);
671*b2f0caf1SEmmanuel Vadot
672*b2f0caf1SEmmanuel Vadot rv = regnode_resolve_parent(regnode);
673*b2f0caf1SEmmanuel Vadot if (rv != 0)
674*b2f0caf1SEmmanuel Vadot return (rv);
675*b2f0caf1SEmmanuel Vadot if (regnode->parent != NULL)
676*b2f0caf1SEmmanuel Vadot rv = regnode_disable(regnode->parent);
677*b2f0caf1SEmmanuel Vadot return (rv);
678*b2f0caf1SEmmanuel Vadot }
679*b2f0caf1SEmmanuel Vadot
680*b2f0caf1SEmmanuel Vadot /*
681*b2f0caf1SEmmanuel Vadot * Stop regulator.
682*b2f0caf1SEmmanuel Vadot */
683*b2f0caf1SEmmanuel Vadot int
regnode_stop(struct regnode * regnode,int depth)684*b2f0caf1SEmmanuel Vadot regnode_stop(struct regnode *regnode, int depth)
685*b2f0caf1SEmmanuel Vadot {
686*b2f0caf1SEmmanuel Vadot int udelay;
687*b2f0caf1SEmmanuel Vadot int rv;
688*b2f0caf1SEmmanuel Vadot
689*b2f0caf1SEmmanuel Vadot REG_TOPO_ASSERT();
690*b2f0caf1SEmmanuel Vadot rv = 0;
691*b2f0caf1SEmmanuel Vadot
692*b2f0caf1SEmmanuel Vadot REGNODE_XLOCK(regnode);
693*b2f0caf1SEmmanuel Vadot /* The first node must not be enabled. */
694*b2f0caf1SEmmanuel Vadot if ((regnode->enable_cnt != 0) && (depth == 0)) {
695*b2f0caf1SEmmanuel Vadot REGNODE_UNLOCK(regnode);
696*b2f0caf1SEmmanuel Vadot return (EBUSY);
697*b2f0caf1SEmmanuel Vadot }
698*b2f0caf1SEmmanuel Vadot /* Disable regulator for each node in chain, starting from consumer */
699*b2f0caf1SEmmanuel Vadot if ((regnode->enable_cnt == 0) &&
700*b2f0caf1SEmmanuel Vadot ((regnode->flags & REGULATOR_FLAGS_NOT_DISABLE) == 0)) {
701*b2f0caf1SEmmanuel Vadot rv = REGNODE_STOP(regnode, &udelay);
702*b2f0caf1SEmmanuel Vadot if (rv != 0) {
703*b2f0caf1SEmmanuel Vadot REGNODE_UNLOCK(regnode);
704*b2f0caf1SEmmanuel Vadot return (rv);
705*b2f0caf1SEmmanuel Vadot }
706*b2f0caf1SEmmanuel Vadot regnode_delay(udelay);
707*b2f0caf1SEmmanuel Vadot }
708*b2f0caf1SEmmanuel Vadot REGNODE_UNLOCK(regnode);
709*b2f0caf1SEmmanuel Vadot
710*b2f0caf1SEmmanuel Vadot rv = regnode_resolve_parent(regnode);
711*b2f0caf1SEmmanuel Vadot if (rv != 0)
712*b2f0caf1SEmmanuel Vadot return (rv);
713*b2f0caf1SEmmanuel Vadot if (regnode->parent != NULL && regnode->parent->enable_cnt == 0)
714*b2f0caf1SEmmanuel Vadot rv = regnode_stop(regnode->parent, depth + 1);
715*b2f0caf1SEmmanuel Vadot return (rv);
716*b2f0caf1SEmmanuel Vadot }
717*b2f0caf1SEmmanuel Vadot
718*b2f0caf1SEmmanuel Vadot /*
719*b2f0caf1SEmmanuel Vadot * Get regulator status. (REGULATOR_STATUS_*)
720*b2f0caf1SEmmanuel Vadot */
721*b2f0caf1SEmmanuel Vadot int
regnode_status(struct regnode * regnode,int * status)722*b2f0caf1SEmmanuel Vadot regnode_status(struct regnode *regnode, int *status)
723*b2f0caf1SEmmanuel Vadot {
724*b2f0caf1SEmmanuel Vadot int rv;
725*b2f0caf1SEmmanuel Vadot
726*b2f0caf1SEmmanuel Vadot REG_TOPO_ASSERT();
727*b2f0caf1SEmmanuel Vadot
728*b2f0caf1SEmmanuel Vadot REGNODE_XLOCK(regnode);
729*b2f0caf1SEmmanuel Vadot rv = REGNODE_STATUS(regnode, status);
730*b2f0caf1SEmmanuel Vadot REGNODE_UNLOCK(regnode);
731*b2f0caf1SEmmanuel Vadot return (rv);
732*b2f0caf1SEmmanuel Vadot }
733*b2f0caf1SEmmanuel Vadot
734*b2f0caf1SEmmanuel Vadot /*
735*b2f0caf1SEmmanuel Vadot * Get actual regulator voltage.
736*b2f0caf1SEmmanuel Vadot */
737*b2f0caf1SEmmanuel Vadot int
regnode_get_voltage(struct regnode * regnode,int * uvolt)738*b2f0caf1SEmmanuel Vadot regnode_get_voltage(struct regnode *regnode, int *uvolt)
739*b2f0caf1SEmmanuel Vadot {
740*b2f0caf1SEmmanuel Vadot int rv;
741*b2f0caf1SEmmanuel Vadot
742*b2f0caf1SEmmanuel Vadot REG_TOPO_ASSERT();
743*b2f0caf1SEmmanuel Vadot
744*b2f0caf1SEmmanuel Vadot REGNODE_XLOCK(regnode);
745*b2f0caf1SEmmanuel Vadot rv = REGNODE_GET_VOLTAGE(regnode, uvolt);
746*b2f0caf1SEmmanuel Vadot REGNODE_UNLOCK(regnode);
747*b2f0caf1SEmmanuel Vadot
748*b2f0caf1SEmmanuel Vadot /* Pass call into parent, if regulator is in bypass mode. */
749*b2f0caf1SEmmanuel Vadot if (rv == ENOENT) {
750*b2f0caf1SEmmanuel Vadot rv = regnode_resolve_parent(regnode);
751*b2f0caf1SEmmanuel Vadot if (rv != 0)
752*b2f0caf1SEmmanuel Vadot return (rv);
753*b2f0caf1SEmmanuel Vadot if (regnode->parent != NULL)
754*b2f0caf1SEmmanuel Vadot rv = regnode_get_voltage(regnode->parent, uvolt);
755*b2f0caf1SEmmanuel Vadot
756*b2f0caf1SEmmanuel Vadot }
757*b2f0caf1SEmmanuel Vadot return (rv);
758*b2f0caf1SEmmanuel Vadot }
759*b2f0caf1SEmmanuel Vadot
760*b2f0caf1SEmmanuel Vadot /*
761*b2f0caf1SEmmanuel Vadot * Set regulator voltage.
762*b2f0caf1SEmmanuel Vadot */
763*b2f0caf1SEmmanuel Vadot int
regnode_set_voltage(struct regnode * regnode,int min_uvolt,int max_uvolt)764*b2f0caf1SEmmanuel Vadot regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt)
765*b2f0caf1SEmmanuel Vadot {
766*b2f0caf1SEmmanuel Vadot int udelay;
767*b2f0caf1SEmmanuel Vadot int rv;
768*b2f0caf1SEmmanuel Vadot
769*b2f0caf1SEmmanuel Vadot REG_TOPO_ASSERT();
770*b2f0caf1SEmmanuel Vadot
771*b2f0caf1SEmmanuel Vadot REGNODE_XLOCK(regnode);
772*b2f0caf1SEmmanuel Vadot
773*b2f0caf1SEmmanuel Vadot rv = REGNODE_SET_VOLTAGE(regnode, min_uvolt, max_uvolt, &udelay);
774*b2f0caf1SEmmanuel Vadot if (rv == 0)
775*b2f0caf1SEmmanuel Vadot regnode_delay(udelay);
776*b2f0caf1SEmmanuel Vadot REGNODE_UNLOCK(regnode);
777*b2f0caf1SEmmanuel Vadot return (rv);
778*b2f0caf1SEmmanuel Vadot }
779*b2f0caf1SEmmanuel Vadot
780*b2f0caf1SEmmanuel Vadot /*
781*b2f0caf1SEmmanuel Vadot * Consumer variant of regnode_set_voltage().
782*b2f0caf1SEmmanuel Vadot */
783*b2f0caf1SEmmanuel Vadot static int
regnode_set_voltage_checked(struct regnode * regnode,struct regulator * reg,int min_uvolt,int max_uvolt)784*b2f0caf1SEmmanuel Vadot regnode_set_voltage_checked(struct regnode *regnode, struct regulator *reg,
785*b2f0caf1SEmmanuel Vadot int min_uvolt, int max_uvolt)
786*b2f0caf1SEmmanuel Vadot {
787*b2f0caf1SEmmanuel Vadot int udelay;
788*b2f0caf1SEmmanuel Vadot int all_max_uvolt;
789*b2f0caf1SEmmanuel Vadot int all_min_uvolt;
790*b2f0caf1SEmmanuel Vadot struct regulator *tmp;
791*b2f0caf1SEmmanuel Vadot int rv;
792*b2f0caf1SEmmanuel Vadot
793*b2f0caf1SEmmanuel Vadot REG_TOPO_ASSERT();
794*b2f0caf1SEmmanuel Vadot
795*b2f0caf1SEmmanuel Vadot REGNODE_XLOCK(regnode);
796*b2f0caf1SEmmanuel Vadot /* Return error if requested range is outside of regulator range. */
797*b2f0caf1SEmmanuel Vadot if ((min_uvolt > regnode->std_param.max_uvolt) ||
798*b2f0caf1SEmmanuel Vadot (max_uvolt < regnode->std_param.min_uvolt)) {
799*b2f0caf1SEmmanuel Vadot REGNODE_UNLOCK(regnode);
800*b2f0caf1SEmmanuel Vadot return (ERANGE);
801*b2f0caf1SEmmanuel Vadot }
802*b2f0caf1SEmmanuel Vadot
803*b2f0caf1SEmmanuel Vadot /* Get actual voltage range for all consumers. */
804*b2f0caf1SEmmanuel Vadot all_min_uvolt = regnode->std_param.min_uvolt;
805*b2f0caf1SEmmanuel Vadot all_max_uvolt = regnode->std_param.max_uvolt;
806*b2f0caf1SEmmanuel Vadot TAILQ_FOREACH(tmp, ®node->consumers_list, link) {
807*b2f0caf1SEmmanuel Vadot /* Don't take requestor in account. */
808*b2f0caf1SEmmanuel Vadot if (tmp == reg)
809*b2f0caf1SEmmanuel Vadot continue;
810*b2f0caf1SEmmanuel Vadot if (all_min_uvolt < tmp->min_uvolt)
811*b2f0caf1SEmmanuel Vadot all_min_uvolt = tmp->min_uvolt;
812*b2f0caf1SEmmanuel Vadot if (all_max_uvolt > tmp->max_uvolt)
813*b2f0caf1SEmmanuel Vadot all_max_uvolt = tmp->max_uvolt;
814*b2f0caf1SEmmanuel Vadot }
815*b2f0caf1SEmmanuel Vadot
816*b2f0caf1SEmmanuel Vadot /* Test if request fits to actual contract. */
817*b2f0caf1SEmmanuel Vadot if ((min_uvolt > all_max_uvolt) ||
818*b2f0caf1SEmmanuel Vadot (max_uvolt < all_min_uvolt)) {
819*b2f0caf1SEmmanuel Vadot REGNODE_UNLOCK(regnode);
820*b2f0caf1SEmmanuel Vadot return (ERANGE);
821*b2f0caf1SEmmanuel Vadot }
822*b2f0caf1SEmmanuel Vadot
823*b2f0caf1SEmmanuel Vadot /* Adjust new range.*/
824*b2f0caf1SEmmanuel Vadot if (min_uvolt < all_min_uvolt)
825*b2f0caf1SEmmanuel Vadot min_uvolt = all_min_uvolt;
826*b2f0caf1SEmmanuel Vadot if (max_uvolt > all_max_uvolt)
827*b2f0caf1SEmmanuel Vadot max_uvolt = all_max_uvolt;
828*b2f0caf1SEmmanuel Vadot
829*b2f0caf1SEmmanuel Vadot rv = REGNODE_SET_VOLTAGE(regnode, min_uvolt, max_uvolt, &udelay);
830*b2f0caf1SEmmanuel Vadot regnode_delay(udelay);
831*b2f0caf1SEmmanuel Vadot REGNODE_UNLOCK(regnode);
832*b2f0caf1SEmmanuel Vadot return (rv);
833*b2f0caf1SEmmanuel Vadot }
834*b2f0caf1SEmmanuel Vadot
835*b2f0caf1SEmmanuel Vadot int
regnode_set_constraint(struct regnode * regnode)836*b2f0caf1SEmmanuel Vadot regnode_set_constraint(struct regnode *regnode)
837*b2f0caf1SEmmanuel Vadot {
838*b2f0caf1SEmmanuel Vadot int status, rv, uvolt;
839*b2f0caf1SEmmanuel Vadot
840*b2f0caf1SEmmanuel Vadot if (regnode->std_param.boot_on != true &&
841*b2f0caf1SEmmanuel Vadot regnode->std_param.always_on != true)
842*b2f0caf1SEmmanuel Vadot return (0);
843*b2f0caf1SEmmanuel Vadot
844*b2f0caf1SEmmanuel Vadot rv = regnode_status(regnode, &status);
845*b2f0caf1SEmmanuel Vadot if (rv != 0) {
846*b2f0caf1SEmmanuel Vadot if (bootverbose)
847*b2f0caf1SEmmanuel Vadot printf("Cannot get regulator status for %s\n",
848*b2f0caf1SEmmanuel Vadot regnode_get_name(regnode));
849*b2f0caf1SEmmanuel Vadot return (rv);
850*b2f0caf1SEmmanuel Vadot }
851*b2f0caf1SEmmanuel Vadot
852*b2f0caf1SEmmanuel Vadot if (status == REGULATOR_STATUS_ENABLED)
853*b2f0caf1SEmmanuel Vadot return (0);
854*b2f0caf1SEmmanuel Vadot
855*b2f0caf1SEmmanuel Vadot rv = regnode_get_voltage(regnode, &uvolt);
856*b2f0caf1SEmmanuel Vadot if (rv != 0) {
857*b2f0caf1SEmmanuel Vadot if (bootverbose)
858*b2f0caf1SEmmanuel Vadot printf("Cannot get regulator voltage for %s\n",
859*b2f0caf1SEmmanuel Vadot regnode_get_name(regnode));
860*b2f0caf1SEmmanuel Vadot return (rv);
861*b2f0caf1SEmmanuel Vadot }
862*b2f0caf1SEmmanuel Vadot
863*b2f0caf1SEmmanuel Vadot if (uvolt < regnode->std_param.min_uvolt ||
864*b2f0caf1SEmmanuel Vadot uvolt > regnode->std_param.max_uvolt) {
865*b2f0caf1SEmmanuel Vadot if (bootverbose)
866*b2f0caf1SEmmanuel Vadot printf("Regulator %s current voltage %d is not in the"
867*b2f0caf1SEmmanuel Vadot " acceptable range : %d<->%d\n",
868*b2f0caf1SEmmanuel Vadot regnode_get_name(regnode),
869*b2f0caf1SEmmanuel Vadot uvolt, regnode->std_param.min_uvolt,
870*b2f0caf1SEmmanuel Vadot regnode->std_param.max_uvolt);
871*b2f0caf1SEmmanuel Vadot return (ERANGE);
872*b2f0caf1SEmmanuel Vadot }
873*b2f0caf1SEmmanuel Vadot
874*b2f0caf1SEmmanuel Vadot rv = regnode_enable(regnode);
875*b2f0caf1SEmmanuel Vadot if (rv != 0) {
876*b2f0caf1SEmmanuel Vadot if (bootverbose)
877*b2f0caf1SEmmanuel Vadot printf("Cannot enable regulator %s\n",
878*b2f0caf1SEmmanuel Vadot regnode_get_name(regnode));
879*b2f0caf1SEmmanuel Vadot return (rv);
880*b2f0caf1SEmmanuel Vadot }
881*b2f0caf1SEmmanuel Vadot
882*b2f0caf1SEmmanuel Vadot return (0);
883*b2f0caf1SEmmanuel Vadot }
884*b2f0caf1SEmmanuel Vadot
885*b2f0caf1SEmmanuel Vadot #ifdef FDT
886*b2f0caf1SEmmanuel Vadot phandle_t
regnode_get_ofw_node(struct regnode * regnode)887*b2f0caf1SEmmanuel Vadot regnode_get_ofw_node(struct regnode *regnode)
888*b2f0caf1SEmmanuel Vadot {
889*b2f0caf1SEmmanuel Vadot
890*b2f0caf1SEmmanuel Vadot return (regnode->ofw_node);
891*b2f0caf1SEmmanuel Vadot }
892*b2f0caf1SEmmanuel Vadot #endif
893*b2f0caf1SEmmanuel Vadot
894*b2f0caf1SEmmanuel Vadot /* --------------------------------------------------------------------------
895*b2f0caf1SEmmanuel Vadot *
896*b2f0caf1SEmmanuel Vadot * Regulator consumers interface.
897*b2f0caf1SEmmanuel Vadot *
898*b2f0caf1SEmmanuel Vadot */
899*b2f0caf1SEmmanuel Vadot /* Helper function for regulator_get*() */
900*b2f0caf1SEmmanuel Vadot static regulator_t
regulator_create(struct regnode * regnode,device_t cdev)901*b2f0caf1SEmmanuel Vadot regulator_create(struct regnode *regnode, device_t cdev)
902*b2f0caf1SEmmanuel Vadot {
903*b2f0caf1SEmmanuel Vadot struct regulator *reg;
904*b2f0caf1SEmmanuel Vadot
905*b2f0caf1SEmmanuel Vadot REG_TOPO_ASSERT();
906*b2f0caf1SEmmanuel Vadot
907*b2f0caf1SEmmanuel Vadot reg = malloc(sizeof(struct regulator), M_REGULATOR,
908*b2f0caf1SEmmanuel Vadot M_WAITOK | M_ZERO);
909*b2f0caf1SEmmanuel Vadot reg->cdev = cdev;
910*b2f0caf1SEmmanuel Vadot reg->regnode = regnode;
911*b2f0caf1SEmmanuel Vadot reg->enable_cnt = 0;
912*b2f0caf1SEmmanuel Vadot
913*b2f0caf1SEmmanuel Vadot REGNODE_XLOCK(regnode);
914*b2f0caf1SEmmanuel Vadot regnode->ref_cnt++;
915*b2f0caf1SEmmanuel Vadot TAILQ_INSERT_TAIL(®node->consumers_list, reg, link);
916*b2f0caf1SEmmanuel Vadot reg ->min_uvolt = regnode->std_param.min_uvolt;
917*b2f0caf1SEmmanuel Vadot reg ->max_uvolt = regnode->std_param.max_uvolt;
918*b2f0caf1SEmmanuel Vadot REGNODE_UNLOCK(regnode);
919*b2f0caf1SEmmanuel Vadot
920*b2f0caf1SEmmanuel Vadot return (reg);
921*b2f0caf1SEmmanuel Vadot }
922*b2f0caf1SEmmanuel Vadot
923*b2f0caf1SEmmanuel Vadot int
regulator_enable(regulator_t reg)924*b2f0caf1SEmmanuel Vadot regulator_enable(regulator_t reg)
925*b2f0caf1SEmmanuel Vadot {
926*b2f0caf1SEmmanuel Vadot int rv;
927*b2f0caf1SEmmanuel Vadot struct regnode *regnode;
928*b2f0caf1SEmmanuel Vadot
929*b2f0caf1SEmmanuel Vadot regnode = reg->regnode;
930*b2f0caf1SEmmanuel Vadot KASSERT(regnode->ref_cnt > 0,
931*b2f0caf1SEmmanuel Vadot ("Attempt to access unreferenced regulator: %s\n", regnode->name));
932*b2f0caf1SEmmanuel Vadot REG_TOPO_SLOCK();
933*b2f0caf1SEmmanuel Vadot rv = regnode_enable(regnode);
934*b2f0caf1SEmmanuel Vadot if (rv == 0)
935*b2f0caf1SEmmanuel Vadot reg->enable_cnt++;
936*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
937*b2f0caf1SEmmanuel Vadot return (rv);
938*b2f0caf1SEmmanuel Vadot }
939*b2f0caf1SEmmanuel Vadot
940*b2f0caf1SEmmanuel Vadot int
regulator_disable(regulator_t reg)941*b2f0caf1SEmmanuel Vadot regulator_disable(regulator_t reg)
942*b2f0caf1SEmmanuel Vadot {
943*b2f0caf1SEmmanuel Vadot int rv;
944*b2f0caf1SEmmanuel Vadot struct regnode *regnode;
945*b2f0caf1SEmmanuel Vadot
946*b2f0caf1SEmmanuel Vadot regnode = reg->regnode;
947*b2f0caf1SEmmanuel Vadot KASSERT(regnode->ref_cnt > 0,
948*b2f0caf1SEmmanuel Vadot ("Attempt to access unreferenced regulator: %s\n", regnode->name));
949*b2f0caf1SEmmanuel Vadot KASSERT(reg->enable_cnt > 0,
950*b2f0caf1SEmmanuel Vadot ("Attempt to disable already disabled regulator: %s\n",
951*b2f0caf1SEmmanuel Vadot regnode->name));
952*b2f0caf1SEmmanuel Vadot REG_TOPO_SLOCK();
953*b2f0caf1SEmmanuel Vadot rv = regnode_disable(regnode);
954*b2f0caf1SEmmanuel Vadot if (rv == 0)
955*b2f0caf1SEmmanuel Vadot reg->enable_cnt--;
956*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
957*b2f0caf1SEmmanuel Vadot return (rv);
958*b2f0caf1SEmmanuel Vadot }
959*b2f0caf1SEmmanuel Vadot
960*b2f0caf1SEmmanuel Vadot int
regulator_stop(regulator_t reg)961*b2f0caf1SEmmanuel Vadot regulator_stop(regulator_t reg)
962*b2f0caf1SEmmanuel Vadot {
963*b2f0caf1SEmmanuel Vadot int rv;
964*b2f0caf1SEmmanuel Vadot struct regnode *regnode;
965*b2f0caf1SEmmanuel Vadot
966*b2f0caf1SEmmanuel Vadot regnode = reg->regnode;
967*b2f0caf1SEmmanuel Vadot KASSERT(regnode->ref_cnt > 0,
968*b2f0caf1SEmmanuel Vadot ("Attempt to access unreferenced regulator: %s\n", regnode->name));
969*b2f0caf1SEmmanuel Vadot KASSERT(reg->enable_cnt == 0,
970*b2f0caf1SEmmanuel Vadot ("Attempt to stop already enabled regulator: %s\n", regnode->name));
971*b2f0caf1SEmmanuel Vadot
972*b2f0caf1SEmmanuel Vadot REG_TOPO_SLOCK();
973*b2f0caf1SEmmanuel Vadot rv = regnode_stop(regnode, 0);
974*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
975*b2f0caf1SEmmanuel Vadot return (rv);
976*b2f0caf1SEmmanuel Vadot }
977*b2f0caf1SEmmanuel Vadot
978*b2f0caf1SEmmanuel Vadot int
regulator_status(regulator_t reg,int * status)979*b2f0caf1SEmmanuel Vadot regulator_status(regulator_t reg, int *status)
980*b2f0caf1SEmmanuel Vadot {
981*b2f0caf1SEmmanuel Vadot int rv;
982*b2f0caf1SEmmanuel Vadot struct regnode *regnode;
983*b2f0caf1SEmmanuel Vadot
984*b2f0caf1SEmmanuel Vadot regnode = reg->regnode;
985*b2f0caf1SEmmanuel Vadot KASSERT(regnode->ref_cnt > 0,
986*b2f0caf1SEmmanuel Vadot ("Attempt to access unreferenced regulator: %s\n", regnode->name));
987*b2f0caf1SEmmanuel Vadot
988*b2f0caf1SEmmanuel Vadot if (reg->enable_cnt == 0) {
989*b2f0caf1SEmmanuel Vadot *status = 0;
990*b2f0caf1SEmmanuel Vadot return (0);
991*b2f0caf1SEmmanuel Vadot }
992*b2f0caf1SEmmanuel Vadot REG_TOPO_SLOCK();
993*b2f0caf1SEmmanuel Vadot rv = regnode_status(regnode, status);
994*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
995*b2f0caf1SEmmanuel Vadot return (rv);
996*b2f0caf1SEmmanuel Vadot }
997*b2f0caf1SEmmanuel Vadot
998*b2f0caf1SEmmanuel Vadot int
regulator_get_voltage(regulator_t reg,int * uvolt)999*b2f0caf1SEmmanuel Vadot regulator_get_voltage(regulator_t reg, int *uvolt)
1000*b2f0caf1SEmmanuel Vadot {
1001*b2f0caf1SEmmanuel Vadot int rv;
1002*b2f0caf1SEmmanuel Vadot struct regnode *regnode;
1003*b2f0caf1SEmmanuel Vadot
1004*b2f0caf1SEmmanuel Vadot regnode = reg->regnode;
1005*b2f0caf1SEmmanuel Vadot KASSERT(regnode->ref_cnt > 0,
1006*b2f0caf1SEmmanuel Vadot ("Attempt to access unreferenced regulator: %s\n", regnode->name));
1007*b2f0caf1SEmmanuel Vadot
1008*b2f0caf1SEmmanuel Vadot REG_TOPO_SLOCK();
1009*b2f0caf1SEmmanuel Vadot rv = regnode_get_voltage(regnode, uvolt);
1010*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
1011*b2f0caf1SEmmanuel Vadot return (rv);
1012*b2f0caf1SEmmanuel Vadot }
1013*b2f0caf1SEmmanuel Vadot
1014*b2f0caf1SEmmanuel Vadot int
regulator_set_voltage(regulator_t reg,int min_uvolt,int max_uvolt)1015*b2f0caf1SEmmanuel Vadot regulator_set_voltage(regulator_t reg, int min_uvolt, int max_uvolt)
1016*b2f0caf1SEmmanuel Vadot {
1017*b2f0caf1SEmmanuel Vadot struct regnode *regnode;
1018*b2f0caf1SEmmanuel Vadot int rv;
1019*b2f0caf1SEmmanuel Vadot
1020*b2f0caf1SEmmanuel Vadot regnode = reg->regnode;
1021*b2f0caf1SEmmanuel Vadot KASSERT(regnode->ref_cnt > 0,
1022*b2f0caf1SEmmanuel Vadot ("Attempt to access unreferenced regulator: %s\n", regnode->name));
1023*b2f0caf1SEmmanuel Vadot
1024*b2f0caf1SEmmanuel Vadot REG_TOPO_SLOCK();
1025*b2f0caf1SEmmanuel Vadot
1026*b2f0caf1SEmmanuel Vadot rv = regnode_set_voltage_checked(regnode, reg, min_uvolt, max_uvolt);
1027*b2f0caf1SEmmanuel Vadot if (rv == 0) {
1028*b2f0caf1SEmmanuel Vadot reg->min_uvolt = min_uvolt;
1029*b2f0caf1SEmmanuel Vadot reg->max_uvolt = max_uvolt;
1030*b2f0caf1SEmmanuel Vadot }
1031*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
1032*b2f0caf1SEmmanuel Vadot return (rv);
1033*b2f0caf1SEmmanuel Vadot }
1034*b2f0caf1SEmmanuel Vadot
1035*b2f0caf1SEmmanuel Vadot int
regulator_check_voltage(regulator_t reg,int uvolt)1036*b2f0caf1SEmmanuel Vadot regulator_check_voltage(regulator_t reg, int uvolt)
1037*b2f0caf1SEmmanuel Vadot {
1038*b2f0caf1SEmmanuel Vadot int rv;
1039*b2f0caf1SEmmanuel Vadot struct regnode *regnode;
1040*b2f0caf1SEmmanuel Vadot
1041*b2f0caf1SEmmanuel Vadot regnode = reg->regnode;
1042*b2f0caf1SEmmanuel Vadot KASSERT(regnode->ref_cnt > 0,
1043*b2f0caf1SEmmanuel Vadot ("Attempt to access unreferenced regulator: %s\n", regnode->name));
1044*b2f0caf1SEmmanuel Vadot
1045*b2f0caf1SEmmanuel Vadot REG_TOPO_SLOCK();
1046*b2f0caf1SEmmanuel Vadot rv = REGNODE_CHECK_VOLTAGE(regnode, uvolt);
1047*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
1048*b2f0caf1SEmmanuel Vadot return (rv);
1049*b2f0caf1SEmmanuel Vadot }
1050*b2f0caf1SEmmanuel Vadot
1051*b2f0caf1SEmmanuel Vadot const char *
regulator_get_name(regulator_t reg)1052*b2f0caf1SEmmanuel Vadot regulator_get_name(regulator_t reg)
1053*b2f0caf1SEmmanuel Vadot {
1054*b2f0caf1SEmmanuel Vadot struct regnode *regnode;
1055*b2f0caf1SEmmanuel Vadot
1056*b2f0caf1SEmmanuel Vadot regnode = reg->regnode;
1057*b2f0caf1SEmmanuel Vadot KASSERT(regnode->ref_cnt > 0,
1058*b2f0caf1SEmmanuel Vadot ("Attempt to access unreferenced regulator: %s\n", regnode->name));
1059*b2f0caf1SEmmanuel Vadot return (regnode->name);
1060*b2f0caf1SEmmanuel Vadot }
1061*b2f0caf1SEmmanuel Vadot
1062*b2f0caf1SEmmanuel Vadot int
regulator_get_by_name(device_t cdev,const char * name,regulator_t * reg)1063*b2f0caf1SEmmanuel Vadot regulator_get_by_name(device_t cdev, const char *name, regulator_t *reg)
1064*b2f0caf1SEmmanuel Vadot {
1065*b2f0caf1SEmmanuel Vadot struct regnode *regnode;
1066*b2f0caf1SEmmanuel Vadot
1067*b2f0caf1SEmmanuel Vadot REG_TOPO_SLOCK();
1068*b2f0caf1SEmmanuel Vadot regnode = regnode_find_by_name(name);
1069*b2f0caf1SEmmanuel Vadot if (regnode == NULL) {
1070*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
1071*b2f0caf1SEmmanuel Vadot return (ENODEV);
1072*b2f0caf1SEmmanuel Vadot }
1073*b2f0caf1SEmmanuel Vadot *reg = regulator_create(regnode, cdev);
1074*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
1075*b2f0caf1SEmmanuel Vadot return (0);
1076*b2f0caf1SEmmanuel Vadot }
1077*b2f0caf1SEmmanuel Vadot
1078*b2f0caf1SEmmanuel Vadot int
regulator_get_by_id(device_t cdev,device_t pdev,intptr_t id,regulator_t * reg)1079*b2f0caf1SEmmanuel Vadot regulator_get_by_id(device_t cdev, device_t pdev, intptr_t id, regulator_t *reg)
1080*b2f0caf1SEmmanuel Vadot {
1081*b2f0caf1SEmmanuel Vadot struct regnode *regnode;
1082*b2f0caf1SEmmanuel Vadot
1083*b2f0caf1SEmmanuel Vadot REG_TOPO_SLOCK();
1084*b2f0caf1SEmmanuel Vadot
1085*b2f0caf1SEmmanuel Vadot regnode = regnode_find_by_id(pdev, id);
1086*b2f0caf1SEmmanuel Vadot if (regnode == NULL) {
1087*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
1088*b2f0caf1SEmmanuel Vadot return (ENODEV);
1089*b2f0caf1SEmmanuel Vadot }
1090*b2f0caf1SEmmanuel Vadot *reg = regulator_create(regnode, cdev);
1091*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
1092*b2f0caf1SEmmanuel Vadot
1093*b2f0caf1SEmmanuel Vadot return (0);
1094*b2f0caf1SEmmanuel Vadot }
1095*b2f0caf1SEmmanuel Vadot
1096*b2f0caf1SEmmanuel Vadot int
regulator_release(regulator_t reg)1097*b2f0caf1SEmmanuel Vadot regulator_release(regulator_t reg)
1098*b2f0caf1SEmmanuel Vadot {
1099*b2f0caf1SEmmanuel Vadot struct regnode *regnode;
1100*b2f0caf1SEmmanuel Vadot
1101*b2f0caf1SEmmanuel Vadot regnode = reg->regnode;
1102*b2f0caf1SEmmanuel Vadot KASSERT(regnode->ref_cnt > 0,
1103*b2f0caf1SEmmanuel Vadot ("Attempt to access unreferenced regulator: %s\n", regnode->name));
1104*b2f0caf1SEmmanuel Vadot REG_TOPO_SLOCK();
1105*b2f0caf1SEmmanuel Vadot while (reg->enable_cnt > 0) {
1106*b2f0caf1SEmmanuel Vadot regnode_disable(regnode);
1107*b2f0caf1SEmmanuel Vadot reg->enable_cnt--;
1108*b2f0caf1SEmmanuel Vadot }
1109*b2f0caf1SEmmanuel Vadot REGNODE_XLOCK(regnode);
1110*b2f0caf1SEmmanuel Vadot TAILQ_REMOVE(®node->consumers_list, reg, link);
1111*b2f0caf1SEmmanuel Vadot regnode->ref_cnt--;
1112*b2f0caf1SEmmanuel Vadot REGNODE_UNLOCK(regnode);
1113*b2f0caf1SEmmanuel Vadot REG_TOPO_UNLOCK();
1114*b2f0caf1SEmmanuel Vadot
1115*b2f0caf1SEmmanuel Vadot free(reg, M_REGULATOR);
1116*b2f0caf1SEmmanuel Vadot return (0);
1117*b2f0caf1SEmmanuel Vadot }
1118*b2f0caf1SEmmanuel Vadot
1119*b2f0caf1SEmmanuel Vadot #ifdef FDT
1120*b2f0caf1SEmmanuel Vadot /* Default DT mapper. */
1121*b2f0caf1SEmmanuel Vadot int
regdev_default_ofw_map(device_t dev,phandle_t xref,int ncells,pcell_t * cells,intptr_t * id)1122*b2f0caf1SEmmanuel Vadot regdev_default_ofw_map(device_t dev, phandle_t xref, int ncells,
1123*b2f0caf1SEmmanuel Vadot pcell_t *cells, intptr_t *id)
1124*b2f0caf1SEmmanuel Vadot {
1125*b2f0caf1SEmmanuel Vadot if (ncells == 0)
1126*b2f0caf1SEmmanuel Vadot *id = 1;
1127*b2f0caf1SEmmanuel Vadot else if (ncells == 1)
1128*b2f0caf1SEmmanuel Vadot *id = cells[0];
1129*b2f0caf1SEmmanuel Vadot else
1130*b2f0caf1SEmmanuel Vadot return (ERANGE);
1131*b2f0caf1SEmmanuel Vadot
1132*b2f0caf1SEmmanuel Vadot return (0);
1133*b2f0caf1SEmmanuel Vadot }
1134*b2f0caf1SEmmanuel Vadot
1135*b2f0caf1SEmmanuel Vadot int
regulator_parse_ofw_stdparam(device_t pdev,phandle_t node,struct regnode_init_def * def)1136*b2f0caf1SEmmanuel Vadot regulator_parse_ofw_stdparam(device_t pdev, phandle_t node,
1137*b2f0caf1SEmmanuel Vadot struct regnode_init_def *def)
1138*b2f0caf1SEmmanuel Vadot {
1139*b2f0caf1SEmmanuel Vadot phandle_t supply_xref;
1140*b2f0caf1SEmmanuel Vadot struct regnode_std_param *par;
1141*b2f0caf1SEmmanuel Vadot int rv;
1142*b2f0caf1SEmmanuel Vadot
1143*b2f0caf1SEmmanuel Vadot par = &def->std_param;
1144*b2f0caf1SEmmanuel Vadot rv = OF_getprop_alloc(node, "regulator-name",
1145*b2f0caf1SEmmanuel Vadot (void **)&def->name);
1146*b2f0caf1SEmmanuel Vadot if (rv <= 0) {
1147*b2f0caf1SEmmanuel Vadot device_printf(pdev, "%s: Missing regulator name\n",
1148*b2f0caf1SEmmanuel Vadot __func__);
1149*b2f0caf1SEmmanuel Vadot return (ENXIO);
1150*b2f0caf1SEmmanuel Vadot }
1151*b2f0caf1SEmmanuel Vadot
1152*b2f0caf1SEmmanuel Vadot rv = OF_getencprop(node, "regulator-min-microvolt", &par->min_uvolt,
1153*b2f0caf1SEmmanuel Vadot sizeof(par->min_uvolt));
1154*b2f0caf1SEmmanuel Vadot if (rv <= 0)
1155*b2f0caf1SEmmanuel Vadot par->min_uvolt = 0;
1156*b2f0caf1SEmmanuel Vadot
1157*b2f0caf1SEmmanuel Vadot rv = OF_getencprop(node, "regulator-max-microvolt", &par->max_uvolt,
1158*b2f0caf1SEmmanuel Vadot sizeof(par->max_uvolt));
1159*b2f0caf1SEmmanuel Vadot if (rv <= 0)
1160*b2f0caf1SEmmanuel Vadot par->max_uvolt = 0;
1161*b2f0caf1SEmmanuel Vadot
1162*b2f0caf1SEmmanuel Vadot rv = OF_getencprop(node, "regulator-min-microamp", &par->min_uamp,
1163*b2f0caf1SEmmanuel Vadot sizeof(par->min_uamp));
1164*b2f0caf1SEmmanuel Vadot if (rv <= 0)
1165*b2f0caf1SEmmanuel Vadot par->min_uamp = 0;
1166*b2f0caf1SEmmanuel Vadot
1167*b2f0caf1SEmmanuel Vadot rv = OF_getencprop(node, "regulator-max-microamp", &par->max_uamp,
1168*b2f0caf1SEmmanuel Vadot sizeof(par->max_uamp));
1169*b2f0caf1SEmmanuel Vadot if (rv <= 0)
1170*b2f0caf1SEmmanuel Vadot par->max_uamp = 0;
1171*b2f0caf1SEmmanuel Vadot
1172*b2f0caf1SEmmanuel Vadot rv = OF_getencprop(node, "regulator-ramp-delay", &par->ramp_delay,
1173*b2f0caf1SEmmanuel Vadot sizeof(par->ramp_delay));
1174*b2f0caf1SEmmanuel Vadot if (rv <= 0)
1175*b2f0caf1SEmmanuel Vadot par->ramp_delay = 0;
1176*b2f0caf1SEmmanuel Vadot
1177*b2f0caf1SEmmanuel Vadot rv = OF_getencprop(node, "regulator-enable-ramp-delay",
1178*b2f0caf1SEmmanuel Vadot &par->enable_delay, sizeof(par->enable_delay));
1179*b2f0caf1SEmmanuel Vadot if (rv <= 0)
1180*b2f0caf1SEmmanuel Vadot par->enable_delay = 0;
1181*b2f0caf1SEmmanuel Vadot
1182*b2f0caf1SEmmanuel Vadot if (OF_hasprop(node, "regulator-boot-on"))
1183*b2f0caf1SEmmanuel Vadot par->boot_on = true;
1184*b2f0caf1SEmmanuel Vadot
1185*b2f0caf1SEmmanuel Vadot if (OF_hasprop(node, "regulator-always-on"))
1186*b2f0caf1SEmmanuel Vadot par->always_on = true;
1187*b2f0caf1SEmmanuel Vadot
1188*b2f0caf1SEmmanuel Vadot if (OF_hasprop(node, "enable-active-high"))
1189*b2f0caf1SEmmanuel Vadot par->enable_active_high = 1;
1190*b2f0caf1SEmmanuel Vadot
1191*b2f0caf1SEmmanuel Vadot rv = OF_getencprop(node, "vin-supply", &supply_xref,
1192*b2f0caf1SEmmanuel Vadot sizeof(supply_xref));
1193*b2f0caf1SEmmanuel Vadot if (rv >= 0) {
1194*b2f0caf1SEmmanuel Vadot rv = OF_getprop_alloc(supply_xref, "regulator-name",
1195*b2f0caf1SEmmanuel Vadot (void **)&def->parent_name);
1196*b2f0caf1SEmmanuel Vadot if (rv <= 0)
1197*b2f0caf1SEmmanuel Vadot def->parent_name = NULL;
1198*b2f0caf1SEmmanuel Vadot }
1199*b2f0caf1SEmmanuel Vadot return (0);
1200*b2f0caf1SEmmanuel Vadot }
1201*b2f0caf1SEmmanuel Vadot
1202*b2f0caf1SEmmanuel Vadot int
regulator_get_by_ofw_property(device_t cdev,phandle_t cnode,char * name,regulator_t * reg)1203*b2f0caf1SEmmanuel Vadot regulator_get_by_ofw_property(device_t cdev, phandle_t cnode, char *name,
1204*b2f0caf1SEmmanuel Vadot regulator_t *reg)
1205*b2f0caf1SEmmanuel Vadot {
1206*b2f0caf1SEmmanuel Vadot phandle_t *cells;
1207*b2f0caf1SEmmanuel Vadot device_t regdev;
1208*b2f0caf1SEmmanuel Vadot int ncells, rv;
1209*b2f0caf1SEmmanuel Vadot intptr_t id;
1210*b2f0caf1SEmmanuel Vadot
1211*b2f0caf1SEmmanuel Vadot *reg = NULL;
1212*b2f0caf1SEmmanuel Vadot
1213*b2f0caf1SEmmanuel Vadot if (cnode <= 0)
1214*b2f0caf1SEmmanuel Vadot cnode = ofw_bus_get_node(cdev);
1215*b2f0caf1SEmmanuel Vadot if (cnode <= 0) {
1216*b2f0caf1SEmmanuel Vadot device_printf(cdev, "%s called on not ofw based device\n",
1217*b2f0caf1SEmmanuel Vadot __func__);
1218*b2f0caf1SEmmanuel Vadot return (ENXIO);
1219*b2f0caf1SEmmanuel Vadot }
1220*b2f0caf1SEmmanuel Vadot
1221*b2f0caf1SEmmanuel Vadot cells = NULL;
1222*b2f0caf1SEmmanuel Vadot ncells = OF_getencprop_alloc_multi(cnode, name, sizeof(*cells),
1223*b2f0caf1SEmmanuel Vadot (void **)&cells);
1224*b2f0caf1SEmmanuel Vadot if (ncells <= 0)
1225*b2f0caf1SEmmanuel Vadot return (ENOENT);
1226*b2f0caf1SEmmanuel Vadot
1227*b2f0caf1SEmmanuel Vadot /* Translate xref to device */
1228*b2f0caf1SEmmanuel Vadot regdev = OF_device_from_xref(cells[0]);
1229*b2f0caf1SEmmanuel Vadot if (regdev == NULL) {
1230*b2f0caf1SEmmanuel Vadot OF_prop_free(cells);
1231*b2f0caf1SEmmanuel Vadot return (ENODEV);
1232*b2f0caf1SEmmanuel Vadot }
1233*b2f0caf1SEmmanuel Vadot
1234*b2f0caf1SEmmanuel Vadot /* Map regulator to number */
1235*b2f0caf1SEmmanuel Vadot rv = REGDEV_MAP(regdev, cells[0], ncells - 1, cells + 1, &id);
1236*b2f0caf1SEmmanuel Vadot OF_prop_free(cells);
1237*b2f0caf1SEmmanuel Vadot if (rv != 0)
1238*b2f0caf1SEmmanuel Vadot return (rv);
1239*b2f0caf1SEmmanuel Vadot return (regulator_get_by_id(cdev, regdev, id, reg));
1240*b2f0caf1SEmmanuel Vadot }
1241*b2f0caf1SEmmanuel Vadot #endif
1242*b2f0caf1SEmmanuel Vadot
1243*b2f0caf1SEmmanuel Vadot /* --------------------------------------------------------------------------
1244*b2f0caf1SEmmanuel Vadot *
1245*b2f0caf1SEmmanuel Vadot * Regulator utility functions.
1246*b2f0caf1SEmmanuel Vadot *
1247*b2f0caf1SEmmanuel Vadot */
1248*b2f0caf1SEmmanuel Vadot
1249*b2f0caf1SEmmanuel Vadot /* Convert raw selector value to real voltage */
1250*b2f0caf1SEmmanuel Vadot int
regulator_range_sel8_to_volt(struct regulator_range * ranges,int nranges,uint8_t sel,int * volt)1251*b2f0caf1SEmmanuel Vadot regulator_range_sel8_to_volt(struct regulator_range *ranges, int nranges,
1252*b2f0caf1SEmmanuel Vadot uint8_t sel, int *volt)
1253*b2f0caf1SEmmanuel Vadot {
1254*b2f0caf1SEmmanuel Vadot struct regulator_range *range;
1255*b2f0caf1SEmmanuel Vadot int i;
1256*b2f0caf1SEmmanuel Vadot
1257*b2f0caf1SEmmanuel Vadot if (nranges == 0)
1258*b2f0caf1SEmmanuel Vadot panic("Voltage regulator have zero ranges\n");
1259*b2f0caf1SEmmanuel Vadot
1260*b2f0caf1SEmmanuel Vadot for (i = 0; i < nranges ; i++) {
1261*b2f0caf1SEmmanuel Vadot range = ranges + i;
1262*b2f0caf1SEmmanuel Vadot
1263*b2f0caf1SEmmanuel Vadot if (!(sel >= range->min_sel &&
1264*b2f0caf1SEmmanuel Vadot sel <= range->max_sel))
1265*b2f0caf1SEmmanuel Vadot continue;
1266*b2f0caf1SEmmanuel Vadot
1267*b2f0caf1SEmmanuel Vadot sel -= range->min_sel;
1268*b2f0caf1SEmmanuel Vadot
1269*b2f0caf1SEmmanuel Vadot *volt = range->min_uvolt + sel * range->step_uvolt;
1270*b2f0caf1SEmmanuel Vadot return (0);
1271*b2f0caf1SEmmanuel Vadot }
1272*b2f0caf1SEmmanuel Vadot
1273*b2f0caf1SEmmanuel Vadot return (ERANGE);
1274*b2f0caf1SEmmanuel Vadot }
1275*b2f0caf1SEmmanuel Vadot
1276*b2f0caf1SEmmanuel Vadot int
regulator_range_volt_to_sel8(struct regulator_range * ranges,int nranges,int min_uvolt,int max_uvolt,uint8_t * out_sel)1277*b2f0caf1SEmmanuel Vadot regulator_range_volt_to_sel8(struct regulator_range *ranges, int nranges,
1278*b2f0caf1SEmmanuel Vadot int min_uvolt, int max_uvolt, uint8_t *out_sel)
1279*b2f0caf1SEmmanuel Vadot {
1280*b2f0caf1SEmmanuel Vadot struct regulator_range *range;
1281*b2f0caf1SEmmanuel Vadot uint8_t sel;
1282*b2f0caf1SEmmanuel Vadot int uvolt;
1283*b2f0caf1SEmmanuel Vadot int rv, i;
1284*b2f0caf1SEmmanuel Vadot
1285*b2f0caf1SEmmanuel Vadot if (nranges == 0)
1286*b2f0caf1SEmmanuel Vadot panic("Voltage regulator have zero ranges\n");
1287*b2f0caf1SEmmanuel Vadot
1288*b2f0caf1SEmmanuel Vadot for (i = 0; i < nranges; i++) {
1289*b2f0caf1SEmmanuel Vadot range = ranges + i;
1290*b2f0caf1SEmmanuel Vadot uvolt = range->min_uvolt +
1291*b2f0caf1SEmmanuel Vadot (range->max_sel - range->min_sel) * range->step_uvolt;
1292*b2f0caf1SEmmanuel Vadot
1293*b2f0caf1SEmmanuel Vadot if ((min_uvolt > uvolt) ||
1294*b2f0caf1SEmmanuel Vadot (max_uvolt < range->min_uvolt))
1295*b2f0caf1SEmmanuel Vadot continue;
1296*b2f0caf1SEmmanuel Vadot
1297*b2f0caf1SEmmanuel Vadot if (min_uvolt <= range->min_uvolt)
1298*b2f0caf1SEmmanuel Vadot min_uvolt = range->min_uvolt;
1299*b2f0caf1SEmmanuel Vadot
1300*b2f0caf1SEmmanuel Vadot /* if step == 0 -> fixed voltage range. */
1301*b2f0caf1SEmmanuel Vadot if (range->step_uvolt == 0)
1302*b2f0caf1SEmmanuel Vadot sel = 0;
1303*b2f0caf1SEmmanuel Vadot else
1304*b2f0caf1SEmmanuel Vadot sel = DIV_ROUND_UP(min_uvolt - range->min_uvolt,
1305*b2f0caf1SEmmanuel Vadot range->step_uvolt);
1306*b2f0caf1SEmmanuel Vadot
1307*b2f0caf1SEmmanuel Vadot
1308*b2f0caf1SEmmanuel Vadot sel += range->min_sel;
1309*b2f0caf1SEmmanuel Vadot
1310*b2f0caf1SEmmanuel Vadot break;
1311*b2f0caf1SEmmanuel Vadot }
1312*b2f0caf1SEmmanuel Vadot
1313*b2f0caf1SEmmanuel Vadot if (i >= nranges)
1314*b2f0caf1SEmmanuel Vadot return (ERANGE);
1315*b2f0caf1SEmmanuel Vadot
1316*b2f0caf1SEmmanuel Vadot /* Verify new settings. */
1317*b2f0caf1SEmmanuel Vadot rv = regulator_range_sel8_to_volt(ranges, nranges, sel, &uvolt);
1318*b2f0caf1SEmmanuel Vadot if (rv != 0)
1319*b2f0caf1SEmmanuel Vadot return (rv);
1320*b2f0caf1SEmmanuel Vadot if ((uvolt < min_uvolt) || (uvolt > max_uvolt))
1321*b2f0caf1SEmmanuel Vadot return (ERANGE);
1322*b2f0caf1SEmmanuel Vadot
1323*b2f0caf1SEmmanuel Vadot *out_sel = sel;
1324*b2f0caf1SEmmanuel Vadot return (0);
1325*b2f0caf1SEmmanuel Vadot }
1326