Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions boards/ti/lp_mspm33c321a/lp_mspm33c321a.dts
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,9 @@
clock-frequency = <32768>;
ti,xtal-startup-delay-us = <640000>;
};

&vref0 {
status = "okay";
pinctrl-0 = <&analog_pa23>;
pinctrl-names = "default";
};
2 changes: 1 addition & 1 deletion drivers/regulator/Kconfig.mspm0
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ config REGULATOR_MSPM0_VREF
bool "TI MSPM0 VREF peripheral driver"
depends on REGULATOR
depends on DT_HAS_TI_MSPM0_VREF_ENABLED
select PINCTRL
default y
select USE_MSPM0_DL_VREF
help
Enable the MSPM0 VREF driver

Expand Down
200 changes: 142 additions & 58 deletions drivers/regulator/regulator_mspm0_vref.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,52 +6,150 @@

#define DT_DRV_COMPAT ti_mspm0_vref

#include <errno.h>
#include <zephyr/drivers/regulator.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/dt-bindings/clock/mspm0_clock.h>
#include <zephyr/dt-bindings/regulator/mspm0_vref.h>
#include <zephyr/logging/log.h>

/* TI Driverlib includes */
#include <ti/driverlib/dl_vref.h>
#include <zephyr/sys/util.h>

LOG_MODULE_REGISTER(vref, CONFIG_LOG_DEFAULT_LEVEL);

/* vref output voltages in microvolts */
#define VREF_1_4V 1400000
#define VREF_2_5V 2500000

struct regulator_mspm0_vref_gprcm {
volatile uint32_t pwren; /**< Power Enable register, offset: 0x00 */
volatile uint32_t rstctl; /**< Reset Control register, offset: 0x04 */
uint8_t reserved_1[0xC]; /**< Reserved, offset: 0x08 - 0x14 */
volatile const uint32_t stat; /**< Status register, offset: 0x14 */
};

struct regulator_mspm0_vref_regs {
uint8_t reserved_1[0x800]; /**< Reserved, offset: 0x000 - 0x800 */
volatile struct regulator_mspm0_vref_gprcm gprcm; /**< Power/reset control, offset: 0x800 */
uint8_t reserved_2[0x7E8]; /**< Reserved, offset: 0x818 - 0x1000 */
volatile uint32_t clkdiv; /**< Clock Divider register, offset: 0x1000 */
uint8_t reserved_3[0x4]; /**< Reserved, offset: 0x1004 - 0x1008 */
volatile uint32_t clksel; /**< Clock Selection register, offset: 0x1008 */
uint8_t reserved_4[0xF4]; /**< Reserved, offset: 0x100C - 0x1100 */
volatile uint32_t ctl0; /**< Control 0 register, offset: 0x1100 */
volatile uint32_t ctl1; /**< Control 1 register, offset: 0x1104 */
volatile uint32_t ctl2; /**< Control 2 register, offset: 0x1108 */
volatile uint32_t v2ien; /**< V2I Enable register, offset: 0x110C */
};

/* pwren bits */
#define VREF_PWREN_ENABLE BIT(0)
#define VREF_PWREN_KEY GENMASK(31, 24)
#define VREF_PWREN_KEY_UNLOCK 0x26U

/* rstctl bits */
#define VREF_RSTCTL_RESETASSERT BIT(0)
#define VREF_RSTCTL_RESETSTKYCLR BIT(1)
#define VREF_RSTCTL_KEY GENMASK(31, 24)
#define VREF_RSTCTL_KEY_UNLOCK 0xB1U

/* stat bits */
#define VREF_STAT_RESETSTKY BIT(16)

/* clkdiv bits */
#define VREF_CLKDIV_RATIO GENMASK(2, 0)
#define VREF_CLKDIV_RATIO_VAL(x) ((x) - 1)

/* clksel bits */
#define VREF_CLKSEL_LFCLK_SEL BIT(1)
#define VREF_CLKSEL_MFCLK_SEL BIT(2)
#define VREF_CLKSEL_BUSCLK_SEL BIT(3)

/* ctl0 bits */
#define VREF_CTL0_ENABLE BIT(0)
#define VREF_CTL0_COMP_VREF_ENABLE BIT(1)
#define VREF_CTL0_BUFCONFIG BIT(7)
#define VREF_CTL0_BUFCONFIG_2_5V 0U
#define VREF_CTL0_BUFCONFIG_1_4V VREF_CTL0_BUFCONFIG
#define VREF_CTL0_SHMODE BIT(8)

/* ctl1 bits */
#define VREF_CTL1_READY BIT(0)

