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/extres/regulator/regulator_fixed.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 2016 Michal Meloun <mmel@FreeBSD.org>
    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 AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, 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 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include "opt_platform.h"
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/bus.h>
   34 #include <sys/conf.h>
   35 #include <sys/gpio.h>
   36 #include <sys/kernel.h>
   37 #include <sys/kobj.h>
   38 #include <sys/module.h>
   39 #include <sys/mutex.h>
   40 
   41 #ifdef FDT
   42 #include <dev/fdt/fdt_common.h>
   43 #include <dev/ofw/ofw_bus.h>
   44 #include <dev/ofw/ofw_bus_subr.h>
   45 #endif
   46 #include <dev/gpio/gpiobusvar.h>
   47 #include <dev/extres/regulator/regulator_fixed.h>
   48 
   49 #ifdef FDT
   50 #include "regdev_if.h"
   51 #endif
   52 
   53 MALLOC_DEFINE(M_FIXEDREGULATOR, "fixedregulator", "Fixed regulator");
   54 
   55 /* GPIO list for shared pins. */
   56 typedef TAILQ_HEAD(gpio_list, gpio_entry) gpio_list_t;
   57 struct gpio_entry {
   58         TAILQ_ENTRY(gpio_entry) link;
   59         struct gpiobus_pin      gpio_pin;
   60         int                     use_cnt;
   61         int                     enable_cnt;
   62         bool                    always_on;
   63 };
   64 static gpio_list_t gpio_list = TAILQ_HEAD_INITIALIZER(gpio_list);
   65 static struct mtx gpio_list_mtx;
   66 MTX_SYSINIT(gpio_list_lock, &gpio_list_mtx, "Regulator GPIO lock", MTX_DEF);
   67 
   68 struct regnode_fixed_sc {
   69         struct regnode_std_param *param;
   70         bool                    gpio_open_drain;
   71         struct gpio_entry       *gpio_entry;
   72 };
   73 
   74 static int regnode_fixed_init(struct regnode *regnode);
   75 static int regnode_fixed_enable(struct regnode *regnode, bool enable,
   76     int *udelay);
   77 static int regnode_fixed_status(struct regnode *regnode, int *status);
   78 static int regnode_fixed_stop(struct regnode *regnode, int *udelay);
   79 static int regnode_fixed_get_voltage(struct regnode *regnode, int *uvolt);
   80 
   81 static regnode_method_t regnode_fixed_methods[] = {
   82         /* Regulator interface */
   83         REGNODEMETHOD(regnode_init,             regnode_fixed_init),
   84         REGNODEMETHOD(regnode_enable,           regnode_fixed_enable),
   85         REGNODEMETHOD(regnode_status,           regnode_fixed_status),
   86         REGNODEMETHOD(regnode_stop,             regnode_fixed_stop),
   87         REGNODEMETHOD(regnode_get_voltage,      regnode_fixed_get_voltage),
   88         REGNODEMETHOD(regnode_check_voltage,    regnode_method_check_voltage),
   89         REGNODEMETHOD_END
   90 };
   91 DEFINE_CLASS_1(regnode_fixed, regnode_fixed_class, regnode_fixed_methods,
   92    sizeof(struct regnode_fixed_sc), regnode_class);
   93 
   94 /*
   95  * GPIO list functions.
   96  * Two or more regulators can share single GPIO pins, so we must track all
   97  * GPIOs in gpio_list.
   98  * The GPIO pin is registerd and reseved for first consumer, all others share
   99  * gpio_entry with it.
  100  */
  101 static struct gpio_entry *
  102 regnode_get_gpio_entry(struct gpiobus_pin *gpio_pin)
  103 {
  104         struct gpio_entry *entry, *tmp;
  105         device_t busdev;
  106         int rv;
  107 
  108         busdev = GPIO_GET_BUS(gpio_pin->dev);
  109         if (busdev == NULL)
  110                 return (NULL);
  111         entry = malloc(sizeof(struct gpio_entry), M_FIXEDREGULATOR,
  112             M_WAITOK | M_ZERO);
  113 
  114         mtx_lock(&gpio_list_mtx);
  115 
  116         TAILQ_FOREACH(tmp, &gpio_list, link) {
  117                 if (tmp->gpio_pin.dev == gpio_pin->dev &&
  118                     tmp->gpio_pin.pin == gpio_pin->pin) {
  119                         tmp->use_cnt++;
  120                         mtx_unlock(&gpio_list_mtx);
  121                         free(entry, M_FIXEDREGULATOR);
  122                         return (tmp);
  123                 }
  124         }
  125 
  126         /* Reserve pin. */
  127         /* XXX Can we call gpiobus_acquire_pin() with gpio_list_mtx held? */
  128         rv = gpiobus_acquire_pin(busdev, gpio_pin->pin);
  129         if (rv != 0) {
  130                 mtx_unlock(&gpio_list_mtx);
  131                 free(entry, M_FIXEDREGULATOR);
  132                 return (NULL);
  133         }
  134         /* Everything is OK, build new entry and insert it to list. */
  135         entry->gpio_pin = *gpio_pin;
  136         entry->use_cnt = 1;
  137         TAILQ_INSERT_TAIL(&gpio_list, entry, link);
  138 
  139         mtx_unlock(&gpio_list_mtx);
  140         return (entry);
  141 }
  142 
  143 
  144 /*
  145  * Regulator class implementation.
  146  */
  147 static int
  148 regnode_fixed_init(struct regnode *regnode)
  149 {
  150         device_t dev;
  151         struct regnode_fixed_sc *sc;
  152         struct gpiobus_pin *pin;
  153         uint32_t flags;
  154         int rv;
  155 
  156         sc = regnode_get_softc(regnode);
  157         dev = regnode_get_device(regnode);
  158         sc->param = regnode_get_stdparam(regnode);
  159         if (sc->gpio_entry == NULL)
  160                 return (0);
  161         pin = &sc->gpio_entry->gpio_pin;
  162 
  163         flags = GPIO_PIN_OUTPUT;
  164         if (sc->gpio_open_drain)
  165                 flags |= GPIO_PIN_OPENDRAIN;
  166         if (sc->param->boot_on || sc->param->always_on) {
  167                 rv = GPIO_PIN_SET(pin->dev, pin->pin, sc->param->enable_active_high);
  168                 if (rv != 0) {
  169                         device_printf(dev, "Cannot set GPIO pin: %d\n",
  170                             pin->pin);
  171                         return (rv);
  172                 }
  173         }
  174 
  175         rv = GPIO_PIN_SETFLAGS(pin->dev, pin->pin, flags);
  176         if (rv != 0) {
  177                 device_printf(dev, "Cannot configure GPIO pin: %d\n", pin->pin);
  178                 return (rv);
  179         }
  180 
  181         return (0);
  182 }
  183 
  184 /*
  185  * Enable/disable regulator.
  186  * Take shared GPIO pins in account
  187  */
  188 static int
  189 regnode_fixed_enable(struct regnode *regnode, bool enable, int *udelay)
  190 {
  191         device_t dev;
  192         struct regnode_fixed_sc *sc;
  193         struct gpiobus_pin *pin;
  194         int rv;
  195 
  196         sc = regnode_get_softc(regnode);
  197         dev = regnode_get_device(regnode);
  198 
  199         *udelay = 0;
  200         if (sc->gpio_entry == NULL)
  201                 return (0);
  202         pin = &sc->gpio_entry->gpio_pin;
  203         if (enable) {
  204                 sc->gpio_entry->enable_cnt++;
  205                 if (sc->gpio_entry->enable_cnt > 1)
  206                         return (0);
  207         } else {
  208                 KASSERT(sc->gpio_entry->enable_cnt > 0,
  209                     ("Invalid enable count"));
  210                 sc->gpio_entry->enable_cnt--;
  211                 if (sc->gpio_entry->enable_cnt >= 1)
  212                         return (0);
  213         }
  214         if (sc->gpio_entry->always_on && !enable)
  215                 return (0);
  216         if (!sc->param->enable_active_high)
  217                 enable = !enable;
  218         rv = GPIO_PIN_SET(pin->dev, pin->pin, enable);
  219         if (rv != 0) {
  220                 device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin);
  221                 return (rv);
  222         }
  223         *udelay = sc->param->enable_delay;
  224         return (0);
  225 }
  226 
  227 /*
  228  * Stop (physicaly shutdown) regulator.
  229  * Take shared GPIO pins in account
  230  */
  231 static int
  232 regnode_fixed_stop(struct regnode *regnode, int *udelay)
  233 {
  234         device_t dev;
  235         struct regnode_fixed_sc *sc;
  236         struct gpiobus_pin *pin;
  237         int rv;
  238 
  239         sc = regnode_get_softc(regnode);
  240         dev = regnode_get_device(regnode);
  241 
  242         *udelay = 0;
  243         if (sc->gpio_entry == NULL)
  244                 return (0);
  245         if (sc->gpio_entry->always_on)
  246                 return (0);
  247         pin = &sc->gpio_entry->gpio_pin;
  248         if (sc->gpio_entry->enable_cnt > 0) {
  249                 /* Other regulator(s) are enabled. */
  250                 /* XXXX Any diagnostic message? Or error? */
  251                 return (0);
  252         }
  253         rv = GPIO_PIN_SET(pin->dev, pin->pin,
  254             sc->param->enable_active_high ? false: true);
  255         if (rv != 0) {
  256                 device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin);
  257                 return (rv);
  258         }
  259         *udelay = sc->param->enable_delay;
  260         return (0);
  261 }
  262 
  263 static int
  264 regnode_fixed_status(struct regnode *regnode, int *status)
  265 {
  266         struct regnode_fixed_sc *sc;
  267         struct gpiobus_pin *pin;
  268         uint32_t val;
  269         int rv;
  270 
  271         sc = regnode_get_softc(regnode);
  272 
  273         *status = 0;
  274         if (sc->gpio_entry == NULL) {
  275                 *status = REGULATOR_STATUS_ENABLED;
  276                 return (0);
  277         }
  278         pin = &sc->gpio_entry->gpio_pin;
  279 
  280         rv = GPIO_PIN_GET(pin->dev, pin->pin, &val);
  281         if (rv == 0) {
  282                 if (!sc->param->enable_active_high ^ (val != 0))
  283                         *status = REGULATOR_STATUS_ENABLED;
  284         }
  285         return (rv);
  286 }
  287 
  288 static int
  289 regnode_fixed_get_voltage(struct regnode *regnode, int *uvolt)
  290 {
  291         struct regnode_fixed_sc *sc;
  292 
  293         sc = regnode_get_softc(regnode);
  294         *uvolt = sc->param->min_uvolt;
  295         return (0);
  296 }
  297 
  298 int
  299 regnode_fixed_register(device_t dev, struct regnode_fixed_init_def *init_def)
  300 {
  301         struct regnode *regnode;
  302         struct regnode_fixed_sc *sc;
  303 
  304         regnode = regnode_create(dev, &regnode_fixed_class,
  305             &init_def->reg_init_def);
  306         if (regnode == NULL) {
  307                 device_printf(dev, "Cannot create regulator.\n");
  308                 return(ENXIO);
  309         }
  310         sc = regnode_get_softc(regnode);
  311         sc->gpio_open_drain = init_def->gpio_open_drain;
  312         if (init_def->gpio_pin != NULL) {
  313                 sc->gpio_entry = regnode_get_gpio_entry(init_def->gpio_pin);
  314                 if (sc->gpio_entry == NULL)
  315                         return(ENXIO);
  316         }
  317         regnode = regnode_register(regnode);
  318         if (regnode == NULL) {
  319                 device_printf(dev, "Cannot register regulator.\n");
  320                 return(ENXIO);
  321         }
  322 
  323         if (sc->gpio_entry != NULL)
  324                 sc->gpio_entry->always_on |= sc->param->always_on;
  325 
  326         return (0);
  327 }
  328 
  329 /*
  330  * OFW Driver implementation.
  331  */
  332 #ifdef FDT
  333 
  334 struct  regfix_softc
  335 {
  336         device_t                        dev;
  337         bool                            attach_done;
  338         struct regnode_fixed_init_def   init_def;
  339         phandle_t                       gpio_prodxref;
  340         pcell_t                         *gpio_cells;
  341         int                             gpio_ncells;
  342         struct gpiobus_pin              gpio_pin;
  343 };
  344 
  345 static struct ofw_compat_data compat_data[] = {
  346         {"regulator-fixed",             1},
  347         {NULL,                          0},
  348 };
  349 
  350 static int
  351 regfix_get_gpio(struct regfix_softc * sc)
  352 {
  353         device_t busdev;
  354         phandle_t node;
  355 
  356         int rv;
  357 
  358         if (sc->gpio_prodxref == 0)
  359                 return (0);
  360 
  361         node = ofw_bus_get_node(sc->dev);
  362 
  363         /* Test if controller exist. */
  364         sc->gpio_pin.dev = OF_device_from_xref(sc->gpio_prodxref);
  365         if (sc->gpio_pin.dev == NULL)
  366                 return (ENODEV);
  367 
  368         /* Test if GPIO bus already exist. */
  369         busdev = GPIO_GET_BUS(sc->gpio_pin.dev);
  370         if (busdev == NULL)
  371                 return (ENODEV);
  372 
  373         rv = gpio_map_gpios(sc->gpio_pin.dev, node,
  374             OF_node_from_xref(sc->gpio_prodxref), sc->gpio_ncells,
  375             sc->gpio_cells, &(sc->gpio_pin.pin), &(sc->gpio_pin.flags));
  376         if (rv != 0) {
  377                 device_printf(sc->dev, "Cannot map the gpio property.\n");
  378                 return (ENXIO);
  379         }
  380         sc->init_def.gpio_pin = &sc->gpio_pin;
  381         return (0);
  382 }
  383 
  384 static int
  385 regfix_parse_fdt(struct regfix_softc * sc)
  386 {
  387         phandle_t node;
  388         int rv;
  389         struct regnode_init_def *init_def;
  390 
  391         node = ofw_bus_get_node(sc->dev);
  392         init_def = &sc->init_def.reg_init_def;
  393 
  394         rv = regulator_parse_ofw_stdparam(sc->dev, node, init_def);
  395         if (rv != 0) {
  396                 device_printf(sc->dev, "Cannot parse standard parameters.\n");
  397                 return(rv);
  398         }
  399 
  400         if (init_def->std_param.min_uvolt != init_def->std_param.max_uvolt) {
  401                 device_printf(sc->dev, "min_uvolt != max_uvolt\n");
  402                 return (ENXIO);
  403         }
  404         /* Fixed regulator uses 'startup-delay-us' property for enable_delay */
  405         rv = OF_getencprop(node, "startup-delay-us",
  406            &init_def->std_param.enable_delay,
  407            sizeof(init_def->std_param.enable_delay));
  408         if (rv <= 0)
  409                 init_def->std_param.enable_delay = 0;
  410         /* GPIO pin */
  411         if (OF_hasprop(node, "gpio-open-drain"))
  412                 sc->init_def.gpio_open_drain = true;
  413 
  414         if (!OF_hasprop(node, "gpio"))
  415                 return (0);
  416         rv = ofw_bus_parse_xref_list_alloc(node, "gpio", "#gpio-cells", 0,
  417             &sc->gpio_prodxref, &sc->gpio_ncells, &sc->gpio_cells);
  418         if (rv != 0) {
  419                 sc->gpio_prodxref = 0;
  420                 device_printf(sc->dev, "Malformed gpio property\n");
  421                 return (ENXIO);
  422         }
  423         return (0);
  424 }
  425 
  426 static void
  427 regfix_new_pass(device_t dev)
  428 {
  429         struct regfix_softc * sc;
  430         int rv;
  431 
  432         sc = device_get_softc(dev);
  433         bus_generic_new_pass(dev);
  434 
  435         if (sc->attach_done)
  436                 return;
  437 
  438         /* Try to get and configure GPIO. */
  439         rv = regfix_get_gpio(sc);
  440         if (rv != 0)
  441                 return;
  442 
  443         /* Register regulator. */
  444         regnode_fixed_register(sc->dev, &sc->init_def);
  445         sc->attach_done = true;
  446 }
  447 
  448 static int
  449 regfix_probe(device_t dev)
  450 {
  451 
  452         if (!ofw_bus_status_okay(dev))
  453                 return (ENXIO);
  454 
  455         if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
  456                 return (ENXIO);
  457 
  458         device_set_desc(dev, "Fixed Regulator");
  459         return (BUS_PROBE_DEFAULT);
  460 }
  461 
  462 static int
  463 regfix_detach(device_t dev)
  464 {
  465 
  466         /* This device is always present. */
  467         return (EBUSY);
  468 }
  469 
  470 static int
  471 regfix_attach(device_t dev)
  472 {
  473         struct regfix_softc * sc;
  474         int rv;
  475 
  476         sc = device_get_softc(dev);
  477         sc->dev = dev;
  478 
  479         /* Parse FDT data. */
  480         rv = regfix_parse_fdt(sc);
  481         if (rv != 0)
  482                 return(ENXIO);
  483 
  484         /* Fill reset of init. */
  485         sc->init_def.reg_init_def.id = 1;
  486         sc->init_def.reg_init_def.flags = REGULATOR_FLAGS_STATIC;
  487 
  488         /* Try to get and configure GPIO. */
  489         rv = regfix_get_gpio(sc);
  490         if (rv != 0)
  491                 return (bus_generic_attach(dev));
  492 
  493         /* Register regulator. */
  494         regnode_fixed_register(sc->dev, &sc->init_def);
  495         sc->attach_done = true;
  496 
  497         return (bus_generic_attach(dev));
  498 }
  499 
  500 static device_method_t regfix_methods[] = {
  501         /* Device interface */
  502         DEVMETHOD(device_probe,         regfix_probe),
  503         DEVMETHOD(device_attach,        regfix_attach),
  504         DEVMETHOD(device_detach,        regfix_detach),
  505         /* Bus interface */
  506         DEVMETHOD(bus_new_pass,         regfix_new_pass),
  507         /* Regdev interface */
  508         DEVMETHOD(regdev_map,           regdev_default_ofw_map),
  509 
  510         DEVMETHOD_END
  511 };
  512 
  513 DEFINE_CLASS_0(regfix, regfix_driver, regfix_methods,
  514     sizeof(struct regfix_softc));
  515 EARLY_DRIVER_MODULE(regfix, simplebus, regfix_driver, 0, 0, BUS_PASS_BUS);
  516 
  517 #endif /* FDT */

Cache object: 4f0ed2af284218c89054f97c3c29f5cc


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