/* * Copyright (c) 2023 Grinn * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT maxim_max20335_regulator #include #include #include #include #include #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)