/* ctl2 bits */
#define VREF_CTL2_SHCYCLE GENMASK(15, 0)
#define VREF_CTL2_HCYCLE GENMASK(31, 16)

/* v2ien bits */
#define VREF_V2IEN_V2I_EN BIT(0)

struct regulator_mspm0_vref_data {
struct regulator_common_data common;
DL_VREF_Config vref_cfg;
uint32_t regulator_uv;
uint16_t sample_cycle_count;
bool v2i_enable;
uint16_t hold_cycle_count;
bool sh_mode_enable;
};

struct regulator_mspm0_vref_config {
struct regulator_common_config common;
const struct pinctrl_dev_config *vref_pin;
DL_VREF_ClockConfig vref_clock_cfg;
VREF_Regs *regs;
struct regulator_mspm0_vref_regs *regs;
uint32_t clock_sel;
uint32_t clock_div;
};

static void regulator_mspm0_vref_configure(const struct regulator_mspm0_vref_config *config,
struct regulator_mspm0_vref_data *data)
{
uint32_t buf_config = (data->regulator_uv == VREF_1_4V) ? VREF_CTL0_BUFCONFIG_1_4V
: VREF_CTL0_BUFCONFIG_2_5V;

config->regs->ctl0 = buf_config | (data->sh_mode_enable ? VREF_CTL0_SHMODE : 0);
config->regs->ctl2 =
FIELD_PREP(VREF_CTL2_SHCYCLE, data->sample_cycle_count + data->hold_cycle_count) |
FIELD_PREP(VREF_CTL2_HCYCLE, data->hold_cycle_count);
config->regs->v2ien = data->v2i_enable ? VREF_V2IEN_V2I_EN : 0;
}

static regulator_mode_t
regulator_mspm0_vref_mode_from_regs(const struct regulator_mspm0_vref_config *config)
{
regulator_mode_t mode = MSPM0_VREF_MODE_NORMAL;

if (config->regs->ctl0 & VREF_CTL0_SHMODE) {
mode |= MSPM0_VREF_MODE_SHMODE;
}
if (config->regs->v2ien & VREF_V2IEN_V2I_EN) {
mode |= MSPM0_VREF_MODE_V2I;
}

return mode;
}

static int regulator_mspm0_vref_enable(const struct device *dev)
{
DL_VREF_enableInternalRef(((const struct regulator_mspm0_vref_config *)dev->config)->regs);
const struct regulator_mspm0_vref_config *config = dev->config;

config->regs->ctl0 |= VREF_CTL0_ENABLE;

return 0;
}

static int regulator_mspm0_vref_disable(const struct device *dev)
{
DL_VREF_disableInternalRef(((const struct regulator_mspm0_vref_config *)dev->config)->regs);
const struct regulator_mspm0_vref_config *config = dev->config;

config->regs->ctl0 &= ~VREF_CTL0_ENABLE;

return 0;
}

