Path: blob/main/sys/arm/nvidia/as3722_regulators.c
39478 views
/*-1* Copyright 2016 Michal Meloun <[email protected]>2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526#include <sys/param.h>27#include <sys/systm.h>28#include <sys/bus.h>29#include <sys/gpio.h>30#include <sys/kernel.h>31#include <sys/module.h>32#include <sys/malloc.h>33#include <sys/rman.h>34#include <sys/sx.h>3536#include <machine/bus.h>3738#include <dev/regulator/regulator.h>39#include <dev/gpio/gpiobusvar.h>4041#include <dt-bindings/mfd/as3722.h>4243#include "as3722.h"4445MALLOC_DEFINE(M_AS3722_REG, "AS3722 regulator", "AS3722 power regulator");4647#define DIV_ROUND_UP(n,d) howmany(n, d)4849enum as3722_reg_id {50AS3722_REG_ID_SD0,51AS3722_REG_ID_SD1,52AS3722_REG_ID_SD2,53AS3722_REG_ID_SD3,54AS3722_REG_ID_SD4,55AS3722_REG_ID_SD5,56AS3722_REG_ID_SD6,57AS3722_REG_ID_LDO0,58AS3722_REG_ID_LDO1,59AS3722_REG_ID_LDO2,60AS3722_REG_ID_LDO3,61AS3722_REG_ID_LDO4,62AS3722_REG_ID_LDO5,63AS3722_REG_ID_LDO6,64AS3722_REG_ID_LDO7,65AS3722_REG_ID_LDO9,66AS3722_REG_ID_LDO10,67AS3722_REG_ID_LDO11,68};6970/* Regulator HW definition. */71struct reg_def {72intptr_t id; /* ID */73char *name; /* Regulator name */74char *supply_name; /* Source property name */75uint8_t volt_reg;76uint8_t volt_vsel_mask;77uint8_t enable_reg;78uint8_t enable_mask;79uint8_t ext_enable_reg;80uint8_t ext_enable_mask;81struct regulator_range *ranges;82int nranges;83};8485struct as3722_reg_sc {86struct regnode *regnode;87struct as3722_softc *base_sc;88struct reg_def *def;89phandle_t xref;9091struct regnode_std_param *param;92int ext_control;93int enable_tracking;9495int enable_usec;96};9798static struct regulator_range as3722_sd016_ranges[] = {99REG_RANGE_INIT(0x00, 0x00, 0, 0),100REG_RANGE_INIT(0x01, 0x5A, 610000, 10000),101};102103static struct regulator_range as3722_sd0_lv_ranges[] = {104REG_RANGE_INIT(0x00, 0x00, 0, 0),105REG_RANGE_INIT(0x01, 0x6E, 410000, 10000),106};107108static struct regulator_range as3722_sd_ranges[] = {109REG_RANGE_INIT(0x00, 0x00, 0, 0),110REG_RANGE_INIT(0x01, 0x40, 612500, 12500),111REG_RANGE_INIT(0x41, 0x70, 1425000, 25000),112REG_RANGE_INIT(0x71, 0x7F, 2650000, 50000),113};114115static struct regulator_range as3722_ldo3_ranges[] = {116REG_RANGE_INIT(0x00, 0x00, 0, 0),117REG_RANGE_INIT(0x01, 0x2D, 620000, 20000),118};119120static struct regulator_range as3722_ldo_ranges[] = {121REG_RANGE_INIT(0x00, 0x00, 0, 0),122REG_RANGE_INIT(0x01, 0x24, 825000, 25000),123REG_RANGE_INIT(0x40, 0x7F, 1725000, 25000),124};125126static struct reg_def as3722s_def[] = {127{128.id = AS3722_REG_ID_SD0,129.name = "sd0",130.volt_reg = AS3722_SD0_VOLTAGE,131.volt_vsel_mask = AS3722_SD_VSEL_MASK,132.enable_reg = AS3722_SD_CONTROL,133.enable_mask = AS3722_SDN_CTRL(0),134.ext_enable_reg = AS3722_ENABLE_CTRL1,135.ext_enable_mask = AS3722_SD0_EXT_ENABLE_MASK,136.ranges = as3722_sd016_ranges,137.nranges = nitems(as3722_sd016_ranges),138},139{140.id = AS3722_REG_ID_SD1,141.name = "sd1",142.volt_reg = AS3722_SD1_VOLTAGE,143.volt_vsel_mask = AS3722_SD_VSEL_MASK,144.enable_reg = AS3722_SD_CONTROL,145.enable_mask = AS3722_SDN_CTRL(1),146.ext_enable_reg = AS3722_ENABLE_CTRL1,147.ext_enable_mask = AS3722_SD1_EXT_ENABLE_MASK,148.ranges = as3722_sd_ranges,149.nranges = nitems(as3722_sd_ranges),150},151{152.id = AS3722_REG_ID_SD2,153.name = "sd2",154.supply_name = "vsup-sd2",155.volt_reg = AS3722_SD2_VOLTAGE,156.volt_vsel_mask = AS3722_SD_VSEL_MASK,157.enable_reg = AS3722_SD_CONTROL,158.enable_mask = AS3722_SDN_CTRL(2),159.ext_enable_reg = AS3722_ENABLE_CTRL1,160.ext_enable_mask = AS3722_SD2_EXT_ENABLE_MASK,161.ranges = as3722_sd_ranges,162.nranges = nitems(as3722_sd_ranges),163},164{165.id = AS3722_REG_ID_SD3,166.name = "sd3",167.supply_name = "vsup-sd3",168.volt_reg = AS3722_SD3_VOLTAGE,169.volt_vsel_mask = AS3722_SD_VSEL_MASK,170.enable_reg = AS3722_SD_CONTROL,171.enable_mask = AS3722_SDN_CTRL(3),172.ext_enable_reg = AS3722_ENABLE_CTRL1,173.ext_enable_mask = AS3722_SD3_EXT_ENABLE_MASK,174.ranges = as3722_sd_ranges,175.nranges = nitems(as3722_sd_ranges),176},177{178.id = AS3722_REG_ID_SD4,179.name = "sd4",180.supply_name = "vsup-sd4",181.volt_reg = AS3722_SD4_VOLTAGE,182.volt_vsel_mask = AS3722_SD_VSEL_MASK,183.enable_reg = AS3722_SD_CONTROL,184.enable_mask = AS3722_SDN_CTRL(4),185.ext_enable_reg = AS3722_ENABLE_CTRL2,186.ext_enable_mask = AS3722_SD4_EXT_ENABLE_MASK,187.ranges = as3722_sd_ranges,188.nranges = nitems(as3722_sd_ranges),189},190{191.id = AS3722_REG_ID_SD5,192.name = "sd5",193.supply_name = "vsup-sd5",194.volt_reg = AS3722_SD5_VOLTAGE,195.volt_vsel_mask = AS3722_SD_VSEL_MASK,196.enable_reg = AS3722_SD_CONTROL,197.enable_mask = AS3722_SDN_CTRL(5),198.ext_enable_reg = AS3722_ENABLE_CTRL2,199.ext_enable_mask = AS3722_SD5_EXT_ENABLE_MASK,200.ranges = as3722_sd_ranges,201.nranges = nitems(as3722_sd_ranges),202},203{204.id = AS3722_REG_ID_SD6,205.name = "sd6",206.volt_reg = AS3722_SD6_VOLTAGE,207.volt_vsel_mask = AS3722_SD_VSEL_MASK,208.enable_reg = AS3722_SD_CONTROL,209.enable_mask = AS3722_SDN_CTRL(6),210.ext_enable_reg = AS3722_ENABLE_CTRL2,211.ext_enable_mask = AS3722_SD6_EXT_ENABLE_MASK,212.ranges = as3722_sd016_ranges,213.nranges = nitems(as3722_sd016_ranges),214},215{216.id = AS3722_REG_ID_LDO0,217.name = "ldo0",218.supply_name = "vin-ldo0",219.volt_reg = AS3722_LDO0_VOLTAGE,220.volt_vsel_mask = AS3722_LDO0_VSEL_MASK,221.enable_reg = AS3722_LDO_CONTROL0,222.enable_mask = AS3722_LDO0_CTRL,223.ext_enable_reg = AS3722_ENABLE_CTRL3,224.ext_enable_mask = AS3722_LDO0_EXT_ENABLE_MASK,225.ranges = as3722_ldo_ranges,226.nranges = nitems(as3722_ldo_ranges),227},228{229.id = AS3722_REG_ID_LDO1,230.name = "ldo1",231.supply_name = "vin-ldo1-6",232.volt_reg = AS3722_LDO1_VOLTAGE,233.volt_vsel_mask = AS3722_LDO_VSEL_MASK,234.enable_reg = AS3722_LDO_CONTROL0,235.enable_mask = AS3722_LDO1_CTRL,236.ext_enable_reg = AS3722_ENABLE_CTRL3,237.ext_enable_mask = AS3722_LDO1_EXT_ENABLE_MASK,238.ranges = as3722_ldo_ranges,239.nranges = nitems(as3722_ldo_ranges),240},241{242.id = AS3722_REG_ID_LDO2,243.name = "ldo2",244.supply_name = "vin-ldo2-5-7",245.volt_reg = AS3722_LDO2_VOLTAGE,246.volt_vsel_mask = AS3722_LDO_VSEL_MASK,247.enable_reg = AS3722_LDO_CONTROL0,248.enable_mask = AS3722_LDO2_CTRL,249.ext_enable_reg = AS3722_ENABLE_CTRL3,250.ext_enable_mask = AS3722_LDO2_EXT_ENABLE_MASK,251.ranges = as3722_ldo_ranges,252.nranges = nitems(as3722_ldo_ranges),253},254{255.id = AS3722_REG_ID_LDO3,256.name = "ldo3",257.supply_name = "vin-ldo3-4",258.volt_reg = AS3722_LDO3_VOLTAGE,259.volt_vsel_mask = AS3722_LDO3_VSEL_MASK,260.enable_reg = AS3722_LDO_CONTROL0,261.enable_mask = AS3722_LDO3_CTRL,262.ext_enable_reg = AS3722_ENABLE_CTRL3,263.ext_enable_mask = AS3722_LDO3_EXT_ENABLE_MASK,264.ranges = as3722_ldo3_ranges,265.nranges = nitems(as3722_ldo3_ranges),266},267{268.id = AS3722_REG_ID_LDO4,269.name = "ldo4",270.supply_name = "vin-ldo3-4",271.volt_reg = AS3722_LDO4_VOLTAGE,272.volt_vsel_mask = AS3722_LDO_VSEL_MASK,273.enable_reg = AS3722_LDO_CONTROL0,274.enable_mask = AS3722_LDO4_CTRL,275.ext_enable_reg = AS3722_ENABLE_CTRL4,276.ext_enable_mask = AS3722_LDO4_EXT_ENABLE_MASK,277.ranges = as3722_ldo_ranges,278.nranges = nitems(as3722_ldo_ranges),279},280{281.id = AS3722_REG_ID_LDO5,282.name = "ldo5",283.supply_name = "vin-ldo2-5-7",284.volt_reg = AS3722_LDO5_VOLTAGE,285.volt_vsel_mask = AS3722_LDO_VSEL_MASK,286.enable_reg = AS3722_LDO_CONTROL0,287.enable_mask = AS3722_LDO5_CTRL,288.ext_enable_reg = AS3722_ENABLE_CTRL4,289.ext_enable_mask = AS3722_LDO5_EXT_ENABLE_MASK,290.ranges = as3722_ldo_ranges,291.nranges = nitems(as3722_ldo_ranges),292},293{294.id = AS3722_REG_ID_LDO6,295.name = "ldo6",296.supply_name = "vin-ldo1-6",297.volt_reg = AS3722_LDO6_VOLTAGE,298.volt_vsel_mask = AS3722_LDO_VSEL_MASK,299.enable_reg = AS3722_LDO_CONTROL0,300.enable_mask = AS3722_LDO6_CTRL,301.ext_enable_reg = AS3722_ENABLE_CTRL4,302.ext_enable_mask = AS3722_LDO6_EXT_ENABLE_MASK,303.ranges = as3722_ldo_ranges,304.nranges = nitems(as3722_ldo_ranges),305},306{307.id = AS3722_REG_ID_LDO7,308.name = "ldo7",309.supply_name = "vin-ldo2-5-7",310.volt_reg = AS3722_LDO7_VOLTAGE,311.volt_vsel_mask = AS3722_LDO_VSEL_MASK,312.enable_reg = AS3722_LDO_CONTROL0,313.enable_mask = AS3722_LDO7_CTRL,314.ext_enable_reg = AS3722_ENABLE_CTRL4,315.ext_enable_mask = AS3722_LDO7_EXT_ENABLE_MASK,316.ranges = as3722_ldo_ranges,317.nranges = nitems(as3722_ldo_ranges),318},319{320.id = AS3722_REG_ID_LDO9,321.name = "ldo9",322.supply_name = "vin-ldo9-10",323.volt_reg = AS3722_LDO9_VOLTAGE,324.volt_vsel_mask = AS3722_LDO_VSEL_MASK,325.enable_reg = AS3722_LDO_CONTROL1,326.enable_mask = AS3722_LDO9_CTRL,327.ext_enable_reg = AS3722_ENABLE_CTRL5,328.ext_enable_mask = AS3722_LDO9_EXT_ENABLE_MASK,329.ranges = as3722_ldo_ranges,330.nranges = nitems(as3722_ldo_ranges),331},332{333.id = AS3722_REG_ID_LDO10,334.name = "ldo10",335.supply_name = "vin-ldo9-10",336.volt_reg = AS3722_LDO10_VOLTAGE,337.volt_vsel_mask = AS3722_LDO_VSEL_MASK,338.enable_reg = AS3722_LDO_CONTROL1,339.enable_mask = AS3722_LDO10_CTRL,340.ext_enable_reg = AS3722_ENABLE_CTRL5,341.ext_enable_mask = AS3722_LDO10_EXT_ENABLE_MASK,342.ranges = as3722_ldo_ranges,343.nranges = nitems(as3722_ldo_ranges),344},345{346.id = AS3722_REG_ID_LDO11,347.name = "ldo11",348.supply_name = "vin-ldo11",349.volt_reg = AS3722_LDO11_VOLTAGE,350.volt_vsel_mask = AS3722_LDO_VSEL_MASK,351.enable_reg = AS3722_LDO_CONTROL1,352.enable_mask = AS3722_LDO11_CTRL,353.ext_enable_reg = AS3722_ENABLE_CTRL5,354.ext_enable_mask = AS3722_LDO11_EXT_ENABLE_MASK,355.ranges = as3722_ldo_ranges,356.nranges = nitems(as3722_ldo_ranges),357},358};359360struct as3722_regnode_init_def {361struct regnode_init_def reg_init_def;362int ext_control;363int enable_tracking;364};365366static int as3722_regnode_init(struct regnode *regnode);367static int as3722_regnode_enable(struct regnode *regnode, bool enable,368int *udelay);369static int as3722_regnode_set_volt(struct regnode *regnode, int min_uvolt,370int max_uvolt, int *udelay);371static int as3722_regnode_get_volt(struct regnode *regnode, int *uvolt);372static regnode_method_t as3722_regnode_methods[] = {373/* Regulator interface */374REGNODEMETHOD(regnode_init, as3722_regnode_init),375REGNODEMETHOD(regnode_enable, as3722_regnode_enable),376REGNODEMETHOD(regnode_set_voltage, as3722_regnode_set_volt),377REGNODEMETHOD(regnode_get_voltage, as3722_regnode_get_volt),378REGNODEMETHOD_END379};380DEFINE_CLASS_1(as3722_regnode, as3722_regnode_class, as3722_regnode_methods,381sizeof(struct as3722_reg_sc), regnode_class);382383static int384as3722_read_sel(struct as3722_reg_sc *sc, uint8_t *sel)385{386int rv;387388rv = RD1(sc->base_sc, sc->def->volt_reg, sel);389if (rv != 0)390return (rv);391*sel &= sc->def->volt_vsel_mask;392*sel >>= ffs(sc->def->volt_vsel_mask) - 1;393return (0);394}395396static int397as3722_write_sel(struct as3722_reg_sc *sc, uint8_t sel)398{399int rv;400401sel <<= ffs(sc->def->volt_vsel_mask) - 1;402sel &= sc->def->volt_vsel_mask;403404rv = RM1(sc->base_sc, sc->def->volt_reg,405sc->def->volt_vsel_mask, sel);406if (rv != 0)407return (rv);408return (rv);409}410411static bool412as3722_sd0_is_low_voltage(struct as3722_reg_sc *sc)413{414uint8_t val;415int rv;416417rv = RD1(sc->base_sc, AS3722_FUSE7, &val);418if (rv != 0)419return (rv);420return (val & AS3722_FUSE7_SD0_LOW_VOLTAGE ? true : false);421}422423static int424as3722_reg_extreg_setup(struct as3722_reg_sc *sc, int ext_pwr_ctrl)425{426uint8_t val;427int rv;428429val = ext_pwr_ctrl << (ffs(sc->def->ext_enable_mask) - 1);430rv = RM1(sc->base_sc, sc->def->ext_enable_reg,431sc->def->ext_enable_mask, val);432return (rv);433}434435static int436as3722_reg_enable(struct as3722_reg_sc *sc)437{438int rv;439440rv = RM1(sc->base_sc, sc->def->enable_reg,441sc->def->enable_mask, sc->def->enable_mask);442return (rv);443}444445static int446as3722_reg_disable(struct as3722_reg_sc *sc)447{448int rv;449450rv = RM1(sc->base_sc, sc->def->enable_reg,451sc->def->enable_mask, 0);452return (rv);453}454455static int456as3722_regnode_init(struct regnode *regnode)457{458struct as3722_reg_sc *sc;459int rv;460461sc = regnode_get_softc(regnode);462463sc->enable_usec = 500;464if (sc->def->id == AS3722_REG_ID_SD0) {465if (as3722_sd0_is_low_voltage(sc)) {466sc->def->ranges = as3722_sd0_lv_ranges;467sc->def->nranges = nitems(as3722_sd0_lv_ranges);468}469sc->enable_usec = 600;470} else if (sc->def->id == AS3722_REG_ID_LDO3) {471if (sc->enable_tracking) {472rv = RM1(sc->base_sc, sc->def->volt_reg,473AS3722_LDO3_MODE_MASK,474AS3722_LDO3_MODE_PMOS_TRACKING);475if (rv < 0) {476device_printf(sc->base_sc->dev,477"LDO3 tracking failed: %d\n", rv);478return (rv);479}480}481}482483if (sc->ext_control) {484rv = as3722_reg_enable(sc);485if (rv < 0) {486device_printf(sc->base_sc->dev,487"Failed to enable %s regulator: %d\n",488sc->def->name, rv);489return (rv);490}491rv = as3722_reg_extreg_setup(sc, sc->ext_control);492if (rv < 0) {493device_printf(sc->base_sc->dev,494"%s ext control failed: %d", sc->def->name, rv);495return (rv);496}497}498return (0);499}500501static void502as3722_fdt_parse(struct as3722_softc *sc, phandle_t node, struct reg_def *def,503struct as3722_regnode_init_def *init_def)504{505int rv;506phandle_t parent, supply_node;507char prop_name[64]; /* Maximum OFW property name length. */508509rv = regulator_parse_ofw_stdparam(sc->dev, node,510&init_def->reg_init_def);511512rv = OF_getencprop(node, "ams,ext-control", &init_def->ext_control,513sizeof(init_def->ext_control));514if (rv <= 0)515init_def->ext_control = 0;516if (init_def->ext_control > 3) {517device_printf(sc->dev,518"Invalid value for ams,ext-control property: %d\n",519init_def->ext_control);520init_def->ext_control = 0;521}522if (OF_hasprop(node, "ams,enable-tracking"))523init_def->enable_tracking = 1;524525/* Get parent supply. */526if (def->supply_name == NULL)527return;528529parent = OF_parent(node);530snprintf(prop_name, sizeof(prop_name), "%s-supply",531def->supply_name);532rv = OF_getencprop(parent, prop_name, &supply_node,533sizeof(supply_node));534if (rv <= 0)535return;536supply_node = OF_node_from_xref(supply_node);537rv = OF_getprop_alloc(supply_node, "regulator-name",538(void **)&init_def->reg_init_def.parent_name);539if (rv <= 0)540init_def->reg_init_def.parent_name = NULL;541}542543static struct as3722_reg_sc *544as3722_attach(struct as3722_softc *sc, phandle_t node, struct reg_def *def)545{546struct as3722_reg_sc *reg_sc;547struct as3722_regnode_init_def init_def;548struct regnode *regnode;549550bzero(&init_def, sizeof(init_def));551552as3722_fdt_parse(sc, node, def, &init_def);553init_def.reg_init_def.id = def->id;554init_def.reg_init_def.ofw_node = node;555regnode = regnode_create(sc->dev, &as3722_regnode_class,556&init_def.reg_init_def);557if (regnode == NULL) {558device_printf(sc->dev, "Cannot create regulator.\n");559return (NULL);560}561reg_sc = regnode_get_softc(regnode);562563/* Init regulator softc. */564reg_sc->regnode = regnode;565reg_sc->base_sc = sc;566reg_sc->def = def;567reg_sc->xref = OF_xref_from_node(node);568569reg_sc->param = regnode_get_stdparam(regnode);570reg_sc->ext_control = init_def.ext_control;571reg_sc->enable_tracking = init_def.enable_tracking;572573regnode_register(regnode);574if (bootverbose) {575int volt, rv;576regnode_topo_slock();577rv = regnode_get_voltage(regnode, &volt);578if (rv == ENODEV) {579device_printf(sc->dev,580" Regulator %s: parent doesn't exist yet.\n",581regnode_get_name(regnode));582} else if (rv != 0) {583device_printf(sc->dev,584" Regulator %s: voltage: INVALID!!!\n",585regnode_get_name(regnode));586} else {587device_printf(sc->dev,588" Regulator %s: voltage: %d uV\n",589regnode_get_name(regnode), volt);590}591regnode_topo_unlock();592}593594return (reg_sc);595}596597int598as3722_regulator_attach(struct as3722_softc *sc, phandle_t node)599{600struct as3722_reg_sc *reg;601phandle_t child, rnode;602int i;603604rnode = ofw_bus_find_child(node, "regulators");605if (rnode <= 0) {606device_printf(sc->dev, " Cannot find regulators subnode\n");607return (ENXIO);608}609610sc->nregs = nitems(as3722s_def);611sc->regs = malloc(sizeof(struct as3722_reg_sc *) * sc->nregs,612M_AS3722_REG, M_WAITOK | M_ZERO);613614/* Attach all known regulators if exist in DT. */615for (i = 0; i < sc->nregs; i++) {616child = ofw_bus_find_child(rnode, as3722s_def[i].name);617if (child == 0) {618if (bootverbose)619device_printf(sc->dev,620"Regulator %s missing in DT\n",621as3722s_def[i].name);622continue;623}624reg = as3722_attach(sc, child, as3722s_def + i);625if (reg == NULL) {626device_printf(sc->dev, "Cannot attach regulator: %s\n",627as3722s_def[i].name);628return (ENXIO);629}630sc->regs[i] = reg;631}632return (0);633}634635int636as3722_regulator_map(device_t dev, phandle_t xref, int ncells,637pcell_t *cells, int *num)638{639struct as3722_softc *sc;640int i;641642sc = device_get_softc(dev);643for (i = 0; i < sc->nregs; i++) {644if (sc->regs[i] == NULL)645continue;646if (sc->regs[i]->xref == xref) {647*num = sc->regs[i]->def->id;648return (0);649}650}651return (ENXIO);652}653654static int655as3722_regnode_enable(struct regnode *regnode, bool val, int *udelay)656{657struct as3722_reg_sc *sc;658int rv;659660sc = regnode_get_softc(regnode);661662if (val)663rv = as3722_reg_enable(sc);664else665rv = as3722_reg_disable(sc);666*udelay = sc->enable_usec;667return (rv);668}669670static int671as3722_regnode_set_volt(struct regnode *regnode, int min_uvolt, int max_uvolt,672int *udelay)673{674struct as3722_reg_sc *sc;675uint8_t sel;676int rv;677678sc = regnode_get_softc(regnode);679680*udelay = 0;681rv = regulator_range_volt_to_sel8(sc->def->ranges, sc->def->nranges,682min_uvolt, max_uvolt, &sel);683if (rv != 0)684return (rv);685rv = as3722_write_sel(sc, sel);686return (rv);687688}689690static int691as3722_regnode_get_volt(struct regnode *regnode, int *uvolt)692{693struct as3722_reg_sc *sc;694uint8_t sel;695int rv;696697sc = regnode_get_softc(regnode);698rv = as3722_read_sel(sc, &sel);699if (rv != 0)700return (rv);701702/* LDO6 have bypass. */703if (sc->def->id == AS3722_REG_ID_LDO6 && sel == AS3722_LDO6_SEL_BYPASS)704return (ENOENT);705rv = regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges,706sel, uvolt);707return (rv);708}709710711