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: releng/11.0/sys/dev/extres/regulator/regulator_fixed.c 300750 2016-05-26 15:45:36Z ian $"); 29296906Smmel 30296906Smmel#include "opt_platform.h" 31296906Smmel#include <sys/param.h> 32296906Smmel#include <sys/conf.h> 33296906Smmel#include <sys/gpio.h> 34296906Smmel#include <sys/kernel.h> 35296906Smmel#include <sys/kobj.h> 36296906Smmel#include <sys/systm.h> 37296906Smmel#include <sys/module.h> 38296906Smmel#include <sys/mutex.h> 39296906Smmel 40296906Smmel#ifdef FDT 41296906Smmel#include <dev/fdt/fdt_common.h> 42296906Smmel#include <dev/ofw/ofw_bus.h> 43296906Smmel#include <dev/ofw/ofw_bus_subr.h> 44296906Smmel#endif 45296906Smmel#include <dev/gpio/gpiobusvar.h> 46296906Smmel#include <dev/extres/regulator/regulator_fixed.h> 47296906Smmel 48296906Smmel#include "regdev_if.h" 49296906Smmel 50296906SmmelMALLOC_DEFINE(M_FIXEDREGULATOR, "fixedregulator", "Fixed regulator"); 51296906Smmel 52296906Smmel/* GPIO list for shared pins. */ 53296906Smmeltypedef TAILQ_HEAD(gpio_list, gpio_entry) gpio_list_t; 54296906Smmelstruct gpio_entry { 55296906Smmel TAILQ_ENTRY(gpio_entry) link; 56296906Smmel struct gpiobus_pin gpio_pin; 57296906Smmel int use_cnt; 58296906Smmel int enable_cnt; 59296906Smmel}; 60296906Smmelstatic gpio_list_t gpio_list = TAILQ_HEAD_INITIALIZER(gpio_list); 61296906Smmelstatic struct mtx gpio_list_mtx; 62296906SmmelMTX_SYSINIT(gpio_list_lock, &gpio_list_mtx, "Regulator GPIO lock", MTX_DEF); 63296906Smmel 64296906Smmelstruct regnode_fixed_sc { 65296906Smmel struct regnode_std_param *param; 66296906Smmel bool gpio_open_drain; 67296906Smmel struct gpio_entry *gpio_entry; 68296906Smmel}; 69296906Smmel 70296906Smmelstatic int regnode_fixed_init(struct regnode *regnode); 71296906Smmelstatic int regnode_fixed_enable(struct regnode *regnode, bool enable, 72296906Smmel int *udelay); 73296906Smmelstatic int regnode_fixed_status(struct regnode *regnode, int *status); 74296906Smmel 75296906Smmelstatic regnode_method_t regnode_fixed_methods[] = { 76296906Smmel /* Regulator interface */ 77296906Smmel REGNODEMETHOD(regnode_init, regnode_fixed_init), 78296906Smmel REGNODEMETHOD(regnode_enable, regnode_fixed_enable), 79296906Smmel REGNODEMETHOD(regnode_status, regnode_fixed_status), 80296906Smmel REGNODEMETHOD_END 81296906Smmel}; 82296906SmmelDEFINE_CLASS_1(regnode_fixed, regnode_fixed_class, regnode_fixed_methods, 83296906Smmel sizeof(struct regnode_fixed_sc), regnode_class); 84296906Smmel 85296906Smmel/* 86296906Smmel * GPIO list functions. 87296906Smmel * Two or more regulators can share single GPIO pins, so we must track all 88296906Smmel * GPIOs in gpio_list. 89296906Smmel * The GPIO pin is registerd and reseved for first consumer, all others share 90296906Smmel * gpio_entry with it. 91296906Smmel */ 92296906Smmelstatic struct gpio_entry * 93296906Smmelregnode_get_gpio_entry(struct gpiobus_pin *gpio_pin) 94296906Smmel{ 95296906Smmel struct gpio_entry *entry, *tmp; 96296906Smmel device_t busdev; 97296906Smmel int rv; 98296906Smmel 99296906Smmel busdev = GPIO_GET_BUS(gpio_pin->dev); 100296906Smmel if (busdev == NULL) 101296906Smmel return (NULL); 102296906Smmel entry = malloc(sizeof(struct gpio_entry), M_FIXEDREGULATOR, 103296906Smmel M_WAITOK | M_ZERO); 104296906Smmel 105296906Smmel mtx_lock(&gpio_list_mtx); 106296906Smmel 107296906Smmel TAILQ_FOREACH(tmp, &gpio_list, link) { 108296906Smmel if (tmp->gpio_pin.dev == gpio_pin->dev && 109296906Smmel tmp->gpio_pin.pin == gpio_pin->pin) { 110296906Smmel tmp->use_cnt++; 111296906Smmel mtx_unlock(&gpio_list_mtx); 112296906Smmel free(entry, M_FIXEDREGULATOR); 113296906Smmel return (tmp); 114296906Smmel } 115296906Smmel } 116296906Smmel 117296906Smmel /* Reserve pin. */ 118300750Sian /* XXX Can we call gpiobus_acquire_pin() with gpio_list_mtx held? */ 119300750Sian rv = gpiobus_acquire_pin(busdev, gpio_pin->pin); 120296906Smmel if (rv != 0) { 121296906Smmel mtx_unlock(&gpio_list_mtx); 122296906Smmel free(entry, M_FIXEDREGULATOR); 123296906Smmel return (NULL); 124296906Smmel } 125296906Smmel /* Everything is OK, build new entry and insert it to list. */ 126296906Smmel entry->gpio_pin = *gpio_pin; 127296906Smmel entry->use_cnt = 1; 128296906Smmel TAILQ_INSERT_TAIL(&gpio_list, entry, link); 129296906Smmel 130296906Smmel mtx_unlock(&gpio_list_mtx); 131296906Smmel return (entry); 132296906Smmel} 133296906Smmel 134296906Smmel 135296906Smmel/* 136296906Smmel * Regulator class implementation. 137296906Smmel */ 138296906Smmelstatic int 139296906Smmelregnode_fixed_init(struct regnode *regnode) 140296906Smmel{ 141296906Smmel device_t dev; 142296906Smmel struct regnode_fixed_sc *sc; 143296906Smmel struct gpiobus_pin *pin; 144296906Smmel uint32_t flags; 145296906Smmel bool enable; 146296906Smmel int rv; 147296906Smmel 148296906Smmel sc = regnode_get_softc(regnode); 149296906Smmel dev = regnode_get_device(regnode); 150296906Smmel sc->param = regnode_get_stdparam(regnode); 151296906Smmel if (sc->gpio_entry == NULL) 152296906Smmel return (0); 153296906Smmel pin = &sc->gpio_entry->gpio_pin; 154296906Smmel 155296906Smmel flags = GPIO_PIN_OUTPUT; 156296906Smmel if (sc->gpio_open_drain) 157296906Smmel flags |= GPIO_PIN_OPENDRAIN; 158296906Smmel enable = sc->param->boot_on || sc->param->always_on; 159296906Smmel if (!sc->param->enable_active_high) 160296906Smmel enable = !enable; 161296906Smmel rv = GPIO_PIN_SET(pin->dev, pin->pin, enable); 162296906Smmel if (rv != 0) { 163296906Smmel device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin); 164296906Smmel return (rv); 165296906Smmel } 166296906Smmel rv = GPIO_PIN_SETFLAGS(pin->dev, pin->pin, flags); 167296906Smmel if (rv != 0) { 168296906Smmel device_printf(dev, "Cannot configure GPIO pin: %d\n", pin->pin); 169296906Smmel return (rv); 170296906Smmel } 171296906Smmel 172296906Smmel return (0); 173296906Smmel} 174296906Smmel 175296906Smmel/* 176296906Smmel * Enable/disable regulator. 177296906Smmel * Take shared GPIO pins in account 178296906Smmel */ 179296906Smmelstatic int 180296906Smmelregnode_fixed_enable(struct regnode *regnode, bool enable, int *udelay) 181296906Smmel{ 182296906Smmel device_t dev; 183296906Smmel struct regnode_fixed_sc *sc; 184296906Smmel struct gpiobus_pin *pin; 185296906Smmel int rv; 186296906Smmel 187296906Smmel sc = regnode_get_softc(regnode); 188296906Smmel dev = regnode_get_device(regnode); 189296906Smmel 190296906Smmel *udelay = 0; 191296906Smmel if (sc->param->always_on && !enable) 192296906Smmel return (0); 193296906Smmel if (sc->gpio_entry == NULL) 194296906Smmel return (0); 195296906Smmel pin = &sc->gpio_entry->gpio_pin; 196296906Smmel if (enable) { 197296906Smmel sc->gpio_entry->enable_cnt++; 198296906Smmel if (sc->gpio_entry->enable_cnt > 1) 199296906Smmel return (0); 200296906Smmel } else { 201296906Smmel KASSERT(sc->gpio_entry->enable_cnt > 0, 202296906Smmel ("Invalid enable count")); 203296906Smmel sc->gpio_entry->enable_cnt--; 204296906Smmel if (sc->gpio_entry->enable_cnt >= 1) 205296906Smmel return (0); 206296906Smmel } 207296906Smmel if (!sc->param->enable_active_high) 208296906Smmel enable = !enable; 209296906Smmel rv = GPIO_PIN_SET(pin->dev, pin->pin, enable); 210296906Smmel if (rv != 0) { 211296906Smmel device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin); 212296906Smmel return (rv); 213296906Smmel } 214296906Smmel *udelay = sc->param->enable_delay; 215296906Smmel return (0); 216296906Smmel} 217296906Smmel 218296906Smmelstatic int 219296906Smmelregnode_fixed_status(struct regnode *regnode, int *status) 220296906Smmel{ 221296906Smmel struct regnode_fixed_sc *sc; 222296906Smmel struct gpiobus_pin *pin; 223296906Smmel uint32_t val; 224296906Smmel int rv; 225296906Smmel 226296906Smmel sc = regnode_get_softc(regnode); 227296906Smmel 228296906Smmel *status = 0; 229296906Smmel if (sc->gpio_entry == NULL) { 230296906Smmel *status = REGULATOR_STATUS_ENABLED; 231296906Smmel return (0); 232296906Smmel } 233296906Smmel pin = &sc->gpio_entry->gpio_pin; 234296906Smmel 235296906Smmel rv = GPIO_PIN_GET(pin->dev, pin->pin, &val); 236296906Smmel if (rv == 0) { 237296906Smmel if (!sc->param->enable_active_high ^ (val != 0)) 238296906Smmel *status = REGULATOR_STATUS_ENABLED; 239296906Smmel } 240296906Smmel return (rv); 241296906Smmel} 242296906Smmel 243296906Smmelint 244296906Smmelregnode_fixed_register(device_t dev, struct regnode_fixed_init_def *init_def) 245296906Smmel{ 246296906Smmel struct regnode *regnode; 247296906Smmel struct regnode_fixed_sc *sc; 248296906Smmel 249296906Smmel regnode = regnode_create(dev, ®node_fixed_class, 250296906Smmel &init_def->reg_init_def); 251296906Smmel if (regnode == NULL) { 252296906Smmel device_printf(dev, "Cannot create regulator.\n"); 253296906Smmel return(ENXIO); 254296906Smmel } 255296906Smmel sc = regnode_get_softc(regnode); 256296906Smmel sc->gpio_open_drain = init_def->gpio_open_drain; 257296906Smmel if (init_def->gpio_pin != NULL) { 258296906Smmel sc->gpio_entry = regnode_get_gpio_entry(init_def->gpio_pin); 259296906Smmel if (sc->gpio_entry == NULL) 260296906Smmel return(ENXIO); 261296906Smmel } 262296906Smmel regnode = regnode_register(regnode); 263296906Smmel if (regnode == NULL) { 264296906Smmel device_printf(dev, "Cannot register regulator.\n"); 265296906Smmel return(ENXIO); 266296906Smmel } 267296906Smmel return (0); 268296906Smmel} 269296906Smmel 270296906Smmel/* 271296906Smmel * OFW Driver implementation. 272296906Smmel */ 273296906Smmel#ifdef FDT 274296906Smmel 275296906Smmelstruct regfix_softc 276296906Smmel{ 277296906Smmel device_t dev; 278296906Smmel bool attach_done; 279296906Smmel struct regnode_fixed_init_def init_def; 280296906Smmel phandle_t gpio_prodxref; 281296906Smmel pcell_t *gpio_cells; 282296906Smmel int gpio_ncells; 283296906Smmel struct gpiobus_pin gpio_pin; 284296906Smmel}; 285296906Smmel 286296906Smmelstatic struct ofw_compat_data compat_data[] = { 287296906Smmel {"regulator-fixed", 1}, 288296906Smmel {NULL, 0}, 289296906Smmel}; 290296906Smmel 291296906Smmelstatic int 292296906Smmelregfix_get_gpio(struct regfix_softc * sc) 293296906Smmel{ 294296906Smmel device_t busdev; 295296906Smmel phandle_t node; 296296906Smmel 297296906Smmel int rv; 298296906Smmel 299296906Smmel if (sc->gpio_prodxref == 0) 300296906Smmel return (0); 301296906Smmel 302296906Smmel node = ofw_bus_get_node(sc->dev); 303296906Smmel 304296906Smmel /* Test if controller exist. */ 305296906Smmel sc->gpio_pin.dev = OF_device_from_xref(sc->gpio_prodxref); 306296906Smmel if (sc->gpio_pin.dev == NULL) 307296906Smmel return (ENODEV); 308296906Smmel 309296906Smmel /* Test if GPIO bus already exist. */ 310296906Smmel busdev = GPIO_GET_BUS(sc->gpio_pin.dev); 311296906Smmel if (busdev == NULL) 312296906Smmel return (ENODEV); 313296906Smmel 314296906Smmel rv = gpio_map_gpios(sc->gpio_pin.dev, node, 315296906Smmel OF_node_from_xref(sc->gpio_prodxref), sc->gpio_ncells, 316296906Smmel sc->gpio_cells, &(sc->gpio_pin.pin), &(sc->gpio_pin.flags)); 317296906Smmel if (rv != 0) { 318296906Smmel device_printf(sc->dev, "Cannot map the gpio property.\n"); 319296906Smmel return (ENXIO); 320296906Smmel } 321296906Smmel sc->init_def.gpio_pin = &sc->gpio_pin; 322296906Smmel return (0); 323296906Smmel} 324296906Smmel 325296906Smmelstatic int 326296906Smmelregfix_parse_fdt(struct regfix_softc * sc) 327296906Smmel{ 328296906Smmel phandle_t node; 329296906Smmel int rv; 330296906Smmel struct regnode_init_def *init_def; 331296906Smmel 332296906Smmel node = ofw_bus_get_node(sc->dev); 333296906Smmel init_def = &sc->init_def.reg_init_def; 334296906Smmel 335296906Smmel rv = regulator_parse_ofw_stdparam(sc->dev, node, init_def); 336296906Smmel if (rv != 0) { 337296906Smmel device_printf(sc->dev, "Cannot parse standard parameters.\n"); 338296906Smmel return(rv); 339296906Smmel } 340296906Smmel 341296906Smmel /* Fixed regulator uses 'startup-delay-us' property for enable_delay */ 342296906Smmel rv = OF_getencprop(node, "startup-delay-us", 343296906Smmel &init_def->std_param.enable_delay, 344296906Smmel sizeof(init_def->std_param.enable_delay)); 345296906Smmel if (rv <= 0) 346296906Smmel init_def->std_param.enable_delay = 0; 347296906Smmel /* GPIO pin */ 348296906Smmel if (OF_hasprop(node, "gpio-open-drain")) 349296906Smmel sc->init_def.gpio_open_drain = true; 350296906Smmel 351296906Smmel if (!OF_hasprop(node, "gpio")) 352296906Smmel return (0); 353296906Smmel rv = ofw_bus_parse_xref_list_alloc(node, "gpio", "#gpio-cells", 0, 354296906Smmel &sc->gpio_prodxref, &sc->gpio_ncells, &sc->gpio_cells); 355296906Smmel if (rv != 0) { 356296906Smmel sc->gpio_prodxref = 0; 357296906Smmel device_printf(sc->dev, "Malformed gpio property\n"); 358296906Smmel return (ENXIO); 359296906Smmel } 360296906Smmel return (0); 361296906Smmel} 362296906Smmel 363296906Smmelstatic void 364296906Smmelregfix_new_pass(device_t dev) 365296906Smmel{ 366296906Smmel struct regfix_softc * sc; 367296906Smmel int rv; 368296906Smmel 369296906Smmel sc = device_get_softc(dev); 370296906Smmel bus_generic_new_pass(dev); 371296906Smmel 372296906Smmel if (sc->attach_done) 373296906Smmel return; 374296906Smmel 375296906Smmel /* Try to get and configure GPIO. */ 376296906Smmel rv = regfix_get_gpio(sc); 377296906Smmel if (rv != 0) 378296906Smmel return; 379296906Smmel 380296906Smmel /* Register regulator. */ 381296906Smmel regnode_fixed_register(sc->dev, &sc->init_def); 382296906Smmel sc->attach_done = true; 383296906Smmel} 384296906Smmel 385296906Smmelstatic int 386296906Smmelregfix_probe(device_t dev) 387296906Smmel{ 388296906Smmel 389296906Smmel if (!ofw_bus_status_okay(dev)) 390296906Smmel return (ENXIO); 391296906Smmel 392296906Smmel if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 393296906Smmel return (ENXIO); 394296906Smmel 395296906Smmel device_set_desc(dev, "Fixed Regulator"); 396296906Smmel return (BUS_PROBE_DEFAULT); 397296906Smmel} 398296906Smmel 399296906Smmelstatic int 400296906Smmelregfix_detach(device_t dev) 401296906Smmel{ 402296906Smmel 403296906Smmel /* This device is always present. */ 404296906Smmel return (EBUSY); 405296906Smmel} 406296906Smmel 407296906Smmelstatic int 408296906Smmelregfix_attach(device_t dev) 409296906Smmel{ 410296906Smmel struct regfix_softc * sc; 411296906Smmel int rv; 412296906Smmel 413296906Smmel sc = device_get_softc(dev); 414296906Smmel sc->dev = dev; 415296906Smmel 416296906Smmel /* Parse FDT data. */ 417296906Smmel rv = regfix_parse_fdt(sc); 418296906Smmel if (rv != 0) 419296906Smmel return(ENXIO); 420296906Smmel 421296906Smmel /* Fill reset of init. */ 422296906Smmel sc->init_def.reg_init_def.id = 1; 423296906Smmel sc->init_def.reg_init_def.flags = REGULATOR_FLAGS_STATIC; 424296906Smmel 425296906Smmel /* Try to get and configure GPIO. */ 426296906Smmel rv = regfix_get_gpio(sc); 427296906Smmel if (rv != 0) 428296906Smmel return (bus_generic_attach(dev)); 429296906Smmel 430296906Smmel /* Register regulator. */ 431296906Smmel regnode_fixed_register(sc->dev, &sc->init_def); 432296906Smmel sc->attach_done = true; 433296906Smmel 434296906Smmel return (bus_generic_attach(dev)); 435296906Smmel} 436296906Smmel 437296906Smmelstatic device_method_t regfix_methods[] = { 438296906Smmel /* Device interface */ 439296906Smmel DEVMETHOD(device_probe, regfix_probe), 440296906Smmel DEVMETHOD(device_attach, regfix_attach), 441296906Smmel DEVMETHOD(device_detach, regfix_detach), 442296906Smmel /* Bus interface */ 443296906Smmel DEVMETHOD(bus_new_pass, regfix_new_pass), 444296906Smmel /* Regdev interface */ 445296906Smmel DEVMETHOD(regdev_map, regdev_default_ofw_map), 446296906Smmel 447296906Smmel DEVMETHOD_END 448296906Smmel}; 449296906Smmel 450296906Smmelstatic devclass_t regfix_devclass; 451296906SmmelDEFINE_CLASS_0(regfix, regfix_driver, regfix_methods, 452296906Smmel sizeof(struct regfix_softc)); 453296906SmmelEARLY_DRIVER_MODULE(regfix, simplebus, regfix_driver, 454296906Smmel regfix_devclass, 0, 0, BUS_PASS_BUS); 455296906Smmel 456296906Smmel#endif /* FDT */ 457