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/fan53555.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) 2016 Jared McNeill <jmcneill@invisible.ca>
    5  * Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.org>
    6  * Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org>
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/bus.h>
   35 #include <sys/kernel.h>
   36 #include <sys/module.h>
   37 #include <sys/mutex.h>
   38 #include <sys/rman.h>
   39 #include <machine/bus.h>
   40 
   41 #include <dev/iicbus/iiconf.h>
   42 #include <dev/iicbus/iicbus.h>
   43 
   44 #include <dev/ofw/ofw_bus.h>
   45 #include <dev/ofw/ofw_bus_subr.h>
   46 
   47 #include <dev/extres/regulator/regulator.h>
   48 
   49 #include "regdev_if.h"
   50 
   51 /* Registers */
   52 #define FAN53555_VSEL0          0x00
   53 #define FAN53555_VSEL1          0x01
   54 #define  FAN53555_VSEL_ENA              (1 << 7)
   55 #define  FAN53555_VSEL_MODE             (1 << 6)
   56 #define  FAN53555_VSEL_MASK             0x3f
   57 #define FAN53555_CTRL           0x02
   58 #define FAN53555_ID1            0x03
   59 #define  FAN53555_ID1_DIE_ID(x)         ((x) & 0x0F)
   60 #define FAN53555_ID2            0x04
   61 #define  FAN53555_ID2_DIE_REV(x)        ((x) & 0x0F)
   62 #define FAN53555_MON            0x05
   63 
   64 #define TCS4525_VSEL0           0x11
   65 #define TCS4525_VSEL1           0x10
   66 #define TCS4525_CHIP_ID_12      12
   67 
   68 #if 0
   69 #define dprintf(sc, format, arg...)                                     \
   70         device_printf(sc->base_dev, "%s: " format, __func__, arg)
   71 #else
   72 #define dprintf(sc, format, arg...)
   73 #endif
   74 
   75 enum fan53555_pmic_type {
   76         FAN53555 = 1,
   77         SYR827,
   78         SYR828,
   79         TCS4525,
   80 };
   81 
   82 static struct ofw_compat_data compat_data[] = {
   83         {"fcs,fan53555",        FAN53555},
   84         {"silergy,syr827",      SYR827},
   85         {"silergy,syr828",      SYR828},
   86         {"tcs,tcs4525",         TCS4525},
   87         {NULL,          0}
   88 };
   89 
   90 struct fan53555_reg_sc {
   91         struct regnode          *regnode;
   92         char                    *name;
   93         device_t                base_dev;
   94         uint8_t                 live_reg;
   95         uint8_t                 sleep_reg;
   96         struct regulator_range  *range;
   97         struct regnode_std_param *param;
   98 };
   99 
  100 struct fan53555_softc {
  101         device_t                dev;
  102         uint8_t                 live_reg;
  103         uint8_t                 sleep_reg;
  104 };
  105 
  106 static struct regulator_range syr_8_range =
  107    REG_RANGE_INIT(  0, 0x3F,  712500, 12500);
  108 
  109 static struct regulator_range fan_0_0_range =
  110    REG_RANGE_INIT(  0, 0x3F,  600000, 10000);
  111 static struct regulator_range fan_0_13_range =
  112    REG_RANGE_INIT(  0, 0x3F,  800000, 10000);
  113 static struct regulator_range fan_1_range =
  114    REG_RANGE_INIT(  0, 0x3F,  600000, 10000);
  115 static struct regulator_range fan_4_range =
  116    REG_RANGE_INIT(  0, 0x3F,  603000, 12826);
  117 
  118 static struct regulator_range tcs_12_range =
  119    REG_RANGE_INIT(  0, 0x3F,  800000, 6250);
  120 
  121 static int
  122 fan53555_read(device_t dev, uint8_t reg, uint8_t *val)
  123 {
  124         uint8_t addr;
  125         int rv;
  126         struct iic_msg msgs[2] = {
  127                 {0, IIC_M_WR | IIC_M_NOSTOP, 1, &addr},
  128                 {0, IIC_M_RD, 1, val},
  129         };
  130 
  131         msgs[0].slave = iicbus_get_addr(dev);
  132         msgs[1].slave = iicbus_get_addr(dev);
  133         addr = reg;
  134 
  135         rv = iicbus_transfer_excl(dev, msgs, 2, IIC_INTRWAIT);
  136         if (rv != 0) {
  137                 device_printf(dev, "Error when reading reg 0x%02X, rv: %d\n",
  138                     reg,  rv);
  139                 return (EIO);
  140         }
  141 
  142         return (0);
  143 }
  144 
  145 static int
  146 fan53555_write(device_t dev, uint8_t reg, uint8_t val)
  147 {
  148         uint8_t data[2];
  149         int rv;
  150 
  151         struct iic_msg msgs[1] = {
  152                 {0, IIC_M_WR, 2, data},
  153         };
  154 
  155         msgs[0].slave = iicbus_get_addr(dev);
  156         data[0] = reg;
  157         data[1] = val;
  158 
  159         rv = iicbus_transfer_excl(dev, msgs, 1, IIC_INTRWAIT);
  160         if (rv != 0) {
  161                 device_printf(dev,
  162                     "Error when writing reg 0x%02X, rv: %d\n", reg, rv);
  163                 return (EIO);
  164         }
  165         return (0);
  166 }
  167 
  168 static int
  169 fan53555_read_sel(struct fan53555_reg_sc *sc, uint8_t *sel)
  170 {
  171         int rv;
  172 
  173         rv = fan53555_read(sc->base_dev, sc->live_reg, sel);
  174         if (rv != 0)
  175                 return (rv);
  176         *sel &= FAN53555_VSEL_MASK;
  177         return (0);
  178 }
  179 
  180 static int
  181 fan53555_write_sel(struct fan53555_reg_sc *sc, uint8_t sel)
  182 {
  183         int rv;
  184         uint8_t reg;
  185 
  186         rv = fan53555_read(sc->base_dev, sc->live_reg, &reg);
  187         if (rv != 0)
  188                 return (rv);
  189         reg &= ~FAN53555_VSEL_MASK;
  190         reg |= sel;
  191 
  192         rv = fan53555_write(sc->base_dev, sc->live_reg, reg);
  193         if (rv != 0)
  194                 return (rv);
  195         return (rv);
  196 }
  197 
  198 static int
  199 fan53555_regnode_init(struct regnode *regnode)
  200 {
  201         return (0);
  202 }
  203 
  204 static int
  205 fan53555_regnode_enable(struct regnode *regnode, bool enable, int *udelay)
  206 {
  207         struct fan53555_reg_sc *sc;
  208         uint8_t val;
  209 
  210         sc = regnode_get_softc(regnode);
  211 
  212         dprintf(sc, "%sabling regulator %s\n", enable ? "En" : "Dis",
  213             sc->name);
  214         fan53555_read(sc->base_dev, sc->live_reg, &val);
  215         if (enable)
  216                 val |=FAN53555_VSEL_ENA;
  217         else
  218                 val &= ~FAN53555_VSEL_ENA;
  219         fan53555_write(sc->base_dev, sc->live_reg, val);
  220 
  221         *udelay = sc->param->enable_delay;
  222         return (0);
  223 }
  224 
  225 
  226 static int
  227 fan53555_regnode_set_voltage(struct regnode *regnode, int min_uvolt,
  228     int max_uvolt, int *udelay)
  229 {
  230         struct fan53555_reg_sc *sc;
  231         uint8_t sel;
  232         int uvolt, rv;
  233 
  234         sc = regnode_get_softc(regnode);
  235 
  236         dprintf(sc, "Setting %s to %d<->%d uvolts\n", sc->name, min_uvolt,
  237             max_uvolt);
  238         rv = regulator_range_volt_to_sel8(sc->range, 1, min_uvolt, max_uvolt,
  239             &sel);
  240         if (rv != 0)
  241                 return (rv);
  242         *udelay = sc->param->ramp_delay;
  243         rv = fan53555_write_sel(sc, sel);
  244         dprintf(sc, "Regulator %s writing sel: 0x%02X\n", sc->name, sel);
  245 
  246         fan53555_read_sel(sc, &sel);
  247         regulator_range_sel8_to_volt(sc->range, 1, sel, &uvolt);
  248         dprintf(sc, "Regulator %s set to %d uvolt (sel: 0x%02X)\n", sc->name,
  249             uvolt, sel);
  250 
  251         return (rv);
  252 }
  253 
  254 static int
  255 fan53555_regnode_get_voltage(struct regnode *regnode, int *uvolt)
  256 {
  257         struct fan53555_reg_sc *sc;
  258         uint8_t sel;
  259         int rv;
  260 
  261         sc = regnode_get_softc(regnode);
  262 
  263         rv = fan53555_read_sel(sc, &sel);
  264         if (rv != 0)
  265                 return (rv);
  266         rv = regulator_range_sel8_to_volt(sc->range, 1, sel, uvolt);
  267         dprintf(sc, "Regulator %s is at %d uvolt ((sel: 0x%02X)\n", sc->name,
  268             *uvolt, sel);
  269 
  270         return (rv);
  271 }
  272 
  273 static regnode_method_t fan53555_regnode_methods[] = {
  274         /* Regulator interface */
  275         REGNODEMETHOD(regnode_init,             fan53555_regnode_init),
  276         REGNODEMETHOD(regnode_enable,           fan53555_regnode_enable),
  277         REGNODEMETHOD(regnode_set_voltage,      fan53555_regnode_set_voltage),
  278         REGNODEMETHOD(regnode_get_voltage,      fan53555_regnode_get_voltage),
  279         REGNODEMETHOD_END
  280 };
  281 DEFINE_CLASS_1(fan53555_regnode, fan53555_regnode_class,
  282     fan53555_regnode_methods, sizeof(struct fan53555_reg_sc), regnode_class);
  283 
  284 static struct regulator_range *
  285 fan53555_get_range(struct fan53555_softc *sc, int type, uint8_t id,
  286     uint8_t rev)
  287 {
  288         if (type == SYR827 || type == SYR828) {
  289                 switch (id) {
  290                 case 8:
  291                         return (&syr_8_range);
  292                 default:
  293                         return (NULL);
  294                 }
  295         }
  296 
  297         if (type == FAN53555) {
  298                 switch (id) {
  299                 case 0:
  300                         if (rev == 0)
  301                                 return (&fan_0_0_range);
  302                         else if (rev == 13)
  303                                 return (&fan_0_13_range);
  304                         else
  305                                 return (NULL);
  306                 case 1:
  307                 case 3:
  308                 case 5:
  309                 case 8:
  310                         return (&fan_1_range);
  311                 case 4:
  312                         return (&fan_4_range);
  313                 default:
  314                         return (NULL);
  315                 }
  316         }
  317 
  318         if (type == TCS4525) {
  319                 switch (id) {
  320                 case TCS4525_CHIP_ID_12:
  321                         return (&tcs_12_range);
  322                 default:
  323                         return (NULL);
  324                 }
  325         }
  326 
  327         return (NULL);
  328 }
  329 
  330 static struct fan53555_reg_sc *
  331 fan53555_reg_attach(struct fan53555_softc *sc, phandle_t node, int  type)
  332 {
  333         struct fan53555_reg_sc *reg_sc;
  334         struct regnode_init_def initdef;
  335         struct regnode *regnode;
  336         static struct regulator_range *range;
  337         uint8_t id1, id2;
  338 
  339         memset(&initdef, 0, sizeof(initdef));
  340         if (regulator_parse_ofw_stdparam(sc->dev, node, &initdef) != 0) {
  341                 device_printf(sc->dev, "cannot parse regulator FDT data\n");
  342                 return (NULL);
  343         }
  344 
  345         if (fan53555_read(sc->dev, FAN53555_ID1, &id1) != 0) {
  346                 device_printf(sc->dev, "cannot read ID1\n");
  347                 return (NULL);
  348         }
  349 
  350         if (fan53555_read(sc->dev, FAN53555_ID2, &id2) != 0) {
  351                 device_printf(sc->dev, "cannot read ID2\n");
  352                 return (NULL);
  353         }
  354         dprintf(sc, "Device ID1: 0x%02X, ID2: 0x%02X\n", id1, id2);
  355 
  356         range = fan53555_get_range(sc, type, FAN53555_ID1_DIE_ID(id1),
  357              FAN53555_ID2_DIE_REV(id2));
  358         if (range == NULL) {
  359                 device_printf(sc->dev,
  360                     "cannot determine chip type (ID1: 0x%02X, ID2: 0x%02X)\n",
  361                     id1, id2);
  362                 return (NULL);
  363         }
  364 
  365         initdef.id = 1;
  366         initdef.ofw_node = node;
  367 
  368         regnode = regnode_create(sc->dev, &fan53555_regnode_class, &initdef);
  369         if (regnode == NULL) {
  370                 device_printf(sc->dev, "cannot create regulator\n");
  371                 return (NULL);
  372         }
  373 
  374         reg_sc = regnode_get_softc(regnode);
  375         reg_sc->name = "fan53555";
  376         reg_sc->regnode = regnode;
  377         reg_sc->base_dev = sc->dev;
  378         reg_sc->param = regnode_get_stdparam(regnode);
  379         reg_sc->range = range;
  380         reg_sc->live_reg = sc->live_reg;
  381         reg_sc->sleep_reg = sc->sleep_reg;
  382 
  383         dprintf(sc->dev, "live_reg: %d, sleep_reg: %d\n", reg_sc->live_reg,
  384             reg_sc->sleep_reg);
  385 
  386         regnode_register(regnode);
  387 
  388         if (bootverbose) {
  389                 int volt, rv;
  390                 regnode_topo_slock();
  391                 rv = regnode_get_voltage(regnode, &volt);
  392                 if (rv == ENODEV) {
  393                         device_printf(sc->dev,
  394                            " Regulator %s: parent doesn't exist yet.\n",
  395                            regnode_get_name(regnode));
  396                 } else if (rv != 0) {
  397                         device_printf(sc->dev,
  398                            " Regulator %s: voltage: INVALID!!!\n",
  399                            regnode_get_name(regnode));
  400                 } else {
  401                         device_printf(sc->dev,
  402                             " Regulator %s: voltage: %d uV\n",
  403                             regnode_get_name(regnode), volt);
  404                 }
  405                 regnode_topo_unlock();
  406         }
  407 
  408         return (reg_sc);
  409 }
  410 
  411 static int
  412 fan53555_probe(device_t dev)
  413 {
  414         int type;
  415 
  416         if (!ofw_bus_status_okay(dev))
  417                 return (ENXIO);
  418 
  419         type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
  420         switch (type) {
  421         case FAN53555:
  422                 device_set_desc(dev, "FAN53555 PMIC");
  423                 break;
  424         case SYR827:
  425                 device_set_desc(dev, "SYR827 PMIC");
  426                 break;
  427         case SYR828:
  428                 device_set_desc(dev, "SYR828 PMIC");
  429                 break;
  430         case TCS4525:
  431                 device_set_desc(dev, "TCS4525 PMIC");
  432                 break;
  433         default:
  434                 return (ENXIO);
  435         }
  436 
  437         return (BUS_PROBE_DEFAULT);
  438 }
  439 
  440 static int
  441 fan53555_attach(device_t dev)
  442 {
  443         struct fan53555_softc *sc;
  444         phandle_t node;
  445         int type, susp_sel, rv;
  446 
  447         sc = device_get_softc(dev);
  448         sc->dev = dev;
  449         node = ofw_bus_get_node(dev);
  450         type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
  451 
  452         rv = OF_getencprop(node, "fcs,suspend-voltage-selector", &susp_sel,
  453                 sizeof(susp_sel));
  454         if (rv <= 0)
  455                 susp_sel = 1;
  456 
  457         switch (type) {
  458         case FAN53555:
  459         case SYR827:
  460         case SYR828:
  461                 if (susp_sel == 1) {
  462                         sc->live_reg = FAN53555_VSEL0;
  463                         sc->sleep_reg = FAN53555_VSEL1;
  464                 } else {
  465                         sc->live_reg = FAN53555_VSEL1;
  466                         sc->sleep_reg = FAN53555_VSEL0;
  467                 }
  468                 break;
  469         case TCS4525:
  470                 if (susp_sel == 1) {
  471                         sc->live_reg = TCS4525_VSEL0;
  472                         sc->sleep_reg = TCS4525_VSEL1;
  473                 } else {
  474                         sc->live_reg = TCS4525_VSEL1;
  475                         sc->sleep_reg = TCS4525_VSEL0;
  476                 }
  477                 break;
  478         default:
  479                 return (ENXIO);
  480         }
  481         if (fan53555_reg_attach(sc, node, type) == NULL)
  482                 device_printf(dev, "cannot attach regulator.\n");
  483 
  484         return (0);
  485 }
  486 
  487 static int
  488 fan53555_detach(device_t dev)
  489 {
  490 
  491         /* We cannot detach regulators */
  492         return (EBUSY);
  493 }
  494 
  495 static device_method_t fan53555_methods[] = {
  496         DEVMETHOD(device_probe,         fan53555_probe),
  497         DEVMETHOD(device_attach,        fan53555_attach),
  498         DEVMETHOD(device_detach,        fan53555_detach),
  499 
  500         /* Regdev interface */
  501         DEVMETHOD(regdev_map,           regdev_default_ofw_map),
  502 
  503         DEVMETHOD_END
  504 };
  505 
  506 static DEFINE_CLASS_0(fan53555_pmic, fan53555_driver, fan53555_methods,
  507     sizeof(struct fan53555_softc));
  508 
  509 EARLY_DRIVER_MODULE(fan53555, iicbus, fan53555_driver, 0, 0, BUS_PASS_RESOURCE);
  510 MODULE_VERSION(fan53555, 1);
  511 MODULE_DEPEND(fan53555, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
  512 IICBUS_FDT_PNP_INFO(compat_data);

Cache object: bae29d070214f545e51430f824f8fd98


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