Skip to content

Commit c94dbad

Browse files
committed
drivers: dac: Add driver support for TI MSPM0 G-Series DAC module
Add support for the DAC module on TI’s MSPM0 G-Series MCUs. The DAC supports 8-bit and 12-bit resolution. Signed-off-by: Santhosh Charles <[email protected]>
1 parent 1f08f4f commit c94dbad

File tree

5 files changed

+228
-0
lines changed

5 files changed

+228
-0
lines changed

drivers/dac/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ zephyr_library_sources_ifdef(CONFIG_DAC_MCUX_GAU dac_mcux_gau.c)
3030
zephyr_library_sources_ifdef(CONFIG_DAC_TEST dac_test.c)
3131
zephyr_library_sources_ifdef(CONFIG_DAC_MAX22017 dac_max22017.c)
3232
zephyr_library_sources_ifdef(CONFIG_DAC_RENESAS_RA dac_renesas_ra.c)
33+
zephyr_library_sources_ifdef(CONFIG_DAC_MSPM0 dac_mspm0.c)

drivers/dac/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,6 @@ source "drivers/dac/Kconfig.renesas_ra"
6969

7070
source "drivers/dac/Kconfig.samd5x"
7171

72+
source "drivers/dac/Kconfig.mspm0"
73+
7274
endif # DAC

drivers/dac/Kconfig.mspm0

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# TI MSPM0 DAC Driver Configuration
2+
3+
# Copyright (c) 2025 Linumiz GmbH
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
config DAC_MSPM0
7+
bool "TI MSPM0 Digital To Analog Converter (DAC) Driver"
8+
default y
9+
depends on DT_HAS_TI_MSPM0_DAC_ENABLED
10+
select USE_MSPM0_DL_DAC12
11+
help
12+
Enable support for the DAC (Digital-to-Analog Converter)
13+
peripheral driver for Texas Instruments MSPM0 G-Series MCUs.
14+
15+
config DAC_MSPM0_TIMEOUT_MS
16+
int "DAC MSPM0 module ready timeout in milliseconds"
17+
default 50
18+
depends on DAC_MSPM0
19+
help
20+
Timeout in milliseconds to wait for the DAC module to be
21+
ready after enabling.
22+
23+
config DAC_MSPM0_VREF_SOURCE
24+
bool "Select external VREF+/VREF- as voltage reference"
25+
default n
26+
depends on DAC_MSPM0
27+
help
28+
Select external voltage reference (VREF+/VREF-) for DAC
29+
instead of the internal reference supply (VDDA/VSSA).

