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/iicbus/pmic/act8846_regulator.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/bus.h>
   34 #include <sys/kernel.h>
   35 #include <sys/module.h>
   36 #include <sys/mutex.h>
   37 #include <sys/rman.h>
   38 #include <machine/bus.h>
   39 
   40 #include <dev/iicbus/iiconf.h>
   41 #include <dev/iicbus/iicbus.h>
   42 
   43 #include <dev/ofw/ofw_bus.h>
   44 #include <dev/ofw/ofw_bus_subr.h>
   45 
   46 #include <dev/extres/regulator/regulator.h>
   47 
   48 #include <dev/iicbus/pmic/act8846.h>
   49 
   50 #include "regdev_if.h"
   51 
   52 MALLOC_DEFINE(M_ACT8846_REG, "ACT8846 regulator", "ACT8846 power regulator");
   53 
   54 #if 0
   55 #define dprintf(sc, format, arg...)
   56         device_printf(sc->base_sc->dev, "%s: " format, __func__, arg) */
   57 #else
   58 #define dprintf(sc, format, arg...)
   59 #endif
   60 
   61 enum act8846_reg_id {
   62         ACT8846_REG_ID_REG1,
   63         ACT8846_REG_ID_REG2,
   64         ACT8846_REG_ID_REG3,
   65         ACT8846_REG_ID_REG4,
   66         ACT8846_REG_ID_REG5,
   67         ACT8846_REG_ID_REG6,
   68         ACT8846_REG_ID_REG7,
   69         ACT8846_REG_ID_REG8,
   70         ACT8846_REG_ID_REG9,
   71         ACT8846_REG_ID_REG10,
   72         ACT8846_REG_ID_REG11,
   73         ACT8846_REG_ID_REG12,
   74         ACT8846_REG_ID_REG13,
   75 };
   76 
   77 struct act8846_regdef {
   78         intptr_t                id;             /* ID */
   79         char                    *name;          /* Regulator name */
   80         char                    *supply_name;   /* Source property name */
   81         uint8_t                 enable_reg;
   82         uint8_t                 enable_mask;
   83         uint8_t                 voltage_reg;
   84         uint8_t                 voltage_mask;
   85         struct regulator_range  *ranges;
   86         int                     nranges;
   87 };
   88 struct act8846_softc;
   89 
   90 struct act8846_reg_sc {
   91         struct regnode          *regnode;
   92         struct act8846_softc    *base_sc;
   93         struct act8846_regdef   *def;
   94         phandle_t               xref;
   95         struct regnode_std_param *param;
   96 };
   97 
   98 
   99 static struct regulator_range act8846_ranges[] = {
  100         REG_RANGE_INIT(  0, 23,  600000, 25000),
  101         REG_RANGE_INIT( 24, 47, 1200000, 50000),
  102         REG_RANGE_INIT( 48, 64, 2400000, 100000),
  103 };
  104 
  105 static struct act8846_regdef act8846_regdefs[] = {
  106         {
  107                 .id = ACT8846_REG_ID_REG1,
  108                 .name = "REG1",
  109                 .supply_name = "vp1",
  110                 .enable_reg = ACT8846_REG1_CTRL,
  111                 .enable_mask = ACT8846_CTRL_ENA,
  112         },
  113         {
  114                 .id = ACT8846_REG_ID_REG2,
  115                 .name = "REG2",
  116                 .supply_name = "vp2",
  117                 .enable_reg = ACT8846_REG2_CTRL,
  118                 .enable_mask = ACT8846_CTRL_ENA,
  119                 .voltage_reg = ACT8846_REG2_VSET0,
  120                 .voltage_mask = ACT8846_VSEL_MASK,
  121                 .ranges = act8846_ranges,
  122                 .nranges = nitems(act8846_ranges),
  123         },
  124         {
  125                 .id = ACT8846_REG_ID_REG3,
  126                 .name = "REG3",
  127                 .supply_name = "vp3",
  128                 .enable_reg = ACT8846_REG3_CTRL,
  129                 .enable_mask = ACT8846_CTRL_ENA,
  130                 .voltage_reg = ACT8846_REG3_VSET0,
  131                 .voltage_mask = ACT8846_VSEL_MASK,
  132                 .ranges = act8846_ranges,
  133                 .nranges = nitems(act8846_ranges),
  134         },
  135         {
  136                 .id = ACT8846_REG_ID_REG4,
  137                 .name = "REG4",
  138                 .supply_name = "vp4",
  139                 .enable_reg = ACT8846_REG4_CTRL,
  140                 .enable_mask = ACT8846_CTRL_ENA,
  141                 .voltage_reg = ACT8846_REG4_VSET0,
  142                 .voltage_mask = ACT8846_VSEL_MASK,
  143                 .ranges = act8846_ranges,
  144                 .nranges = nitems(act8846_ranges),
  145         },
  146         {
  147                 .id = ACT8846_REG_ID_REG5,
  148                 .name = "REG5",
  149                 .supply_name = "inl1",
  150                 .enable_reg = ACT8846_REG5_CTRL,
  151                 .enable_mask = ACT8846_CTRL_ENA,
  152                 .voltage_reg = ACT8846_REG5_VSET,
  153                 .voltage_mask = ACT8846_VSEL_MASK,
  154                 .ranges = act8846_ranges,
  155                 .nranges = nitems(act8846_ranges),
  156         },
  157         {
  158                 .id = ACT8846_REG_ID_REG6,
  159                 .name = "REG6",
  160                 .supply_name = "inl1",
  161                 .enable_reg = ACT8846_REG6_CTRL,
  162                 .enable_mask = ACT8846_CTRL_ENA,
  163                 .voltage_reg = ACT8846_REG6_VSET,
  164                 .voltage_mask = ACT8846_VSEL_MASK,
  165                 .ranges = act8846_ranges,
  166                 .nranges = nitems(act8846_ranges),
  167         },
  168         {
  169                 .id = ACT8846_REG_ID_REG7,
  170                 .name = "REG7",
  171                 .supply_name = "inl1",
  172                 .enable_reg = ACT8846_REG7_CTRL,
  173                 .enable_mask = ACT8846_CTRL_ENA,
  174                 .voltage_reg = ACT8846_REG7_VSET,
  175                 .voltage_mask = ACT8846_VSEL_MASK,
  176                 .ranges = act8846_ranges,
  177                 .nranges = nitems(act8846_ranges),
  178         },
  179         {
  180                 .id = ACT8846_REG_ID_REG8,
  181                 .name = "REG8",
  182                 .supply_name = "inl2",
  183                 .enable_reg = ACT8846_REG8_CTRL,
  184                 .enable_mask = ACT8846_CTRL_ENA,
  185                 .voltage_reg = ACT8846_REG8_VSET,
  186                 .voltage_mask = ACT8846_VSEL_MASK,
  187                 .ranges = act8846_ranges,
  188                 .nranges = nitems(act8846_ranges),
  189         },
  190         {
  191                 .id = ACT8846_REG_ID_REG9,
  192                 .name = "REG9",
  193                 .supply_name = "inl2",
  194                 .enable_reg = ACT8846_REG9_CTRL,
  195                 .enable_mask = ACT8846_CTRL_ENA,
  196                 .voltage_reg = ACT8846_REG9_VSET,
  197                 .voltage_mask = ACT8846_VSEL_MASK,
  198                 .ranges = act8846_ranges,
  199                 .nranges = nitems(act8846_ranges),
  200         },
  201         {
  202                 .id = ACT8846_REG_ID_REG10,
  203                 .name = "REG10",
  204                 .supply_name = "inl3",
  205                 .enable_reg = ACT8846_REG10_CTRL,
  206                 .enable_mask = ACT8846_CTRL_ENA,
  207                 .voltage_reg = ACT8846_REG10_VSET,
  208                 .voltage_mask = ACT8846_VSEL_MASK,
  209                 .ranges = act8846_ranges,
  210                 .nranges = nitems(act8846_ranges),
  211         },
  212         {
  213                 .id = ACT8846_REG_ID_REG11,
  214                 .name = "REG11",
  215                 .supply_name = "inl3",
  216                 .enable_reg = ACT8846_REG11_CTRL,
  217                 .enable_mask = ACT8846_CTRL_ENA,
  218                 .voltage_reg = ACT8846_REG11_VSET,
  219                 .voltage_mask = ACT8846_VSEL_MASK,
  220                 .ranges = act8846_ranges,
  221                 .nranges = nitems(act8846_ranges),
  222         },
  223         {
  224                 .id = ACT8846_REG_ID_REG12,
  225                 .name = "REG12",
  226                 .supply_name = "inl3",
  227                 .enable_reg = ACT8846_REG12_CTRL,
  228                 .enable_mask = ACT8846_CTRL_ENA,
  229                 .voltage_reg = ACT8846_REG12_VSET,
  230                 .voltage_mask = ACT8846_VSEL_MASK,
  231                 .ranges = act8846_ranges,
  232                 .nranges = nitems(act8846_ranges),
  233         },
  234         {
  235                 .id = ACT8846_REG_ID_REG13,
  236                 .name = "REG13",
  237                 .supply_name = "inl1",
  238                 .enable_reg = ACT8846_REG13_CTRL,
  239                 .enable_mask = ACT8846_CTRL_ENA,
  240         },
  241 };
  242 
  243 static int
  244 act8846_read_sel(struct act8846_reg_sc *sc, uint8_t *sel)
  245 {
  246         int rv;
  247 
  248         rv = RD1(sc->base_sc, sc->def->voltage_reg, sel);
  249         if (rv != 0)
  250                 return (rv);
  251         *sel &= sc->def->voltage_mask;
  252         *sel >>= ffs(sc->def->voltage_mask) - 1;
  253         return (0);
  254 }
  255 
  256 static int
  257 act8846_write_sel(struct act8846_reg_sc *sc, uint8_t sel)
  258 {
  259         int rv;
  260 
  261         sel <<= ffs(sc->def->voltage_mask) - 1;
  262         sel &= sc->def->voltage_mask;
  263 
  264         rv = RM1(sc->base_sc, sc->def->voltage_reg,
  265             sc->def->voltage_mask, sel);
  266         if (rv != 0)
  267                 return (rv);
  268         return (rv);
  269 }
  270 
  271 static int
  272 act8846_regnode_init(struct regnode *regnode)
  273 {
  274         return (0);
  275 }
  276 
  277 static int
  278 act8846_regnode_enable(struct regnode *regnode, bool enable, int *udelay)
  279 {
  280         struct act8846_reg_sc *sc;
  281         int rv;
  282 
  283         sc = regnode_get_softc(regnode);
  284 
  285         dprintf(sc, "%sabling regulator %s\n",
  286             enable ? "En" : "Dis",
  287             sc->def->name);
  288         rv = RM1(sc->base_sc, sc->def->enable_reg,
  289             sc->def->enable_mask, enable ? sc->def->enable_mask: 0);
  290         *udelay = sc->param->enable_delay;
  291 
  292         return (rv);
  293 }
  294 
  295 static int
  296 act8846_regnode_set_voltage(struct regnode *regnode, int min_uvolt,
  297     int max_uvolt, int *udelay)
  298 {
  299         struct act8846_reg_sc *sc;
  300         uint8_t sel;
  301         int uvolt, rv;
  302 
  303         sc = regnode_get_softc(regnode);
  304 
  305         if (sc->def->ranges == NULL)
  306                 return (ENXIO);
  307 
  308         dprintf(sc, "Setting %s to %d<->%d uvolts\n",
  309             sc->def->name,
  310             min_uvolt,
  311             max_uvolt);
  312         rv = regulator_range_volt_to_sel8(sc->def->ranges, sc->def->nranges,
  313             min_uvolt, max_uvolt, &sel);
  314         if (rv != 0)
  315                 return (rv);
  316         *udelay = sc->param->ramp_delay;
  317         rv = act8846_write_sel(sc, sel);
  318 
  319         act8846_read_sel(sc, &sel);
  320         regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges,
  321             sel, &uvolt);
  322         dprintf(sc, "Regulator %s set to %d uvolt\n", sc->def->name,
  323             uvolt);
  324 
  325         return (rv);
  326 }
  327 
  328 static int
  329 act8846_regnode_get_voltage(struct regnode *regnode, int *uvolt)
  330 {
  331         struct act8846_reg_sc *sc;
  332         uint8_t sel;
  333         int rv;
  334 
  335         sc = regnode_get_softc(regnode);
  336 
  337         if (sc->def->ranges == NULL) {
  338                 if (sc->def->id == ACT8846_REG_ID_REG13) {
  339                         *uvolt = 1800000;
  340                         return (0);
  341                 }
  342                 return (ENXIO);
  343         }
  344 
  345         rv = act8846_read_sel(sc, &sel);
  346         if (rv != 0)
  347                 return (rv);
  348         rv = regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges,
  349             sel, uvolt);
  350         dprintf(sc, "Regulator %s is at %d uvolt\n", sc->def->name,
  351             *uvolt);
  352 
  353         return (rv);
  354 }
  355 
  356 static regnode_method_t act8846_regnode_methods[] = {
  357         /* Regulator interface */
  358         REGNODEMETHOD(regnode_init,             act8846_regnode_init),
  359         REGNODEMETHOD(regnode_enable,           act8846_regnode_enable),
  360         REGNODEMETHOD(regnode_set_voltage,      act8846_regnode_set_voltage),
  361         REGNODEMETHOD(regnode_get_voltage,      act8846_regnode_get_voltage),
  362         REGNODEMETHOD_END
  363 };
  364 DEFINE_CLASS_1(act8846_regnode, act8846_regnode_class, act8846_regnode_methods,
  365     sizeof(struct act8846_reg_sc), regnode_class);
  366 
  367 static int
  368 act8846_fdt_parse(struct act8846_softc *sc, phandle_t pnode, phandle_t node,
  369     struct act8846_regdef *def, struct regnode_init_def *init_def)
  370 {
  371         int rv;
  372         phandle_t supply_node;
  373         char prop_name[64]; /* Maximum OFW property name length. */
  374 
  375         rv = regulator_parse_ofw_stdparam(sc->dev, node, init_def);
  376 
  377         /* Get parent supply. */
  378         if (def->supply_name == NULL)
  379                  return (0);
  380 
  381         snprintf(prop_name, sizeof(prop_name), "%s-supply",
  382             def->supply_name);
  383         rv = OF_getencprop(pnode, prop_name, &supply_node,
  384             sizeof(supply_node));
  385         if (rv <= 0)
  386                 return (rv);
  387         supply_node = OF_node_from_xref(supply_node);
  388         rv = OF_getprop_alloc(supply_node, "regulator-name",
  389             (void **)&init_def->parent_name);
  390         if (rv <= 0)
  391                 init_def->parent_name = NULL;
  392         return (0);
  393 }
  394 
  395 static struct act8846_reg_sc *
  396 act8846_attach(struct act8846_softc *sc, phandle_t pnode, phandle_t node,
  397     struct act8846_regdef *def)
  398 {
  399         struct act8846_reg_sc *reg_sc;
  400         struct regnode_init_def initdef;
  401         struct regnode *regnode;
  402 
  403         memset(&initdef, 0, sizeof(initdef));
  404         if (act8846_fdt_parse(sc, pnode, node, def, &initdef) != 0) {
  405                 device_printf(sc->dev, "cannot parse FDT data for regulator\n");
  406                 return (NULL);
  407         }
  408         initdef.id = def->id;
  409         initdef.ofw_node = node;
  410 
  411         regnode = regnode_create(sc->dev, &act8846_regnode_class, &initdef);
  412         if (regnode == NULL) {
  413                 device_printf(sc->dev, "cannot create regulator\n");
  414                 return (NULL);
  415         }
  416 
  417         reg_sc = regnode_get_softc(regnode);
  418         reg_sc->base_sc = sc;
  419         reg_sc->def = def;
  420         reg_sc->xref = OF_xref_from_node(node);
  421         reg_sc->param = regnode_get_stdparam(regnode);
  422 
  423         regnode_register(regnode);
  424 
  425         if (bootverbose) {
  426                 int volt, rv;
  427                 regnode_topo_slock();
  428                 rv = regnode_get_voltage(regnode, &volt);
  429                 if (rv == ENODEV) {
  430                         device_printf(sc->dev,
  431                            " Regulator %s: parent doesn't exist yet.\n",
  432                            regnode_get_name(regnode));
  433                 } else if (rv != 0) {
  434                         device_printf(sc->dev,
  435                            " Regulator %s: voltage: INVALID!!!\n",
  436                            regnode_get_name(regnode));
  437                 } else {
  438                         device_printf(sc->dev,
  439                             " Regulator %s: voltage: %d uV\n",
  440                             regnode_get_name(regnode), volt);
  441                 }
  442                 regnode_topo_unlock();
  443         }
  444 
  445         return (reg_sc);
  446 }
  447 
  448 
  449 int
  450 act8846_regulator_attach(struct act8846_softc *sc, phandle_t node)
  451 {
  452         struct act8846_reg_sc *reg;
  453         phandle_t child, rnode;
  454         int i;
  455 
  456         rnode = ofw_bus_find_child(node, "regulators");
  457         if (rnode <= 0) {
  458                 device_printf(sc->dev, " Cannot find regulators subnode\n");
  459                 return (ENXIO);
  460         }
  461 
  462         /* ACT8846 specific definitio. */
  463         sc->nregs = nitems(act8846_regdefs);
  464         sc->regs = malloc(sizeof(struct act8846_reg_sc *) * sc->nregs,
  465             M_ACT8846_REG, M_WAITOK | M_ZERO);
  466 
  467 
  468         /* Attach all known regulators if exist in DT. */
  469         for (i = 0; i < sc->nregs; i++) {
  470                 child = ofw_bus_find_child(rnode, act8846_regdefs[i].name);
  471                 if (child == 0) {
  472                         if (bootverbose)
  473                                 device_printf(sc->dev,
  474                                     "Regulator %s missing in DT\n",
  475                                     act8846_regdefs[i].name);
  476                         continue;
  477                 }
  478                 reg = act8846_attach(sc, node, child, act8846_regdefs + i);
  479                 if (reg == NULL) {
  480                         device_printf(sc->dev, "Cannot attach regulator: %s\n",
  481                             act8846_regdefs[i].name);
  482                         return (ENXIO);
  483                 }
  484                 sc->regs[i] = reg;
  485         }
  486         return (0);
  487 }
  488 
  489 int
  490 act8846_regulator_map(device_t dev, phandle_t xref, int ncells,
  491     pcell_t *cells, int *num)
  492 {
  493         struct act8846_softc *sc;
  494         int i;
  495 
  496         sc = device_get_softc(dev);
  497         for (i = 0; i < sc->nregs; i++) {
  498                 if (sc->regs[i] == NULL)
  499                         continue;
  500                 if (sc->regs[i]->xref == xref) {
  501                         *num = sc->regs[i]->def->id;
  502                         return (0);
  503                 }
  504         }
  505         return (ENXIO);
  506 }

Cache object: a2560c4625d715bbcaf8a2936b2e8bc3


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