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, ®node_topo_lock, "Regulator topology lock"); 139296906Smmel 140296906Smmel#define REG_TOPO_SLOCK() sx_slock(®node_topo_lock) 141296906Smmel#define REG_TOPO_XLOCK() sx_xlock(®node_topo_lock) 142296906Smmel#define REG_TOPO_UNLOCK() sx_unlock(®node_topo_lock) 143296906Smmel#define REG_TOPO_ASSERT() sx_assert(®node_topo_lock, SA_LOCKED) 144296906Smmel#define REG_TOPO_XASSERT() sx_assert(®node_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, ®node_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, ®node_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(®node->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(®node->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(®node_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 (®node->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, ®node->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(®node->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(®node->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