drivers/dac/dac_mspm0.c

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
/*
2+
* Copyright (c) 2025 Linumiz GmbH
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT ti_mspm0_dac
8+
9+
#include <zephyr/device.h>
10+
#include <zephyr/devicetree.h>
11+
#include <zephyr/drivers/dac.h>
12+
#include <zephyr/irq.h>
13+
#include <zephyr/kernel.h>
14+
15+
/* TI Driverlib includes */
16+
#include <ti/devices/msp/peripherals/hw_dac12.h>
17+
#include <ti/driverlib/dl_dac12.h>
18+
19+
/* DAC valid resolutions */
20+
#define DAC_RESOLUTION_8BIT 8
21+
#define DAC_RESOLUTION_12BIT 12
22+
23+
/* 8-bit Binary Repr Range */
24+
#define DAC8_BINARY_REPR_MIN 0
25+
#define DAC8_BINARY_REPR_MAX 255
26+
27+
/* 12-bit Binary Repr Range */
28+
#define DAC12_BINARY_REPR_MIN 0
29+
#define DAC12_BINARY_REPR_MAX 4095
30+
31+
/* DAC Primary Channel ID */
32+
#define DAC_CHANNEL_ID_PRIMARY 0
33+
34+
/* Timeout to wait until the DAC module is ready after enabling */
35+
#define DAC_MOD_RDY_TIMEOUT K_MSEC(CONFIG_DAC_MSPM0_TIMEOUT_MS)
36+
37+
struct dac_mspm0_config {
38+
DAC12_Regs *dac_base;
39+
void (*irq_config_func)(const struct device *dev);
40+
};
41+
42+
struct dac_mspm0_data {
43+
uint8_t resolution;
44+
struct k_mutex lock;
45+
struct k_sem mod_rdy;
46+
};
47+
48+
static void dac_mspm0_isr(const struct device *dev)
49+
{
50+
const struct dac_mspm0_config *config = dev->config;
51+
struct dac_mspm0_data *data = dev->data;
52+
53+
if (DL_DAC12_getPendingInterrupt(config->dac_base) == DL_DAC12_IIDX_MODULE_READY) {
54+
k_sem_give(&data->mod_rdy);
55+
}
56+
}
57+
58+
static int dac_mspm0_channel_setup(const struct device *dev,
59+
const struct dac_channel_cfg *channel_cfg)
60+
{
61+
const struct dac_mspm0_config *config = dev->config;
62+
struct dac_mspm0_data *data = dev->data;
63+
int ret = 0;
64+
65+
if (channel_cfg->channel_id != DAC_CHANNEL_ID_PRIMARY) {
66+
return -EINVAL;
67+
}
68+
69+
if (channel_cfg->resolution != DAC_RESOLUTION_8BIT &&
70+
channel_cfg->resolution != DAC_RESOLUTION_12BIT) {
71+
return -ENOTSUP;
72+
}
73+
74+
k_mutex_lock(&data->lock, K_FOREVER);
75+
k_sem_reset(&data->mod_rdy);
76+
77+
/* DAC must be disabled before configuration */
78+
DL_DAC12_disable(config->dac_base);
79+
80+
DL_DAC12_configDataFormat(config->dac_base, DL_DAC12_REPRESENTATION_BINARY,
81+
(channel_cfg->resolution == DAC_RESOLUTION_12BIT) ?
82+
DL_DAC12_RESOLUTION_12BIT : DL_DAC12_RESOLUTION_8BIT);
83+
84+
/* buffered must be true to enable amplifier for output drive */
85+
DL_DAC12_setAmplifier(config->dac_base,
86+
(channel_cfg->buffered) ? DL_DAC12_AMP_ON : DL_DAC12_AMP_OFF_0V);
87+
88+
if (IS_ENABLED(CONFIG_DAC_MSPM0_VREF_SOURCE)) {
89+
DL_DAC12_setReferenceVoltageSource(config->dac_base,
90+
DL_DAC12_VREF_SOURCE_VEREFP_VEREFN);
91+
} else {
92+
DL_DAC12_setReferenceVoltageSource(config->dac_base,
93+
DL_DAC12_VREF_SOURCE_VDDA_VSSA);
94+
}
95+
96+
/* internal must be true to route output to OPA, ADC, COMP and DAC_OUT pin */
97+
if (channel_cfg->internal) {
98+
DL_DAC12_enableOutputPin(config->dac_base);
99+
} else {
100+
DL_DAC12_disableOutputPin(config->dac_base);
101+
}
102+
103+
DL_DAC12_enable(config->dac_base);
104+
105+
if (k_sem_take(&data->mod_rdy, DAC_MOD_RDY_TIMEOUT) != 0) {
106+
ret = -ETIMEDOUT;
107+
goto unlock;
108+
}
109+
110+
data->resolution = channel_cfg->resolution;
111+
DL_DAC12_performSelfCalibrationBlocking(config->dac_base);
112+
113+
unlock:
114+
k_mutex_unlock(&data->lock);
115+
return ret;
116+
}
117+
118+
static int dac_mspm0_write_value(const struct device *dev, uint8_t channel, uint32_t value)
119+
{
120+
const struct dac_mspm0_config *config = dev->config;
121+
struct dac_mspm0_data *data = dev->data;
122+
int ret = 0;
123+
124+
k_mutex_lock(&data->lock, K_FOREVER);
125+
126+
/* Validate channel and resolution */
127+
if (channel != DAC_CHANNEL_ID_PRIMARY || data->resolution == 0) {
128+
ret = -EINVAL;
129+
goto unlock;
130+
}
131+
132+
if (data->resolution == DAC_RESOLUTION_12BIT) {
133+
if (value > DAC12_BINARY_REPR_MAX || value < DAC12_BINARY_REPR_MIN) {
134+
ret = -EINVAL;
135+
goto unlock;
136+
}
137+
DL_DAC12_output12(config->dac_base, value);
138+
139+
} else {
140+
if (value > DAC8_BINARY_REPR_MAX || value < DAC8_BINARY_REPR_MIN) {
141+
ret = -EINVAL;
142+
goto unlock;
143+
}
144+
DL_DAC12_output8(config->dac_base, (uint8_t)value);
145+
}
146+
147+
unlock:
148+
k_mutex_unlock(&data->lock);
149+
return ret;
150+
}
151+
152+
static int dac_mspm0_init(const struct device *dev)
153+
{
154+
const struct dac_mspm0_config *config = dev->config;
155+
156+
DL_DAC12_enablePower(config->dac_base);
157+
158+
config->irq_config_func(dev);
159+
DL_DAC12_enableInterrupt(config->dac_base, DL_DAC12_INTERRUPT_MODULE_READY);
160+
161+
return 0;
162+
}
163+
164+
static DEVICE_API(dac, dac_mspm0_driver_api) = {
165+
.channel_setup = dac_mspm0_channel_setup,
166+
.write_value = dac_mspm0_write_value
167+
};
168+
169+
#define DAC_MSPM0_DEFINE(id) \
170+
\
171+
static void dac_mspm0_irq_config_##id(const struct device *dev) \
172+
{ \
173+
IRQ_CONNECT(DT_INST_IRQN(id), DT_INST_IRQ(id, priority), dac_mspm0_isr, \
174+
DEVICE_DT_INST_GET(id), 0); \
175+
irq_enable(DT_INST_IRQN(id)); \
176+
}; \
177+
\
178+
static const struct dac_mspm0_config dac_mspm0_config_##id = { \
179+
.dac_base = (DAC12_Regs *)DT_INST_REG_ADDR(id), \
180+
.irq_config_func = dac_mspm0_irq_config_##id, \
181+
}; \
182+
\
183+
static struct dac_mspm0_data dac_mspm0_data_##id = { \
184+
/* Configure resolution at channel setup */ \
185+
.lock = Z_MUTEX_INITIALIZER(dac_mspm0_data_##id.lock), \
186+
.mod_rdy = Z_SEM_INITIALIZER(dac_mspm0_data_##id.mod_rdy, 0, 1), \
187+
}; \
188+
\
189+
DEVICE_DT_INST_DEFINE(id, &dac_mspm0_init, NULL, &dac_mspm0_data_##id, \
190+
&dac_mspm0_config_##id, POST_KERNEL, CONFIG_DAC_INIT_PRIORITY, \
191+
&dac_mspm0_driver_api);
192+
193+
DT_INST_FOREACH_STATUS_OKAY(DAC_MSPM0_DEFINE)

modules/Kconfig.mspm0

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,6 @@ config USE_MSPM0_DL_UART
1414

1515
config USE_MSPM0_DL_TIMER
1616
bool
17+
18+
config USE_MSPM0_DL_DAC12
19+
bool

0 commit comments

Comments
 (0)