The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/gpio/gpioregulator.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 96bcdbd904ecbe520ef38aa1e8aab621


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.