drivers: regulator: fix/improve usage of devicetree properties
Most of devicetree properties for regulator, such as: - regulator-min/max-microvolt - regulator-min/max-microamp - regulator-allowed-modes - etc. Are meant to specify limits on what consumers may set. They are **NOT** meant to describe the hardware capabilities. For example, I could have a BUCK converter that supports 0-5V output voltage, but my circuit may only allow working on the 2.7-3.3V range. This patch reworks the API so that the API class layer manages this information. This is done by drivers collecting all such fields in a common configuration structure that is later accessed by the class layer. This simplifies drivers implementation. For example, if A consumer calls regulator_set_voltage() with a voltage that is supported but not allowed, driver code won't be called. Similarly, if a regulator is configured to be `always-on`, enable/disable driver code will never be called. Drivers have been adjusted. PCA9420 mode settings have been removed from devicetree in this commit as they are not actual modes but PMIC states. This will be refactored in a follow-up commit. Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
This commit is contained in:
parent
1029a4db6f
commit
10ce9684c3
7 changed files with 222 additions and 158 deletions
|
@ -16,18 +16,29 @@ void regulator_common_data_init(const struct device *dev)
|
|||
|
||||
int regulator_enable(const struct device *dev)
|
||||
{
|
||||
const struct regulator_driver_api *api =
|
||||
(const struct regulator_driver_api *)dev->api;
|
||||
const struct regulator_common_config *config =
|
||||
(struct regulator_common_config *)dev->config;
|
||||
struct regulator_common_data *data =
|
||||
(struct regulator_common_data *)dev->data;
|
||||
int ret = 0;
|
||||
|
||||
/* enable not supported (always on) */
|
||||
if (api->enable == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* regulator must stay always on */
|
||||
if ((config->flags & REGULATOR_ALWAYS_ON) != 0U) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void)k_mutex_lock(&data->lock, K_FOREVER);
|
||||
|
||||
data->refcnt++;
|
||||
|
||||
if (data->refcnt == 1) {
|
||||
const struct regulator_driver_api *api =
|
||||
(const struct regulator_driver_api *)dev->api;
|
||||
|
||||
ret = api->enable(dev);
|
||||
if (ret < 0) {
|
||||
data->refcnt--;
|
||||
|
@ -41,18 +52,29 @@ int regulator_enable(const struct device *dev)
|
|||
|
||||
int regulator_disable(const struct device *dev)
|
||||
{
|
||||
const struct regulator_driver_api *api =
|
||||
(const struct regulator_driver_api *)dev->api;
|
||||
const struct regulator_common_config *config =
|
||||
(struct regulator_common_config *)dev->config;
|
||||
struct regulator_common_data *data =
|
||||
(struct regulator_common_data *)dev->data;
|
||||
int ret = 0;
|
||||
|
||||
/* disable not supported (always on) */
|
||||
if (api->disable == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* regulator must stay always on */
|
||||
if ((config->flags & REGULATOR_ALWAYS_ON) != 0U) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void)k_mutex_lock(&data->lock, K_FOREVER);
|
||||
|
||||
data->refcnt--;
|
||||
|
||||
if (data->refcnt == 0) {
|
||||
const struct regulator_driver_api *api =
|
||||
(const struct regulator_driver_api *)dev->api;
|
||||
|
||||
ret = api->disable(dev);
|
||||
if (ret < 0) {
|
||||
data->refcnt++;
|
||||
|
@ -67,7 +89,16 @@ int regulator_disable(const struct device *dev)
|
|||
bool regulator_is_supported_voltage(const struct device *dev, int32_t min_uv,
|
||||
int32_t max_uv)
|
||||
{
|
||||
unsigned int volt_cnt = regulator_count_voltages(dev);
|
||||
const struct regulator_common_config *config =
|
||||
(struct regulator_common_config *)dev->config;
|
||||
unsigned int volt_cnt;
|
||||
|
||||
/* voltage may not be allowed, even if supported */
|
||||
if ((min_uv < config->min_uv) || (max_uv > config->max_uv)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
volt_cnt = regulator_count_voltages(dev);
|
||||
|
||||
for (unsigned int idx = 0U; idx < volt_cnt; idx++) {
|
||||
int32_t volt_uv;
|
||||
|
@ -81,3 +112,69 @@ bool regulator_is_supported_voltage(const struct device *dev, int32_t min_uv,
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
int regulator_set_voltage(const struct device *dev, int32_t min_uv,
|
||||
int32_t max_uv)
|
||||
{
|
||||
const struct regulator_common_config *config =
|
||||
(struct regulator_common_config *)dev->config;
|
||||
const struct regulator_driver_api *api =
|
||||
(const struct regulator_driver_api *)dev->api;
|
||||
|
||||
if (api->set_voltage == NULL) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/* voltage may not be allowed, even if supported */
|
||||
if ((min_uv < config->min_uv) || (max_uv > config->max_uv)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return api->set_voltage(dev, min_uv, max_uv);
|
||||
}
|
||||
|
||||
int regulator_set_current_limit(const struct device *dev, int32_t min_ua,
|
||||
int32_t max_ua)
|
||||
{
|
||||
const struct regulator_common_config *config =
|
||||
(struct regulator_common_config *)dev->config;
|
||||
const struct regulator_driver_api *api =
|
||||
(const struct regulator_driver_api *)dev->api;
|
||||
|
||||
if (api->set_current_limit == NULL) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/* current limit may not be allowed, even if supported */
|
||||
if ((min_ua < config->min_ua) || (max_ua > config->max_ua)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return api->set_current_limit(dev, min_ua, max_ua);
|
||||
}
|
||||
|
||||
int regulator_set_mode(const struct device *dev, regulator_mode_t mode)
|
||||
{
|
||||
const struct regulator_common_config *config =
|
||||
(struct regulator_common_config *)dev->config;
|
||||
const struct regulator_driver_api *api =
|
||||
(const struct regulator_driver_api *)dev->api;
|
||||
|
||||
if (api->set_mode == NULL) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/* no mode restrictions */
|
||||
if (config->allowed_modes_cnt == 0U) {
|
||||
return api->set_mode(dev, mode);
|
||||
}
|
||||
|
||||
/* check if mode is allowed, apply if it is */
|
||||
for (uint8_t i = 0U; i < config->allowed_modes_cnt; i++) {
|
||||
if (mode == config->allowed_modes[i]) {
|
||||
return api->set_mode(dev, mode);
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
|
|
@ -15,16 +15,11 @@
|
|||
|
||||
LOG_MODULE_REGISTER(regulator_fixed, CONFIG_REGULATOR_LOG_LEVEL);
|
||||
|
||||
#define OPTION_ALWAYS_ON_POS 0
|
||||
#define OPTION_ALWAYS_ON BIT(OPTION_ALWAYS_ON_POS)
|
||||
#define OPTION_BOOT_ON_POS 1
|
||||
#define OPTION_BOOT_ON BIT(OPTION_BOOT_ON_POS)
|
||||
|
||||
struct regulator_fixed_config {
|
||||
struct regulator_common_config common;
|
||||
uint32_t startup_delay_us;
|
||||
uint32_t off_on_delay_us;
|
||||
struct gpio_dt_spec enable;
|
||||
uint8_t options;
|
||||
};
|
||||
|
||||
struct regulator_fixed_data {
|
||||
|
@ -36,10 +31,6 @@ static int regulator_fixed_enable(const struct device *dev)
|
|||
const struct regulator_fixed_config *cfg = dev->config;
|
||||
int ret;
|
||||
|
||||
if ((cfg->options & OPTION_ALWAYS_ON) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = gpio_pin_set_dt(&cfg->enable, 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
|
@ -56,10 +47,6 @@ static int regulator_fixed_disable(const struct device *dev)
|
|||
{
|
||||
const struct regulator_fixed_config *cfg = dev->config;
|
||||
|
||||
if ((cfg->options & OPTION_ALWAYS_ON) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return gpio_pin_set_dt(&cfg->enable, 0);
|
||||
}
|
||||
|
||||
|
@ -80,7 +67,7 @@ static int regulator_fixed_init(const struct device *dev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
if ((cfg->options & (OPTION_ALWAYS_ON | OPTION_BOOT_ON)) != 0U) {
|
||||
if ((cfg->common.flags & REGULATOR_INIT_ENABLED) != 0U) {
|
||||
ret = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_ACTIVE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
|
@ -101,13 +88,10 @@ static int regulator_fixed_init(const struct device *dev)
|
|||
static struct regulator_fixed_data data##inst; \
|
||||
\
|
||||
static const struct regulator_fixed_config config##inst = { \
|
||||
.common = REGULATOR_DT_INST_COMMON_CONFIG_INIT(inst), \
|
||||
.startup_delay_us = DT_INST_PROP(inst, startup_delay_us), \
|
||||
.off_on_delay_us = DT_INST_PROP(inst, off_on_delay_us), \
|
||||
.enable = GPIO_DT_SPEC_INST_GET(inst, enable_gpios), \
|
||||
.options = (DT_INST_PROP(inst, regulator_boot_on) \
|
||||
<< OPTION_BOOT_ON_POS) | \
|
||||
(DT_INST_PROP(inst, regulator_always_on) \
|
||||
<< OPTION_ALWAYS_ON_POS), \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(inst, regulator_fixed_init, NULL, &data##inst, \
|
||||
|
|
|
@ -81,6 +81,8 @@
|
|||
/** VIN ILIM minimum value, uA */
|
||||
#define PCA9420_VIN_ILIM_MIN_UA 85000
|
||||
|
||||
/** Number of modes */
|
||||
#define PCA9420_NUM_MODES 4U
|
||||
/** Offset applied to MODECFG* registers for a given mode */
|
||||
#define PCA9420_MODECFG_OFFSET(mode) ((mode) * 4U)
|
||||
|
||||
|
@ -91,6 +93,7 @@ struct regulator_pca9420_desc {
|
|||
uint8_t vsel_reg;
|
||||
uint8_t vsel_mask;
|
||||
uint8_t vsel_pos;
|
||||
int32_t max_ua;
|
||||
uint8_t num_ranges;
|
||||
const struct linear_range *ranges;
|
||||
};
|
||||
|
@ -98,8 +101,6 @@ struct regulator_pca9420_desc {
|
|||
struct regulator_pca9420_common_config {
|
||||
struct i2c_dt_spec i2c;
|
||||
int32_t vin_ilim_ua;
|
||||
const uint8_t *allowed_modes;
|
||||
regulator_mode_t allowed_modes_cnt;
|
||||
bool enable_modesel_pins;
|
||||
};
|
||||
|
||||
|
@ -108,9 +109,8 @@ struct regulator_pca9420_common_data {
|
|||
};
|
||||
|
||||
struct regulator_pca9420_config {
|
||||
int32_t max_ua;
|
||||
struct regulator_common_config common;
|
||||
bool enable_inverted;
|
||||
bool boot_on;
|
||||
const struct regulator_pca9420_desc *desc;
|
||||
const struct device *parent;
|
||||
};
|
||||
|
@ -151,6 +151,7 @@ static const struct regulator_pca9420_desc buck1_desc = {
|
|||
.vsel_mask = PCA9420_MODECFG_0_SW1_OUT_MASK,
|
||||
.vsel_pos = PCA9420_MODECFG_0_SW1_OUT_POS,
|
||||
.vsel_reg = PCA9420_MODECFG_0_0,
|
||||
.max_ua = 250000,
|
||||
.ranges = buck1_ranges,
|
||||
.num_ranges = ARRAY_SIZE(buck1_ranges),
|
||||
};
|
||||
|
@ -162,6 +163,7 @@ static const struct regulator_pca9420_desc buck2_desc = {
|
|||
.vsel_mask = PCA9420_MODECFG_1_SW2_OUT_MASK,
|
||||
.vsel_pos = PCA9420_MODECFG_1_SW2_OUT_POS,
|
||||
.vsel_reg = PCA9420_MODECFG_0_1,
|
||||
.max_ua = 500000,
|
||||
.ranges = buck2_ranges,
|
||||
.num_ranges = ARRAY_SIZE(buck2_ranges),
|
||||
};
|
||||
|
@ -173,6 +175,7 @@ static const struct regulator_pca9420_desc ldo1_desc = {
|
|||
.vsel_mask = PCA9420_MODECFG_2_LDO1_OUT_MASK,
|
||||
.vsel_pos = PCA9420_MODECFG_2_LDO1_OUT_POS,
|
||||
.vsel_reg = PCA9420_MODECFG_0_2,
|
||||
.max_ua = 1000,
|
||||
.ranges = ldo1_ranges,
|
||||
.num_ranges = ARRAY_SIZE(ldo1_ranges),
|
||||
};
|
||||
|
@ -184,25 +187,11 @@ static const struct regulator_pca9420_desc ldo2_desc = {
|
|||
.vsel_reg = PCA9420_MODECFG_0_3,
|
||||
.vsel_mask = PCA9420_MODECFG_3_LDO2_OUT_MASK,
|
||||
.vsel_pos = PCA9420_MODECFG_3_LDO2_OUT_POS,
|
||||
.max_ua = 250000,
|
||||
.ranges = ldo2_ranges,
|
||||
.num_ranges = ARRAY_SIZE(ldo2_ranges),
|
||||
};
|
||||
|
||||
static bool regulator_pca9420_is_mode_allowed(const struct device *dev,
|
||||
regulator_mode_t mode)
|
||||
{
|
||||
const struct regulator_pca9420_config *config = dev->config;
|
||||
const struct regulator_pca9420_common_config *cconfig = config->parent->config;
|
||||
|
||||
for (uint8_t i = 0U; i < cconfig->allowed_modes_cnt; i++) {
|
||||
if (mode == cconfig->allowed_modes[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsigned int regulator_pca9420_count_voltages(const struct device *dev)
|
||||
{
|
||||
const struct regulator_pca9420_config *config = dev->config;
|
||||
|
@ -276,9 +265,9 @@ static int regulator_pca9420_get_current_limit(const struct device *dev,
|
|||
const struct regulator_pca9420_common_config *cconfig = config->parent->config;
|
||||
|
||||
if (cconfig->vin_ilim_ua == 0U) {
|
||||
*curr_ua = config->max_ua;
|
||||
*curr_ua = config->desc->max_ua;
|
||||
} else {
|
||||
*curr_ua = MIN(config->max_ua, cconfig->vin_ilim_ua);
|
||||
*curr_ua = MIN(config->desc->max_ua, cconfig->vin_ilim_ua);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -292,10 +281,6 @@ static int regulator_pca9420_set_mode(const struct device *dev,
|
|||
struct regulator_pca9420_common_data *cdata = config->parent->data;
|
||||
int ret;
|
||||
|
||||
if (!regulator_pca9420_is_mode_allowed(dev, mode)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* change mode, to allow configuring voltage, but return -EPERM to
|
||||
* indicate we are not really changing mode, as it is managed externally
|
||||
*/
|
||||
|
@ -349,7 +334,7 @@ static int regulator_pca9420_init(const struct device *dev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (config->boot_on) {
|
||||
if ((config->common.flags & REGULATOR_INIT_ENABLED) != 0U) {
|
||||
rc = regulator_pca9420_enable(dev);
|
||||
}
|
||||
|
||||
|
@ -368,12 +353,12 @@ static int regulator_pca9420_common_init(const struct device *dev)
|
|||
}
|
||||
|
||||
if (config->enable_modesel_pins) {
|
||||
/* enable MODESEL0/1 pins for each allowed mode */
|
||||
for (uint8_t i = 0U; i < config->allowed_modes_cnt; i++) {
|
||||
/* enable MODESEL0/1 pins for each mode */
|
||||
for (uint8_t i = 0U; i < PCA9420_NUM_MODES; i++) {
|
||||
ret = i2c_reg_update_byte_dt(
|
||||
&config->i2c,
|
||||
PCA9420_MODECFG_0_0 +
|
||||
PCA9420_MODECFG_OFFSET(config->allowed_modes[i]),
|
||||
PCA9420_MODECFG_OFFSET(i),
|
||||
PCA9420_MODECFG_0_X_EN_MODE_SEL_BY_PIN,
|
||||
PCA9420_MODECFG_0_X_EN_MODE_SEL_BY_PIN);
|
||||
if (ret < 0) {
|
||||
|
@ -418,9 +403,8 @@ static const struct regulator_driver_api api = {
|
|||
static struct regulator_pca9420_data data_##id; \
|
||||
\
|
||||
static const struct regulator_pca9420_config config_##id = { \
|
||||
.max_ua = DT_PROP(node_id, regulator_max_microamp), \
|
||||
.common = REGULATOR_DT_COMMON_CONFIG_INIT(node_id), \
|
||||
.enable_inverted = DT_PROP(node_id, enable_inverted), \
|
||||
.boot_on = DT_PROP(node_id, regulator_boot_on), \
|
||||
.desc = &name ## _desc, \
|
||||
.parent = _parent, \
|
||||
}; \
|
||||
|
@ -436,18 +420,13 @@ static const struct regulator_driver_api api = {
|
|||
())
|
||||
|
||||
#define REGULATOR_PCA9420_DEFINE_ALL(inst) \
|
||||
static const uint8_t allowed_modes_##inst[] = \
|
||||
DT_INST_PROP(inst, regulator_allowed_modes); \
|
||||
\
|
||||
static struct regulator_pca9420_common_data data_##inst = { \
|
||||
.mode = DT_INST_PROP(inst, regulator_initial_mode) \
|
||||
.mode = 0U \
|
||||
}; \
|
||||
\
|
||||
static const struct regulator_pca9420_common_config config_##inst = { \
|
||||
.i2c = I2C_DT_SPEC_INST_GET(inst), \
|
||||
.vin_ilim_ua = DT_INST_PROP(inst, nxp_vin_ilim_microamp), \
|
||||
.allowed_modes = allowed_modes_##inst, \
|
||||
.allowed_modes_cnt = ARRAY_SIZE(allowed_modes_##inst), \
|
||||
.enable_modesel_pins = \
|
||||
DT_INST_PROP(inst, nxp_enable_modesel_pins), \
|
||||
}; \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue