Path: blob/main/sys/arm64/nvidia/tegra210/max77620_regulators.c
48262 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright 2020 Michal Meloun <[email protected]>4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#include <sys/param.h>28#include <sys/systm.h>29#include <sys/bus.h>30#include <sys/gpio.h>31#include <sys/kernel.h>32#include <sys/module.h>33#include <sys/malloc.h>34#include <sys/rman.h>35#include <sys/sx.h>3637#include <machine/bus.h>3839#include <dev/regulator/regulator.h>40#include <dev/gpio/gpiobusvar.h>4142#include <dt-bindings/mfd/max77620.h>4344#include "max77620.h"4546MALLOC_DEFINE(M_MAX77620_REG, "MAX77620 regulator", "MAX77620 power regulator");4748#define DIV_ROUND_UP(n,d) howmany(n, d)4950enum max77620_reg_id {51MAX77620_REG_ID_SD0,52MAX77620_REG_ID_SD1,53MAX77620_REG_ID_SD2,54MAX77620_REG_ID_SD3,55MAX77620_REG_ID_LDO0,56MAX77620_REG_ID_LDO1,57MAX77620_REG_ID_LDO2,58MAX77620_REG_ID_LDO3,59MAX77620_REG_ID_LDO4,60MAX77620_REG_ID_LDO5,61MAX77620_REG_ID_LDO6,62MAX77620_REG_ID_LDO7,63MAX77620_REG_ID_LDO8,64};6566/* Initial configuration. */67struct max77620_regnode_init_def {68struct regnode_init_def reg_init_def;69int active_fps_src;70int active_fps_pu_slot;71int active_fps_pd_slot;72int suspend_fps_src;73int suspend_fps_pu_slot;74int suspend_fps_pd_slot;75int ramp_rate_setting;76};7778/* Regulator HW definition. */79struct reg_def {80intptr_t id; /* ID */81char *name; /* Regulator name */82char *supply_name; /* Source property name */83bool is_sd_reg; /* SD or LDO regulator? */84uint8_t volt_reg;85uint8_t volt_vsel_mask;86uint8_t cfg_reg;87uint8_t fps_reg;88uint8_t pwr_mode_reg;89uint8_t pwr_mode_mask;90uint8_t pwr_mode_shift;91struct regulator_range *ranges;92int nranges;93};9495struct max77620_reg_sc {96struct regnode *regnode;97struct max77620_softc *base_sc;98struct reg_def *def;99phandle_t xref;100101struct regnode_std_param *param;102/* Configured values */103int active_fps_src;104int active_fps_pu_slot;105int active_fps_pd_slot;106int suspend_fps_src;107int suspend_fps_pu_slot;108int suspend_fps_pd_slot;109int ramp_rate_setting;110int enable_usec;111uint8_t enable_pwr_mode;112113/* Cached values */114uint8_t fps_src;115uint8_t pwr_mode;116int pwr_ramp_delay;117};118119static struct regulator_range max77620_sd0_ranges[] = {120REG_RANGE_INIT(0, 64, 600000, 12500), /* 0.6V - 1.4V / 12.5mV */121};122123static struct regulator_range max77620_sd1_ranges[] = {124REG_RANGE_INIT(0, 76, 600000, 12500), /* 0.6V - 1.55V / 12.5mV */125};126127static struct regulator_range max77620_sdx_ranges[] = {128REG_RANGE_INIT(0, 255, 600000, 12500), /* 0.6V - 3.7875V / 12.5mV */129};130131static struct regulator_range max77620_ldo0_1_ranges[] = {132REG_RANGE_INIT(0, 63, 800000, 25000), /* 0.8V - 2.375V / 25mV */133};134135static struct regulator_range max77620_ldo4_ranges[] = {136REG_RANGE_INIT(0, 63, 800000, 12500), /* 0.8V - 1.5875V / 12.5mV */137};138139static struct regulator_range max77620_ldox_ranges[] = {140REG_RANGE_INIT(0, 63, 800000, 50000), /* 0.8V - 3.95V / 50mV */141};142143static struct reg_def max77620s_def[] = {144{145.id = MAX77620_REG_ID_SD0,146.name = "sd0",147.supply_name = "in-sd0",148.is_sd_reg = true,149.volt_reg = MAX77620_REG_SD0,150.volt_vsel_mask = MAX77620_SD0_VSEL_MASK,151.cfg_reg = MAX77620_REG_CFG_SD0,152.fps_reg = MAX77620_REG_FPS_SD0,153.pwr_mode_reg = MAX77620_REG_CFG_SD0,154.pwr_mode_mask = MAX77620_SD_POWER_MODE_MASK,155.pwr_mode_shift = MAX77620_SD_POWER_MODE_SHIFT,156.ranges = max77620_sd0_ranges,157.nranges = nitems(max77620_sd0_ranges),158},159{160.id = MAX77620_REG_ID_SD1,161.name = "sd1",162.supply_name = "in-sd1",163.is_sd_reg = true,164.volt_reg = MAX77620_REG_SD1,165.volt_vsel_mask = MAX77620_SD1_VSEL_MASK,166.cfg_reg = MAX77620_REG_CFG_SD1,167.fps_reg = MAX77620_REG_FPS_SD1,168.pwr_mode_reg = MAX77620_REG_CFG_SD1,169.pwr_mode_mask = MAX77620_SD_POWER_MODE_MASK,170.pwr_mode_shift = MAX77620_SD_POWER_MODE_SHIFT,171.ranges = max77620_sd1_ranges,172.nranges = nitems(max77620_sd1_ranges),173},174{175.id = MAX77620_REG_ID_SD2,176.name = "sd2",177.supply_name = "in-sd2",178.is_sd_reg = true,179.volt_reg = MAX77620_REG_SD2,180.volt_vsel_mask = MAX77620_SDX_VSEL_MASK,181.cfg_reg = MAX77620_REG_CFG_SD2,182.fps_reg = MAX77620_REG_FPS_SD2,183.pwr_mode_reg = MAX77620_REG_CFG_SD2,184.pwr_mode_mask = MAX77620_SD_POWER_MODE_MASK,185.pwr_mode_shift = MAX77620_SD_POWER_MODE_SHIFT,186.ranges = max77620_sdx_ranges,187.nranges = nitems(max77620_sdx_ranges),188},189{190.id = MAX77620_REG_ID_SD3,191.name = "sd3",192.supply_name = "in-sd3",193.is_sd_reg = true,194.volt_reg = MAX77620_REG_SD3,195.volt_vsel_mask = MAX77620_SDX_VSEL_MASK,196.cfg_reg = MAX77620_REG_CFG_SD3,197.fps_reg = MAX77620_REG_FPS_SD3,198.pwr_mode_reg = MAX77620_REG_CFG_SD3,199.pwr_mode_mask = MAX77620_SD_POWER_MODE_MASK,200.pwr_mode_shift = MAX77620_SD_POWER_MODE_SHIFT,201.ranges = max77620_sdx_ranges,202.nranges = nitems(max77620_sdx_ranges),203},204{205.id = MAX77620_REG_ID_LDO0,206.name = "ldo0",207.supply_name = "vin-ldo0-1",208.volt_reg = MAX77620_REG_CFG_LDO0,209.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,210.is_sd_reg = false,211.cfg_reg = MAX77620_REG_CFG2_LDO0,212.fps_reg = MAX77620_REG_FPS_LDO0,213.pwr_mode_reg = MAX77620_REG_CFG_LDO0,214.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,215.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,216.ranges = max77620_ldo0_1_ranges,217.nranges = nitems(max77620_ldo0_1_ranges),218},219{220.id = MAX77620_REG_ID_LDO1,221.name = "ldo1",222.supply_name = "in-ldo0-1",223.is_sd_reg = false,224.volt_reg = MAX77620_REG_CFG_LDO1,225.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,226.cfg_reg = MAX77620_REG_CFG2_LDO1,227.fps_reg = MAX77620_REG_FPS_LDO1,228.pwr_mode_reg = MAX77620_REG_CFG_LDO1,229.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,230.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,231.ranges = max77620_ldo0_1_ranges,232.nranges = nitems(max77620_ldo0_1_ranges),233},234{235.id = MAX77620_REG_ID_LDO2,236.name = "ldo2",237.supply_name = "in-ldo2",238.is_sd_reg = false,239.volt_reg = MAX77620_REG_CFG_LDO2,240.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,241.cfg_reg = MAX77620_REG_CFG2_LDO2,242.fps_reg = MAX77620_REG_FPS_LDO2,243.pwr_mode_reg = MAX77620_REG_CFG_LDO2,244.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,245.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,246.ranges = max77620_ldox_ranges,247.nranges = nitems(max77620_ldox_ranges),248},249{250.id = MAX77620_REG_ID_LDO3,251.name = "ldo3",252.supply_name = "in-ldo3-5",253.is_sd_reg = false,254.volt_reg = MAX77620_REG_CFG_LDO3,255.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,256.cfg_reg = MAX77620_REG_CFG2_LDO3,257.fps_reg = MAX77620_REG_FPS_LDO3,258.pwr_mode_reg = MAX77620_REG_CFG_LDO3,259.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,260.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,261.ranges = max77620_ldox_ranges,262.nranges = nitems(max77620_ldox_ranges),263},264{265.id = MAX77620_REG_ID_LDO4,266.name = "ldo4",267.supply_name = "in-ldo4-6",268.is_sd_reg = false,269.volt_reg = MAX77620_REG_CFG_LDO4,270.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,271.cfg_reg = MAX77620_REG_CFG2_LDO4,272.fps_reg = MAX77620_REG_FPS_LDO4,273.pwr_mode_reg = MAX77620_REG_CFG_LDO4,274.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,275.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,276.ranges = max77620_ldo4_ranges,277.nranges = nitems(max77620_ldo4_ranges),278},279{280.id = MAX77620_REG_ID_LDO5,281.name = "ldo5",282.supply_name = "in-ldo3-5",283.is_sd_reg = false,284.volt_reg = MAX77620_REG_CFG_LDO5,285.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,286.cfg_reg = MAX77620_REG_CFG2_LDO5,287.fps_reg = MAX77620_REG_FPS_LDO5,288.pwr_mode_reg = MAX77620_REG_CFG_LDO5,289.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,290.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,291.ranges = max77620_ldox_ranges,292.nranges = nitems(max77620_ldox_ranges),293},294{295.id = MAX77620_REG_ID_LDO6,296.name = "ldo6",297.supply_name = "in-ldo4-6",298.is_sd_reg = false,299.volt_reg = MAX77620_REG_CFG_LDO6,300.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,301.cfg_reg = MAX77620_REG_CFG2_LDO6,302.fps_reg = MAX77620_REG_FPS_LDO6,303.pwr_mode_reg = MAX77620_REG_CFG_LDO6,304.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,305.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,306.ranges = max77620_ldox_ranges,307.nranges = nitems(max77620_ldox_ranges),308},309{310.id = MAX77620_REG_ID_LDO7,311.name = "ldo7",312.supply_name = "in-ldo7-8",313.is_sd_reg = false,314.volt_reg = MAX77620_REG_CFG_LDO7,315.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,316.cfg_reg = MAX77620_REG_CFG2_LDO7,317.fps_reg = MAX77620_REG_FPS_LDO7,318.pwr_mode_reg = MAX77620_REG_CFG_LDO7,319.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,320.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,321.ranges = max77620_ldox_ranges,322.nranges = nitems(max77620_ldox_ranges),323},324{325.id = MAX77620_REG_ID_LDO8,326.name = "ldo8",327.supply_name = "in-ldo7-8",328.is_sd_reg = false,329.volt_reg = MAX77620_REG_CFG_LDO8,330.volt_vsel_mask = MAX77620_LDO_VSEL_MASK,331.cfg_reg = MAX77620_REG_CFG2_LDO8,332.fps_reg = MAX77620_REG_FPS_LDO8,333.pwr_mode_reg = MAX77620_REG_CFG_LDO8,334.pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK,335.pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT,336.ranges = max77620_ldox_ranges,337.nranges = nitems(max77620_ldox_ranges),338},339};340341342static int max77620_regnode_init(struct regnode *regnode);343static int max77620_regnode_enable(struct regnode *regnode, bool enable,344int *udelay);345static int max77620_regnode_set_volt(struct regnode *regnode, int min_uvolt,346int max_uvolt, int *udelay);347static int max77620_regnode_get_volt(struct regnode *regnode, int *uvolt);348static regnode_method_t max77620_regnode_methods[] = {349/* Regulator interface */350REGNODEMETHOD(regnode_init, max77620_regnode_init),351REGNODEMETHOD(regnode_enable, max77620_regnode_enable),352REGNODEMETHOD(regnode_set_voltage, max77620_regnode_set_volt),353REGNODEMETHOD(regnode_get_voltage, max77620_regnode_get_volt),354REGNODEMETHOD_END355};356DEFINE_CLASS_1(max77620_regnode, max77620_regnode_class, max77620_regnode_methods,357sizeof(struct max77620_reg_sc), regnode_class);358359static int360max77620_get_sel(struct max77620_reg_sc *sc, uint8_t *sel)361{362int rv;363364rv = RD1(sc->base_sc, sc->def->volt_reg, sel);365if (rv != 0) {366printf("%s: cannot read volatge selector: %d\n",367regnode_get_name(sc->regnode), rv);368return (rv);369}370*sel &= sc->def->volt_vsel_mask;371*sel >>= ffs(sc->def->volt_vsel_mask) - 1;372return (0);373}374375static int376max77620_set_sel(struct max77620_reg_sc *sc, uint8_t sel)377{378int rv;379380sel <<= ffs(sc->def->volt_vsel_mask) - 1;381sel &= sc->def->volt_vsel_mask;382383rv = RM1(sc->base_sc, sc->def->volt_reg,384sc->def->volt_vsel_mask, sel);385if (rv != 0) {386printf("%s: cannot set volatge selector: %d\n",387regnode_get_name(sc->regnode), rv);388return (rv);389}390return (rv);391}392393static int394max77620_get_fps_src(struct max77620_reg_sc *sc, uint8_t *fps_src)395{396uint8_t val;397int rv;398399rv = RD1(sc->base_sc, sc->def->fps_reg, &val);400if (rv != 0)401return (rv);402403*fps_src = (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT;404return (0);405}406407static int408max77620_set_fps_src(struct max77620_reg_sc *sc, uint8_t fps_src)409{410int rv;411412rv = RM1(sc->base_sc, sc->def->fps_reg, MAX77620_FPS_SRC_MASK,413fps_src << MAX77620_FPS_SRC_SHIFT);414if (rv != 0)415return (rv);416sc->fps_src = fps_src;417return (0);418}419420static int421max77620_set_fps_slots(struct max77620_reg_sc *sc, bool suspend)422{423uint8_t mask, val;424int pu_slot, pd_slot, rv;425426if (suspend) {427pu_slot = sc->suspend_fps_pu_slot;428pd_slot = sc->suspend_fps_pd_slot;429} else {430pu_slot = sc->active_fps_pu_slot;431pd_slot = sc->active_fps_pd_slot;432}433434mask = 0;435val = 0;436if (pu_slot >= 0) {437mask |= MAX77620_FPS_PU_PERIOD_MASK;438val |= ((uint8_t)pu_slot << MAX77620_FPS_PU_PERIOD_SHIFT) &439MAX77620_FPS_PU_PERIOD_MASK;440}441if (pd_slot >= 0) {442mask |= MAX77620_FPS_PD_PERIOD_MASK;443val |= ((uint8_t)pd_slot << MAX77620_FPS_PD_PERIOD_SHIFT) &444MAX77620_FPS_PD_PERIOD_MASK;445}446447rv = RM1(sc->base_sc, sc->def->fps_reg, mask, val);448if (rv != 0)449return (rv);450return (0);451}452453static int454max77620_get_pwr_mode(struct max77620_reg_sc *sc, uint8_t *pwr_mode)455{456uint8_t val;457int rv;458459rv = RD1(sc->base_sc, sc->def->pwr_mode_reg, &val);460if (rv != 0)461return (rv);462463*pwr_mode = (val & sc->def->pwr_mode_mask) >> sc->def->pwr_mode_shift;464return (0);465}466467static int468max77620_set_pwr_mode(struct max77620_reg_sc *sc, uint8_t pwr_mode)469{470int rv;471472rv = RM1(sc->base_sc, sc->def->pwr_mode_reg, sc->def->pwr_mode_shift,473pwr_mode << sc->def->pwr_mode_shift);474if (rv != 0)475return (rv);476sc->pwr_mode = pwr_mode;477return (0);478}479480static int481max77620_get_pwr_ramp_delay(struct max77620_reg_sc *sc, int *rate)482{483uint8_t val;484int rv;485486rv = RD1(sc->base_sc, sc->def->cfg_reg, &val);487if (rv != 0)488return (rv);489490if (sc->def->is_sd_reg) {491val = (val & MAX77620_SD_SR_MASK) >> MAX77620_SD_SR_SHIFT;492if (val == 0)493*rate = 13750;494else if (val == 1)495*rate = 27500;496else if (val == 2)497*rate = 55000;498else499*rate = 100000;500} else {501val = (val & MAX77620_LDO_SLEW_RATE_MASK) >>502MAX77620_LDO_SLEW_RATE_SHIFT;503if (val == 0)504*rate = 100000;505else506*rate = 5000;507}508sc->pwr_ramp_delay = *rate;509return (0);510}511512static int513max77620_set_pwr_ramp_delay(struct max77620_reg_sc *sc, int rate)514{515uint8_t val, mask;516int rv;517518if (sc->def->is_sd_reg) {519if (rate <= 13750)520val = 0;521else if (rate <= 27500)522val = 1;523else if (rate <= 55000)524val = 2;525else526val = 3;527val <<= MAX77620_SD_SR_SHIFT;528mask = MAX77620_SD_SR_MASK;529} else {530if (rate <= 5000)531val = 1;532else533val = 0;534val <<= MAX77620_LDO_SLEW_RATE_SHIFT;535mask = MAX77620_LDO_SLEW_RATE_MASK;536}537rv = RM1(sc->base_sc, sc->def->cfg_reg, mask, val);538if (rv != 0)539return (rv);540return (0);541}542543static int544max77620_regnode_init(struct regnode *regnode)545{546struct max77620_reg_sc *sc;547uint8_t val;548int intval, rv;549550sc = regnode_get_softc(regnode);551sc->enable_usec = 500;552sc->enable_pwr_mode = MAX77620_POWER_MODE_NORMAL;553#if 0554{555uint8_t val1, val2, val3;556RD1(sc->base_sc, sc->def->volt_reg, &val1);557RD1(sc->base_sc, sc->def->cfg_reg, &val2);558RD1(sc->base_sc, sc->def->fps_reg, &val3);559printf("%s: Volt: 0x%02X, CFG: 0x%02X, FPS: 0x%02X\n", regnode_get_name(sc->regnode), val1, val2, val3);560}561#endif562/* Get current power mode */563rv = max77620_get_pwr_mode(sc, &val);564if (rv != 0) {565printf("%s: cannot read current power mode: %d\n",566regnode_get_name(sc->regnode), rv);567return (rv);568}569sc->pwr_mode = val;570571/* Get current power ramp delay */572rv = max77620_get_pwr_ramp_delay(sc, &intval);573if (rv != 0) {574printf("%s: cannot read current power mode: %d\n",575regnode_get_name(sc->regnode), rv);576return (rv);577}578sc->pwr_ramp_delay = intval;579580/* Get FPS source if is not specified. */581if (sc->active_fps_src == -1) {582rv = max77620_get_fps_src(sc, &val);583if (rv != 0) {584printf("%s: cannot read current FPS source: %d\n",585regnode_get_name(sc->regnode), rv);586return (rv);587}588sc->active_fps_src = val;589}590591/* Configure power mode non-FPS controlled regulators. */592if (sc->active_fps_src != MAX77620_FPS_SRC_NONE ||593(sc->pwr_mode != MAX77620_POWER_MODE_DISABLE &&594sc->pwr_mode != sc->enable_pwr_mode)) {595rv = max77620_set_pwr_mode(sc, (uint8_t)sc->enable_pwr_mode);596if (rv != 0) {597printf("%s: cannot set power mode: %d\n",598regnode_get_name(sc->regnode), rv);599return (rv);600}601}602603/* Set FPS source. */604rv = max77620_set_fps_src(sc, sc->active_fps_src);605if (rv != 0) {606printf("%s: cannot setup FPS source: %d\n",607regnode_get_name(sc->regnode), rv);608return (rv);609}610/* Set FPS slots. */611rv = max77620_set_fps_slots(sc, false);612if (rv != 0) {613printf("%s: cannot setup power slots: %d\n",614regnode_get_name(sc->regnode), rv);615return (rv);616}617/* Setup power ramp . */618if (sc->ramp_rate_setting != -1) {619rv = max77620_set_pwr_ramp_delay(sc, sc->pwr_ramp_delay);620if (rv != 0) {621printf("%s: cannot set power ramp delay: %d\n",622regnode_get_name(sc->regnode), rv);623return (rv);624}625}626627return (0);628}629630static void631max77620_fdt_parse(struct max77620_softc *sc, phandle_t node, struct reg_def *def,632struct max77620_regnode_init_def *init_def)633{634int rv;635phandle_t parent, supply_node;636char prop_name[64]; /* Maximum OFW property name length. */637638rv = regulator_parse_ofw_stdparam(sc->dev, node,639&init_def->reg_init_def);640641rv = OF_getencprop(node, "maxim,active-fps-source",642&init_def->active_fps_src, sizeof(init_def->active_fps_src));643if (rv <= 0)644init_def->active_fps_src = MAX77620_FPS_SRC_DEF;645646rv = OF_getencprop(node, "maxim,active-fps-power-up-slot",647&init_def->active_fps_pu_slot, sizeof(init_def->active_fps_pu_slot));648if (rv <= 0)649init_def->active_fps_pu_slot = -1;650651rv = OF_getencprop(node, "maxim,active-fps-power-down-slot",652&init_def->active_fps_pd_slot, sizeof(init_def->active_fps_pd_slot));653if (rv <= 0)654init_def->active_fps_pd_slot = -1;655656rv = OF_getencprop(node, "maxim,suspend-fps-source",657&init_def->suspend_fps_src, sizeof(init_def->suspend_fps_src));658if (rv <= 0)659init_def->suspend_fps_src = -1;660661rv = OF_getencprop(node, "maxim,suspend-fps-power-up-slot",662&init_def->suspend_fps_pu_slot, sizeof(init_def->suspend_fps_pu_slot));663if (rv <= 0)664init_def->suspend_fps_pu_slot = -1;665666rv = OF_getencprop(node, "maxim,suspend-fps-power-down-slot",667&init_def->suspend_fps_pd_slot, sizeof(init_def->suspend_fps_pd_slot));668if (rv <= 0)669init_def->suspend_fps_pd_slot = -1;670671rv = OF_getencprop(node, "maxim,ramp-rate-setting",672&init_def->ramp_rate_setting, sizeof(init_def->ramp_rate_setting));673if (rv <= 0)674init_def->ramp_rate_setting = -1;675676/* Get parent supply. */677if (def->supply_name == NULL)678return;679680parent = OF_parent(node);681snprintf(prop_name, sizeof(prop_name), "%s-supply",682def->supply_name);683rv = OF_getencprop(parent, prop_name, &supply_node,684sizeof(supply_node));685if (rv <= 0)686return;687supply_node = OF_node_from_xref(supply_node);688rv = OF_getprop_alloc(supply_node, "regulator-name",689(void **)&init_def->reg_init_def.parent_name);690if (rv <= 0)691init_def->reg_init_def.parent_name = NULL;692}693694static struct max77620_reg_sc *695max77620_attach(struct max77620_softc *sc, phandle_t node, struct reg_def *def)696{697struct max77620_reg_sc *reg_sc;698struct max77620_regnode_init_def init_def;699struct regnode *regnode;700701bzero(&init_def, sizeof(init_def));702703max77620_fdt_parse(sc, node, def, &init_def);704init_def.reg_init_def.id = def->id;705init_def.reg_init_def.ofw_node = node;706regnode = regnode_create(sc->dev, &max77620_regnode_class,707&init_def.reg_init_def);708if (regnode == NULL) {709device_printf(sc->dev, "Cannot create regulator.\n");710return (NULL);711}712reg_sc = regnode_get_softc(regnode);713714/* Init regulator softc. */715reg_sc->regnode = regnode;716reg_sc->base_sc = sc;717reg_sc->def = def;718reg_sc->xref = OF_xref_from_node(node);719reg_sc->param = regnode_get_stdparam(regnode);720reg_sc->active_fps_src = init_def.active_fps_src;721reg_sc->active_fps_pu_slot = init_def.active_fps_pu_slot;722reg_sc->active_fps_pd_slot = init_def.active_fps_pd_slot;723reg_sc->suspend_fps_src = init_def.suspend_fps_src;724reg_sc->suspend_fps_pu_slot = init_def.suspend_fps_pu_slot;725reg_sc->suspend_fps_pd_slot = init_def.suspend_fps_pd_slot;726reg_sc->ramp_rate_setting = init_def.ramp_rate_setting;727728regnode_register(regnode);729if (bootverbose) {730int volt, rv;731regnode_topo_slock();732rv = regnode_get_voltage(regnode, &volt);733if (rv == ENODEV) {734device_printf(sc->dev,735" Regulator %s: parent doesn't exist yet.\n",736regnode_get_name(regnode));737} else if (rv != 0) {738device_printf(sc->dev,739" Regulator %s: voltage: INVALID!!!\n",740regnode_get_name(regnode));741} else {742device_printf(sc->dev,743" Regulator %s: voltage: %d uV\n",744regnode_get_name(regnode), volt);745device_printf(sc->dev,746" FPS source: %d, mode: %d, ramp delay: %d\n",747reg_sc->fps_src, reg_sc->pwr_mode,748reg_sc->pwr_ramp_delay);749}750regnode_topo_unlock();751}752753return (reg_sc);754}755756int757max77620_regulator_attach(struct max77620_softc *sc, phandle_t node)758{759struct max77620_reg_sc *reg;760phandle_t child, rnode;761int i;762763rnode = ofw_bus_find_child(node, "regulators");764if (rnode <= 0) {765device_printf(sc->dev, " Cannot find regulators subnode\n");766return (ENXIO);767}768769sc->nregs = nitems(max77620s_def);770sc->regs = malloc(sizeof(struct max77620_reg_sc *) * sc->nregs,771M_MAX77620_REG, M_WAITOK | M_ZERO);772773774/* Attach all known regulators if exist in DT. */775for (i = 0; i < sc->nregs; i++) {776child = ofw_bus_find_child(rnode, max77620s_def[i].name);777if (child == 0) {778if (bootverbose)779device_printf(sc->dev,780"Regulator %s missing in DT\n",781max77620s_def[i].name);782continue;783}784if (ofw_bus_node_status_okay(child) == 0)785continue;786reg = max77620_attach(sc, child, max77620s_def + i);787if (reg == NULL) {788device_printf(sc->dev, "Cannot attach regulator: %s\n",789max77620s_def[i].name);790return (ENXIO);791}792sc->regs[i] = reg;793}794return (0);795}796797int798max77620_regulator_map(device_t dev, phandle_t xref, int ncells,799pcell_t *cells, intptr_t *num)800{801struct max77620_softc *sc;802int i;803804sc = device_get_softc(dev);805for (i = 0; i < sc->nregs; i++) {806if (sc->regs[i] == NULL)807continue;808if (sc->regs[i]->xref == xref) {809*num = sc->regs[i]->def->id;810return (0);811}812}813814return (ENXIO);815}816817static int818max77620_regnode_enable(struct regnode *regnode, bool val, int *udelay)819{820821struct max77620_reg_sc *sc;822uint8_t mode;823int rv;824825sc = regnode_get_softc(regnode);826827if (sc->active_fps_src != MAX77620_FPS_SRC_NONE) {828*udelay = 0;829return (0);830}831832if (val)833mode = sc->enable_pwr_mode;834else835mode = MAX77620_POWER_MODE_DISABLE;836837rv = max77620_set_pwr_mode(sc, mode);838if (rv != 0) {839printf("%s: cannot set power mode: %d\n",840regnode_get_name(sc->regnode), rv);841return (rv);842}843844*udelay = sc->enable_usec;845return (0);846}847848static int849max77620_regnode_set_volt(struct regnode *regnode, int min_uvolt, int max_uvolt,850int *udelay)851{852struct max77620_reg_sc *sc;853uint8_t sel;854int rv;855856sc = regnode_get_softc(regnode);857858*udelay = 0;859rv = regulator_range_volt_to_sel8(sc->def->ranges, sc->def->nranges,860min_uvolt, max_uvolt, &sel);861if (rv != 0)862return (rv);863rv = max77620_set_sel(sc, sel);864return (rv);865}866867static int868max77620_regnode_get_volt(struct regnode *regnode, int *uvolt)869{870871struct max77620_reg_sc *sc;872uint8_t sel;873int rv;874875sc = regnode_get_softc(regnode);876rv = max77620_get_sel(sc, &sel);877if (rv != 0)878return (rv);879880rv = regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges,881sel, uvolt);882return (rv);883return(0);884}885886887