380 lines
11 KiB
C
380 lines
11 KiB
C
/*
|
|
* Copyright (c) 2023 Grinn
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define DT_DRV_COMPAT maxim_max20335_regulator
|
|
|
|
#include <zephyr/drivers/i2c.h>
|
|
#include <zephyr/drivers/regulator.h>
|
|
#include <zephyr/dt-bindings/regulator/max20335.h>
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/sys/linear_range.h>
|
|
|
|
#define MAX20335_BUCK1_CFG 0x0DU
|
|
#define MAX20335_BUCK1_VSET 0x0EU
|
|
#define MAX20335_BUCK2_CFG 0x0FU
|
|
#define MAX20335_BUCK2_VSET 0x10U
|
|
#define MAX20335_BUCK12_CSET 0x11U
|
|
#define MAX20335_PWR_CMD 0x1FU
|
|
#define MAX20335_BUCK1_CSET_MASK 0xF0U
|
|
#define MAX20335_BUCK2_CSET_MASK 0x0FU
|
|
#define MAX20335_BUCK2_CSET_SHIFT 4
|
|
#define MAX20335_BUCK_EN BIT(3)
|
|
#define MAX20335_BUCK_EN_MASK GENMASK(4, 3)
|
|
|
|
#define MAX20335_LDO1_CFG 0x12U
|
|
#define MAX20335_LDO1_VSET 0x13U
|
|
#define MAX20335_LDO2_CFG 0x14U
|
|
#define MAX20335_LDO2_VSET 0x15U
|
|
#define MAX20335_LDO3_CFG 0x16U
|
|
#define MAX20335_LDO3_VSET 0x17U
|
|
#define MAX20335_LDO_MODE_MASK BIT(0)
|
|
#define MAX20335_LDO_EN BIT(1)
|
|
#define MAX20335_LDO_EN_MASK GENMASK(2, 1)
|
|
|
|
#define MAX20335_OFF_MODE 0xB2U
|
|
|
|
enum max20335_pmic_sources {
|
|
MAX20335_PMIC_SOURCE_BUCK1,
|
|
MAX20335_PMIC_SOURCE_BUCK2,
|
|
MAX20335_PMIC_SOURCE_LDO1,
|
|
MAX20335_PMIC_SOURCE_LDO2,
|
|
MAX20335_PMIC_SOURCE_LDO3,
|
|
};
|
|
|
|
struct regulator_max20335_desc {
|
|
uint8_t vsel_reg;
|
|
uint8_t enable_mask;
|
|
uint8_t enable_val;
|
|
uint8_t cfg_reg;
|
|
const struct linear_range *uv_range;
|
|
const struct linear_range *ua_range;
|
|
};
|
|
|
|
struct regulator_max20335_common_config {
|
|
struct i2c_dt_spec bus;
|
|
};
|
|
|
|
struct regulator_max20335_config {
|
|
struct regulator_common_config common;
|
|
struct i2c_dt_spec bus;
|
|
const struct regulator_max20335_desc *desc;
|
|
uint8_t source;
|
|
};
|
|
|
|
struct regulator_max20335_data {
|
|
struct regulator_common_data common;
|
|
};
|
|
|
|
static const struct linear_range buck1_range = LINEAR_RANGE_INIT(700000, 25000U, 0x0U, 0x3FU);
|
|
static const struct linear_range buck2_range = LINEAR_RANGE_INIT(700000, 50000U, 0x0U, 0x3FU);
|
|
static const struct linear_range buck12_current_limit_range =
|
|
LINEAR_RANGE_INIT(50000, 25000U, 0x02U, 0x0FU);
|
|
static const struct linear_range ldo1_range = LINEAR_RANGE_INIT(800000, 100000U, 0x0U, 0x1CU);
|
|
static const struct linear_range ldo23_range = LINEAR_RANGE_INIT(900000, 100000U, 0x0U, 0x1FU);
|
|
|
|
static const struct regulator_max20335_desc __maybe_unused buck1_desc = {
|
|
.vsel_reg = MAX20335_BUCK1_VSET,
|
|
.enable_mask = MAX20335_BUCK_EN_MASK,
|
|
.enable_val = MAX20335_BUCK_EN,
|
|
.cfg_reg = MAX20335_BUCK1_CFG,
|
|
.uv_range = &buck1_range,
|
|
.ua_range = &buck12_current_limit_range,
|
|
};
|
|
|
|
static const struct regulator_max20335_desc __maybe_unused buck2_desc = {
|
|
.vsel_reg = MAX20335_BUCK2_VSET,
|
|
.enable_mask = MAX20335_BUCK_EN_MASK,
|
|
.enable_val = MAX20335_BUCK_EN,
|
|
.cfg_reg = MAX20335_BUCK2_CFG,
|
|
.uv_range = &buck2_range,
|
|
.ua_range = &buck12_current_limit_range,
|
|
};
|
|
|
|
static const struct regulator_max20335_desc __maybe_unused ldo1_desc = {
|
|
.vsel_reg = MAX20335_LDO1_VSET,
|
|
.enable_mask = MAX20335_LDO_EN_MASK,
|
|
.enable_val = MAX20335_LDO_EN,
|
|
.cfg_reg = MAX20335_LDO1_CFG,
|
|
.uv_range = &ldo1_range,
|
|
};
|
|
|
|
static const struct regulator_max20335_desc __maybe_unused ldo2_desc = {
|
|
.vsel_reg = MAX20335_LDO2_VSET,
|
|
.enable_mask = MAX20335_LDO_EN_MASK,
|
|
.enable_val = MAX20335_LDO_EN,
|
|
.cfg_reg = MAX20335_LDO2_CFG,
|
|
.uv_range = &ldo23_range,
|
|
};
|
|
|
|
static const struct regulator_max20335_desc __maybe_unused ldo3_desc = {
|
|
.vsel_reg = MAX20335_LDO3_VSET,
|
|
.enable_mask = MAX20335_LDO_EN_MASK,
|
|
.enable_val = MAX20335_LDO_EN,
|
|
.cfg_reg = MAX20335_LDO3_CFG,
|
|
.uv_range = &ldo23_range,
|
|
};
|
|
|
|
static int regulator_max20335_set_enable(const struct device *dev, bool enable)
|
|
{
|
|
const struct regulator_max20335_config *config = dev->config;
|
|
|
|
return i2c_reg_update_byte_dt(&config->bus,
|
|
config->desc->cfg_reg,
|
|
config->desc->enable_mask,
|
|
enable ? config->desc->enable_val : 0);
|
|
}
|
|
|
|
static int regulator_max20335_enable(const struct device *dev)
|
|
{
|
|
return regulator_max20335_set_enable(dev, true);
|
|
}
|
|
|
|
static int regulator_max20335_disable(const struct device *dev)
|
|
{
|
|
return regulator_max20335_set_enable(dev, false);
|
|
}
|
|
|
|
static int regulator_max20335_set_mode(const struct device *dev, regulator_mode_t mode)
|
|
{
|
|
const struct regulator_max20335_config *config = dev->config;
|
|
|
|
if (mode > MAX20335_LOAD_SWITCH_MODE) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
switch (config->source) {
|
|
case MAX20335_PMIC_SOURCE_LDO1:
|
|
__fallthrough;
|
|
case MAX20335_PMIC_SOURCE_LDO2:
|
|
__fallthrough;
|
|
case MAX20335_PMIC_SOURCE_LDO3:
|
|
return i2c_reg_update_byte_dt(&config->bus,
|
|
config->desc->cfg_reg,
|
|
MAX20335_LDO_MODE_MASK,
|
|
mode);
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
}
|
|
|
|
static unsigned int regulator_max20335_count_voltages(const struct device *dev)
|
|
{
|
|
const struct regulator_max20335_config *config = dev->config;
|
|
|
|
return linear_range_values_count(config->desc->uv_range);
|
|
}
|
|
|
|
static int regulator_max20335_list_voltage(const struct device *dev, unsigned int idx,
|
|
int32_t *volt_uv)
|
|
{
|
|
const struct regulator_max20335_config *config = dev->config;
|
|
|
|
return linear_range_get_value(config->desc->uv_range, idx, volt_uv);
|
|
}
|
|
|
|
static int regulator_max20335_set_buck_ldo_voltage(const struct device *dev, int32_t min_uv,
|
|
int32_t max_uv, const struct linear_range *range,
|
|
uint8_t vout_reg)
|
|
{
|
|
const struct regulator_max20335_config *config = dev->config;
|
|
uint16_t idx;
|
|
int ret;
|
|
|
|
ret = linear_range_get_win_index(range, min_uv, max_uv, &idx);
|
|
if (ret == -EINVAL) {
|
|
return ret;
|
|
}
|
|
|
|
return i2c_reg_write_byte_dt(&config->bus, vout_reg, (uint8_t)idx);
|
|
}
|
|
|
|
static int regulator_max20335_buck12_ldo123_get_voltage(const struct device *dev,
|
|
const struct linear_range *range,
|
|
uint8_t vout_reg, int32_t *volt_uv)
|
|
{
|
|
const struct regulator_max20335_config *config = dev->config;
|
|
uint8_t idx;
|
|
int ret;
|
|
|
|
ret = i2c_reg_read_byte_dt(&config->bus, vout_reg, &idx);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
return linear_range_get_value(range, idx, volt_uv);
|
|
}
|
|
|
|
static int regulator_max20335_get_voltage(const struct device *dev, int32_t *volt_uv)
|
|
{
|
|
const struct regulator_max20335_config *config = dev->config;
|
|
|
|
return regulator_max20335_buck12_ldo123_get_voltage(dev,
|
|
config->desc->uv_range,
|
|
config->desc->vsel_reg,
|
|
volt_uv);
|
|
}
|
|
|
|
static int regulator_max20335_set_voltage(const struct device *dev, int32_t min_uv, int32_t max_uv)
|
|
{
|
|
const struct regulator_max20335_config *config = dev->config;
|
|
|
|
return regulator_max20335_set_buck_ldo_voltage(dev,
|
|
min_uv,
|
|
max_uv,
|
|
config->desc->uv_range,
|
|
config->desc->vsel_reg);
|
|
}
|
|
|
|
static unsigned int regulator_max20335_count_current_limits(const struct device *dev)
|
|
{
|
|
const struct regulator_max20335_config *config = dev->config;
|
|
|
|
if (config->source != MAX20335_PMIC_SOURCE_BUCK1 &&
|
|
config->source != MAX20335_PMIC_SOURCE_BUCK2) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return linear_range_values_count(config->desc->ua_range);
|
|
}
|
|
|
|
static int regulator_max20335_list_current_limit(const struct device *dev, unsigned int idx,
|
|
int32_t *current_ua)
|
|
{
|
|
const struct regulator_max20335_config *config = dev->config;
|
|
|
|
if (config->source != MAX20335_PMIC_SOURCE_BUCK1 &&
|
|
config->source != MAX20335_PMIC_SOURCE_BUCK2) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return linear_range_get_value(config->desc->ua_range, idx, current_ua);
|
|
}
|
|
|
|
static int regulator_max20335_set_current_limit(const struct device *dev,
|
|
int32_t min_ua,
|
|
int32_t max_ua)
|
|
{
|
|
const struct regulator_max20335_config *config = dev->config;
|
|
uint8_t val;
|
|
uint16_t idx;
|
|
int ret;
|
|
|
|
if (config->source != MAX20335_PMIC_SOURCE_BUCK1 &&
|
|
config->source != MAX20335_PMIC_SOURCE_BUCK2) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
ret = i2c_reg_read_byte_dt(&config->bus, MAX20335_BUCK12_CSET, &val);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
ret = linear_range_get_win_index(config->desc->ua_range, min_ua, max_ua, &idx);
|
|
if (ret == -EINVAL) {
|
|
return ret;
|
|
}
|
|
|
|
switch (config->source) {
|
|
case MAX20335_PMIC_SOURCE_BUCK1:
|
|
val = idx | (val & MAX20335_BUCK1_CSET_MASK);
|
|
break;
|
|
case MAX20335_PMIC_SOURCE_BUCK2:
|
|
val = (idx << MAX20335_BUCK2_CSET_SHIFT) | (val & MAX20335_BUCK2_CSET_MASK);
|
|
break;
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return i2c_reg_write_byte_dt(&config->bus, MAX20335_BUCK12_CSET, val);
|
|
}
|
|
|
|
static int regulator_max20335_power_off(const struct device *dev)
|
|
{
|
|
const struct regulator_max20335_common_config *common_config = dev->config;
|
|
|
|
return i2c_reg_write_byte_dt(&common_config->bus, MAX20335_PWR_CMD, MAX20335_OFF_MODE);
|
|
}
|
|
|
|
static int regulator_max20335_init(const struct device *dev)
|
|
{
|
|
const struct regulator_max20335_config *config = dev->config;
|
|
|
|
if (!i2c_is_ready_dt(&config->bus)) {
|
|
return -ENODEV;
|
|
}
|
|
|
|
regulator_common_data_init(dev);
|
|
|
|
return regulator_common_init(dev, false);
|
|
}
|
|
|
|
static int regulator_max20335_common_init(const struct device *dev)
|
|
{
|
|
const struct regulator_max20335_common_config *common_config = dev->config;
|
|
|
|
if (!i2c_is_ready_dt(&common_config->bus)) {
|
|
return -ENODEV;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct regulator_parent_driver_api parent_api = {
|
|
.ship_mode = regulator_max20335_power_off,
|
|
};
|
|
|
|
static const struct regulator_driver_api api = {
|
|
.enable = regulator_max20335_enable,
|
|
.disable = regulator_max20335_disable,
|
|
.set_mode = regulator_max20335_set_mode,
|
|
.count_voltages = regulator_max20335_count_voltages,
|
|
.list_voltage = regulator_max20335_list_voltage,
|
|
.set_voltage = regulator_max20335_set_voltage,
|
|
.get_voltage = regulator_max20335_get_voltage,
|
|
.count_current_limits = regulator_max20335_count_current_limits,
|
|
.list_current_limit = regulator_max20335_list_current_limit,
|
|
.set_current_limit = regulator_max20335_set_current_limit,
|
|
};
|
|
|
|
#define REGULATOR_MAX20335_DEFINE(node_id, id, child_name, _source) \
|
|
static const struct regulator_max20335_config regulator_max20335_config_##id = { \
|
|
.common = REGULATOR_DT_COMMON_CONFIG_INIT(node_id), \
|
|
.bus = I2C_DT_SPEC_GET(DT_GPARENT(node_id)), \
|
|
.desc = &child_name##_desc, \
|
|
.source = _source, \
|
|
}; \
|
|
\
|
|
static struct regulator_max20335_data regulator_max20335_data_##id; \
|
|
DEVICE_DT_DEFINE(node_id, regulator_max20335_init, NULL, \
|
|
®ulator_max20335_data_##id, \
|
|
®ulator_max20335_config_##id, \
|
|
POST_KERNEL, \
|
|
CONFIG_REGULATOR_MAXIM_MAX20335_INIT_PRIORITY, \
|
|
&api);
|
|
|
|
#define REGULATOR_MAX20335_DEFINE_COND(inst, child, source) \
|
|
COND_CODE_1(DT_NODE_EXISTS(DT_INST_CHILD(inst, child)), \
|
|
(REGULATOR_MAX20335_DEFINE(DT_INST_CHILD(inst, child), \
|
|
child##inst, child, source)), \
|
|
())
|
|
|
|
#define REGULATOR_MAX20335_DEFINE_ALL(inst) \
|
|
static const struct regulator_max20335_common_config common_config_##inst = { \
|
|
.bus = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)), \
|
|
}; \
|
|
\
|
|
DEVICE_DT_INST_DEFINE(inst, regulator_max20335_common_init, \
|
|
NULL, NULL, &common_config_##inst, POST_KERNEL, \
|
|
CONFIG_REGULATOR_MAXIM_MAX20335_COMMON_INIT_PRIORITY, \
|
|
&parent_api); \
|
|
\
|
|
REGULATOR_MAX20335_DEFINE_COND(inst, buck1, MAX20335_PMIC_SOURCE_BUCK1) \
|
|
REGULATOR_MAX20335_DEFINE_COND(inst, buck2, MAX20335_PMIC_SOURCE_BUCK2) \
|
|
REGULATOR_MAX20335_DEFINE_COND(inst, ldo1, MAX20335_PMIC_SOURCE_LDO1) \
|
|
REGULATOR_MAX20335_DEFINE_COND(inst, ldo2, MAX20335_PMIC_SOURCE_LDO2) \
|
|
REGULATOR_MAX20335_DEFINE_COND(inst, ldo3, MAX20335_PMIC_SOURCE_LDO3)
|
|
|
|
DT_INST_FOREACH_STATUS_OKAY(REGULATOR_MAX20335_DEFINE_ALL)
|