drivers: regulator: adp5360: initial version
Add a new regulator driver for Analog Devices ADP5360. While it is a MFD device, only support for BUCK/BUCKBOOST regulators is added in this patch. Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
This commit is contained in:
parent
c5d798173c
commit
e05df8faf1
8 changed files with 475 additions and 0 deletions
|
@ -4,6 +4,7 @@
|
|||
zephyr_library()
|
||||
|
||||
zephyr_library_sources(regulator_common.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_REGULATOR_ADP5360 regulator_adp5360.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_REGULATOR_FAKE regulator_fake.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_REGULATOR_FIXED regulator_fixed.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM1100 regulator_npm1100.c)
|
||||
|
|
|
@ -27,6 +27,7 @@ module = REGULATOR
|
|||
module-str = regulator
|
||||
source "subsys/logging/Kconfig.template.log_config"
|
||||
|
||||
source "drivers/regulator/Kconfig.adp5360"
|
||||
source "drivers/regulator/Kconfig.fake"
|
||||
source "drivers/regulator/Kconfig.fixed"
|
||||
source "drivers/regulator/Kconfig.npm1100"
|
||||
|
|
28
drivers/regulator/Kconfig.adp5360
Normal file
28
drivers/regulator/Kconfig.adp5360
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
# SPDX -License-Identifier: Apache-2.0
|
||||
|
||||
config REGULATOR_ADP5360
|
||||
bool "ADP5360 PMIC regulator driver"
|
||||
default y
|
||||
depends on DT_HAS_ADI_ADP5360_REGULATOR_ENABLED
|
||||
select I2C
|
||||
help
|
||||
Enable the Analog Devices ADP5360 PMIC regulator driver
|
||||
|
||||
if REGULATOR_ADP5360
|
||||
|
||||
config REGULATOR_ADP5360_COMMON_INIT_PRIORITY
|
||||
int "ADP5360 regulator driver init priority (common part)"
|
||||
default 75
|
||||
help
|
||||
Init priority for the Analog Devices ADP5360 regulator driver (common
|
||||
part). It must be greater than I2C init priority.
|
||||
|
||||
config REGULATOR_ADP5360_INIT_PRIORITY
|
||||
int "ADP5360 regulator driver init priority"
|
||||
default 76
|
||||
help
|
||||
Init priority for the Analog Devices ADP5360 regulator driver. It must
|
||||
be greater than REGULATOR_ADP5360_COMMON_INIT_PRIORITY.
|
||||
|
||||
endif
|
308
drivers/regulator/regulator_adp5360.c
Normal file
308
drivers/regulator/regulator_adp5360.c
Normal file
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT adi_adp5360_regulator
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/drivers/regulator.h>
|
||||
#include <zephyr/dt-bindings/regulator/adp5360.h>
|
||||
#include <zephyr/sys/linear_range.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
/* ADP5360 regulator related registers */
|
||||
#define ADP5360_BUCK_CFG 0x29U
|
||||
#define ADP5360_BUCK_OUTPUT 0x2AU
|
||||
#define ADP5360_BUCKBST_CFG 0x2BU
|
||||
#define ADP5360_BUCKBST_OUTPUT 0x2CU
|
||||
|
||||
/* Buck/boost configure register. */
|
||||
#define ADP5360_BUCK_CFG_SS_MSK GENMASK(7, 6)
|
||||
#define ADP5360_BUCK_CFG_SS_POS 6U
|
||||
#define ADP5360_BUCK_CFG_BST_ILIM_MSK GENMASK(5, 3)
|
||||
#define ADP5360_BUCK_CFG_BST_ILIM_POS 3U
|
||||
#define ADP5360_BUCK_CFG_BUCK_ILIM_MSK GENMASK(5, 3)
|
||||
#define ADP5360_BUCK_CFG_BUCK_ILIM_POS 3U
|
||||
#define ADP5360_BUCK_CFG_BUCK_MODE_MSK BIT(3)
|
||||
#define ADP5360_BUCK_CFG_BUCK_MODE_POS 3U
|
||||
#define ADP5360_BUCK_CFG_STP_MSK BIT(2)
|
||||
#define ADP5360_BUCK_CFG_DISCHG_MSK BIT(1)
|
||||
#define ADP5360_BUCK_CFG_EN_MSK BIT(0)
|
||||
|
||||
/* Buck/boost output voltage setting register. */
|
||||
#define ADP5360_BUCK_OUTPUT_VOUT_MSK GENMASK(5, 0)
|
||||
#define ADP5360_BUCK_OUTPUT_VOUT_POS 0U
|
||||
#define ADP5360_BUCK_OUTPUT_DLY_MSK GENMASK(7, 6)
|
||||
#define ADP5360_BUCK_OUTPUT_DLY_POS 6U
|
||||
|
||||
struct regulator_adp5360_desc {
|
||||
uint8_t cfg_reg;
|
||||
uint8_t out_reg;
|
||||
bool has_modes;
|
||||
const struct linear_range *ranges;
|
||||
uint8_t nranges;
|
||||
};
|
||||
|
||||
static const struct linear_range buck_ranges[] = {
|
||||
LINEAR_RANGE_INIT(600000, 50000U, 0x0U, 0x3FU),
|
||||
};
|
||||
|
||||
static const struct regulator_adp5360_desc buck_desc = {
|
||||
.cfg_reg = ADP5360_BUCK_CFG,
|
||||
.out_reg = ADP5360_BUCK_OUTPUT,
|
||||
.has_modes = true,
|
||||
.ranges = buck_ranges,
|
||||
.nranges = ARRAY_SIZE(buck_ranges),
|
||||
};
|
||||
|
||||
static const struct linear_range buckboost_ranges[] = {
|
||||
LINEAR_RANGE_INIT(1800000, 100000U, 0x0U, 0x0BU),
|
||||
LINEAR_RANGE_INIT(2950000, 50000U, 0xCU, 0x3FU),
|
||||
};
|
||||
|
||||
static const struct regulator_adp5360_desc buckboost_desc = {
|
||||
.cfg_reg = ADP5360_BUCKBST_CFG,
|
||||
.out_reg = ADP5360_BUCKBST_OUTPUT,
|
||||
.has_modes = false,
|
||||
.ranges = buckboost_ranges,
|
||||
.nranges = ARRAY_SIZE(buckboost_ranges),
|
||||
};
|
||||
|
||||
struct regulator_adp5360_config {
|
||||
struct regulator_common_config common;
|
||||
struct i2c_dt_spec i2c;
|
||||
const struct regulator_adp5360_desc *desc;
|
||||
int8_t dly_idx;
|
||||
int8_t ss_idx;
|
||||
int8_t ilim_idx;
|
||||
bool stp_en;
|
||||
bool dis_en;
|
||||
};
|
||||
|
||||
struct regulator_adp5360_data {
|
||||
struct regulator_common_data data;
|
||||
};
|
||||
|
||||
static unsigned int regulator_adp5360_count_voltages(const struct device *dev)
|
||||
{
|
||||
const struct regulator_adp5360_config *config = dev->config;
|
||||
|
||||
return linear_range_group_values_count(config->desc->ranges, config->desc->nranges);
|
||||
}
|
||||
|
||||
static int regulator_adp5360_list_voltage(const struct device *dev, unsigned int idx,
|
||||
int32_t *volt_uv)
|
||||
{
|
||||
const struct regulator_adp5360_config *config = dev->config;
|
||||
|
||||
return linear_range_group_get_value(config->desc->ranges, config->desc->nranges, idx,
|
||||
volt_uv);
|
||||
}
|
||||
|
||||
static int regulator_adp5360_set_voltage(const struct device *dev, int32_t min_uv, int32_t max_uv)
|
||||
{
|
||||
const struct regulator_adp5360_config *config = dev->config;
|
||||
uint16_t idx;
|
||||
int ret;
|
||||
|
||||
ret = linear_range_group_get_win_index(config->desc->ranges, config->desc->nranges, min_uv,
|
||||
max_uv, &idx);
|
||||
if (ret == -EINVAL) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return i2c_reg_update_byte_dt(&config->i2c, config->desc->out_reg,
|
||||
ADP5360_BUCK_OUTPUT_VOUT_MSK,
|
||||
(uint8_t)idx << ADP5360_BUCK_OUTPUT_VOUT_POS);
|
||||
}
|
||||
|
||||
static int regulator_adp5360_get_voltage(const struct device *dev, int32_t *volt_uv)
|
||||
{
|
||||
const struct regulator_adp5360_config *config = dev->config;
|
||||
int ret;
|
||||
uint8_t raw_reg;
|
||||
|
||||
ret = i2c_reg_read_byte_dt(&config->i2c, config->desc->out_reg, &raw_reg);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
raw_reg = (raw_reg & ADP5360_BUCK_OUTPUT_VOUT_MSK) >> ADP5360_BUCK_OUTPUT_VOUT_POS;
|
||||
|
||||
return linear_range_group_get_value(config->desc->ranges, config->desc->nranges, raw_reg,
|
||||
volt_uv);
|
||||
}
|
||||
|
||||
static int regulator_adp5360_set_mode(const struct device *dev, regulator_mode_t mode)
|
||||
{
|
||||
const struct regulator_adp5360_config *config = dev->config;
|
||||
|
||||
if (!config->desc->has_modes || (mode > ADP5360_MODE_PWM)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return i2c_reg_update_byte_dt(&config->i2c, config->desc->cfg_reg,
|
||||
ADP5360_BUCK_CFG_BUCK_MODE_MSK,
|
||||
mode << ADP5360_BUCK_CFG_BUCK_MODE_POS);
|
||||
}
|
||||
|
||||
static int regulator_adp5360_get_mode(const struct device *dev, regulator_mode_t *mode)
|
||||
{
|
||||
const struct regulator_adp5360_config *config = dev->config;
|
||||
uint8_t val;
|
||||
int ret;
|
||||
|
||||
if (!config->desc->has_modes) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
ret = i2c_reg_read_byte_dt(&config->i2c, config->desc->cfg_reg, &val);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
*mode = (val & ADP5360_BUCK_CFG_BUCK_MODE_MSK) >> ADP5360_BUCK_CFG_BUCK_MODE_POS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int regulator_adp5360_enable(const struct device *dev)
|
||||
{
|
||||
const struct regulator_adp5360_config *config = dev->config;
|
||||
|
||||
return i2c_reg_update_byte_dt(&config->i2c, config->desc->cfg_reg, ADP5360_BUCK_CFG_EN_MSK,
|
||||
1U);
|
||||
}
|
||||
|
||||
static int regulator_adp5360_disable(const struct device *dev)
|
||||
{
|
||||
const struct regulator_adp5360_config *config = dev->config;
|
||||
|
||||
return i2c_reg_update_byte_dt(&config->i2c, config->desc->cfg_reg, ADP5360_BUCK_CFG_EN_MSK,
|
||||
0U);
|
||||
}
|
||||
|
||||
static int regulator_adp5360_init(const struct device *dev)
|
||||
{
|
||||
const struct regulator_adp5360_config *config = dev->config;
|
||||
int ret;
|
||||
uint8_t val, nval, msk;
|
||||
|
||||
regulator_common_data_init(dev);
|
||||
|
||||
if (!i2c_is_ready_dt(&config->i2c)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* apply optional delay */
|
||||
msk = 0U;
|
||||
nval = 0U;
|
||||
|
||||
ret = i2c_reg_read_byte_dt(&config->i2c, config->desc->out_reg, &val);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (config->dly_idx >= 0) {
|
||||
msk |= ADP5360_BUCK_OUTPUT_DLY_MSK;
|
||||
nval |= ((uint8_t)config->dly_idx << ADP5360_BUCK_OUTPUT_DLY_POS) &
|
||||
ADP5360_BUCK_OUTPUT_DLY_MSK;
|
||||
}
|
||||
|
||||
if (msk != 0U) {
|
||||
ret = i2c_reg_write_byte_dt(&config->i2c, config->desc->out_reg,
|
||||
(val & ~msk) | nval);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* apply optional initial configuration */
|
||||
msk = 0U;
|
||||
nval = 0U;
|
||||
|
||||
ret = i2c_reg_read_byte_dt(&config->i2c, config->desc->cfg_reg, &val);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (config->ss_idx >= 0) {
|
||||
msk |= ADP5360_BUCK_CFG_SS_MSK;
|
||||
nval |= ((uint8_t)config->ss_idx << ADP5360_BUCK_CFG_SS_POS) &
|
||||
ADP5360_BUCK_CFG_SS_MSK;
|
||||
}
|
||||
|
||||
if (config->ilim_idx >= 0) {
|
||||
if (config->desc->has_modes) {
|
||||
msk |= ADP5360_BUCK_CFG_BUCK_ILIM_MSK;
|
||||
nval |= ((uint8_t)config->ilim_idx << ADP5360_BUCK_CFG_BUCK_ILIM_POS) &
|
||||
ADP5360_BUCK_CFG_BUCK_ILIM_MSK;
|
||||
} else {
|
||||
msk |= ADP5360_BUCK_CFG_BST_ILIM_MSK;
|
||||
nval |= ((uint8_t)config->ilim_idx << ADP5360_BUCK_CFG_BST_ILIM_POS) &
|
||||
ADP5360_BUCK_CFG_BST_ILIM_MSK;
|
||||
}
|
||||
}
|
||||
|
||||
if (config->stp_en) {
|
||||
msk |= ADP5360_BUCK_CFG_STP_MSK;
|
||||
nval |= ADP5360_BUCK_CFG_STP_MSK;
|
||||
}
|
||||
|
||||
if (config->dis_en) {
|
||||
msk |= ADP5360_BUCK_CFG_DISCHG_MSK;
|
||||
nval |= ADP5360_BUCK_CFG_DISCHG_MSK;
|
||||
}
|
||||
|
||||
if (msk != 0U) {
|
||||
ret = i2c_reg_write_byte_dt(&config->i2c, config->desc->cfg_reg,
|
||||
(val & ~msk) | nval);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return regulator_common_init(dev, (val & ADP5360_BUCK_CFG_EN_MSK) != 0U);
|
||||
}
|
||||
|
||||
static const struct regulator_driver_api api = {
|
||||
.enable = regulator_adp5360_enable,
|
||||
.disable = regulator_adp5360_disable,
|
||||
.count_voltages = regulator_adp5360_count_voltages,
|
||||
.list_voltage = regulator_adp5360_list_voltage,
|
||||
.set_voltage = regulator_adp5360_set_voltage,
|
||||
.get_voltage = regulator_adp5360_get_voltage,
|
||||
.set_mode = regulator_adp5360_set_mode,
|
||||
.get_mode = regulator_adp5360_get_mode,
|
||||
};
|
||||
|
||||
#define REGULATOR_ADP5360_DEFINE(node_id, id, name) \
|
||||
static struct regulator_adp5360_data data_##id; \
|
||||
\
|
||||
static const struct regulator_adp5360_config config_##id = { \
|
||||
.common = REGULATOR_DT_COMMON_CONFIG_INIT(node_id), \
|
||||
.i2c = I2C_DT_SPEC_GET(DT_GPARENT(node_id)), \
|
||||
.desc = &name##_desc, \
|
||||
.dly_idx = DT_ENUM_IDX_OR(node_id, adi_switch_delay_us, -1), \
|
||||
.ss_idx = DT_ENUM_IDX_OR(node_id, adi_soft_start_ms, -1), \
|
||||
.ilim_idx = DT_ENUM_IDX_OR(node_id, adi_ilim_milliamp, -1), \
|
||||
.stp_en = DT_PROP(node_id, adi_enable_stop_pulse), \
|
||||
.dis_en = DT_PROP(node_id, adi_enable_output_discharge), \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_DEFINE(node_id, regulator_adp5360_init, NULL, &data_##id, &config_##id, \
|
||||
POST_KERNEL, CONFIG_REGULATOR_ADP5360_INIT_PRIORITY, &api);
|
||||
|
||||
#define REGULATOR_ADP5360_DEFINE_COND(inst, child) \
|
||||
COND_CODE_1(DT_NODE_EXISTS(DT_INST_CHILD(inst, child)), \
|
||||
(REGULATOR_ADP5360_DEFINE(DT_INST_CHILD(inst, child), child##inst, child)), \
|
||||
())
|
||||
|
||||
#define REGULATOR_ADP5360_DEFINE_ALL(inst) \
|
||||
REGULATOR_ADP5360_DEFINE_COND(inst, buck) \
|
||||
REGULATOR_ADP5360_DEFINE_COND(inst, buckboost)
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(REGULATOR_ADP5360_DEFINE_ALL)
|
Loading…
Add table
Add a link
Reference in a new issue