/* * Copyright 2023 NXP * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT nxp_vref #include #include #include #include #include #include #include static const struct linear_range utrim_range = LINEAR_RANGE_INIT(1000000, 100000U, 0x0U, 0xBU); struct regulator_nxp_vref_data { struct regulator_common_data common; }; struct regulator_nxp_vref_config { struct regulator_common_config common; VREF_Type *base; uint8_t gnd_sel; uint16_t buf_start_delay; uint16_t bg_start_time; }; static int regulator_nxp_vref_enable(const struct device *dev) { const struct regulator_nxp_vref_config *config = dev->config; VREF_Type *const base = config->base; volatile uint32_t *const csr = &base->CSR; *csr |= VREF_CSR_LPBGEN_MASK | VREF_CSR_LPBG_BUF_EN_MASK; /* Wait for bandgap startup */ k_busy_wait(config->bg_start_time); /* Enable high accuracy bandgap */ *csr |= VREF_CSR_HCBGEN_MASK; /* Monitor until stable */ while (!(*csr & VREF_CSR_VREFST_MASK)) ; /* Enable output buffer */ *csr |= VREF_CSR_BUF21EN_MASK; return 0; } static int regulator_nxp_vref_disable(const struct device *dev) { const struct regulator_nxp_vref_config *config = dev->config; VREF_Type *const base = config->base; /* * Disable HC Bandgap, LP Bandgap, and Buf21 * to achieve "Off" mode of VREF */ base->CSR &= ~(VREF_CSR_BUF21EN_MASK | VREF_CSR_HCBGEN_MASK | VREF_CSR_LPBGEN_MASK); return 0; } static int regulator_nxp_vref_set_mode(const struct device *dev, regulator_mode_t mode) { const struct regulator_nxp_vref_config *config = dev->config; VREF_Type *const base = config->base; uint32_t csr = base->CSR; if (mode == NXP_VREF_MODE_STANDBY) { csr &= ~VREF_CSR_REGEN_MASK & ~VREF_CSR_CHOPEN_MASK & ~VREF_CSR_HI_PWR_LV_MASK & ~VREF_CSR_BUF21EN_MASK; } else if (mode == NXP_VREF_MODE_LOW_POWER) { csr &= ~VREF_CSR_REGEN_MASK & ~VREF_CSR_CHOPEN_MASK & ~VREF_CSR_HI_PWR_LV_MASK; csr |= VREF_CSR_BUF21EN_MASK; } else if (mode == NXP_VREF_MODE_HIGH_POWER) { csr &= ~VREF_CSR_REGEN_MASK & ~VREF_CSR_CHOPEN_MASK; csr |= VREF_CSR_HI_PWR_LV_MASK & VREF_CSR_BUF21EN_MASK; } else if (mode == NXP_VREF_MODE_INTERNAL_REGULATOR) { csr |= VREF_CSR_REGEN_MASK & VREF_CSR_CHOPEN_MASK & VREF_CSR_HI_PWR_LV_MASK & VREF_CSR_BUF21EN_MASK; } else { return -EINVAL; } base->CSR = csr; k_busy_wait(config->buf_start_delay); return 0; } static int regulator_nxp_vref_get_mode(const struct device *dev, regulator_mode_t *mode) { const struct regulator_nxp_vref_config *config = dev->config; VREF_Type *const base = config->base; uint32_t csr = base->CSR; /* Check bits to determine mode */ if (csr & VREF_CSR_REGEN_MASK) { *mode = NXP_VREF_MODE_INTERNAL_REGULATOR; } else if (csr & VREF_CSR_HI_PWR_LV_MASK) { *mode = NXP_VREF_MODE_HIGH_POWER; } else if (csr & VREF_CSR_BUF21EN_MASK) { *mode = NXP_VREF_MODE_LOW_POWER; } else { *mode = NXP_VREF_MODE_STANDBY; } return 0; } static inline unsigned int regulator_nxp_vref_count_voltages(const struct device *dev) { return linear_range_values_count(&utrim_range); } static int regulator_nxp_vref_list_voltage(const struct device *dev, unsigned int idx, int32_t *volt_uv) { return linear_range_get_value(&utrim_range, idx, volt_uv); } static int regulator_nxp_vref_set_voltage(const struct device *dev, int32_t min_uv, int32_t max_uv) { const struct regulator_nxp_vref_config *config = dev->config; VREF_Type *const base = config->base; uint16_t idx; int ret; ret = linear_range_get_win_index(&utrim_range, min_uv, max_uv, &idx); if (ret < 0) { return ret; } base->UTRIM &= ~VREF_UTRIM_TRIM2V1_MASK; base->UTRIM |= VREF_UTRIM_TRIM2V1_MASK & idx; return 0; } static int regulator_nxp_vref_get_voltage(const struct device *dev, int32_t *volt_uv) { const struct regulator_nxp_vref_config *config = dev->config; VREF_Type *const base = config->base; uint16_t idx; int ret; /* Linear range index is the register value */ idx = (base->UTRIM & VREF_UTRIM_TRIM2V1_MASK) >> VREF_UTRIM_TRIM2V1_SHIFT; ret = linear_range_get_value(&utrim_range, base->UTRIM, volt_uv); return ret; } static const struct regulator_driver_api api = { .enable = regulator_nxp_vref_enable, .disable = regulator_nxp_vref_disable, .set_mode = regulator_nxp_vref_set_mode, .get_mode = regulator_nxp_vref_get_mode, .set_voltage = regulator_nxp_vref_set_voltage, .get_voltage = regulator_nxp_vref_get_voltage, .list_voltage = regulator_nxp_vref_list_voltage, .count_voltages = regulator_nxp_vref_count_voltages, }; static int regulator_nxp_vref_init(const struct device *dev) { const struct regulator_nxp_vref_config *config = dev->config; VREF_Type *base = config->base; int ret; regulator_common_data_init(dev); /* Select ground */ base->CSR &= ~VREF_CSR_REFL_GRD_SEL_MASK; base->CSR |= config->gnd_sel; ret = regulator_nxp_vref_disable(dev); if (ret < 0) { return ret; } return regulator_common_init(dev, false); } #define REGULATOR_NXP_VREF_DEFINE(inst) \ static struct regulator_nxp_vref_data data_##inst; \ \ static const struct regulator_nxp_vref_config config_##inst = { \ .common = REGULATOR_DT_INST_COMMON_CONFIG_INIT(inst), \ .base = (VREF_Type *) DT_INST_REG_ADDR(inst), \ .gnd_sel = DT_INST_ENUM_IDX_OR(inst, nxp_ground_select, 0), \ .buf_start_delay = DT_INST_PROP(inst, \ nxp_buffer_startup_delay_us), \ .bg_start_time = DT_INST_PROP(inst, \ nxp_bandgap_startup_time_us), \ }; \ \ DEVICE_DT_INST_DEFINE(inst, regulator_nxp_vref_init, NULL, &data_##inst,\ &config_##inst, POST_KERNEL, \ CONFIG_REGULATOR_NXP_VREF_INIT_PRIORITY, &api); \ DT_INST_FOREACH_STATUS_OKAY(REGULATOR_NXP_VREF_DEFINE)