regulator: bd718x7: Split driver to common and bd718x7 specific parts

Few ROHM PMICs allow setting the voltage states for different system states
like RUN, IDLE, SUSPEND and LPSR. States are then changed via SoC specific
mechanisms. bd718x7 driver implemented device-tree parsing functions for
these state specific voltages. The parsing functions can be re-used by
other ROHM chip drivers like bd71828. Split the generic functions from
bd718x7-regulator.c to rohm-regulator.c and export them for other modules
to use.

Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
Acked-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
This commit is contained in:
Matti Vaittinen 2020-01-20 15:44:45 +02:00 committed by Lee Jones
parent ae866dec74
commit 21b72156ed
5 changed files with 221 additions and 128 deletions

View File

@ -197,6 +197,7 @@ config REGULATOR_BD70528
config REGULATOR_BD718XX config REGULATOR_BD718XX
tristate "ROHM BD71837 Power Regulator" tristate "ROHM BD71837 Power Regulator"
depends on MFD_ROHM_BD718XX depends on MFD_ROHM_BD718XX
select REGULATOR_ROHM
help help
This driver supports voltage regulators on ROHM BD71837 PMIC. This driver supports voltage regulators on ROHM BD71837 PMIC.
This will enable support for the software controllable buck This will enable support for the software controllable buck
@ -790,6 +791,9 @@ config REGULATOR_RN5T618
Say y here to support the regulators found on Ricoh RN5T567, Say y here to support the regulators found on Ricoh RN5T567,
RN5T618 or RC5T619 PMIC. RN5T618 or RC5T619 PMIC.
config REGULATOR_ROHM
tristate
config REGULATOR_RT5033 config REGULATOR_RT5033
tristate "Richtek RT5033 Regulators" tristate "Richtek RT5033 Regulators"
depends on MFD_RT5033 depends on MFD_RT5033

View File

@ -99,6 +99,7 @@ obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o
obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o
obj-$(CONFIG_REGULATOR_ROHM) += rohm-regulator.o
obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o
obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o

View File