static int regulator_mspm0_vref_get_voltage(const struct device *dev, int32_t *volt_uv)
{
const struct regulator_mspm0_vref_config *config = dev->config;
#ifdef CONFIG_REGULATOR_THREAD_SAFE_REFCNT
struct regulator_mspm0_vref_data *data = dev->data;
#endif

if (volt_uv == NULL) {
return -EINVAL;
Expand All @@ -61,7 +159,7 @@ static int regulator_mspm0_vref_get_voltage(const struct device *dev, int32_t *v
k_mutex_lock(&data->common.lock, K_FOREVER);
#endif

if (config->regs->CTL0 & VREF_CTL0_BUFCONFIG_MASK) {
if (config->regs->ctl0 & VREF_CTL0_BUFCONFIG) {
*volt_uv = VREF_1_4V;
} else {
*volt_uv = VREF_2_5V;
Expand Down Expand Up @@ -96,18 +194,14 @@ static int regulator_mspm0_vref_set_voltage(const struct device *dev, int32_t mi
#endif

if (data->common.refcnt != 0) {
volt_get = (config->regs->CTL0 & VREF_CTL0_BUFCONFIG_MASK) ? VREF_1_4V : VREF_2_5V;
volt_get = (config->regs->ctl0 & VREF_CTL0_BUFCONFIG) ? VREF_1_4V : VREF_2_5V;
if (volt_set != volt_get) {
ret = -EBUSY;
goto out;
}
} else {
if (volt_set == VREF_2_5V) {
data->vref_cfg.bufConfig = DL_VREF_BUFCONFIG_OUTPUT_2_5V;
} else {
data->vref_cfg.bufConfig = DL_VREF_BUFCONFIG_OUTPUT_1_4V;
}
DL_VREF_configReference(config->regs, &data->vref_cfg);
data->regulator_uv = volt_set;
regulator_mspm0_vref_configure(config, data);
}
out:

Expand All @@ -121,7 +215,9 @@ static int regulator_mspm0_vref_set_voltage(const struct device *dev, int32_t mi
static int regulator_mspm0_vref_get_mode(const struct device *dev, regulator_mode_t *mode)
{
const struct regulator_mspm0_vref_config *config = dev->config;
#ifdef CONFIG_REGULATOR_THREAD_SAFE_REFCNT
struct regulator_mspm0_vref_data *data = dev->data;
#endif

if (mode == NULL) {
return -EINVAL;
Expand All @@ -131,11 +227,7 @@ static int regulator_mspm0_vref_get_mode(const struct device *dev, regulator_mod
k_mutex_lock(&data->common.lock, K_FOREVER);
#endif

if (config->regs->CTL0 & VREF_CTL0_SHMODE_MASK) {
*mode = MSPM0_VREF_MODE_SHMODE;
} else {
*mode = MSPM0_VREF_MODE_NORMAL;
}
*mode = regulator_mspm0_vref_mode_from_regs(config);

#ifdef CONFIG_REGULATOR_THREAD_SAFE_REFCNT
k_mutex_unlock(&data->common.lock);
Expand All @@ -155,26 +247,21 @@ static int regulator_mspm0_vref_set_mode(const struct device *dev, regulator_mod
k_mutex_lock(&data->common.lock, K_FOREVER);
#endif

if (mode & ~(MSPM0_VREF_MODE_SHMODE | MSPM0_VREF_MODE_V2I)) {
ret = -ENOTSUP;
goto out;
}

if (data->common.refcnt != 0) {
mode_get = (config->regs->CTL0 & VREF_CTL0_SHMODE_MASK) ? MSPM0_VREF_MODE_SHMODE
: MSPM0_VREF_MODE_NORMAL;
mode_get = regulator_mspm0_vref_mode_from_regs(config);
if (mode_get != mode) {
ret = -EBUSY;
goto out;
}
} else {
switch (mode) {
case MSPM0_VREF_MODE_SHMODE:
data->vref_cfg.shModeEnable = DL_VREF_SHMODE_ENABLE;
break;
case MSPM0_VREF_MODE_NORMAL:
data->vref_cfg.shModeEnable = DL_VREF_SHMODE_DISABLE;
break;
default:
ret = -EINVAL;
goto out;
}
DL_VREF_configReference(config->regs, &data->vref_cfg);
data->sh_mode_enable = (mode & MSPM0_VREF_MODE_SHMODE) != 0;
data->v2i_enable = (mode & MSPM0_VREF_MODE_V2I) != 0;
regulator_mspm0_vref_configure(config, data);
}
out:

Expand All @@ -200,10 +287,13 @@ static int regulator_mspm0_vref_init(const struct device *dev)
}

/* Enable power */
DL_VREF_enablePower(config->regs);
delay_cycles(CONFIG_MSPM0_PERIPH_STARTUP_DELAY);
DL_VREF_configReference(config->regs, &data->vref_cfg);
DL_VREF_setClockConfig(config->regs, &config->vref_clock_cfg);
config->regs->gprcm.pwren =
FIELD_PREP(VREF_PWREN_KEY, VREF_PWREN_KEY_UNLOCK) | VREF_PWREN_ENABLE;
msp_delay_peripheral_startup();
regulator_mspm0_vref_configure(config, data);
config->regs->clksel = config->clock_sel;
config->regs->clkdiv =
FIELD_PREP(VREF_CLKDIV_RATIO, VREF_CLKDIV_RATIO_VAL(config->clock_div));

ret = regulator_common_init(dev, false);
if (ret) {
Expand All @@ -223,34 +313,28 @@ static DEVICE_API(regulator, mspm0_vref_api) = {
.get_mode = regulator_mspm0_vref_get_mode,
};

#define VREF_CLOCK_DIVIDE_RATIO(n) CONCAT(DL_VREF_CLOCK_DIVIDE_, DT_INST_PROP(n, ti_clk_div))

#define REGULATOR_MSPM0_VREF_DEFINE(n) \
\
PINCTRL_DT_INST_DEFINE(n); \
\
static struct regulator_mspm0_vref_data data_##n = { \
.vref_cfg = { \
.vrefEnable = DL_VREF_ENABLE_DISABLE, \
.bufConfig = (DT_INST_PROP(n, regulator_uv) == VREF_1_4V \
? DL_VREF_BUFCONFIG_OUTPUT_1_4V \
: DL_VREF_BUFCONFIG_OUTPUT_2_5V), \
.shModeEnable = DT_INST_PROP(n, ti_sample_hold_enable) \
? DL_VREF_SHMODE_ENABLE : DL_VREF_SHMODE_DISABLE, \
.shCycleCount = DT_INST_PROP(n, ti_sample_cycles), \
.holdCycleCount = DT_INST_PROP(n, ti_hold_cycles), \
}, \
.regulator_uv = DT_INST_PROP(n, regulator_uv), \
.sh_mode_enable = DT_INST_PROP(n, ti_sample_hold_enable), \
.sample_cycle_count = DT_INST_PROP(n, ti_sample_cycles), \
.v2i_enable = DT_INST_PROP(n, ti_v2i_enable), \
.hold_cycle_count = DT_INST_PROP(n, ti_hold_cycles), \
.regulator_uv = DT_INST_PROP(n, regulator_uv), \
.sh_mode_enable = DT_INST_PROP(n, ti_sample_hold_enable), \
.sample_cycle_count = DT_INST_PROP(n, ti_sample_cycles), \
.hold_cycle_count = DT_INST_PROP(n, ti_hold_cycles), \
}; \
\
static const struct regulator_mspm0_vref_config config_##n = { \
.common = REGULATOR_DT_INST_COMMON_CONFIG_INIT(n), \
.vref_pin = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
.regs = (VREF_Regs *)DT_INST_REG_ADDR(n), \
.vref_clock_cfg = { \
.clockSel = \
MSPM0_CLOCK_PERIPH_REG_MASK(DT_INST_CLOCKS_CELL(n, clk)), \
.divideRatio = VREF_CLOCK_DIVIDE_RATIO(n), \
}, \
.regs = (struct regulator_mspm0_vref_regs *)DT_INST_REG_ADDR(n), \
.clock_sel = MSPM0_CLOCK_PERIPH_REG_MASK(DT_INST_CLOCKS_CELL(n, clk)), \
.clock_div = DT_INST_PROP(n, ti_clk_div), \
}; \
\
DEVICE_DT_INST_DEFINE(n, regulator_mspm0_vref_init, NULL, &data_##n, \
Expand Down
3 changes: 3 additions & 0 deletions dts/arm/ti/mspm0/mspm0.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <arm/armv6-m.dtsi>
#include <zephyr/dt-bindings/clock/mspm0_clock.h>
#include <zephyr/dt-bindings/regulator/mspm0_vref.h>
#include <freq.h>

/ {
Expand Down Expand Up @@ -199,6 +200,8 @@
regulator-uv = <1400000>;
ti,sample-cycles = <10>;
ti,hold-cycles = <40>;
regulator-allowed-modes = <MSPM0_VREF_MODE_NORMAL>,
<MSPM0_VREF_MODE_SHMODE>;
status = "disabled";
};

Expand Down
17 changes: 17 additions & 0 deletions dts/arm/ti/mspm33c/mspm33c.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <arm/armv8-m.dtsi>
#include <freq.h>
#include <zephyr/dt-bindings/clock/mspm0_clock.h>
#include <zephyr/dt-bindings/regulator/mspm0_vref.h>

/ {
cpus {
Expand Down Expand Up @@ -214,6 +215,22 @@
#dma-cells = <2>;
status = "disabled";
};

vref0: vref@400e8000 {
compatible = "ti,mspm0-vref";
reg = <0x400e8000 0x2000>;
clocks = <&ckm MSPM0_CLOCK_BUSCLK>;
ti,clk-div = <0x1>;
off-on-delay-us = <350>;
regulator-uv = <1400000>;
ti,sample-cycles = <10>;
ti,hold-cycles = <40>;
regulator-allowed-modes = <MSPM0_VREF_MODE_NORMAL>,
<MSPM0_VREF_MODE_SHMODE>,
<MSPM0_VREF_MODE_V2I>,
<MSPM0_VREF_MODE_SHMODE_V2I>;
status = "disabled";
};
};
};

Expand Down
4 changes: 4 additions & 0 deletions dts/bindings/regulator/ti,mspm0-vref.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ properties:
type: boolean
description: Enable sample & hold mode

ti,v2i-enable:
type: boolean
description: Enable voltage-to-current mode

ti,sample-cycles:
type: int
description: Number of sample cycles for sample & hold mode
Expand Down
Loading
Loading