From fd02931841e4060fb56ac4f69ed92e2c4f7b0083 Mon Sep 17 00:00:00 2001 From: Michal Meloun Date: Tue, 18 Oct 2016 12:27:46 +0000 Subject: [PATCH] REGULATOR: Move functions for handling with regulator ranges to common file. They can be useful for other PMICs. MFC after: 2 weeks --- sys/arm/nvidia/as3722_regulators.c | 128 ++++----------------------- sys/dev/extres/regulator/regulator.c | 86 ++++++++++++++++++ sys/dev/extres/regulator/regulator.h | 21 ++++- 3 files changed, 123 insertions(+), 112 deletions(-) diff --git a/sys/arm/nvidia/as3722_regulators.c b/sys/arm/nvidia/as3722_regulators.c index 314428faa9b6..8ea00d902cab 100644 --- a/sys/arm/nvidia/as3722_regulators.c +++ b/sys/arm/nvidia/as3722_regulators.c @@ -71,13 +71,6 @@ enum as3722_reg_id { AS3722_REG_ID_LDO11, }; -struct regulator_range { - u_int min_uvolt; - u_int step_uvolt; - u_int min_sel; - u_int max_sel; -}; - /* Regulator HW definition. */ struct reg_def { @@ -107,40 +100,32 @@ struct as3722_reg_sc { int enable_usec; }; -#define RANGE_INIT(_min_sel, _max_sel, _min_uvolt, _step_uvolt) \ -{ \ - .min_sel = _min_sel, \ - .max_sel = _max_sel, \ - .min_uvolt = _min_uvolt, \ - .step_uvolt = _step_uvolt, \ -} - static struct regulator_range as3722_sd016_ranges[] = { - RANGE_INIT(0x00, 0x00, 0, 0), - RANGE_INIT(0x01, 0x5A, 610000, 10000), + REG_RANGE_INIT(0x00, 0x00, 0, 0), + REG_RANGE_INIT(0x01, 0x5A, 610000, 10000), }; static struct regulator_range as3722_sd0_lv_ranges[] = { - RANGE_INIT(0x00, 0x00, 0, 0), - RANGE_INIT(0x01, 0x6E, 410000, 10000), + REG_RANGE_INIT(0x00, 0x00, 0, 0), + REG_RANGE_INIT(0x01, 0x6E, 410000, 10000), }; static struct regulator_range as3722_sd_ranges[] = { - RANGE_INIT(0x00, 0x00, 0, 0), - RANGE_INIT(0x01, 0x40, 612500, 12500), - RANGE_INIT(0x41, 0x70, 1425000, 25000), - RANGE_INIT(0x71, 0x7F, 2650000, 50000), + REG_RANGE_INIT(0x00, 0x00, 0, 0), + REG_RANGE_INIT(0x01, 0x40, 612500, 12500), + REG_RANGE_INIT(0x41, 0x70, 1425000, 25000), + REG_RANGE_INIT(0x71, 0x7F, 2650000, 50000), }; static struct regulator_range as3722_ldo3_ranges[] = { - RANGE_INIT(0x00, 0x00, 0, 0), - RANGE_INIT(0x01, 0x2D, 620000, 20000), + REG_RANGE_INIT(0x00, 0x00, 0, 0), + REG_RANGE_INIT(0x01, 0x2D, 620000, 20000), }; static struct regulator_range as3722_ldo_ranges[] = { - RANGE_INIT(0x00, 0x00, 0, 0), - RANGE_INIT(0x01, 0x24, 825000, 25000), - RANGE_INIT(0x40, 0x7F, 1725000, 25000), + REG_RANGE_INIT(0x00, 0x00, 0, 0), + REG_RANGE_INIT(0x01, 0x24, 825000, 25000), + REG_RANGE_INIT(0x40, 0x7F, 1725000, 25000), }; static struct reg_def as3722s_def[] = { @@ -401,87 +386,6 @@ static regnode_method_t as3722_regnode_methods[] = { DEFINE_CLASS_1(as3722_regnode, as3722_regnode_class, as3722_regnode_methods, sizeof(struct as3722_reg_sc), regnode_class); -static int -regulator_range_sel_to_volt(struct as3722_reg_sc *sc, uint8_t sel, int *volt) -{ - struct regulator_range *range; - struct reg_def *def; - int i; - - def = sc->def; - if (def->nranges == 0) - panic("Voltage regulator have zero ranges\n"); - - for (i = 0; i < def->nranges ; i++) { - range = def->ranges + i; - - if (!(sel >= range->min_sel && - sel <= range->max_sel)) - continue; - - sel -= range->min_sel; - - *volt = range->min_uvolt + sel * range->step_uvolt; - return (0); - } - - return (ERANGE); -} - -static int -regulator_range_volt_to_sel(struct as3722_reg_sc *sc, int min_uvolt, - int max_uvolt, uint8_t *out_sel) -{ - struct regulator_range *range; - struct reg_def *def; - uint8_t sel; - int uvolt; - int rv, i; - - def = sc->def; - if (def->nranges == 0) - panic("Voltage regulator have zero ranges\n"); - - for (i = 0; i < def->nranges; i++) { - range = def->ranges + i; - uvolt = range->min_uvolt + - (range->max_sel - range->min_sel) * range->step_uvolt; - - if ((min_uvolt > uvolt) || - (max_uvolt < range->min_uvolt)) - continue; - - if (min_uvolt <= range->min_uvolt) - min_uvolt = range->min_uvolt; - - /* If step is zero then range is fixed voltage range. */ - if (range->step_uvolt == 0) - sel = 0; - else - sel = DIV_ROUND_UP(min_uvolt - range->min_uvolt, - range->step_uvolt); - - - sel += range->min_sel; - - break; - } - - if (i >= def->nranges) - return (ERANGE); - - /* Verify new settings. */ - rv = regulator_range_sel_to_volt(sc, sel, &uvolt); - if (rv != 0) - return (rv); - if ((uvolt < min_uvolt) || (uvolt > max_uvolt)) - return (ERANGE); - - *out_sel = sel; - return (0); -} - - static int as3722_read_sel(struct as3722_reg_sc *sc, uint8_t *sel) { @@ -783,7 +687,8 @@ as3722_regnode_set_volt(struct regnode *regnode, int min_uvolt, int max_uvolt, sc = regnode_get_softc(regnode); *udelay = 0; - rv = regulator_range_volt_to_sel(sc, min_uvolt, max_uvolt, &sel); + rv = regulator_range_volt_to_sel8(sc->def->ranges, sc->def->nranges, + min_uvolt, max_uvolt, &sel); if (rv != 0) return (rv); rv = as3722_write_sel(sc, sel); @@ -806,6 +711,7 @@ as3722_regnode_get_volt(struct regnode *regnode, int *uvolt) /* LDO6 have bypass. */ if (sc->def->id == AS3722_REG_ID_LDO6 && sel == AS3722_LDO6_SEL_BYPASS) return (ENOENT); - rv = regulator_range_sel_to_volt(sc, sel, uvolt); + rv = regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges, + sel, uvolt); return (rv); } diff --git a/sys/dev/extres/regulator/regulator.c b/sys/dev/extres/regulator/regulator.c index 729de6b69b10..10307b135dea 100644 --- a/sys/dev/extres/regulator/regulator.c +++ b/sys/dev/extres/regulator/regulator.c @@ -53,6 +53,8 @@ __FBSDID("$FreeBSD$"); MALLOC_DEFINE(M_REGULATOR, "regulator", "Regulator framework"); +#define DIV_ROUND_UP(n,d) howmany(n, d) + /* Forward declarations. */ struct regulator; struct regnode; @@ -984,3 +986,87 @@ regulator_get_by_ofw_property(device_t cdev, phandle_t cnode, char *name, return (regulator_get_by_id(cdev, regdev, id, reg)); } #endif + +/* -------------------------------------------------------------------------- + * + * Regulator utility functions. + * + */ + +/* Convert raw selector value to real voltage */ +int +regulator_range_sel8_to_volt(struct regulator_range *ranges, int nranges, + uint8_t sel, int *volt) +{ + struct regulator_range *range; + int i; + + if (nranges == 0) + panic("Voltage regulator have zero ranges\n"); + + for (i = 0; i < nranges ; i++) { + range = ranges + i; + + if (!(sel >= range->min_sel && + sel <= range->max_sel)) + continue; + + sel -= range->min_sel; + + *volt = range->min_uvolt + sel * range->step_uvolt; + return (0); + } + + return (ERANGE); +} + +int +regulator_range_volt_to_sel8(struct regulator_range *ranges, int nranges, + int min_uvolt, int max_uvolt, uint8_t *out_sel) +{ + struct regulator_range *range; + uint8_t sel; + int uvolt; + int rv, i; + + if (nranges == 0) + panic("Voltage regulator have zero ranges\n"); + + for (i = 0; i < nranges; i++) { + range = ranges + i; + uvolt = range->min_uvolt + + (range->max_sel - range->min_sel) * range->step_uvolt; + + if ((min_uvolt > uvolt) || + (max_uvolt < range->min_uvolt)) + continue; + + if (min_uvolt <= range->min_uvolt) + min_uvolt = range->min_uvolt; + + /* if step == 0 -> fixed voltage range. */ + if (range->step_uvolt == 0) + sel = 0; + else + sel = DIV_ROUND_UP(min_uvolt - range->min_uvolt, + range->step_uvolt); + + + sel += range->min_sel; + + break; + } + + if (i >= nranges) + return (ERANGE); + + /* Verify new settings. */ + rv = regulator_range_sel8_to_volt(ranges, nranges, sel, &uvolt); + if (rv != 0) + return (rv); + if ((uvolt < min_uvolt) || (uvolt > max_uvolt)) + return (ERANGE); + + *out_sel = sel; + return (0); +} diff --git a/sys/dev/extres/regulator/regulator.h b/sys/dev/extres/regulator/regulator.h index e509a7e74349..75d673d37c00 100644 --- a/sys/dev/extres/regulator/regulator.h +++ b/sys/dev/extres/regulator/regulator.h @@ -67,9 +67,22 @@ struct regnode_init_def { #ifdef FDT phandle_t ofw_node; /* OFW node of regulator */ #endif - }; +struct regulator_range { + int min_uvolt; + int step_uvolt; + uint8_t min_sel; + uint8_t max_sel; +}; + +#define REG_RANGE_INIT(_min_sel, _max_sel, _min_uvolt, _step_uvolt) { \ + .min_sel = _min_sel, \ + .max_sel = _max_sel, \ + .min_uvolt = _min_uvolt, \ + .step_uvolt = _step_uvolt, \ +} + /* * Shorthands for constructing method tables. */ @@ -125,4 +138,10 @@ int regulator_parse_ofw_stdparam(device_t dev, phandle_t node, struct regnode_init_def *def); #endif +/* Utility functions */ +int regulator_range_volt_to_sel8(struct regulator_range *ranges, int nranges, + int min_uvolt, int max_uvolt, uint8_t *out_sel); +int regulator_range_sel8_to_volt(struct regulator_range *ranges, int nranges, + uint8_t sel, int *volt); + #endif /* _DEV_EXTRES_REGULATOR_H_ */