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/arm/nvidia/as3722_regulators.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 <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/bus.h>
   33 #include <sys/gpio.h>
   34 #include <sys/kernel.h>
   35 #include <sys/module.h>
   36 #include <sys/malloc.h>
   37 #include <sys/rman.h>
   38 #include <sys/sx.h>
   39 
   40 #include <machine/bus.h>
   41 
   42 #include <dev/extres/regulator/regulator.h>
   43 #include <dev/gpio/gpiobusvar.h>
   44 
   45 #include <dt-bindings/mfd/as3722.h>
   46 
   47 #include "as3722.h"
   48 
   49 MALLOC_DEFINE(M_AS3722_REG, "AS3722 regulator", "AS3722 power regulator");
   50 
   51 #define DIV_ROUND_UP(n,d) howmany(n, d)
   52 
   53 enum as3722_reg_id {
   54         AS3722_REG_ID_SD0,
   55         AS3722_REG_ID_SD1,
   56         AS3722_REG_ID_SD2,
   57         AS3722_REG_ID_SD3,
   58         AS3722_REG_ID_SD4,
   59         AS3722_REG_ID_SD5,
   60         AS3722_REG_ID_SD6,
   61         AS3722_REG_ID_LDO0,
   62         AS3722_REG_ID_LDO1,
   63         AS3722_REG_ID_LDO2,
   64         AS3722_REG_ID_LDO3,
   65         AS3722_REG_ID_LDO4,
   66         AS3722_REG_ID_LDO5,
   67         AS3722_REG_ID_LDO6,
   68         AS3722_REG_ID_LDO7,
   69         AS3722_REG_ID_LDO9,
   70         AS3722_REG_ID_LDO10,
   71         AS3722_REG_ID_LDO11,
   72 };
   73 
   74 /* Regulator HW definition. */
   75 struct reg_def {
   76         intptr_t                id;             /* ID */
   77         char                    *name;          /* Regulator name */
   78         char                    *supply_name;   /* Source property name */
   79         uint8_t                 volt_reg;
   80         uint8_t                 volt_vsel_mask;
   81         uint8_t                 enable_reg;
   82         uint8_t                 enable_mask;
   83         uint8_t                 ext_enable_reg;
   84         uint8_t                 ext_enable_mask;
   85         struct regulator_range  *ranges;
   86         int                     nranges;
   87 };
   88 
   89 struct as3722_reg_sc {
   90         struct regnode          *regnode;
   91         struct as3722_softc     *base_sc;
   92         struct reg_def          *def;
   93         phandle_t               xref;
   94 
   95         struct regnode_std_param *param;
   96         int                     ext_control;
   97         int                     enable_tracking;
   98 
   99         int                     enable_usec;
  100 };
  101 
  102 static struct regulator_range as3722_sd016_ranges[] = {
  103         REG_RANGE_INIT(0x00, 0x00,       0,     0),
  104         REG_RANGE_INIT(0x01, 0x5A,  610000, 10000),
  105 };
  106 
  107 static struct regulator_range as3722_sd0_lv_ranges[] = {
  108         REG_RANGE_INIT(0x00, 0x00,       0,     0),
  109         REG_RANGE_INIT(0x01, 0x6E,  410000, 10000),
  110 };
  111 
  112 static struct regulator_range as3722_sd_ranges[] = {
  113         REG_RANGE_INIT(0x00, 0x00,       0,     0),
  114         REG_RANGE_INIT(0x01, 0x40,  612500, 12500),
  115         REG_RANGE_INIT(0x41, 0x70, 1425000, 25000),
  116         REG_RANGE_INIT(0x71, 0x7F, 2650000, 50000),
  117 };
  118 
  119 static struct regulator_range as3722_ldo3_ranges[] = {
  120         REG_RANGE_INIT(0x00, 0x00,       0,     0),
  121         REG_RANGE_INIT(0x01, 0x2D,  620000, 20000),
  122 };
  123 
  124 static struct regulator_range as3722_ldo_ranges[] = {
  125         REG_RANGE_INIT(0x00, 0x00,       0,     0),
  126         REG_RANGE_INIT(0x01, 0x24,  825000, 25000),
  127         REG_RANGE_INIT(0x40, 0x7F, 1725000, 25000),
  128 };
  129 
  130 static struct reg_def as3722s_def[] = {
  131         {
  132                 .id = AS3722_REG_ID_SD0,
  133                 .name = "sd0",
  134                 .volt_reg = AS3722_SD0_VOLTAGE,
  135                 .volt_vsel_mask = AS3722_SD_VSEL_MASK,
  136                 .enable_reg = AS3722_SD_CONTROL,
  137                 .enable_mask = AS3722_SDN_CTRL(0),
  138                 .ext_enable_reg = AS3722_ENABLE_CTRL1,
  139                 .ext_enable_mask = AS3722_SD0_EXT_ENABLE_MASK,
  140                 .ranges = as3722_sd016_ranges,
  141                 .nranges = nitems(as3722_sd016_ranges),
  142         },
  143         {
  144                 .id = AS3722_REG_ID_SD1,
  145                 .name = "sd1",
  146                 .volt_reg = AS3722_SD1_VOLTAGE,
  147                 .volt_vsel_mask = AS3722_SD_VSEL_MASK,
  148                 .enable_reg = AS3722_SD_CONTROL,
  149                 .enable_mask = AS3722_SDN_CTRL(1),
  150                 .ext_enable_reg = AS3722_ENABLE_CTRL1,
  151                 .ext_enable_mask = AS3722_SD1_EXT_ENABLE_MASK,
  152                 .ranges = as3722_sd_ranges,
  153                 .nranges = nitems(as3722_sd_ranges),
  154         },
  155         {
  156                 .id = AS3722_REG_ID_SD2,
  157                 .name = "sd2",
  158                 .supply_name = "vsup-sd2",
  159                 .volt_reg = AS3722_SD2_VOLTAGE,
  160                 .volt_vsel_mask = AS3722_SD_VSEL_MASK,
  161                 .enable_reg = AS3722_SD_CONTROL,
  162                 .enable_mask = AS3722_SDN_CTRL(2),
  163                 .ext_enable_reg = AS3722_ENABLE_CTRL1,
  164                 .ext_enable_mask = AS3722_SD2_EXT_ENABLE_MASK,
  165                 .ranges = as3722_sd_ranges,
  166                 .nranges = nitems(as3722_sd_ranges),
  167         },
  168         {
  169                 .id = AS3722_REG_ID_SD3,
  170                 .name = "sd3",
  171                 .supply_name = "vsup-sd3",
  172                 .volt_reg = AS3722_SD3_VOLTAGE,
  173                 .volt_vsel_mask = AS3722_SD_VSEL_MASK,
  174                 .enable_reg = AS3722_SD_CONTROL,
  175                 .enable_mask = AS3722_SDN_CTRL(3),
  176                 .ext_enable_reg = AS3722_ENABLE_CTRL1,
  177                 .ext_enable_mask = AS3722_SD3_EXT_ENABLE_MASK,
  178                 .ranges = as3722_sd_ranges,
  179                 .nranges = nitems(as3722_sd_ranges),
  180         },
  181         {
  182                 .id = AS3722_REG_ID_SD4,
  183                 .name = "sd4",
  184                 .supply_name = "vsup-sd4",
  185                 .volt_reg = AS3722_SD4_VOLTAGE,
  186                 .volt_vsel_mask = AS3722_SD_VSEL_MASK,
  187                 .enable_reg = AS3722_SD_CONTROL,
  188                 .enable_mask = AS3722_SDN_CTRL(4),
  189                 .ext_enable_reg = AS3722_ENABLE_CTRL2,
  190                 .ext_enable_mask = AS3722_SD4_EXT_ENABLE_MASK,
  191                 .ranges = as3722_sd_ranges,
  192                 .nranges = nitems(as3722_sd_ranges),
  193         },
  194         {
  195                 .id = AS3722_REG_ID_SD5,
  196                 .name = "sd5",
  197                 .supply_name = "vsup-sd5",
  198                 .volt_reg = AS3722_SD5_VOLTAGE,
  199                 .volt_vsel_mask = AS3722_SD_VSEL_MASK,
  200                 .enable_reg = AS3722_SD_CONTROL,
  201                 .enable_mask = AS3722_SDN_CTRL(5),
  202                 .ext_enable_reg = AS3722_ENABLE_CTRL2,
  203                 .ext_enable_mask = AS3722_SD5_EXT_ENABLE_MASK,
  204                 .ranges = as3722_sd_ranges,
  205                 .nranges = nitems(as3722_sd_ranges),
  206         },
  207         {
  208                 .id = AS3722_REG_ID_SD6,
  209                 .name = "sd6",
  210                 .volt_reg = AS3722_SD6_VOLTAGE,
  211                 .volt_vsel_mask = AS3722_SD_VSEL_MASK,
  212                 .enable_reg = AS3722_SD_CONTROL,
  213                 .enable_mask = AS3722_SDN_CTRL(6),
  214                 .ext_enable_reg = AS3722_ENABLE_CTRL2,
  215                 .ext_enable_mask = AS3722_SD6_EXT_ENABLE_MASK,
  216                 .ranges = as3722_sd016_ranges,
  217                 .nranges = nitems(as3722_sd016_ranges),
  218         },
  219         {
  220                 .id = AS3722_REG_ID_LDO0,
  221                 .name = "ldo0",
  222                 .supply_name = "vin-ldo0",
  223                 .volt_reg = AS3722_LDO0_VOLTAGE,
  224                 .volt_vsel_mask = AS3722_LDO0_VSEL_MASK,
  225                 .enable_reg = AS3722_LDO_CONTROL0,
  226                 .enable_mask = AS3722_LDO0_CTRL,
  227                 .ext_enable_reg = AS3722_ENABLE_CTRL3,
  228                 .ext_enable_mask = AS3722_LDO0_EXT_ENABLE_MASK,
  229                 .ranges = as3722_ldo_ranges,
  230                 .nranges = nitems(as3722_ldo_ranges),
  231         },
  232         {
  233                 .id = AS3722_REG_ID_LDO1,
  234                 .name = "ldo1",
  235                 .supply_name = "vin-ldo1-6",
  236                 .volt_reg = AS3722_LDO1_VOLTAGE,
  237                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
  238                 .enable_reg = AS3722_LDO_CONTROL0,
  239                 .enable_mask = AS3722_LDO1_CTRL,
  240                 .ext_enable_reg = AS3722_ENABLE_CTRL3,
  241                 .ext_enable_mask = AS3722_LDO1_EXT_ENABLE_MASK,
  242                 .ranges = as3722_ldo_ranges,
  243                 .nranges = nitems(as3722_ldo_ranges),
  244         },
  245         {
  246                 .id = AS3722_REG_ID_LDO2,
  247                 .name = "ldo2",
  248                 .supply_name = "vin-ldo2-5-7",
  249                 .volt_reg = AS3722_LDO2_VOLTAGE,
  250                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
  251                 .enable_reg = AS3722_LDO_CONTROL0,
  252                 .enable_mask = AS3722_LDO2_CTRL,
  253                 .ext_enable_reg = AS3722_ENABLE_CTRL3,
  254                 .ext_enable_mask = AS3722_LDO2_EXT_ENABLE_MASK,
  255                 .ranges = as3722_ldo_ranges,
  256                 .nranges = nitems(as3722_ldo_ranges),
  257         },
  258         {
  259                 .id = AS3722_REG_ID_LDO3,
  260                 .name = "ldo3",
  261                 .supply_name = "vin-ldo3-4",
  262                 .volt_reg = AS3722_LDO3_VOLTAGE,
  263                 .volt_vsel_mask = AS3722_LDO3_VSEL_MASK,
  264                 .enable_reg = AS3722_LDO_CONTROL0,
  265                 .enable_mask = AS3722_LDO3_CTRL,
  266                 .ext_enable_reg = AS3722_ENABLE_CTRL3,
  267                 .ext_enable_mask = AS3722_LDO3_EXT_ENABLE_MASK,
  268                 .ranges = as3722_ldo3_ranges,
  269                 .nranges = nitems(as3722_ldo3_ranges),
  270         },
  271         {
  272                 .id = AS3722_REG_ID_LDO4,
  273                 .name = "ldo4",
  274                 .supply_name = "vin-ldo3-4",
  275                 .volt_reg = AS3722_LDO4_VOLTAGE,
  276                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
  277                 .enable_reg = AS3722_LDO_CONTROL0,
  278                 .enable_mask = AS3722_LDO4_CTRL,
  279                 .ext_enable_reg = AS3722_ENABLE_CTRL4,
  280                 .ext_enable_mask = AS3722_LDO4_EXT_ENABLE_MASK,
  281                 .ranges = as3722_ldo_ranges,
  282                 .nranges = nitems(as3722_ldo_ranges),
  283         },
  284         {
  285                 .id = AS3722_REG_ID_LDO5,
  286                 .name = "ldo5",
  287                 .supply_name = "vin-ldo2-5-7",
  288                 .volt_reg = AS3722_LDO5_VOLTAGE,
  289                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
  290                 .enable_reg = AS3722_LDO_CONTROL0,
  291                 .enable_mask = AS3722_LDO5_CTRL,
  292                 .ext_enable_reg = AS3722_ENABLE_CTRL4,
  293                 .ext_enable_mask = AS3722_LDO5_EXT_ENABLE_MASK,
  294                 .ranges = as3722_ldo_ranges,
  295                 .nranges = nitems(as3722_ldo_ranges),
  296         },
  297         {
  298                 .id = AS3722_REG_ID_LDO6,
  299                 .name = "ldo6",
  300                 .supply_name = "vin-ldo1-6",
  301                 .volt_reg = AS3722_LDO6_VOLTAGE,
  302                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
  303                 .enable_reg = AS3722_LDO_CONTROL0,
  304                 .enable_mask = AS3722_LDO6_CTRL,
  305                 .ext_enable_reg = AS3722_ENABLE_CTRL4,
  306                 .ext_enable_mask = AS3722_LDO6_EXT_ENABLE_MASK,
  307                 .ranges = as3722_ldo_ranges,
  308                 .nranges = nitems(as3722_ldo_ranges),
  309         },
  310         {
  311                 .id = AS3722_REG_ID_LDO7,
  312                 .name = "ldo7",
  313                 .supply_name = "vin-ldo2-5-7",
  314                 .volt_reg = AS3722_LDO7_VOLTAGE,
  315                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
  316                 .enable_reg = AS3722_LDO_CONTROL0,
  317                 .enable_mask = AS3722_LDO7_CTRL,
  318                 .ext_enable_reg = AS3722_ENABLE_CTRL4,
  319                 .ext_enable_mask = AS3722_LDO7_EXT_ENABLE_MASK,
  320                 .ranges = as3722_ldo_ranges,
  321                 .nranges = nitems(as3722_ldo_ranges),
  322         },
  323         {
  324                 .id = AS3722_REG_ID_LDO9,
  325                 .name = "ldo9",
  326                 .supply_name = "vin-ldo9-10",
  327                 .volt_reg = AS3722_LDO9_VOLTAGE,
  328                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
  329                 .enable_reg = AS3722_LDO_CONTROL1,
  330                 .enable_mask = AS3722_LDO9_CTRL,
  331                 .ext_enable_reg = AS3722_ENABLE_CTRL5,
  332                 .ext_enable_mask = AS3722_LDO9_EXT_ENABLE_MASK,
  333                 .ranges = as3722_ldo_ranges,
  334                 .nranges = nitems(as3722_ldo_ranges),
  335         },
  336         {
  337                 .id = AS3722_REG_ID_LDO10,
  338                 .name = "ldo10",
  339                 .supply_name = "vin-ldo9-10",
  340                 .volt_reg = AS3722_LDO10_VOLTAGE,
  341                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
  342                 .enable_reg = AS3722_LDO_CONTROL1,
  343                 .enable_mask = AS3722_LDO10_CTRL,
  344                 .ext_enable_reg = AS3722_ENABLE_CTRL5,
  345                 .ext_enable_mask = AS3722_LDO10_EXT_ENABLE_MASK,
  346                 .ranges = as3722_ldo_ranges,
  347                 .nranges = nitems(as3722_ldo_ranges),
  348         },
  349         {
  350                 .id = AS3722_REG_ID_LDO11,
  351                 .name = "ldo11",
  352                 .supply_name = "vin-ldo11",
  353                 .volt_reg = AS3722_LDO11_VOLTAGE,
  354                 .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
  355                 .enable_reg = AS3722_LDO_CONTROL1,
  356                 .enable_mask = AS3722_LDO11_CTRL,
  357                 .ext_enable_reg = AS3722_ENABLE_CTRL5,
  358                 .ext_enable_mask = AS3722_LDO11_EXT_ENABLE_MASK,
  359                 .ranges = as3722_ldo_ranges,
  360                 .nranges = nitems(as3722_ldo_ranges),
  361         },
  362 };
  363 
  364 struct as3722_regnode_init_def {
  365         struct regnode_init_def reg_init_def;
  366         int                     ext_control;
  367         int                     enable_tracking;
  368 };
  369 
  370 static int as3722_regnode_init(struct regnode *regnode);
  371 static int as3722_regnode_enable(struct regnode *regnode, bool enable,
  372     int *udelay);
  373 static int as3722_regnode_set_volt(struct regnode *regnode, int min_uvolt,
  374     int max_uvolt, int *udelay);
  375 static int as3722_regnode_get_volt(struct regnode *regnode, int *uvolt);
  376 static regnode_method_t as3722_regnode_methods[] = {
  377         /* Regulator interface */
  378         REGNODEMETHOD(regnode_init,             as3722_regnode_init),
  379         REGNODEMETHOD(regnode_enable,           as3722_regnode_enable),
  380         REGNODEMETHOD(regnode_set_voltage,      as3722_regnode_set_volt),
  381         REGNODEMETHOD(regnode_get_voltage,      as3722_regnode_get_volt),
  382         REGNODEMETHOD_END
  383 };
  384 DEFINE_CLASS_1(as3722_regnode, as3722_regnode_class, as3722_regnode_methods,
  385    sizeof(struct as3722_reg_sc), regnode_class);
  386 
  387 static int
  388 as3722_read_sel(struct as3722_reg_sc *sc, uint8_t *sel)
  389 {
  390         int rv;
  391 
  392         rv = RD1(sc->base_sc, sc->def->volt_reg, sel);
  393         if (rv != 0)
  394                 return (rv);
  395         *sel &= sc->def->volt_vsel_mask;
  396         *sel >>= ffs(sc->def->volt_vsel_mask) - 1;
  397         return (0);
  398 }
  399 
  400 static int
  401 as3722_write_sel(struct as3722_reg_sc *sc, uint8_t sel)
  402 {
  403         int rv;
  404 
  405         sel <<= ffs(sc->def->volt_vsel_mask) - 1;
  406         sel &= sc->def->volt_vsel_mask;
  407 
  408         rv = RM1(sc->base_sc, sc->def->volt_reg,
  409             sc->def->volt_vsel_mask, sel);
  410         if (rv != 0)
  411                 return (rv);
  412         return (rv);
  413 }
  414 
  415 static bool
  416 as3722_sd0_is_low_voltage(struct as3722_reg_sc *sc)
  417 {
  418         uint8_t val;
  419         int rv;
  420 
  421         rv = RD1(sc->base_sc, AS3722_FUSE7, &val);
  422         if (rv != 0)
  423                 return (rv);
  424         return (val & AS3722_FUSE7_SD0_LOW_VOLTAGE ? true : false);
  425 }
  426 
  427 static int
  428 as3722_reg_extreg_setup(struct as3722_reg_sc *sc, int ext_pwr_ctrl)
  429 {
  430         uint8_t val;
  431         int rv;
  432 
  433         val =  ext_pwr_ctrl << (ffs(sc->def->ext_enable_mask) - 1);
  434         rv = RM1(sc->base_sc, sc->def->ext_enable_reg,
  435             sc->def->ext_enable_mask, val);
  436         return (rv);
  437 }
  438 
  439 static int
  440 as3722_reg_enable(struct as3722_reg_sc *sc)
  441 {
  442         int rv;
  443 
  444         rv = RM1(sc->base_sc, sc->def->enable_reg,
  445             sc->def->enable_mask, sc->def->enable_mask);
  446         return (rv);
  447 }
  448 
  449 static int
  450 as3722_reg_disable(struct as3722_reg_sc *sc)
  451 {
  452         int rv;
  453 
  454         rv = RM1(sc->base_sc, sc->def->enable_reg,
  455             sc->def->enable_mask, 0);
  456         return (rv);
  457 }
  458 
  459 static int
  460 as3722_regnode_init(struct regnode *regnode)
  461 {
  462         struct as3722_reg_sc *sc;
  463         int rv;
  464 
  465         sc = regnode_get_softc(regnode);
  466 
  467         sc->enable_usec = 500;
  468         if (sc->def->id == AS3722_REG_ID_SD0) {
  469                 if (as3722_sd0_is_low_voltage(sc)) {
  470                         sc->def->ranges = as3722_sd0_lv_ranges;
  471                         sc->def->nranges = nitems(as3722_sd0_lv_ranges);
  472                 }
  473                 sc->enable_usec = 600;
  474         } else if (sc->def->id == AS3722_REG_ID_LDO3) {
  475                 if (sc->enable_tracking) {
  476                         rv = RM1(sc->base_sc, sc->def->volt_reg,
  477                             AS3722_LDO3_MODE_MASK,
  478                             AS3722_LDO3_MODE_PMOS_TRACKING);
  479                         if (rv < 0) {
  480                                 device_printf(sc->base_sc->dev,
  481                                         "LDO3 tracking failed: %d\n", rv);
  482                                 return (rv);
  483                         }
  484                 }
  485         }
  486 
  487         if (sc->ext_control) {
  488                 rv = as3722_reg_enable(sc);
  489                 if (rv < 0) {
  490                         device_printf(sc->base_sc->dev,
  491                                 "Failed to enable %s regulator: %d\n",
  492                                 sc->def->name, rv);
  493                         return (rv);
  494                 }
  495                 rv = as3722_reg_extreg_setup(sc, sc->ext_control);
  496                 if (rv < 0) {
  497                         device_printf(sc->base_sc->dev,
  498                                 "%s ext control failed: %d", sc->def->name, rv);
  499                         return (rv);
  500                 }
  501         }
  502         return (0);
  503 }
  504 
  505 static void
  506 as3722_fdt_parse(struct as3722_softc *sc, phandle_t node, struct reg_def *def,
  507 struct as3722_regnode_init_def *init_def)
  508 {
  509         int rv;
  510         phandle_t parent, supply_node;
  511         char prop_name[64]; /* Maximum OFW property name length. */
  512 
  513         rv = regulator_parse_ofw_stdparam(sc->dev, node,
  514             &init_def->reg_init_def);
  515 
  516         rv = OF_getencprop(node, "ams,ext-control", &init_def->ext_control,
  517             sizeof(init_def->ext_control));
  518         if (rv <= 0)
  519                 init_def->ext_control = 0;
  520         if (init_def->ext_control > 3) {
  521                 device_printf(sc->dev,
  522                     "Invalid value for ams,ext-control property: %d\n",
  523                     init_def->ext_control);
  524                 init_def->ext_control = 0;
  525         }
  526         if (OF_hasprop(node, "ams,enable-tracking"))
  527                 init_def->enable_tracking = 1;
  528 
  529         /* Get parent supply. */
  530         if (def->supply_name == NULL)
  531                  return;
  532 
  533         parent = OF_parent(node);
  534         snprintf(prop_name, sizeof(prop_name), "%s-supply",
  535             def->supply_name);
  536         rv = OF_getencprop(parent, prop_name, &supply_node,
  537             sizeof(supply_node));
  538         if (rv <= 0)
  539                 return;
  540         supply_node = OF_node_from_xref(supply_node);
  541         rv = OF_getprop_alloc(supply_node, "regulator-name",
  542             (void **)&init_def->reg_init_def.parent_name);
  543         if (rv <= 0)
  544                 init_def->reg_init_def.parent_name = NULL;
  545 }
  546 
  547 static struct as3722_reg_sc *
  548 as3722_attach(struct as3722_softc *sc, phandle_t node, struct reg_def *def)
  549 {
  550         struct as3722_reg_sc *reg_sc;
  551         struct as3722_regnode_init_def init_def;
  552         struct regnode *regnode;
  553 
  554         bzero(&init_def, sizeof(init_def));
  555 
  556         as3722_fdt_parse(sc, node, def, &init_def);
  557         init_def.reg_init_def.id = def->id;
  558         init_def.reg_init_def.ofw_node = node;
  559         regnode = regnode_create(sc->dev, &as3722_regnode_class,
  560             &init_def.reg_init_def);
  561         if (regnode == NULL) {
  562                 device_printf(sc->dev, "Cannot create regulator.\n");
  563                 return (NULL);
  564         }
  565         reg_sc = regnode_get_softc(regnode);
  566 
  567         /* Init regulator softc. */
  568         reg_sc->regnode = regnode;
  569         reg_sc->base_sc = sc;
  570         reg_sc->def = def;
  571         reg_sc->xref = OF_xref_from_node(node);
  572 
  573         reg_sc->param = regnode_get_stdparam(regnode);
  574         reg_sc->ext_control = init_def.ext_control;
  575         reg_sc->enable_tracking = init_def.enable_tracking;
  576 
  577         regnode_register(regnode);
  578         if (bootverbose) {
  579                 int volt, rv;
  580                 regnode_topo_slock();
  581                 rv = regnode_get_voltage(regnode, &volt);
  582                 if (rv == ENODEV) {
  583                         device_printf(sc->dev,
  584                            " Regulator %s: parent doesn't exist yet.\n",
  585                            regnode_get_name(regnode));
  586                 } else if (rv != 0) {
  587                         device_printf(sc->dev,
  588                            " Regulator %s: voltage: INVALID!!!\n",
  589                            regnode_get_name(regnode));
  590                 } else {
  591                         device_printf(sc->dev,
  592                             " Regulator %s: voltage: %d uV\n",
  593                             regnode_get_name(regnode), volt);
  594                 }
  595                 regnode_topo_unlock();
  596         }
  597 
  598         return (reg_sc);
  599 }
  600 
  601 int
  602 as3722_regulator_attach(struct as3722_softc *sc, phandle_t node)
  603 {
  604         struct as3722_reg_sc *reg;
  605         phandle_t child, rnode;
  606         int i;
  607 
  608         rnode = ofw_bus_find_child(node, "regulators");
  609         if (rnode <= 0) {
  610                 device_printf(sc->dev, " Cannot find regulators subnode\n");
  611                 return (ENXIO);
  612         }
  613 
  614         sc->nregs = nitems(as3722s_def);
  615         sc->regs = malloc(sizeof(struct as3722_reg_sc *) * sc->nregs,
  616             M_AS3722_REG, M_WAITOK | M_ZERO);
  617 
  618         /* Attach all known regulators if exist in DT. */
  619         for (i = 0; i < sc->nregs; i++) {
  620                 child = ofw_bus_find_child(rnode, as3722s_def[i].name);
  621                 if (child == 0) {
  622                         if (bootverbose)
  623                                 device_printf(sc->dev,
  624                                     "Regulator %s missing in DT\n",
  625                                     as3722s_def[i].name);
  626                         continue;
  627                 }
  628                 reg = as3722_attach(sc, child, as3722s_def + i);
  629                 if (reg == NULL) {
  630                         device_printf(sc->dev, "Cannot attach regulator: %s\n",
  631                             as3722s_def[i].name);
  632                         return (ENXIO);
  633                 }
  634                 sc->regs[i] = reg;
  635         }
  636         return (0);
  637 }
  638 
  639 int
  640 as3722_regulator_map(device_t dev, phandle_t xref, int ncells,
  641     pcell_t *cells, int *num)
  642 {
  643         struct as3722_softc *sc;
  644         int i;
  645 
  646         sc = device_get_softc(dev);
  647         for (i = 0; i < sc->nregs; i++) {
  648                 if (sc->regs[i] == NULL)
  649                         continue;
  650                 if (sc->regs[i]->xref == xref) {
  651                         *num = sc->regs[i]->def->id;
  652                         return (0);
  653                 }
  654         }
  655         return (ENXIO);
  656 }
  657 
  658 static int
  659 as3722_regnode_enable(struct regnode *regnode, bool val, int *udelay)
  660 {
  661         struct as3722_reg_sc *sc;
  662         int rv;
  663 
  664         sc = regnode_get_softc(regnode);
  665 
  666         if (val)
  667                 rv = as3722_reg_enable(sc);
  668         else
  669                 rv = as3722_reg_disable(sc);
  670         *udelay = sc->enable_usec;
  671         return (rv);
  672 }
  673 
  674 static int
  675 as3722_regnode_set_volt(struct regnode *regnode, int min_uvolt, int max_uvolt,
  676     int *udelay)
  677 {
  678         struct as3722_reg_sc *sc;
  679         uint8_t sel;
  680         int rv;
  681 
  682         sc = regnode_get_softc(regnode);
  683 
  684         *udelay = 0;
  685         rv = regulator_range_volt_to_sel8(sc->def->ranges, sc->def->nranges,
  686             min_uvolt, max_uvolt, &sel);
  687         if (rv != 0)
  688                 return (rv);
  689         rv = as3722_write_sel(sc, sel);
  690         return (rv);
  691 
  692 }
  693 
  694 static int
  695 as3722_regnode_get_volt(struct regnode *regnode, int *uvolt)
  696 {
  697         struct as3722_reg_sc *sc;
  698         uint8_t sel;
  699         int rv;
  700 
  701         sc = regnode_get_softc(regnode);
  702         rv = as3722_read_sel(sc, &sel);
  703         if (rv != 0)
  704                 return (rv);
  705 
  706         /* LDO6 have bypass. */
  707         if (sc->def->id == AS3722_REG_ID_LDO6 && sel == AS3722_LDO6_SEL_BYPASS)
  708                 return (ENOENT);
  709         rv = regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges,
  710             sel, uvolt);
  711         return (rv);
  712 }

Cache object: d6759ad7c31a0a67dad89600958dfcd6


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