1*72f1cf04SJared McNeill /*- 2*72f1cf04SJared McNeill * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca> 3*72f1cf04SJared McNeill * All rights reserved. 4*72f1cf04SJared McNeill * 5*72f1cf04SJared McNeill * Redistribution and use in source and binary forms, with or without 6*72f1cf04SJared McNeill * modification, are permitted provided that the following conditions 7*72f1cf04SJared McNeill * are met: 8*72f1cf04SJared McNeill * 1. Redistributions of source code must retain the above copyright 9*72f1cf04SJared McNeill * notice, this list of conditions and the following disclaimer. 10*72f1cf04SJared McNeill * 2. Redistributions in binary form must reproduce the above copyright 11*72f1cf04SJared McNeill * notice, this list of conditions and the following disclaimer in the 12*72f1cf04SJared McNeill * documentation and/or other materials provided with the distribution. 13*72f1cf04SJared McNeill * 14*72f1cf04SJared McNeill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15*72f1cf04SJared McNeill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16*72f1cf04SJared McNeill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17*72f1cf04SJared McNeill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18*72f1cf04SJared McNeill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19*72f1cf04SJared McNeill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20*72f1cf04SJared McNeill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21*72f1cf04SJared McNeill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22*72f1cf04SJared McNeill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*72f1cf04SJared McNeill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*72f1cf04SJared McNeill * SUCH DAMAGE. 25*72f1cf04SJared McNeill * 26*72f1cf04SJared McNeill * $FreeBSD$ 27*72f1cf04SJared McNeill */ 28*72f1cf04SJared McNeill 29*72f1cf04SJared McNeill /* 30*72f1cf04SJared McNeill * GPIO controlled regulators 31*72f1cf04SJared McNeill */ 32*72f1cf04SJared McNeill 33*72f1cf04SJared McNeill #include <sys/cdefs.h> 34*72f1cf04SJared McNeill __FBSDID("$FreeBSD$"); 35*72f1cf04SJared McNeill 36*72f1cf04SJared McNeill #include <sys/param.h> 37*72f1cf04SJared McNeill #include <sys/systm.h> 38*72f1cf04SJared McNeill #include <sys/bus.h> 39*72f1cf04SJared McNeill #include <sys/rman.h> 40*72f1cf04SJared McNeill #include <sys/kernel.h> 41*72f1cf04SJared McNeill #include <sys/module.h> 42*72f1cf04SJared McNeill #include <sys/gpio.h> 43*72f1cf04SJared McNeill 44*72f1cf04SJared McNeill #include <dev/ofw/ofw_bus.h> 45*72f1cf04SJared McNeill #include <dev/ofw/ofw_bus_subr.h> 46*72f1cf04SJared McNeill 47*72f1cf04SJared McNeill #include <dev/gpio/gpiobusvar.h> 48*72f1cf04SJared McNeill 49*72f1cf04SJared McNeill #include <dev/extres/regulator/regulator.h> 50*72f1cf04SJared McNeill 51*72f1cf04SJared McNeill #include "regdev_if.h" 52*72f1cf04SJared McNeill 53*72f1cf04SJared McNeill struct gpioregulator_state { 54*72f1cf04SJared McNeill int val; 55*72f1cf04SJared McNeill uint32_t mask; 56*72f1cf04SJared McNeill }; 57*72f1cf04SJared McNeill 58*72f1cf04SJared McNeill struct gpioregulator_init_def { 59*72f1cf04SJared McNeill struct regnode_init_def reg_init_def; 60*72f1cf04SJared McNeill struct gpiobus_pin *enable_pin; 61*72f1cf04SJared McNeill int enable_pin_valid; 62*72f1cf04SJared McNeill int startup_delay_us; 63*72f1cf04SJared McNeill int nstates; 64*72f1cf04SJared McNeill struct gpioregulator_state *states; 65*72f1cf04SJared McNeill int npins; 66*72f1cf04SJared McNeill struct gpiobus_pin **pins; 67*72f1cf04SJared McNeill }; 68*72f1cf04SJared McNeill 69*72f1cf04SJared McNeill struct gpioregulator_reg_sc { 70*72f1cf04SJared McNeill struct regnode *regnode; 71*72f1cf04SJared McNeill device_t base_dev; 72*72f1cf04SJared McNeill struct regnode_std_param *param; 73*72f1cf04SJared McNeill struct gpioregulator_init_def *def; 74*72f1cf04SJared McNeill }; 75*72f1cf04SJared McNeill 76*72f1cf04SJared McNeill struct gpioregulator_softc { 77*72f1cf04SJared McNeill device_t dev; 78*72f1cf04SJared McNeill struct gpioregulator_reg_sc *reg_sc; 79*72f1cf04SJared McNeill struct gpioregulator_init_def init_def; 80*72f1cf04SJared McNeill }; 81*72f1cf04SJared McNeill 82*72f1cf04SJared McNeill static int 83*72f1cf04SJared McNeill gpioregulator_regnode_init(struct regnode *regnode) 84*72f1cf04SJared McNeill { 85*72f1cf04SJared McNeill struct gpioregulator_reg_sc *sc; 86*72f1cf04SJared McNeill int error, n; 87*72f1cf04SJared McNeill 88*72f1cf04SJared McNeill sc = regnode_get_softc(regnode); 89*72f1cf04SJared McNeill 90*72f1cf04SJared McNeill if (sc->def->enable_pin_valid == 1) { 91*72f1cf04SJared McNeill error = gpio_pin_setflags(sc->def->enable_pin, GPIO_PIN_OUTPUT); 92*72f1cf04SJared McNeill if (error != 0) 93*72f1cf04SJared McNeill return (error); 94*72f1cf04SJared McNeill } 95*72f1cf04SJared McNeill 96*72f1cf04SJared McNeill for (n = 0; n < sc->def->npins; n++) { 97*72f1cf04SJared McNeill error = gpio_pin_setflags(sc->def->pins[n], GPIO_PIN_OUTPUT); 98*72f1cf04SJared McNeill if (error != 0) 99*72f1cf04SJared McNeill return (error); 100*72f1cf04SJared McNeill } 101*72f1cf04SJared McNeill 102*72f1cf04SJared McNeill return (0); 103*72f1cf04SJared McNeill } 104*72f1cf04SJared McNeill 105*72f1cf04SJared McNeill static int 106*72f1cf04SJared McNeill gpioregulator_regnode_enable(struct regnode *regnode, bool enable, int *udelay) 107*72f1cf04SJared McNeill { 108*72f1cf04SJared McNeill struct gpioregulator_reg_sc *sc; 109*72f1cf04SJared McNeill bool active; 110*72f1cf04SJared McNeill int error; 111*72f1cf04SJared McNeill 112*72f1cf04SJared McNeill sc = regnode_get_softc(regnode); 113*72f1cf04SJared McNeill 114*72f1cf04SJared McNeill if (sc->def->enable_pin_valid == 1) { 115*72f1cf04SJared McNeill active = enable; 116*72f1cf04SJared McNeill if (!sc->param->enable_active_high) 117*72f1cf04SJared McNeill active = !active; 118*72f1cf04SJared McNeill error = gpio_pin_set_active(sc->def->enable_pin, active); 119*72f1cf04SJared McNeill if (error != 0) 120*72f1cf04SJared McNeill return (error); 121*72f1cf04SJared McNeill } 122*72f1cf04SJared McNeill 123*72f1cf04SJared McNeill *udelay = sc->def->startup_delay_us; 124*72f1cf04SJared McNeill 125*72f1cf04SJared McNeill return (0); 126*72f1cf04SJared McNeill } 127*72f1cf04SJared McNeill 128*72f1cf04SJared McNeill static int 129*72f1cf04SJared McNeill gpioregulator_regnode_set_voltage(struct regnode *regnode, int min_uvolt, 130*72f1cf04SJared McNeill int max_uvolt, int *udelay) 131*72f1cf04SJared McNeill { 132*72f1cf04SJared McNeill struct gpioregulator_reg_sc *sc; 133*72f1cf04SJared McNeill const struct gpioregulator_state *state; 134*72f1cf04SJared McNeill int error, n; 135*72f1cf04SJared McNeill 136*72f1cf04SJared McNeill sc = regnode_get_softc(regnode); 137*72f1cf04SJared McNeill state = NULL; 138*72f1cf04SJared McNeill 139*72f1cf04SJared McNeill for (n = 0; n < sc->def->nstates; n++) { 140*72f1cf04SJared McNeill if (sc->def->states[n].val >= min_uvolt && 141*72f1cf04SJared McNeill sc->def->states[n].val <= max_uvolt) { 142*72f1cf04SJared McNeill state = &sc->def->states[n]; 143*72f1cf04SJared McNeill break; 144*72f1cf04SJared McNeill } 145*72f1cf04SJared McNeill } 146*72f1cf04SJared McNeill if (state == NULL) 147*72f1cf04SJared McNeill return (EINVAL); 148*72f1cf04SJared McNeill 149*72f1cf04SJared McNeill for (n = 0; n < sc->def->npins; n++) { 150*72f1cf04SJared McNeill error = gpio_pin_set_active(sc->def->pins[n], 151*72f1cf04SJared McNeill (state->mask >> n) & 1); 152*72f1cf04SJared McNeill if (error != 0) 153*72f1cf04SJared McNeill return (error); 154*72f1cf04SJared McNeill } 155*72f1cf04SJared McNeill 156*72f1cf04SJared McNeill *udelay = sc->def->startup_delay_us; 157*72f1cf04SJared McNeill 158*72f1cf04SJared McNeill return (0); 159*72f1cf04SJared McNeill } 160*72f1cf04SJared McNeill 161*72f1cf04SJared McNeill static int 162*72f1cf04SJared McNeill gpioregulator_regnode_get_voltage(struct regnode *regnode, int *uvolt) 163*72f1cf04SJared McNeill { 164*72f1cf04SJared McNeill struct gpioregulator_reg_sc *sc; 165*72f1cf04SJared McNeill uint32_t mask; 166*72f1cf04SJared McNeill int error, n; 167*72f1cf04SJared McNeill bool active; 168*72f1cf04SJared McNeill 169*72f1cf04SJared McNeill sc = regnode_get_softc(regnode); 170*72f1cf04SJared McNeill mask = 0; 171*72f1cf04SJared McNeill 172*72f1cf04SJared McNeill for (n = 0; n < sc->def->npins; n++) { 173*72f1cf04SJared McNeill error = gpio_pin_is_active(sc->def->pins[n], &active); 174*72f1cf04SJared McNeill if (error != 0) 175*72f1cf04SJared McNeill return (error); 176*72f1cf04SJared McNeill mask |= (active << n); 177*72f1cf04SJared McNeill } 178*72f1cf04SJared McNeill 179*72f1cf04SJared McNeill for (n = 0; n < sc->def->nstates; n++) { 180*72f1cf04SJared McNeill if (sc->def->states[n].mask == mask) { 181*72f1cf04SJared McNeill *uvolt = sc->def->states[n].val; 182*72f1cf04SJared McNeill return (0); 183*72f1cf04SJared McNeill } 184*72f1cf04SJared McNeill } 185*72f1cf04SJared McNeill 186*72f1cf04SJared McNeill return (EIO); 187*72f1cf04SJared McNeill } 188*72f1cf04SJared McNeill 189*72f1cf04SJared McNeill static regnode_method_t gpioregulator_regnode_methods[] = { 190*72f1cf04SJared McNeill /* Regulator interface */ 191*72f1cf04SJared McNeill REGNODEMETHOD(regnode_init, gpioregulator_regnode_init), 192*72f1cf04SJared McNeill REGNODEMETHOD(regnode_enable, gpioregulator_regnode_enable), 193*72f1cf04SJared McNeill REGNODEMETHOD(regnode_set_voltage, gpioregulator_regnode_set_voltage), 194*72f1cf04SJared McNeill REGNODEMETHOD(regnode_get_voltage, gpioregulator_regnode_get_voltage), 195*72f1cf04SJared McNeill REGNODEMETHOD_END 196*72f1cf04SJared McNeill }; 197*72f1cf04SJared McNeill DEFINE_CLASS_1(gpioregulator_regnode, gpioregulator_regnode_class, 198*72f1cf04SJared McNeill gpioregulator_regnode_methods, sizeof(struct gpioregulator_reg_sc), 199*72f1cf04SJared McNeill regnode_class); 200*72f1cf04SJared McNeill 201*72f1cf04SJared McNeill static int 202*72f1cf04SJared McNeill gpioregulator_parse_fdt(struct gpioregulator_softc *sc) 203*72f1cf04SJared McNeill { 204*72f1cf04SJared McNeill uint32_t *pstates, mask; 205*72f1cf04SJared McNeill phandle_t node; 206*72f1cf04SJared McNeill ssize_t len; 207*72f1cf04SJared McNeill int error, n; 208*72f1cf04SJared McNeill 209*72f1cf04SJared McNeill node = ofw_bus_get_node(sc->dev); 210*72f1cf04SJared McNeill pstates = NULL; 211*72f1cf04SJared McNeill mask = 0; 212*72f1cf04SJared McNeill 213*72f1cf04SJared McNeill error = regulator_parse_ofw_stdparam(sc->dev, node, 214*72f1cf04SJared McNeill &sc->init_def.reg_init_def); 215*72f1cf04SJared McNeill if (error != 0) 216*72f1cf04SJared McNeill return (error); 217*72f1cf04SJared McNeill 218*72f1cf04SJared McNeill /* "states" property (required) */ 219*72f1cf04SJared McNeill len = OF_getencprop_alloc(node, "states", sizeof(*pstates), 220*72f1cf04SJared McNeill (void **)&pstates); 221*72f1cf04SJared McNeill if (len < 2) { 222*72f1cf04SJared McNeill device_printf(sc->dev, "invalid 'states' property\n"); 223*72f1cf04SJared McNeill error = EINVAL; 224*72f1cf04SJared McNeill goto done; 225*72f1cf04SJared McNeill } 226*72f1cf04SJared McNeill sc->init_def.nstates = len / 2; 227*72f1cf04SJared McNeill sc->init_def.states = malloc(sc->init_def.nstates * 228*72f1cf04SJared McNeill sizeof(*sc->init_def.states), M_DEVBUF, M_WAITOK); 229*72f1cf04SJared McNeill for (n = 0; n < sc->init_def.nstates; n++) { 230*72f1cf04SJared McNeill sc->init_def.states[n].val = pstates[n * 2 + 0]; 231*72f1cf04SJared McNeill sc->init_def.states[n].mask = pstates[n * 2 + 1]; 232*72f1cf04SJared McNeill mask |= sc->init_def.states[n].mask; 233*72f1cf04SJared McNeill } 234*72f1cf04SJared McNeill 235*72f1cf04SJared McNeill /* "startup-delay-us" property (optional) */ 236*72f1cf04SJared McNeill len = OF_getencprop(node, "startup-delay-us", 237*72f1cf04SJared McNeill &sc->init_def.startup_delay_us, 238*72f1cf04SJared McNeill sizeof(sc->init_def.startup_delay_us)); 239*72f1cf04SJared McNeill if (len <= 0) 240*72f1cf04SJared McNeill sc->init_def.startup_delay_us = 0; 241*72f1cf04SJared McNeill 242*72f1cf04SJared McNeill /* "enable-gpio" property (optional) */ 243*72f1cf04SJared McNeill error = gpio_pin_get_by_ofw_property(sc->dev, node, "enable-gpio", 244*72f1cf04SJared McNeill &sc->init_def.enable_pin); 245*72f1cf04SJared McNeill if (error == 0) 246*72f1cf04SJared McNeill sc->init_def.enable_pin_valid = 1; 247*72f1cf04SJared McNeill 248*72f1cf04SJared McNeill /* "gpios" property */ 249*72f1cf04SJared McNeill sc->init_def.npins = 32 - __builtin_clz(mask); 250*72f1cf04SJared McNeill sc->init_def.pins = malloc(sc->init_def.npins * 251*72f1cf04SJared McNeill sizeof(sc->init_def.pins), M_DEVBUF, M_WAITOK); 252*72f1cf04SJared McNeill for (n = 0; n < sc->init_def.npins; n++) { 253*72f1cf04SJared McNeill error = gpio_pin_get_by_ofw_idx(sc->dev, node, n, 254*72f1cf04SJared McNeill &sc->init_def.pins[n]); 255*72f1cf04SJared McNeill if (error != 0) { 256*72f1cf04SJared McNeill device_printf(sc->dev, "cannot get pin %d\n", n); 257*72f1cf04SJared McNeill goto done; 258*72f1cf04SJared McNeill } 259*72f1cf04SJared McNeill } 260*72f1cf04SJared McNeill 261*72f1cf04SJared McNeill done: 262*72f1cf04SJared McNeill if (error != 0) { 263*72f1cf04SJared McNeill for (n = 0; n < sc->init_def.npins; n++) { 264*72f1cf04SJared McNeill if (sc->init_def.pins[n] != NULL) 265*72f1cf04SJared McNeill gpio_pin_release(sc->init_def.pins[n]); 266*72f1cf04SJared McNeill } 267*72f1cf04SJared McNeill 268*72f1cf04SJared McNeill free(sc->init_def.states, M_DEVBUF); 269*72f1cf04SJared McNeill free(sc->init_def.pins, M_DEVBUF); 270*72f1cf04SJared McNeill 271*72f1cf04SJared McNeill } 272*72f1cf04SJared McNeill OF_prop_free(pstates); 273*72f1cf04SJared McNeill 274*72f1cf04SJared McNeill return (error); 275*72f1cf04SJared McNeill } 276*72f1cf04SJared McNeill 277*72f1cf04SJared McNeill static int 278*72f1cf04SJared McNeill gpioregulator_probe(device_t dev) 279*72f1cf04SJared McNeill { 280*72f1cf04SJared McNeill 281*72f1cf04SJared McNeill if (!ofw_bus_is_compatible(dev, "regulator-gpio")) 282*72f1cf04SJared McNeill return (ENXIO); 283*72f1cf04SJared McNeill 284*72f1cf04SJared McNeill device_set_desc(dev, "GPIO controlled regulator"); 285*72f1cf04SJared McNeill return (BUS_PROBE_GENERIC); 286*72f1cf04SJared McNeill } 287*72f1cf04SJared McNeill 288*72f1cf04SJared McNeill static int 289*72f1cf04SJared McNeill gpioregulator_attach(device_t dev) 290*72f1cf04SJared McNeill { 291*72f1cf04SJared McNeill struct gpioregulator_softc *sc; 292*72f1cf04SJared McNeill struct regnode *regnode; 293*72f1cf04SJared McNeill phandle_t node; 294*72f1cf04SJared McNeill int error; 295*72f1cf04SJared McNeill 296*72f1cf04SJared McNeill sc = device_get_softc(dev); 297*72f1cf04SJared McNeill sc->dev = dev; 298*72f1cf04SJared McNeill node = ofw_bus_get_node(dev); 299*72f1cf04SJared McNeill 300*72f1cf04SJared McNeill error = gpioregulator_parse_fdt(sc); 301*72f1cf04SJared McNeill if (error != 0) { 302*72f1cf04SJared McNeill device_printf(dev, "cannot parse parameters\n"); 303*72f1cf04SJared McNeill return (ENXIO); 304*72f1cf04SJared McNeill } 305*72f1cf04SJared McNeill sc->init_def.reg_init_def.id = 1; 306*72f1cf04SJared McNeill sc->init_def.reg_init_def.ofw_node = node; 307*72f1cf04SJared McNeill 308*72f1cf04SJared McNeill regnode = regnode_create(dev, &gpioregulator_regnode_class, 309*72f1cf04SJared McNeill &sc->init_def.reg_init_def); 310*72f1cf04SJared McNeill if (regnode == NULL) { 311*72f1cf04SJared McNeill device_printf(dev, "cannot create regulator\n"); 312*72f1cf04SJared McNeill return (ENXIO); 313*72f1cf04SJared McNeill } 314*72f1cf04SJared McNeill 315*72f1cf04SJared McNeill sc->reg_sc = regnode_get_softc(regnode); 316*72f1cf04SJared McNeill sc->reg_sc->regnode = regnode; 317*72f1cf04SJared McNeill sc->reg_sc->base_dev = dev; 318*72f1cf04SJared McNeill sc->reg_sc->param = regnode_get_stdparam(regnode); 319*72f1cf04SJared McNeill sc->reg_sc->def = &sc->init_def; 320*72f1cf04SJared McNeill 321*72f1cf04SJared McNeill regnode_register(regnode); 322*72f1cf04SJared McNeill 323*72f1cf04SJared McNeill return (0); 324*72f1cf04SJared McNeill } 325*72f1cf04SJared McNeill 326*72f1cf04SJared McNeill 327*72f1cf04SJared McNeill static device_method_t gpioregulator_methods[] = { 328*72f1cf04SJared McNeill /* Device interface */ 329*72f1cf04SJared McNeill DEVMETHOD(device_probe, gpioregulator_probe), 330*72f1cf04SJared McNeill DEVMETHOD(device_attach, gpioregulator_attach), 331*72f1cf04SJared McNeill 332*72f1cf04SJared McNeill /* Regdev interface */ 333*72f1cf04SJared McNeill DEVMETHOD(regdev_map, regdev_default_ofw_map), 334*72f1cf04SJared McNeill 335*72f1cf04SJared McNeill DEVMETHOD_END 336*72f1cf04SJared McNeill }; 337*72f1cf04SJared McNeill 338*72f1cf04SJared McNeill static driver_t gpioregulator_driver = { 339*72f1cf04SJared McNeill "gpioregulator", 340*72f1cf04SJared McNeill gpioregulator_methods, 341*72f1cf04SJared McNeill sizeof(struct gpioregulator_softc), 342*72f1cf04SJared McNeill }; 343*72f1cf04SJared McNeill 344*72f1cf04SJared McNeill static devclass_t gpioregulator_devclass; 345*72f1cf04SJared McNeill 346*72f1cf04SJared McNeill EARLY_DRIVER_MODULE(gpioregulator, simplebus, gpioregulator_driver, 347*72f1cf04SJared McNeill gpioregulator_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); 348*72f1cf04SJared McNeill MODULE_VERSION(gpioregulator, 1); 349