@ -318,6 +318,7 @@ struct reg_init {
}; };
struct bd718xx_regulator_data { struct bd718xx_regulator_data {
struct regulator_desc desc; struct regulator_desc desc;
const struct rohm_dvs_config dvs;
const struct reg_init init; const struct reg_init init;
const struct reg_init *additional_inits; const struct reg_init *additional_inits;
int additional_init_amnt; int additional_init_amnt;
@ -349,133 +350,15 @@ static const struct reg_init bd71837_ldo6_inits[] = {
}, },
}; };
#define NUM_DVS_BUCKS 4 static int buck_set_hw_dvs_levels(struct device_node *np,
struct of_dvs_setting {
const char *prop;
unsigned int reg;
};
static int set_dvs_levels(const struct of_dvs_setting *dvs,
struct device_node *np,
const struct regulator_desc *desc,
struct regmap *regmap)
{
int ret, i;
unsigned int uv;
ret = of_property_read_u32(np, dvs->prop, &uv);
if (ret) {
if (ret != -EINVAL)
return ret;
return 0;
}
for (i = 0; i < desc->n_voltages; i++) {
ret = regulator_desc_list_voltage_linear_range(desc, i);
if (ret < 0)
continue;
if (ret == uv) {
i <<= ffs(desc->vsel_mask) - 1;
ret = regmap_update_bits(regmap, dvs->reg,
DVS_BUCK_RUN_MASK, i);
break;
}
}
return ret;
}
static int buck4_set_hw_dvs_levels(struct device_node *np,
const struct regulator_desc *desc, const struct regulator_desc *desc,
struct regulator_config *cfg) struct regulator_config *cfg)
{ {
int ret, i; struct bd718xx_regulator_data *data;
const struct of_dvs_setting dvs[] = {
{
.prop = "rohm,dvs-run-voltage",
.reg = BD71837_REG_BUCK4_VOLT_RUN,
},
};
for (i = 0; i < ARRAY_SIZE(dvs); i++) { data = container_of(desc, struct bd718xx_regulator_data, desc);
ret = set_dvs_levels(&dvs[i], np, desc, cfg->regmap);
if (ret)
break;
}
return ret;
}
static int buck3_set_hw_dvs_levels(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *cfg)
{
int ret, i;
const struct of_dvs_setting dvs[] = {
{
.prop = "rohm,dvs-run-voltage",
.reg = BD71837_REG_BUCK3_VOLT_RUN,
},
};
for (i = 0; i < ARRAY_SIZE(dvs); i++) { return rohm_regulator_set_dvs_levels(&data->dvs, np, desc, cfg->regmap);
ret = set_dvs_levels(&dvs[i], np, desc, cfg->regmap);
if (ret)
break;
}
return ret;
}
static int buck2_set_hw_dvs_levels(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *cfg)
{
int ret, i;
const struct of_dvs_setting dvs[] = {
{
.prop = "rohm,dvs-run-voltage",
.reg = BD718XX_REG_BUCK2_VOLT_RUN,
},
{
.prop = "rohm,dvs-idle-voltage",
.reg = BD718XX_REG_BUCK2_VOLT_IDLE,
},
};
for (i = 0; i < ARRAY_SIZE(dvs); i++) {
ret = set_dvs_levels(&dvs[i], np, desc, cfg->regmap);
if (ret)
break;
}
return ret;
}
static int buck1_set_hw_dvs_levels(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *cfg)
{
int ret, i;
const struct of_dvs_setting dvs[] = {
{
.prop = "rohm,dvs-run-voltage",
.reg = BD718XX_REG_BUCK1_VOLT_RUN,
},
{
.prop = "rohm,dvs-idle-voltage",
.reg = BD718XX_REG_BUCK1_VOLT_IDLE,
},
{
.prop = "rohm,dvs-suspend-voltage",
.reg = BD718XX_REG_BUCK1_VOLT_SUSP,
},
};
for (i = 0; i < ARRAY_SIZE(dvs); i++) {
ret = set_dvs_levels(&dvs[i], np, desc, cfg->regmap);
if (ret)
break;
}
return ret;
} }
static const struct bd718xx_regulator_data bd71847_regulators[] = { static const struct bd718xx_regulator_data bd71847_regulators[] = {
@ -496,7 +379,17 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = {
.enable_reg = BD718XX_REG_BUCK1_CTRL, .enable_reg = BD718XX_REG_BUCK1_CTRL,
.enable_mask = BD718XX_BUCK_EN, .enable_mask = BD718XX_BUCK_EN,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_parse_cb = buck1_set_hw_dvs_levels, .of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND,
.run_reg = BD718XX_REG_BUCK1_VOLT_RUN,
.run_mask = DVS_BUCK_RUN_MASK,
.idle_reg = BD718XX_REG_BUCK1_VOLT_IDLE,
.idle_mask = DVS_BUCK_RUN_MASK,
.suspend_reg = BD718XX_REG_BUCK1_VOLT_SUSP,
.suspend_mask = DVS_BUCK_RUN_MASK,
}, },
.init = { .init = {
.reg = BD718XX_REG_BUCK1_CTRL, .reg = BD718XX_REG_BUCK1_CTRL,
@ -520,7 +413,14 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = {
.enable_reg = BD718XX_REG_BUCK2_CTRL, .enable_reg = BD718XX_REG_BUCK2_CTRL,
.enable_mask = BD718XX_BUCK_EN, .enable_mask = BD718XX_BUCK_EN,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_parse_cb = buck2_set_hw_dvs_levels, .of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE,
.run_reg = BD718XX_REG_BUCK2_VOLT_RUN,
.run_mask = DVS_BUCK_RUN_MASK,
.idle_reg = BD718XX_REG_BUCK2_VOLT_IDLE,
.idle_mask = DVS_BUCK_RUN_MASK,
}, },
.init = { .init = {
.reg = BD718XX_REG_BUCK2_CTRL, .reg = BD718XX_REG_BUCK2_CTRL,
@ -792,7 +692,17 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
.enable_reg = BD718XX_REG_BUCK1_CTRL, .enable_reg = BD718XX_REG_BUCK1_CTRL,
.enable_mask = BD718XX_BUCK_EN, .enable_mask = BD718XX_BUCK_EN,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_parse_cb = buck1_set_hw_dvs_levels, .of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND,
.run_reg = BD718XX_REG_BUCK1_VOLT_RUN,
.run_mask = DVS_BUCK_RUN_MASK,
.idle_reg = BD718XX_REG_BUCK1_VOLT_IDLE,
.idle_mask = DVS_BUCK_RUN_MASK,
.suspend_reg = BD718XX_REG_BUCK1_VOLT_SUSP,
.suspend_mask = DVS_BUCK_RUN_MASK,
}, },
.init = { .init = {
.reg = BD718XX_REG_BUCK1_CTRL, .reg = BD718XX_REG_BUCK1_CTRL,
@ -816,7 +726,14 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
.enable_reg = BD718XX_REG_BUCK2_CTRL, .enable_reg = BD718XX_REG_BUCK2_CTRL,
.enable_mask = BD718XX_BUCK_EN, .enable_mask = BD718XX_BUCK_EN,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_parse_cb = buck2_set_hw_dvs_levels, .of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE,
.run_reg = BD718XX_REG_BUCK2_VOLT_RUN,
.run_mask = DVS_BUCK_RUN_MASK,
.idle_reg = BD718XX_REG_BUCK2_VOLT_IDLE,
.idle_mask = DVS_BUCK_RUN_MASK,
}, },
.init = { .init = {
.reg = BD718XX_REG_BUCK2_CTRL, .reg = BD718XX_REG_BUCK2_CTRL,
@ -840,7 +757,12 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
.enable_reg = BD71837_REG_BUCK3_CTRL, .enable_reg = BD71837_REG_BUCK3_CTRL,
.enable_mask = BD718XX_BUCK_EN, .enable_mask = BD718XX_BUCK_EN,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_parse_cb = buck3_set_hw_dvs_levels, .of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN,
.run_reg = BD71837_REG_BUCK3_VOLT_RUN,
.run_mask = DVS_BUCK_RUN_MASK,
}, },
.init = { .init = {
.reg = BD71837_REG_BUCK3_CTRL, .reg = BD71837_REG_BUCK3_CTRL,
@ -864,7 +786,12 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
.enable_reg = BD71837_REG_BUCK4_CTRL, .enable_reg = BD71837_REG_BUCK4_CTRL,
.enable_mask = BD718XX_BUCK_EN, .enable_mask = BD718XX_BUCK_EN,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_parse_cb = buck4_set_hw_dvs_levels, .of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN,
.run_reg = BD71837_REG_BUCK4_VOLT_RUN,
.run_mask = DVS_BUCK_RUN_MASK,
}, },
.init = { .init = {
.reg = BD71837_REG_BUCK4_CTRL, .reg = BD71837_REG_BUCK4_CTRL,

View File

@ -0,0 +1,95 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020 ROHM Semiconductors
#include <linux/errno.h>
#include <linux/mfd/rohm-generic.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
static int set_dvs_level(const struct regulator_desc *desc,
struct device_node *np, struct regmap *regmap,
char *prop, unsigned int reg, unsigned int mask,
unsigned int omask, unsigned int oreg)
{
int ret, i;
uint32_t uv;
ret = of_property_read_u32(np, prop, &uv);
if (ret) {
if (ret != -EINVAL)
return ret;
return 0;
}
if (uv == 0) {
if (omask)
return regmap_update_bits(regmap, oreg, omask, 0);
}
for (i = 0; i < desc->n_voltages; i++) {
ret = regulator_desc_list_voltage_linear_range(desc, i);
if (ret < 0)
continue;
if (ret == uv) {
i <<= ffs(desc->vsel_mask) - 1;
ret = regmap_update_bits(regmap, reg, mask, i);
if (omask && !ret)
ret = regmap_update_bits(regmap, oreg, omask,
omask);
break;
}
}
return ret;
}
int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
struct device_node *np,
const struct regulator_desc *desc,
struct regmap *regmap)
{
int i, ret = 0;
char *prop;
unsigned int reg, mask, omask, oreg = desc->enable_reg;
for (i = 0; i < ROHM_DVS_LEVEL_MAX && !ret; i++) {
if (dvs->level_map & (1 << i)) {
switch (i + 1) {
case ROHM_DVS_LEVEL_RUN:
prop = "rohm,dvs-run-voltage";
reg = dvs->run_reg;
mask = dvs->run_mask;
omask = dvs->run_on_mask;
break;
case ROHM_DVS_LEVEL_IDLE:
prop = "rohm,dvs-idle-voltage";
reg = dvs->idle_reg;
mask = dvs->idle_mask;
omask = dvs->idle_on_mask;
break;
case ROHM_DVS_LEVEL_SUSPEND:
prop = "rohm,dvs-suspend-voltage";
reg = dvs->suspend_reg;
mask = dvs->suspend_mask;
omask = dvs->suspend_on_mask;
break;
case ROHM_DVS_LEVEL_LPSR:
prop = "rohm,dvs-lpsr-voltage";
reg = dvs->lpsr_reg;
mask = dvs->lpsr_mask;
omask = dvs->lpsr_on_mask;
break;
default:
return -EINVAL;
}
ret = set_dvs_level(desc, np, regmap, prop, reg, mask,
omask, oreg);
}
}
return ret;
}
EXPORT_SYMBOL(rohm_regulator_set_dvs_levels);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers");

View File

@ -4,6 +4,9 @@
#ifndef __LINUX_MFD_ROHM_H__ #ifndef __LINUX_MFD_ROHM_H__
#define __LINUX_MFD_ROHM_H__ #define __LINUX_MFD_ROHM_H__
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
enum rohm_chip_type { enum rohm_chip_type {
ROHM_CHIP_TYPE_BD71837 = 0, ROHM_CHIP_TYPE_BD71837 = 0,
ROHM_CHIP_TYPE_BD71847, ROHM_CHIP_TYPE_BD71847,
@ -17,4 +20,67 @@ struct rohm_regmap_dev {
struct regmap *regmap; struct regmap *regmap;
}; };
enum {
ROHM_DVS_LEVEL_UNKNOWN,
ROHM_DVS_LEVEL_RUN,
ROHM_DVS_LEVEL_IDLE,
ROHM_DVS_LEVEL_SUSPEND,
ROHM_DVS_LEVEL_LPSR,
ROHM_DVS_LEVEL_MAX = ROHM_DVS_LEVEL_LPSR,
};
/**
* struct rohm_dvs_config - dynamic voltage scaling register descriptions
*
* @level_map: bitmap representing supported run-levels for this
* regulator
* @run_reg: register address for regulator config at 'run' state
* @run_mask: value mask for regulator voltages at 'run' state
* @run_on_mask: enable mask for regulator at 'run' state
* @idle_reg: register address for regulator config at 'idle' state
* @idle_mask: value mask for regulator voltages at 'idle' state
* @idle_on_mask: enable mask for regulator at 'idle' state
* @suspend_reg: register address for regulator config at 'suspend' state
* @suspend_mask: value mask for regulator voltages at 'suspend' state
* @suspend_on_mask: enable mask for regulator at 'suspend' state
* @lpsr_reg: register address for regulator config at 'lpsr' state
* @lpsr_mask: value mask for regulator voltages at 'lpsr' state
* @lpsr_on_mask: enable mask for regulator at 'lpsr' state
*
* Description of ROHM PMICs voltage configuration registers for different
* system states. This is used to correctly configure the PMIC at startup
* based on values read from DT.
*/
struct rohm_dvs_config {
uint64_t level_map;
unsigned int run_reg;
unsigned int run_mask;
unsigned int run_on_mask;
unsigned int idle_reg;
unsigned int idle_mask;
unsigned int idle_on_mask;
unsigned int suspend_reg;
unsigned int suspend_mask;
unsigned int suspend_on_mask;
unsigned int lpsr_reg;
unsigned int lpsr_mask;
unsigned int lpsr_on_mask;
};
#if IS_ENABLED(CONFIG_REGULATOR_ROHM)
int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
struct device_node *np,
const struct regulator_desc *desc,
struct regmap *regmap);
#else
static inline int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
struct device_node *np,
const struct regulator_desc *desc,
struct regmap *regmap)
{
return 0;
}
#endif
#endif #endif