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

Cache object: eeffe86d2a50ee0383ae903904f45eae


[ 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.