Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers: regulator: Add NXP VREF driver #56822

Merged
merged 4 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions boards/arm/lpcxpresso55s36/lpcxpresso55s36.dts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ zephyr_udc0: &usbfs {
status = "okay";
};

&vref0 {
status = "okay";
};

&dac0 {
status = "okay";
pinctrl-0 = <&pinmux_dac0>;
Expand Down
1 change: 1 addition & 0 deletions drivers/adc/Kconfig.mcux
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ config ADC_MCUX_LPADC
bool "MCUX LPADC driver"
default y
select ADC_CONFIGURABLE_INPUTS
select REGULATOR
depends on DT_HAS_NXP_LPC_LPADC_ENABLED
help
Enable the MCUX LPADC driver.
Expand Down
25 changes: 24 additions & 1 deletion drivers/adc/adc_mcux_lpadc.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@

#include <errno.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/sys/util.h>
#include <fsl_lpadc.h>
#include <zephyr/drivers/regulator.h>

#include <zephyr/drivers/pinctrl.h>

Expand Down Expand Up @@ -43,6 +45,7 @@ struct mcux_lpadc_config {
uint32_t offset_b;
void (*irq_config_func)(const struct device *dev);
const struct pinctrl_dev_config *pincfg;
const struct device **ref_supplies;
};

struct mcux_lpadc_data {
Expand Down Expand Up @@ -392,6 +395,16 @@ static int mcux_lpadc_init(const struct device *dev)
return err;
}

/* Enable necessary regulators */
const struct device **regulator = config->ref_supplies;

while (*regulator != NULL) {
err = regulator_enable(*(regulator++));
if (err) {
return err;
}
}

LPADC_GetDefaultConfig(&adc_config);

adc_config.enableAnalogPreliminary = true;
Expand Down Expand Up @@ -455,8 +468,18 @@ static const struct adc_driver_api mcux_lpadc_driver_api = {
#endif
};

#define LPADC_REGULATOR_DEPENDENCY(node_id, prop, idx) \
DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node_id, prop, idx)),

#define LPADC_REGULATORS_DEFINE(inst) \
static const struct device *mcux_lpadc_ref_supplies_##inst[] = { \
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, nxp_reference_supply), \
(DT_INST_FOREACH_PROP_ELEM(inst, nxp_reference_supply, \
LPADC_REGULATOR_DEPENDENCY)), ()) NULL};

#define LPADC_MCUX_INIT(n) \
LPADC_REGULATORS_DEFINE(n) \
gmarull marked this conversation as resolved.
Show resolved Hide resolved
\
static void mcux_lpadc_config_func_##n(const struct device *dev); \
\
PINCTRL_DT_INST_DEFINE(n); \
Expand All @@ -469,8 +492,8 @@ static const struct adc_driver_api mcux_lpadc_driver_api = {
.offset_b = DT_INST_PROP(n, offset_value_b), \
.irq_config_func = mcux_lpadc_config_func_##n, \
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
.ref_supplies = mcux_lpadc_ref_supplies_##n, \
}; \
\
static struct mcux_lpadc_data mcux_lpadc_data_##n = { \
ADC_CONTEXT_INIT_TIMER(mcux_lpadc_data_##n, ctx), \
ADC_CONTEXT_INIT_LOCK(mcux_lpadc_data_##n, ctx), \
Expand Down
1 change: 1 addition & 0 deletions drivers/regulator/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
1 change: 1 addition & 0 deletions drivers/regulator/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
14 changes: 14 additions & 0 deletions drivers/regulator/Kconfig.nxp_vref
Original file line number Diff line number Diff line change
@@ -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.
221 changes: 221 additions & 0 deletions drivers/regulator/regulator_nxp_vref.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
/*
* Copyright 2023 NXP
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT nxp_vref

#include <errno.h>

#include <zephyr/drivers/regulator.h>
#include <zephyr/dt-bindings/regulator/nxp_vref.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/linear_range.h>
#include <zephyr/sys/util.h>

#include <fsl_device_registers.h>

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;
decsny marked this conversation as resolved.
Show resolved Hide resolved
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);
decsny marked this conversation as resolved.
Show resolved Hide resolved

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)
10 changes: 10 additions & 0 deletions dts/arm/nxp/nxp_lpc55S3x_common.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@
#io-channel-cells = <1>;
dmas = <&dma0 21>, <&dma0 22>;
dma-names = "adc0-dma0", "adc0-dma1";
nxp,reference-supply = <&vref0>;
};

dac0: dac@b2000 {
Expand Down Expand Up @@ -462,6 +463,15 @@
prescaler = <2>;
#pwm-cells = <3>;
};

vref0: vref@b5000 {
compatible = "nxp,vref";
regulator-name = "lpc55s36-vref";
reg = <0xb5000 0x30>;
status = "disabled";
nxp,buffer-startup-delay-us = <400>;
nxp,bandgap-startup-time-us = <20>;
gmarull marked this conversation as resolved.
Show resolved Hide resolved
};
};

&nvic {
Expand Down
4 changes: 4 additions & 0 deletions dts/bindings/adc/nxp,lpc-lpadc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ properties:
required: true
description: Offset value B to use if CONFIG_LPADC_DO_OFFSET_CALIBRATION is false

nxp,reference-supply:
type: phandles
description: References to required regulators which must be enabled for LPADC to function

"#io-channel-cells":
const: 1

Expand Down