1296906Smmel/*-
2296906Smmel * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
3296906Smmel * All rights reserved.
4296906Smmel *
5296906Smmel * Redistribution and use in source and binary forms, with or without
6296906Smmel * modification, are permitted provided that the following conditions
7296906Smmel * are met:
8296906Smmel * 1. Redistributions of source code must retain the above copyright
9296906Smmel *    notice, this list of conditions and the following disclaimer.
10296906Smmel * 2. Redistributions in binary form must reproduce the above copyright
11296906Smmel *    notice, this list of conditions and the following disclaimer in the
12296906Smmel *    documentation and/or other materials provided with the distribution.
13296906Smmel *
14296906Smmel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15296906Smmel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16296906Smmel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17296906Smmel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18296906Smmel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19296906Smmel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20296906Smmel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21296906Smmel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22296906Smmel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23296906Smmel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24296906Smmel * SUCH DAMAGE.
25296906Smmel */
26296906Smmel
27296906Smmel#include <sys/cdefs.h>
28296906Smmel__FBSDID("$FreeBSD: stable/11/sys/dev/extres/regulator/regulator.c 337705 2018-08-13 08:47:54Z mmel $");
29296906Smmel
30296906Smmel#include "opt_platform.h"
31296906Smmel#include <sys/param.h>
32296906Smmel#include <sys/conf.h>
33296906Smmel#include <sys/bus.h>
34296906Smmel#include <sys/kernel.h>
35296906Smmel#include <sys/queue.h>
36296906Smmel#include <sys/kobj.h>
37296906Smmel#include <sys/malloc.h>
38296906Smmel#include <sys/mutex.h>
39296906Smmel#include <sys/limits.h>
40296906Smmel#include <sys/lock.h>
41296906Smmel#include <sys/sysctl.h>
42296906Smmel#include <sys/systm.h>
43296906Smmel#include <sys/sx.h>
44296906Smmel
45296906Smmel#ifdef FDT
46296906Smmel#include <dev/fdt/fdt_common.h>
47296906Smmel#include <dev/ofw/ofw_bus.h>
48296906Smmel#include <dev/ofw/ofw_bus_subr.h>
49296906Smmel#endif
50296906Smmel#include <dev/extres/regulator/regulator.h>
51296906Smmel
52296906Smmel#include "regdev_if.h"
53296906Smmel
54296906SmmelMALLOC_DEFINE(M_REGULATOR, "regulator", "Regulator framework");
55296906Smmel
56308328Smmel#define	DIV_ROUND_UP(n,d) howmany(n, d)
57308328Smmel
58296906Smmel/* Forward declarations. */
59296906Smmelstruct regulator;
60296906Smmelstruct regnode;
61296906Smmel
62296906Smmeltypedef TAILQ_HEAD(regnode_list, regnode) regnode_list_t;
63296906Smmeltypedef TAILQ_HEAD(regulator_list, regulator) regulator_list_t;
64296906Smmel
65296906Smmel/* Default regulator methods. */
66296906Smmelstatic int regnode_method_enable(struct regnode *regnode, bool enable,
67296906Smmel    int *udelay);
68296906Smmelstatic int regnode_method_status(struct regnode *regnode, int *status);
69296906Smmelstatic int regnode_method_set_voltage(struct regnode *regnode, int min_uvolt,
70296906Smmel    int max_uvolt, int *udelay);
71296906Smmelstatic int regnode_method_get_voltage(struct regnode *regnode, int *uvolt);
72296906Smmel
73296906Smmel/*
74296906Smmel * Regulator controller methods.
75296906Smmel */
76296906Smmelstatic regnode_method_t regnode_methods[] = {
77296906Smmel	REGNODEMETHOD(regnode_enable,		regnode_method_enable),
78296906Smmel	REGNODEMETHOD(regnode_status,		regnode_method_status),
79296906Smmel	REGNODEMETHOD(regnode_set_voltage,	regnode_method_set_voltage),
80296906Smmel	REGNODEMETHOD(regnode_get_voltage,	regnode_method_get_voltage),
81296906Smmel
82296906Smmel	REGNODEMETHOD_END
83296906Smmel};
84296906SmmelDEFINE_CLASS_0(regnode, regnode_class, regnode_methods, 0);
85296906Smmel
86296906Smmel/*
87296906Smmel * Regulator node - basic element for modelling SOC and bard power supply
88296906Smmel * chains. Its contains producer data.
89296906Smmel */
90296906Smmelstruct regnode {
91296906Smmel	KOBJ_FIELDS;
92296906Smmel
93296906Smmel	TAILQ_ENTRY(regnode)	reglist_link;	/* Global list entry */
94296906Smmel	regulator_list_t	consumers_list;	/* Consumers list */
95296906Smmel
96296906Smmel	/* Cache for already resolved names */
97296906Smmel	struct regnode		*parent;	/* Resolved parent */
98296906Smmel
99296906Smmel	/* Details of this device. */
100296906Smmel	const char		*name;		/* Globally unique name */
101296906Smmel	const char		*parent_name;	/* Parent name */
102296906Smmel
103296906Smmel	device_t		pdev;		/* Producer device_t */
104296906Smmel	void			*softc;		/* Producer softc */
105296906Smmel	intptr_t		id;		/* Per producer unique id */
106296906Smmel#ifdef FDT
107296906Smmel	 phandle_t 		ofw_node;	/* OFW node of regulator */
108296906Smmel#endif
109296906Smmel	int			flags;		/* REGULATOR_FLAGS_ */
110296906Smmel	struct sx		lock;		/* Lock for this regulator */
111296906Smmel	int			ref_cnt;	/* Reference counter */
112296906Smmel	int			enable_cnt;	/* Enabled counter */
113296906Smmel
114296906Smmel	struct regnode_std_param std_param;	/* Standard parameters */
115296906Smmel};
116296906Smmel
117296906Smmel/*
118296906Smmel * Per consumer data, information about how a consumer is using a regulator
119296906Smmel * node.
120296906Smmel * A pointer to this structure is used as a handle in the consumer interface.
121296906Smmel */
122296906Smmelstruct regulator {
123296906Smmel	device_t		cdev;		/* Consumer device */
124296906Smmel	struct regnode		*regnode;
125296906Smmel	TAILQ_ENTRY(regulator)	link;		/* Consumers list entry */
126296906Smmel
127296906Smmel	int			enable_cnt;
128296906Smmel	int 			min_uvolt;	/* Requested uvolt range */
129296906Smmel	int 			max_uvolt;
130296906Smmel};
131296906Smmel
132296906Smmel/*
133296906Smmel * Regulator names must be system wide unique.
134296906Smmel */
135296906Smmelstatic regnode_list_t regnode_list = TAILQ_HEAD_INITIALIZER(regnode_list);
136296906Smmel
137296906Smmelstatic struct sx		regnode_topo_lock;
138296906SmmelSX_SYSINIT(regulator_topology, &regnode_topo_lock, "Regulator topology lock");
139296906Smmel
140296906Smmel#define REG_TOPO_SLOCK()	sx_slock(&regnode_topo_lock)
141296906Smmel#define REG_TOPO_XLOCK()	sx_xlock(&regnode_topo_lock)
142296906Smmel#define REG_TOPO_UNLOCK()	sx_unlock(&regnode_topo_lock)
143296906Smmel#define REG_TOPO_ASSERT()	sx_assert(&regnode_topo_lock, SA_LOCKED)
144296906Smmel#define REG_TOPO_XASSERT() 	sx_assert(&regnode_topo_lock, SA_XLOCKED)
145296906Smmel
146296906Smmel#define REGNODE_SLOCK(_sc)	sx_slock(&((_sc)->lock))
147296906Smmel#define REGNODE_XLOCK(_sc)	sx_xlock(&((_sc)->lock))
148296906Smmel#define REGNODE_UNLOCK(_sc)	sx_unlock(&((_sc)->lock))
149296906Smmel
150296906Smmel/* ----------------------------------------------------------------------------
151296906Smmel *
152296906Smmel * Default regulator methods for base class.
153296906Smmel *
154296906Smmel */
155296906Smmelstatic int
156296906Smmelregnode_method_enable(struct regnode *regnode, bool enable, int *udelay)
157296906Smmel{
158296906Smmel
159296906Smmel	if (!enable)
160296906Smmel		return (ENXIO);
161296906Smmel
162296906Smmel	*udelay = 0;
163296906Smmel	return (0);
164296906Smmel}
165296906Smmel
166296906Smmelstatic int
167296906Smmelregnode_method_status(struct regnode *regnode, int *status)
168296906Smmel{
169296906Smmel	*status = REGULATOR_STATUS_ENABLED;
170296906Smmel	return (0);
171296906Smmel}
172296906Smmel
173296906Smmelstatic int
174296906Smmelregnode_method_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt,
175296906Smmel    int *udelay)
176296906Smmel{
177296906Smmel
178296906Smmel	if ((min_uvolt > regnode->std_param.max_uvolt) ||
179296906Smmel	    (max_uvolt < regnode->std_param.min_uvolt))
180296906Smmel		return (ERANGE);
181296906Smmel	*udelay = 0;
182296906Smmel	return (0);
183296906Smmel}
184296906Smmel
185296906Smmelstatic int
186296906Smmelregnode_method_get_voltage(struct regnode *regnode, int *uvolt)
187296906Smmel{
188296906Smmel
189296906Smmel	return (regnode->std_param.min_uvolt +
190296906Smmel	    (regnode->std_param.max_uvolt - regnode->std_param.min_uvolt) / 2);
191296906Smmel}
192296906Smmel
193296906Smmel/* ----------------------------------------------------------------------------
194296906Smmel *
195296906Smmel * Internal functions.
196296906Smmel *
197296906Smmel */
198296906Smmel
199296906Smmelstatic struct regnode *
200296906Smmelregnode_find_by_name(const char *name)
201296906Smmel{
202296906Smmel	struct regnode *entry;
203296906Smmel
204296906Smmel	REG_TOPO_ASSERT();
205296906Smmel
206296906Smmel	TAILQ_FOREACH(entry, &regnode_list, reglist_link) {
207296906Smmel		if (strcmp(entry->name, name) == 0)
208296906Smmel			return (entry);
209296906Smmel	}
210296906Smmel	return (NULL);
211296906Smmel}
212296906Smmel
213296906Smmelstatic struct regnode *
214296906Smmelregnode_find_by_id(device_t dev, intptr_t id)
215296906Smmel{
216296906Smmel	struct regnode *entry;
217296906Smmel
218296906Smmel	REG_TOPO_ASSERT();
219296906Smmel
220296906Smmel	TAILQ_FOREACH(entry, &regnode_list, reglist_link) {
221296906Smmel		if ((entry->pdev == dev) && (entry->id ==  id))
222296906Smmel			return (entry);
223296906Smmel	}
224296906Smmel
225296906Smmel	return (NULL);
226296906Smmel}
227296906Smmel
228296906Smmel/*
229296906Smmel * Create and initialize regulator object, but do not register it.
230296906Smmel */
231296906Smmelstruct regnode *
232296906Smmelregnode_create(device_t pdev, regnode_class_t regnode_class,
233296906Smmel    struct regnode_init_def *def)
234296906Smmel{
235296906Smmel	struct regnode *regnode;
236296906Smmel
237296906Smmel	KASSERT(def->name != NULL, ("regulator name is NULL"));
238296906Smmel	KASSERT(def->name[0] != '\0', ("regulator name is empty"));
239296906Smmel
240296906Smmel	REG_TOPO_SLOCK();
241296906Smmel	if (regnode_find_by_name(def->name) != NULL)
242296906Smmel		panic("Duplicated regulator registration: %s\n", def->name);
243296906Smmel	REG_TOPO_UNLOCK();
244296906Smmel
245296906Smmel	/* Create object and initialize it. */
246296906Smmel	regnode = malloc(sizeof(struct regnode), M_REGULATOR,
247296906Smmel	    M_WAITOK | M_ZERO);
248296906Smmel	kobj_init((kobj_t)regnode, (kobj_class_t)regnode_class);
249296906Smmel	sx_init(&regnode->lock, "Regulator node lock");
250296906Smmel
251296906Smmel	/* Allocate softc if required. */
252296906Smmel	if (regnode_class->size > 0) {
253296906Smmel		regnode->softc = malloc(regnode_class->size, M_REGULATOR,
254296906Smmel		    M_WAITOK | M_ZERO);
255296906Smmel	}
256296906Smmel
257296906Smmel
258296906Smmel	/* Copy all strings unless they're flagged as static. */
259296906Smmel	if (def->flags & REGULATOR_FLAGS_STATIC) {
260296906Smmel		regnode->name = def->name;
261296906Smmel		regnode->parent_name = def->parent_name;
262296906Smmel	} else {
263296906Smmel		regnode->name = strdup(def->name, M_REGULATOR);
264296906Smmel		if (def->parent_name != NULL)
265296906Smmel			regnode->parent_name = strdup(def->parent_name,
266296906Smmel			    M_REGULATOR);
267296906Smmel	}
268296906Smmel
269296906Smmel	/* Rest of init. */
270296906Smmel	TAILQ_INIT(&regnode->consumers_list);
271296906Smmel	regnode->id = def->id;
272296906Smmel	regnode->pdev = pdev;
273296906Smmel	regnode->flags = def->flags;
274296906Smmel	regnode->parent = NULL;
275296906Smmel	regnode->std_param = def->std_param;
276296906Smmel#ifdef FDT
277296906Smmel	regnode->ofw_node = def->ofw_node;
278296906Smmel#endif
279296906Smmel
280296906Smmel	return (regnode);
281296906Smmel}
282296906Smmel
283296906Smmel/* Register regulator object. */
284296906Smmelstruct regnode *
285296906Smmelregnode_register(struct regnode *regnode)
286296906Smmel{
287296906Smmel	int rv;
288296906Smmel
289296906Smmel#ifdef FDT
290296906Smmel	if (regnode->ofw_node <= 0)
291296906Smmel		regnode->ofw_node = ofw_bus_get_node(regnode->pdev);
292296906Smmel	if (regnode->ofw_node <= 0)
293296906Smmel		return (NULL);
294296906Smmel#endif
295296906Smmel
296296906Smmel	rv = REGNODE_INIT(regnode);
297296906Smmel	if (rv != 0) {
298296906Smmel		printf("REGNODE_INIT failed: %d\n", rv);
299296906Smmel		return (NULL);
300296906Smmel	}
301296906Smmel
302296906Smmel	REG_TOPO_XLOCK();
303296906Smmel	TAILQ_INSERT_TAIL(&regnode_list, regnode, reglist_link);
304296906Smmel	REG_TOPO_UNLOCK();
305296906Smmel#ifdef FDT
306296906Smmel	OF_device_register_xref(OF_xref_from_node(regnode->ofw_node),
307296906Smmel	    regnode->pdev);
308296906Smmel#endif
309296906Smmel	return (regnode);
310296906Smmel}
311296906Smmel
312296906Smmelstatic int
313296906Smmelregnode_resolve_parent(struct regnode *regnode)
314296906Smmel{
315296906Smmel
316296906Smmel	/* All ready resolved or no parent? */
317296906Smmel	if ((regnode->parent != NULL) ||
318296906Smmel	    (regnode->parent_name == NULL))
319296906Smmel		return (0);
320296906Smmel
321296906Smmel	regnode->parent = regnode_find_by_name(regnode->parent_name);
322296906Smmel	if (regnode->parent == NULL)
323296906Smmel		return (ENODEV);
324296906Smmel	return (0);
325296906Smmel}
326296906Smmel
327296906Smmelstatic void
328296906Smmelregnode_delay(int usec)
329296906Smmel{
330296906Smmel	int ticks;
331296906Smmel
332296906Smmel	if (usec == 0)
333296906Smmel		return;
334296906Smmel	ticks = (usec * hz + 999999) / 1000000;
335296906Smmel
336296906Smmel	if (cold || ticks < 2)
337296906Smmel		DELAY(usec);
338296906Smmel	else
339296906Smmel		pause("REGULATOR", ticks);
340296906Smmel}
341296906Smmel
342296906Smmel/* --------------------------------------------------------------------------
343296906Smmel *
344296906Smmel * Regulator providers interface
345296906Smmel *
346296906Smmel */
347296906Smmel
348296906Smmelconst char *
349296906Smmelregnode_get_name(struct regnode *regnode)
350296906Smmel{
351296906Smmel
352296906Smmel	return (regnode->name);
353296906Smmel}
354296906Smmel
355296906Smmelconst char *
356296906Smmelregnode_get_parent_name(struct regnode *regnode)
357296906Smmel{
358296906Smmel
359296906Smmel	return (regnode->parent_name);
360296906Smmel}
361296906Smmel
362296906Smmelint
363296906Smmelregnode_get_flags(struct regnode *regnode)
364296906Smmel{
365296906Smmel
366296906Smmel	return (regnode->flags);
367296906Smmel}
368296906Smmel
369296906Smmelvoid *
370296906Smmelregnode_get_softc(struct regnode *regnode)
371296906Smmel{
372296906Smmel
373296906Smmel	return (regnode->softc);
374296906Smmel}
375296906Smmel
376296906Smmeldevice_t
377296906Smmelregnode_get_device(struct regnode *regnode)
378296906Smmel{
379296906Smmel
380296906Smmel	return (regnode->pdev);
381296906Smmel}
382296906Smmel
383296906Smmelstruct regnode_std_param *regnode_get_stdparam(struct regnode *regnode)
384296906Smmel{
385296906Smmel
386296906Smmel	return (&regnode->std_param);
387296906Smmel}
388296906Smmel
389296906Smmelvoid regnode_topo_unlock(void)
390296906Smmel{
391296906Smmel
392296906Smmel	REG_TOPO_UNLOCK();
393296906Smmel}
394296906Smmel
395296906Smmelvoid regnode_topo_xlock(void)
396296906Smmel{
397296906Smmel
398296906Smmel	REG_TOPO_XLOCK();
399296906Smmel}
400296906Smmel
401296906Smmelvoid regnode_topo_slock(void)
402296906Smmel{
403296906Smmel
404296906Smmel	REG_TOPO_SLOCK();
405296906Smmel}
406296906Smmel
407296906Smmel
408296906Smmel/* --------------------------------------------------------------------------
409296906Smmel *
410296906Smmel * Real consumers executive
411296906Smmel *
412296906Smmel */
413296906Smmelstruct regnode *
414296906Smmelregnode_get_parent(struct regnode *regnode)
415296906Smmel{
416296906Smmel	int rv;
417296906Smmel
418296906Smmel	REG_TOPO_ASSERT();
419296906Smmel
420296906Smmel	rv = regnode_resolve_parent(regnode);
421296906Smmel	if (rv != 0)
422296906Smmel		return (NULL);
423296906Smmel
424296906Smmel	return (regnode->parent);
425296906Smmel}
426296906Smmel
427296906Smmel/*
428296906Smmel * Enable regulator.
429296906Smmel */
430296906Smmelint
431296906Smmelregnode_enable(struct regnode *regnode)
432296906Smmel{
433296906Smmel	int udelay;
434296906Smmel	int rv;
435296906Smmel
436296906Smmel	REG_TOPO_ASSERT();
437296906Smmel
438296906Smmel	/* Enable regulator for each node in chain, starting from source. */
439296906Smmel	rv = regnode_resolve_parent(regnode);
440296906Smmel	if (rv != 0)
441296906Smmel		return (rv);
442296906Smmel	if (regnode->parent != NULL) {
443296906Smmel		rv = regnode_enable(regnode->parent);
444296906Smmel		if (rv != 0)
445296906Smmel			return (rv);
446296906Smmel	}
447296906Smmel
448296906Smmel	/* Handle this node. */
449296906Smmel	REGNODE_XLOCK(regnode);
450296906Smmel	if (regnode->enable_cnt == 0) {
451296906Smmel		rv = REGNODE_ENABLE(regnode, true, &udelay);
452296906Smmel		if (rv != 0) {
453296906Smmel			REGNODE_UNLOCK(regnode);
454296906Smmel			return (rv);
455296906Smmel		}
456296906Smmel		regnode_delay(udelay);
457296906Smmel	}
458296906Smmel	regnode->enable_cnt++;
459296906Smmel	REGNODE_UNLOCK(regnode);
460296906Smmel	return (0);
461296906Smmel}
462296906Smmel
463296906Smmel/*
464296906Smmel * Disable regulator.
465296906Smmel */
466296906Smmelint
467296906Smmelregnode_disable(struct regnode *regnode)
468296906Smmel{
469296906Smmel	int udelay;
470296906Smmel	int rv;
471296906Smmel
472296906Smmel	REG_TOPO_ASSERT();
473296906Smmel	rv = 0;
474296906Smmel
475296906Smmel	REGNODE_XLOCK(regnode);
476296906Smmel	/* Disable regulator for each node in chain, starting from consumer. */
477296906Smmel	if ((regnode->enable_cnt == 1) &&
478296906Smmel	    ((regnode->flags & REGULATOR_FLAGS_NOT_DISABLE) == 0)) {
479296906Smmel		rv = REGNODE_ENABLE(regnode, false, &udelay);
480296906Smmel		if (rv != 0) {
481296906Smmel			REGNODE_UNLOCK(regnode);
482296906Smmel			return (rv);
483296906Smmel		}
484296906Smmel		regnode_delay(udelay);
485296906Smmel	}
486296906Smmel	regnode->enable_cnt--;
487296906Smmel	REGNODE_UNLOCK(regnode);
488296906Smmel
489296906Smmel	rv = regnode_resolve_parent(regnode);
490296906Smmel	if (rv != 0)
491296906Smmel		return (rv);
492296906Smmel	if (regnode->parent != NULL)
493296906Smmel		rv = regnode_disable(regnode->parent);
494296906Smmel	return (rv);
495296906Smmel}
496296906Smmel
497296906Smmel/*
498296906Smmel * Stop regulator.
499296906Smmel */
500296906Smmelint
501296906Smmelregnode_stop(struct regnode *regnode, int depth)
502296906Smmel{
503296906Smmel	int udelay;
504296906Smmel	int rv;
505296906Smmel
506296906Smmel	REG_TOPO_ASSERT();
507296906Smmel	rv = 0;
508296906Smmel
509296906Smmel	REGNODE_XLOCK(regnode);
510296906Smmel	/* The first node must not be enabled. */
511296906Smmel	if ((regnode->enable_cnt != 0) && (depth == 0)) {
512296906Smmel		REGNODE_UNLOCK(regnode);
513296906Smmel		return (EBUSY);
514296906Smmel	}
515296906Smmel	/* Disable regulator for each node in chain, starting from consumer */
516296906Smmel	if ((regnode->enable_cnt == 0) &&
517296906Smmel	    ((regnode->flags & REGULATOR_FLAGS_NOT_DISABLE) == 0)) {
518337705Smmel		rv = REGNODE_STOP(regnode, &udelay);
519296906Smmel		if (rv != 0) {
520296906Smmel			REGNODE_UNLOCK(regnode);
521296906Smmel			return (rv);
522296906Smmel		}
523296906Smmel		regnode_delay(udelay);
524296906Smmel	}
525296906Smmel	REGNODE_UNLOCK(regnode);
526296906Smmel
527296906Smmel	rv = regnode_resolve_parent(regnode);
528296906Smmel	if (rv != 0)
529296906Smmel		return (rv);
530337705Smmel	if (regnode->parent != NULL && regnode->parent->enable_cnt == 0)
531296906Smmel		rv = regnode_stop(regnode->parent, depth + 1);
532296906Smmel	return (rv);
533296906Smmel}
534296906Smmel
535296906Smmel/*
536296906Smmel * Get regulator status. (REGULATOR_STATUS_*)
537296906Smmel */
538296906Smmelint
539296906Smmelregnode_status(struct regnode *regnode, int *status)
540296906Smmel{
541296906Smmel	int rv;
542296906Smmel
543296906Smmel	REG_TOPO_ASSERT();
544296906Smmel
545296906Smmel	REGNODE_XLOCK(regnode);
546296906Smmel	rv = REGNODE_STATUS(regnode, status);
547296906Smmel	REGNODE_UNLOCK(regnode);
548296906Smmel	return (rv);
549296906Smmel}
550296906Smmel
551296906Smmel/*
552296906Smmel * Get actual regulator voltage.
553296906Smmel */
554296906Smmelint
555296906Smmelregnode_get_voltage(struct regnode *regnode, int *uvolt)
556296906Smmel{
557296906Smmel	int rv;
558296906Smmel
559296906Smmel	REG_TOPO_ASSERT();
560296906Smmel
561296906Smmel	REGNODE_XLOCK(regnode);
562296906Smmel	rv = REGNODE_GET_VOLTAGE(regnode, uvolt);
563296906Smmel	REGNODE_UNLOCK(regnode);
564296906Smmel
565296906Smmel	/* Pass call into parent, if regulator is in bypass mode. */
566296906Smmel	if (rv == ENOENT) {
567296906Smmel		rv = regnode_resolve_parent(regnode);
568296906Smmel		if (rv != 0)
569296906Smmel			return (rv);
570296906Smmel		if (regnode->parent != NULL)
571296906Smmel			rv = regnode_get_voltage(regnode->parent, uvolt);
572296906Smmel
573296906Smmel	}
574296906Smmel	return (rv);
575296906Smmel}
576296906Smmel
577296906Smmel/*
578296906Smmel * Set regulator voltage.
579296906Smmel */
580296906Smmelint
581296906Smmelregnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt)
582296906Smmel{
583296906Smmel	int udelay;
584296906Smmel	int rv;
585296906Smmel
586296906Smmel	REG_TOPO_ASSERT();
587296906Smmel
588296906Smmel	REGNODE_XLOCK(regnode);
589296906Smmel
590296906Smmel	rv = REGNODE_SET_VOLTAGE(regnode, min_uvolt, max_uvolt, &udelay);
591296906Smmel	if (rv == 0)
592296906Smmel		regnode_delay(udelay);
593296906Smmel	REGNODE_UNLOCK(regnode);
594296906Smmel	return (rv);
595296906Smmel}
596296906Smmel
597296906Smmel/*
598296906Smmel * Consumer variant of regnode_set_voltage().
599296906Smmel */
600296906Smmelstatic int
601296906Smmelregnode_set_voltage_checked(struct regnode *regnode, struct regulator *reg,
602296906Smmel    int min_uvolt, int max_uvolt)
603296906Smmel{
604296906Smmel	int udelay;
605296906Smmel	int all_max_uvolt;
606296906Smmel	int all_min_uvolt;
607296906Smmel	struct regulator *tmp;
608296906Smmel	int rv;
609296906Smmel
610296906Smmel	REG_TOPO_ASSERT();
611296906Smmel
612296906Smmel	REGNODE_XLOCK(regnode);
613296906Smmel	/* Return error if requested range is outside of regulator range. */
614296906Smmel	if ((min_uvolt > regnode->std_param.max_uvolt) ||
615296906Smmel	    (max_uvolt < regnode->std_param.min_uvolt)) {
616296906Smmel		REGNODE_UNLOCK(regnode);
617296906Smmel		return (ERANGE);
618296906Smmel	}
619296906Smmel
620296906Smmel	/* Get actual voltage range for all consumers. */
621296906Smmel	all_min_uvolt = regnode->std_param.min_uvolt;
622296906Smmel	all_max_uvolt = regnode->std_param.max_uvolt;
623296906Smmel	TAILQ_FOREACH(tmp, &regnode->consumers_list, link) {
624296906Smmel		/* Don't take requestor in account. */
625296906Smmel		if (tmp == reg)
626296906Smmel			continue;
627296906Smmel		if (all_min_uvolt < tmp->min_uvolt)
628296906Smmel			all_min_uvolt = tmp->min_uvolt;
629296906Smmel		if (all_max_uvolt > tmp->max_uvolt)
630296906Smmel			all_max_uvolt = tmp->max_uvolt;
631296906Smmel	}
632296906Smmel
633296906Smmel	/* Test if request fits to actual contract. */
634296906Smmel	if ((min_uvolt > all_max_uvolt) ||
635296906Smmel	    (max_uvolt < all_min_uvolt)) {
636296906Smmel		REGNODE_UNLOCK(regnode);
637296906Smmel		return (ERANGE);
638296906Smmel	}
639296906Smmel
640296906Smmel	/* Adjust new range.*/
641296906Smmel	if (min_uvolt < all_min_uvolt)
642296906Smmel		min_uvolt = all_min_uvolt;
643296906Smmel	if (max_uvolt > all_max_uvolt)
644296906Smmel		max_uvolt = all_max_uvolt;
645296906Smmel
646296906Smmel	rv = REGNODE_SET_VOLTAGE(regnode, min_uvolt, max_uvolt, &udelay);
647296906Smmel	regnode_delay(udelay);
648296906Smmel	REGNODE_UNLOCK(regnode);
649296906Smmel	return (rv);
650296906Smmel}
651296906Smmel
652296906Smmel#ifdef FDT
653296906Smmelphandle_t
654296906Smmelregnode_get_ofw_node(struct regnode *regnode)
655296906Smmel{
656296906Smmel
657296906Smmel	return (regnode->ofw_node);
658296906Smmel}
659296906Smmel#endif
660296906Smmel
661296906Smmel/* --------------------------------------------------------------------------
662296906Smmel *
663296906Smmel * Regulator consumers interface.
664296906Smmel *
665296906Smmel */
666296906Smmel/* Helper function for regulator_get*() */
667296906Smmelstatic regulator_t
668296906Smmelregulator_create(struct regnode *regnode, device_t cdev)
669296906Smmel{
670296906Smmel	struct regulator *reg;
671296906Smmel
672296906Smmel	REG_TOPO_ASSERT();
673296906Smmel
674296906Smmel	reg =  malloc(sizeof(struct regulator), M_REGULATOR,
675296906Smmel	    M_WAITOK | M_ZERO);
676296906Smmel	reg->cdev = cdev;
677296906Smmel	reg->regnode = regnode;
678296906Smmel	reg->enable_cnt = 0;
679296906Smmel
680296906Smmel	REGNODE_XLOCK(regnode);
681296906Smmel	regnode->ref_cnt++;
682296906Smmel	TAILQ_INSERT_TAIL(&regnode->consumers_list, reg, link);
683296906Smmel	reg ->min_uvolt = regnode->std_param.min_uvolt;
684296906Smmel	reg ->max_uvolt = regnode->std_param.max_uvolt;
685296906Smmel	REGNODE_UNLOCK(regnode);
686296906Smmel
687296906Smmel	return (reg);
688296906Smmel}
689296906Smmel
690296906Smmelint
691296906Smmelregulator_enable(regulator_t reg)
692296906Smmel{
693296906Smmel	int rv;
694296906Smmel	struct regnode *regnode;
695296906Smmel
696296906Smmel	regnode = reg->regnode;
697296906Smmel	KASSERT(regnode->ref_cnt > 0,
698296906Smmel	   ("Attempt to access unreferenced regulator: %s\n", regnode->name));
699296906Smmel	REG_TOPO_SLOCK();
700296906Smmel	rv = regnode_enable(regnode);
701296906Smmel	if (rv == 0)
702296906Smmel		reg->enable_cnt++;
703296906Smmel	REG_TOPO_UNLOCK();
704296906Smmel	return (rv);
705296906Smmel}
706296906Smmel
707296906Smmelint
708296906Smmelregulator_disable(regulator_t reg)
709296906Smmel{
710296906Smmel	int rv;
711296906Smmel	struct regnode *regnode;
712296906Smmel
713296906Smmel	regnode = reg->regnode;
714296906Smmel	KASSERT(regnode->ref_cnt > 0,
715296906Smmel	   ("Attempt to access unreferenced regulator: %s\n", regnode->name));
716296906Smmel	KASSERT(reg->enable_cnt > 0,
717296906Smmel	   ("Attempt to disable already disabled regulator: %s\n",
718296906Smmel	   regnode->name));
719296906Smmel	REG_TOPO_SLOCK();
720296906Smmel	rv = regnode_disable(regnode);
721296906Smmel	if (rv == 0)
722296906Smmel		reg->enable_cnt--;
723296906Smmel	REG_TOPO_UNLOCK();
724296906Smmel	return (rv);
725296906Smmel}
726296906Smmel
727296906Smmelint
728296906Smmelregulator_stop(regulator_t reg)
729296906Smmel{
730296906Smmel	int rv;
731296906Smmel	struct regnode *regnode;
732296906Smmel
733296906Smmel	regnode = reg->regnode;
734296906Smmel	KASSERT(regnode->ref_cnt > 0,
735296906Smmel	   ("Attempt to access unreferenced regulator: %s\n", regnode->name));
736296906Smmel	KASSERT(reg->enable_cnt == 0,
737296906Smmel	   ("Attempt to stop already enabled regulator: %s\n", regnode->name));
738296906Smmel
739296906Smmel	REG_TOPO_SLOCK();
740296906Smmel	rv = regnode_stop(regnode, 0);
741296906Smmel	REG_TOPO_UNLOCK();
742296906Smmel	return (rv);
743296906Smmel}
744296906Smmel
745296906Smmelint
746296906Smmelregulator_status(regulator_t reg, int *status)
747296906Smmel{
748296906Smmel	int rv;
749296906Smmel	struct regnode *regnode;
750296906Smmel
751296906Smmel	regnode = reg->regnode;
752296906Smmel	KASSERT(regnode->ref_cnt > 0,
753296906Smmel	   ("Attempt to access unreferenced regulator: %s\n", regnode->name));
754296906Smmel
755296906Smmel	REG_TOPO_SLOCK();
756296906Smmel	rv = regnode_status(regnode, status);
757296906Smmel	REG_TOPO_UNLOCK();
758296906Smmel	return (rv);
759296906Smmel}
760296906Smmel
761296906Smmelint
762296906Smmelregulator_get_voltage(regulator_t reg, int *uvolt)
763296906Smmel{
764296906Smmel	int rv;
765296906Smmel	struct regnode *regnode;
766296906Smmel
767296906Smmel	regnode = reg->regnode;
768296906Smmel	KASSERT(regnode->ref_cnt > 0,
769296906Smmel	   ("Attempt to access unreferenced regulator: %s\n", regnode->name));
770296906Smmel
771296906Smmel	REG_TOPO_SLOCK();
772296906Smmel	rv = regnode_get_voltage(regnode, uvolt);
773296906Smmel	REG_TOPO_UNLOCK();
774296906Smmel	return (rv);
775296906Smmel}
776296906Smmel
777296906Smmelint
778296906Smmelregulator_set_voltage(regulator_t reg, int min_uvolt, int max_uvolt)
779296906Smmel{
780296906Smmel	struct regnode *regnode;
781296906Smmel	int rv;
782296906Smmel
783296906Smmel	regnode = reg->regnode;
784296906Smmel	KASSERT(regnode->ref_cnt > 0,
785296906Smmel	   ("Attempt to access unreferenced regulator: %s\n", regnode->name));
786296906Smmel
787296906Smmel	REG_TOPO_SLOCK();
788296906Smmel
789296906Smmel	rv = regnode_set_voltage_checked(regnode, reg, min_uvolt, max_uvolt);
790296906Smmel	if (rv == 0) {
791296906Smmel		reg->min_uvolt = min_uvolt;
792296906Smmel		reg->max_uvolt = max_uvolt;
793296906Smmel	}
794296906Smmel	REG_TOPO_UNLOCK();
795296906Smmel	return (rv);
796296906Smmel}
797296906Smmel
798296906Smmelconst char *
799296906Smmelregulator_get_name(regulator_t reg)
800296906Smmel{
801296906Smmel	struct regnode *regnode;
802296906Smmel
803296906Smmel	regnode = reg->regnode;
804296906Smmel	KASSERT(regnode->ref_cnt > 0,
805296906Smmel	   ("Attempt to access unreferenced regulator: %s\n", regnode->name));
806296906Smmel	return (regnode->name);
807296906Smmel}
808296906Smmel
809296906Smmelint
810296906Smmelregulator_get_by_name(device_t cdev, const char *name, regulator_t *reg)
811296906Smmel{
812296906Smmel	struct regnode *regnode;
813296906Smmel
814296906Smmel	REG_TOPO_SLOCK();
815296906Smmel	regnode = regnode_find_by_name(name);
816296906Smmel	if (regnode == NULL) {
817296906Smmel		REG_TOPO_UNLOCK();
818296906Smmel		return (ENODEV);
819296906Smmel	}
820296906Smmel	*reg = regulator_create(regnode, cdev);
821296906Smmel	REG_TOPO_UNLOCK();
822296906Smmel	return (0);
823296906Smmel}
824296906Smmel
825296906Smmelint
826296906Smmelregulator_get_by_id(device_t cdev, device_t pdev, intptr_t id, regulator_t *reg)
827296906Smmel{
828296906Smmel	struct regnode *regnode;
829296906Smmel
830296906Smmel	REG_TOPO_SLOCK();
831296906Smmel
832296906Smmel	regnode = regnode_find_by_id(pdev, id);
833296906Smmel	if (regnode == NULL) {
834296906Smmel		REG_TOPO_UNLOCK();
835296906Smmel		return (ENODEV);
836296906Smmel	}
837296906Smmel	*reg = regulator_create(regnode, cdev);
838296906Smmel	REG_TOPO_UNLOCK();
839296906Smmel
840296906Smmel	return (0);
841296906Smmel}
842296906Smmel
843296906Smmelint
844296906Smmelregulator_release(regulator_t reg)
845296906Smmel{
846296906Smmel	struct regnode *regnode;
847296906Smmel
848296906Smmel	regnode = reg->regnode;
849296906Smmel	KASSERT(regnode->ref_cnt > 0,
850296906Smmel	   ("Attempt to access unreferenced regulator: %s\n", regnode->name));
851296906Smmel	REG_TOPO_SLOCK();
852296906Smmel	while (reg->enable_cnt > 0) {
853296906Smmel		regnode_disable(regnode);
854296906Smmel		reg->enable_cnt--;
855296906Smmel	}
856296906Smmel	REGNODE_XLOCK(regnode);
857296906Smmel	TAILQ_REMOVE(&regnode->consumers_list, reg, link);
858296906Smmel	regnode->ref_cnt--;
859296906Smmel	REGNODE_UNLOCK(regnode);
860296906Smmel	REG_TOPO_UNLOCK();
861296906Smmel
862296906Smmel	free(reg, M_REGULATOR);
863296906Smmel	return (0);
864296906Smmel}
865296906Smmel
866296906Smmel#ifdef FDT
867296906Smmel/* Default DT mapper. */
868296906Smmelint
869296906Smmelregdev_default_ofw_map(device_t dev, phandle_t 	xref, int ncells,
870296906Smmel    pcell_t *cells, intptr_t *id)
871296906Smmel{
872296906Smmel	if (ncells == 0)
873296906Smmel		*id = 1;
874296906Smmel	else if (ncells == 1)
875296906Smmel		*id = cells[0];
876296906Smmel	else
877296906Smmel		return  (ERANGE);
878296906Smmel
879296906Smmel	return (0);
880296906Smmel}
881296906Smmel
882296906Smmelint
883296906Smmelregulator_parse_ofw_stdparam(device_t pdev, phandle_t node,
884296906Smmel    struct regnode_init_def *def)
885296906Smmel{
886296906Smmel	phandle_t supply_xref;
887296906Smmel	struct regnode_std_param *par;
888296906Smmel	int rv;
889296906Smmel
890296906Smmel	par = &def->std_param;
891296906Smmel	rv = OF_getprop_alloc(node, "regulator-name", 1,
892296906Smmel	    (void **)&def->name);
893296906Smmel	if (rv <= 0) {
894296906Smmel		device_printf(pdev, "%s: Missing regulator name\n",
895296906Smmel		 __func__);
896296906Smmel		return (ENXIO);
897296906Smmel	}
898296906Smmel
899296906Smmel	rv = OF_getencprop(node, "regulator-min-microvolt", &par->min_uvolt,
900296906Smmel	    sizeof(par->min_uvolt));
901296906Smmel	if (rv <= 0)
902296906Smmel		par->min_uvolt = 0;
903296906Smmel
904296906Smmel	rv = OF_getencprop(node, "regulator-max-microvolt", &par->max_uvolt,
905296906Smmel	    sizeof(par->max_uvolt));
906296906Smmel	if (rv <= 0)
907296906Smmel		par->max_uvolt = 0;
908296906Smmel
909296906Smmel	rv = OF_getencprop(node, "regulator-min-microamp", &par->min_uamp,
910296906Smmel	    sizeof(par->min_uamp));
911296906Smmel	if (rv <= 0)
912296906Smmel		par->min_uamp = 0;
913296906Smmel
914296906Smmel	rv = OF_getencprop(node, "regulator-max-microamp", &par->max_uamp,
915296906Smmel	    sizeof(par->max_uamp));
916296906Smmel	if (rv <= 0)
917296906Smmel		par->max_uamp = 0;
918296906Smmel
919296906Smmel	rv = OF_getencprop(node, "regulator-ramp-delay", &par->ramp_delay,
920296906Smmel	    sizeof(par->ramp_delay));
921296906Smmel	if (rv <= 0)
922296906Smmel		par->ramp_delay = 0;
923296906Smmel
924296906Smmel	rv = OF_getencprop(node, "regulator-enable-ramp-delay",
925296906Smmel	    &par->enable_delay, sizeof(par->enable_delay));
926296906Smmel	if (rv <= 0)
927296906Smmel		par->enable_delay = 0;
928296906Smmel
929296906Smmel	if (OF_hasprop(node, "regulator-boot-on"))
930296906Smmel		par->boot_on = 1;
931296906Smmel
932296906Smmel	if (OF_hasprop(node, "regulator-always-on"))
933296906Smmel		par->always_on = 1;
934296906Smmel
935296906Smmel	if (OF_hasprop(node, "enable-active-high"))
936296906Smmel		par->enable_active_high = 1;
937296906Smmel
938296906Smmel	rv = OF_getencprop(node, "vin-supply", &supply_xref,
939296906Smmel	    sizeof(supply_xref));
940296906Smmel	if (rv >=  0) {
941296906Smmel		rv = OF_getprop_alloc(supply_xref, "regulator-name", 1,
942296906Smmel		    (void **)&def->parent_name);
943296906Smmel		if (rv <= 0)
944296906Smmel			def->parent_name = NULL;
945296906Smmel	}
946296906Smmel	return (0);
947296906Smmel}
948296906Smmel
949296906Smmelint
950308324Smmelregulator_get_by_ofw_property(device_t cdev, phandle_t cnode, char *name,
951308324Smmel    regulator_t *reg)
952296906Smmel{
953308324Smmel	phandle_t *cells;
954296906Smmel	device_t regdev;
955296906Smmel	int ncells, rv;
956296906Smmel	intptr_t id;
957296906Smmel
958296906Smmel	*reg = NULL;
959296906Smmel
960308324Smmel	if (cnode <= 0)
961308324Smmel		cnode = ofw_bus_get_node(cdev);
962296906Smmel	if (cnode <= 0) {
963296906Smmel		device_printf(cdev, "%s called on not ofw based device\n",
964296906Smmel		 __func__);
965296906Smmel		return (ENXIO);
966296906Smmel	}
967296906Smmel
968296906Smmel	cells = NULL;
969296906Smmel	ncells = OF_getencprop_alloc(cnode, name,  sizeof(*cells),
970296906Smmel	    (void **)&cells);
971296906Smmel	if (ncells <= 0)
972296906Smmel		return (ENXIO);
973296906Smmel
974296906Smmel	/* Translate xref to device */
975296906Smmel	regdev = OF_device_from_xref(cells[0]);
976296906Smmel	if (regdev == NULL) {
977299714Sgonzo		OF_prop_free(cells);
978296906Smmel		return (ENODEV);
979296906Smmel	}
980296906Smmel
981296906Smmel	/* Map regulator to number */
982296906Smmel	rv = REGDEV_MAP(regdev, cells[0], ncells - 1, cells + 1, &id);
983299714Sgonzo	OF_prop_free(cells);
984296906Smmel	if (rv != 0)
985296906Smmel		return (rv);
986296906Smmel	return (regulator_get_by_id(cdev, regdev, id, reg));
987296906Smmel}
988296906Smmel#endif
989308328Smmel
990308328Smmel/* --------------------------------------------------------------------------
991308328Smmel *
992308328Smmel * Regulator utility functions.
993308328Smmel *
994308328Smmel */
995308328Smmel
996308328Smmel/* Convert raw selector value to real voltage */
997308328Smmelint
998308328Smmelregulator_range_sel8_to_volt(struct regulator_range *ranges, int nranges,
999308328Smmel   uint8_t sel, int *volt)
1000308328Smmel{
1001308328Smmel	struct regulator_range *range;
1002308328Smmel	int i;
1003308328Smmel
1004308328Smmel	if (nranges == 0)
1005308328Smmel		panic("Voltage regulator have zero ranges\n");
1006308328Smmel
1007308328Smmel	for (i = 0; i < nranges ; i++) {
1008308328Smmel		range = ranges  + i;
1009308328Smmel
1010308328Smmel		if (!(sel >= range->min_sel &&
1011308328Smmel		      sel <= range->max_sel))
1012308328Smmel			continue;
1013308328Smmel
1014308328Smmel		sel -= range->min_sel;
1015308328Smmel
1016308328Smmel		*volt = range->min_uvolt + sel * range->step_uvolt;
1017308328Smmel		return (0);
1018308328Smmel	}
1019308328Smmel
1020308328Smmel	return (ERANGE);
1021308328Smmel}
1022308328Smmel
1023308328Smmelint
1024308328Smmelregulator_range_volt_to_sel8(struct regulator_range *ranges, int nranges,
1025308328Smmel    int min_uvolt, int max_uvolt, uint8_t *out_sel)
1026308328Smmel{
1027308328Smmel	struct regulator_range *range;
1028308328Smmel	uint8_t sel;
1029308328Smmel	int uvolt;
1030308328Smmel	int rv, i;
1031308328Smmel
1032308328Smmel	if (nranges == 0)
1033308328Smmel		panic("Voltage regulator have zero ranges\n");
1034308328Smmel
1035308328Smmel	for (i = 0; i < nranges; i++) {
1036308328Smmel		range = ranges  + i;
1037308328Smmel		uvolt = range->min_uvolt +
1038308328Smmel		    (range->max_sel - range->min_sel) * range->step_uvolt;
1039308328Smmel
1040308328Smmel		if ((min_uvolt > uvolt) ||
1041308328Smmel		    (max_uvolt < range->min_uvolt))
1042308328Smmel			continue;
1043308328Smmel
1044308328Smmel		if (min_uvolt <= range->min_uvolt)
1045308328Smmel			min_uvolt = range->min_uvolt;
1046308328Smmel
1047308328Smmel		/* if step == 0 -> fixed voltage range. */
1048308328Smmel		if (range->step_uvolt == 0)
1049308328Smmel			sel = 0;
1050308328Smmel		else
1051308328Smmel			sel = DIV_ROUND_UP(min_uvolt - range->min_uvolt,
1052308328Smmel			   range->step_uvolt);
1053308328Smmel
1054308328Smmel
1055308328Smmel		sel += range->min_sel;
1056308328Smmel
1057308328Smmel		break;
1058308328Smmel	}
1059308328Smmel
1060308328Smmel	if (i >= nranges)
1061308328Smmel		return (ERANGE);
1062308328Smmel
1063308328Smmel	/* Verify new settings. */
1064308328Smmel	rv = regulator_range_sel8_to_volt(ranges, nranges, sel, &uvolt);
1065308328Smmel	if (rv != 0)
1066308328Smmel		return (rv);
1067308328Smmel	if ((uvolt < min_uvolt) || (uvolt > max_uvolt))
1068308328Smmel		return (ERANGE);
1069308328Smmel
1070308328Smmel	*out_sel = sel;
1071308328Smmel	return (0);
1072308328Smmel}
1073