diff --git a/drivers/regulator/CMakeLists.txt b/drivers/regulator/CMakeLists.txt index 972618db12d..27bf32076cf 100644 --- a/drivers/regulator/CMakeLists.txt +++ b/drivers/regulator/CMakeLists.txt @@ -15,3 +15,4 @@ zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM6001 regulator_npm6001.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_PCA9420 regulator_pca9420.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_SHELL regulator_shell.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_RPI_PICO regulator_rpi_pico.c) +zephyr_library_sources_ifdef(CONFIG_REGULATOR_NXP_VREF regulator_nxp_vref.c) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 94998fb6191..5ecaf1181ea 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -37,5 +37,6 @@ source "drivers/regulator/Kconfig.npm1300" source "drivers/regulator/Kconfig.npm6001" source "drivers/regulator/Kconfig.pca9420" source "drivers/regulator/Kconfig.rpi_pico" +source "drivers/regulator/Kconfig.nxp_vref" endif # REGULATOR diff --git a/drivers/regulator/Kconfig.nxp_vref b/drivers/regulator/Kconfig.nxp_vref new file mode 100644 index 00000000000..4c9bc54fd13 --- /dev/null +++ b/drivers/regulator/Kconfig.nxp_vref @@ -0,0 +1,14 @@ +# Copyright 2023 NXP +# SPDX -License-Identifier: Apache-2.0 + +config REGULATOR_NXP_VREF + bool "NXP VREF peripheral driver" + default y if DT_HAS_NXP_VREF_ENABLED + help + Enable the NXP VREF driver + +config REGULATOR_NXP_VREF_INIT_PRIORITY + int "NXP VREF peripheral driver init priority" + default 45 + help + Init priority for the NXP VREF peripheral. diff --git a/drivers/regulator/regulator_nxp_vref.c b/drivers/regulator/regulator_nxp_vref.c new file mode 100644 index 00000000000..3d2ba23010e --- /dev/null +++ b/drivers/regulator/regulator_nxp_vref.c @@ -0,0 +1,221 @@ +/* + * 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) diff --git a/dts/bindings/regulator/nxp,vref.yaml b/dts/bindings/regulator/nxp,vref.yaml new file mode 100644 index 00000000000..e3466ad29d5 --- /dev/null +++ b/dts/bindings/regulator/nxp,vref.yaml @@ -0,0 +1,41 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP VREF SOC peripheral + +compatible: "nxp,vref" + +include: + - name: base.yaml + - name: regulator.yaml + property-allowlist: + - regulator-name + - regulator-init-microvolt + - regulator-min-microvolt + - regulator-max-microvolt + - regulator-initial-mode + - regulator-allowed-modes + +properties: + reg: + required: true + + nxp,ground-select: + type: string + enum: + - "VREFL3V" # 0 + - "VSSA" # 1 + + nxp,buffer-startup-delay-us: + type: int + required: true + description: | + Buffer startup delay as specified in the + appropriate device data sheet, in microseconds. + + nxp,bandgap-startup-time-us: + type: int + required: true + description: | + Maximum bandgap startup time as specified in the + appropriate device data sheet, in microseconds. diff --git a/include/zephyr/dt-bindings/regulator/nxp_vref.h b/include/zephyr/dt-bindings/regulator/nxp_vref.h new file mode 100644 index 00000000000..37c3856496a --- /dev/null +++ b/include/zephyr/dt-bindings/regulator/nxp_vref.h @@ -0,0 +1,29 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_NXP_VREF_H +#define ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_NXP_VREF_H + +/** + * @defgroup regulator_nxp_vref Devicetree helpers + * @ingroup regulator_interface + * @{ + */ + +/** + * @name NXP VREF Regulator API Modes + * @{ + */ +#define NXP_VREF_MODE_STANDBY 0 +#define NXP_VREF_MODE_LOW_POWER 1 +#define NXP_VREF_MODE_HIGH_POWER 2 +#define NXP_VREF_MODE_INTERNAL_REGULATOR 3 + +/** @} */ + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_NXP_VREF_H */