From c29803c5bd16d35c3621eeffe51f7ebc9e3ed2da Mon Sep 17 00:00:00 2001 From: Santhosh Charles Date: Wed, 7 Oct 2026 14:58:27 +0530 Subject: [PATCH 01/16] UPSTREAM: dts: bindings: dac: add DT bindings for TI MSPM0 G-Series DAC ... commit 749f4806ed263643b8897f7db4c24c7eefce40d7 upstream. Add devicetree bindings for the TI MSPM0 G-Series DAC module. Signed-off-by: Santhosh Charles --- dts/bindings/dac/ti,mspm0-dac.yaml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 dts/bindings/dac/ti,mspm0-dac.yaml diff --git a/dts/bindings/dac/ti,mspm0-dac.yaml b/dts/bindings/dac/ti,mspm0-dac.yaml new file mode 100644 index 000000000000..443285207946 --- /dev/null +++ b/dts/bindings/dac/ti,mspm0-dac.yaml @@ -0,0 +1,21 @@ +# Copyright (c) 2026 Linumiz +# SPDX-License-Identifier: Apache-2.0 + +description: Texas Instruments MSPM0 G-Series Digital-to-Analog Converter (DAC) + +compatible: "ti,mspm0-dac" + +include: dac-controller.yaml + +properties: + reg: + required: true + + vref: + type: phandle + + "#io-channel-cells": + const: 1 + +io-channel-cells: + - output From 745d1bd99b9f314f138d88e3ada0f3b2dc66cce3 Mon Sep 17 00:00:00 2001 From: Santhosh Charles Date: Wed, 7 Oct 2026 15:00:54 +0530 Subject: [PATCH 02/16] UPSTREAM: drivers: dac: add driver support for TI MSPM0 G-Series DAC module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 3315866bc1127baf248d68f039297433cbddcc80 upstream. 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 --- drivers/dac/CMakeLists.txt | 1 + drivers/dac/Kconfig | 1 + drivers/dac/Kconfig.mspm0 | 13 +++ drivers/dac/dac_mspm0.c | 170 +++++++++++++++++++++++++++++++++++++ modules/Kconfig.mspm0 | 3 + 5 files changed, 188 insertions(+) create mode 100644 drivers/dac/Kconfig.mspm0 create mode 100644 drivers/dac/dac_mspm0.c diff --git a/drivers/dac/CMakeLists.txt b/drivers/dac/CMakeLists.txt index 19e10ecd8fe8..7b588bf6ca7f 100644 --- a/drivers/dac/CMakeLists.txt +++ b/drivers/dac/CMakeLists.txt @@ -30,6 +30,7 @@ zephyr_library_sources_ifdef(CONFIG_DAC_MCUX_DAC12 dac_mcux_dac12.c) zephyr_library_sources_ifdef(CONFIG_DAC_MCUX_DAC32 dac_mcux_dac32.c) zephyr_library_sources_ifdef(CONFIG_DAC_MCUX_GAU dac_mcux_gau.c) zephyr_library_sources_ifdef(CONFIG_DAC_MCUX_LPDAC dac_mcux_lpdac.c) +zephyr_library_sources_ifdef(CONFIG_DAC_MSPM0 dac_mspm0.c) zephyr_library_sources_ifdef(CONFIG_DAC_NXP_HPDAC dac_nxp_hpdac.c) zephyr_library_sources_ifdef(CONFIG_DAC_RENESAS_RA dac_renesas_ra.c) zephyr_library_sources_ifdef(CONFIG_DAC_SAM dac_sam.c) diff --git a/drivers/dac/Kconfig b/drivers/dac/Kconfig index 0fb0934215bc..5a1245a8c466 100644 --- a/drivers/dac/Kconfig +++ b/drivers/dac/Kconfig @@ -48,6 +48,7 @@ source "drivers/dac/Kconfig.mchp" source "drivers/dac/Kconfig.mcp4725" source "drivers/dac/Kconfig.mcp4728" source "drivers/dac/Kconfig.mcux" +source "drivers/dac/Kconfig.mspm0" source "drivers/dac/Kconfig.renesas_ra" source "drivers/dac/Kconfig.sam" source "drivers/dac/Kconfig.sam0" diff --git a/drivers/dac/Kconfig.mspm0 b/drivers/dac/Kconfig.mspm0 new file mode 100644 index 000000000000..15336a39d659 --- /dev/null +++ b/drivers/dac/Kconfig.mspm0 @@ -0,0 +1,13 @@ +# TI MSPM0 DAC Driver Configuration + +# Copyright (c) 2026 Linumiz +# SPDX-License-Identifier: Apache-2.0 + +config DAC_MSPM0 + bool "TI MSPM0 Digital To Analog Converter (DAC) Driver" + default y + depends on DT_HAS_TI_MSPM0_DAC_ENABLED + select USE_MSPM0_DL_DAC12 + help + Enable support for the DAC (Digital-to-Analog Converter) + peripheral driver for Texas Instruments MSPM0 G-Series MCUs. diff --git a/drivers/dac/dac_mspm0.c b/drivers/dac/dac_mspm0.c new file mode 100644 index 000000000000..cbdbe61aacfd --- /dev/null +++ b/drivers/dac/dac_mspm0.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2026 Linumiz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_mspm0_dac + +#include +#include +#include +#include + +/* TI Driverlib includes */ +#include + +#define DAC_RESOLUTION_8BIT 8 +#define DAC_RESOLUTION_12BIT 12 + +#define DAC8_MAX_VALUE 255 +#define DAC12_MAX_VALUE 4095 + +#define DAC_PRIMARY_CHANNEL_ID 0 +#define DAC_READY_TIMEOUT_US 1000 + +struct dac_mspm0_config { + DEVICE_MMIO_ROM; + DL_DAC12_VREF_SOURCE dac_vref_src; +}; + +struct dac_mspm0_data { + DEVICE_MMIO_RAM; + struct k_mutex lock; + uint8_t resolution; +}; + +static inline DAC12_Regs *dac_mspm0_regs(const struct device *dev) +{ + return (DAC12_Regs *)DEVICE_MMIO_GET(dev); +} + +static int dac_mspm0_channel_setup(const struct device *dev, + const struct dac_channel_cfg *channel_cfg) +{ + const struct dac_mspm0_config *config = dev->config; + struct dac_mspm0_data *data = dev->data; + DAC12_Regs *regs = dac_mspm0_regs(dev); + + if (channel_cfg->channel_id != DAC_PRIMARY_CHANNEL_ID) { + return -EINVAL; + } + + if (channel_cfg->resolution != DAC_RESOLUTION_8BIT && + channel_cfg->resolution != DAC_RESOLUTION_12BIT) { + return -ENOTSUP; + } + + k_mutex_lock(&data->lock, K_FOREVER); + + /* DAC must be disabled before configuration */ + DL_DAC12_disable(regs); + + DL_DAC12_configDataFormat(regs, DL_DAC12_REPRESENTATION_BINARY, + (channel_cfg->resolution == DAC_RESOLUTION_12BIT) ? + DL_DAC12_RESOLUTION_12BIT : DL_DAC12_RESOLUTION_8BIT); + + /* buffered must be true to enable amplifier for output drive */ + DL_DAC12_setAmplifier(regs, + (channel_cfg->buffered) ? DL_DAC12_AMP_ON : DL_DAC12_AMP_OFF_0V); + + DL_DAC12_setReferenceVoltageSource(regs, config->dac_vref_src); + + /* + * CTL1.OPS controls output to both internal modules (OPA, ADC, COMP) + * and the external DAC_OUT pin. HW does not allow separate control. + */ + if (channel_cfg->internal) { + DL_DAC12_enableOutputPin(regs); + } else { + DL_DAC12_disableOutputPin(regs); + } + + DL_DAC12_enable(regs); + + /* Wait for DAC core and output buffer to settle */ + if (!WAIT_FOR(DL_DAC12_getInterruptStatus(regs, + DL_DAC12_INTERRUPT_MODULE_READY), + DAC_READY_TIMEOUT_US, k_busy_wait(1))) { + k_mutex_unlock(&data->lock); + return -ETIMEDOUT; + } + + data->resolution = channel_cfg->resolution; + + if (channel_cfg->buffered) { + DL_DAC12_performSelfCalibrationBlocking(regs); + } + + k_mutex_unlock(&data->lock); + + return 0; +} + +static int dac_mspm0_write_value(const struct device *dev, uint8_t channel, uint32_t value) +{ + struct dac_mspm0_data *data = dev->data; + DAC12_Regs *regs = dac_mspm0_regs(dev); + int ret = 0; + + k_mutex_lock(&data->lock, K_FOREVER); + + /* Validate channel and resolution */ + if (channel != DAC_PRIMARY_CHANNEL_ID || data->resolution == 0) { + ret = -EINVAL; + goto unlock; + } + + if (data->resolution == DAC_RESOLUTION_12BIT) { + if (value > DAC12_MAX_VALUE) { + ret = -EINVAL; + goto unlock; + } + DL_DAC12_output12(regs, value); + + } else { + if (value > DAC8_MAX_VALUE) { + ret = -EINVAL; + goto unlock; + } + DL_DAC12_output8(regs, (uint8_t)value); + } + +unlock: + k_mutex_unlock(&data->lock); + return ret; +} + +static int dac_mspm0_init(const struct device *dev) +{ + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); + + DL_DAC12_enablePower(dac_mspm0_regs(dev)); + delay_cycles(CONFIG_MSPM0_PERIPH_STARTUP_DELAY); + + return 0; +} + +static DEVICE_API(dac, dac_mspm0_driver_api) = { + .channel_setup = dac_mspm0_channel_setup, + .write_value = dac_mspm0_write_value +}; + +#define DAC_MSPM0_DEFINE(id) \ + \ + static const struct dac_mspm0_config dac_mspm0_config_##id = { \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(id)), \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(id, vref), \ + (.dac_vref_src = DL_DAC12_VREF_SOURCE_VEREFP_VEREFN), \ + (.dac_vref_src = DL_DAC12_VREF_SOURCE_VDDA_VSSA)), \ + }; \ + \ + static struct dac_mspm0_data dac_mspm0_data_##id = { \ + .lock = Z_MUTEX_INITIALIZER(dac_mspm0_data_##id.lock), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(id, &dac_mspm0_init, NULL, &dac_mspm0_data_##id, \ + &dac_mspm0_config_##id, POST_KERNEL, CONFIG_DAC_INIT_PRIORITY, \ + &dac_mspm0_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(DAC_MSPM0_DEFINE) diff --git a/modules/Kconfig.mspm0 b/modules/Kconfig.mspm0 index cef1043ed1ad..63ec8cdd0d37 100644 --- a/modules/Kconfig.mspm0 +++ b/modules/Kconfig.mspm0 @@ -18,6 +18,9 @@ config USE_MSPM0_DL_TIMER config USE_MSPM0_DL_MCAN bool +config USE_MSPM0_DL_DAC12 + bool + config USE_MSPM0_DL_VREF bool From 784d74e711a3e7af453354882936c51b74ac9e61 Mon Sep 17 00:00:00 2001 From: Santhosh Charles Date: Wed, 7 Oct 2026 15:01:19 +0530 Subject: [PATCH 03/16] UPSTREAM: dts: arm: ti: mspm0: g: add DAC nodes for TI MSPM0 G-Series commit 3fe4a46a7693539a9f9163856ff6ead9d20e7e7f upstream. Add DAC devicetree nodes for MSPM0 G-Series SoCs that include the DAC peripheral: mspm0g150x, mspm0g350x and mspm0gx51x. Signed-off-by: Santhosh Charles --- dts/arm/ti/mspm0/g/mspm0g150x.dtsi | 7 +++++++ dts/arm/ti/mspm0/g/mspm0g350x.dtsi | 7 +++++++ dts/arm/ti/mspm0/g/mspm0gx51x.dtsi | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/dts/arm/ti/mspm0/g/mspm0g150x.dtsi b/dts/arm/ti/mspm0/g/mspm0g150x.dtsi index c029604a0615..4f8e6ea0b320 100644 --- a/dts/arm/ti/mspm0/g/mspm0g150x.dtsi +++ b/dts/arm/ti/mspm0/g/mspm0g150x.dtsi @@ -8,6 +8,13 @@ / { soc { + dac0: dac@40018000 { + compatible = "ti,mspm0-dac"; + reg = <0x40018000 0x2000>; + status = "disabled"; + #io-channel-cells = <1>; + }; + comp0: comp@40008000 { compatible = "ti,mspm0-comparator"; reg = <0x40008000 0x2000>; diff --git a/dts/arm/ti/mspm0/g/mspm0g350x.dtsi b/dts/arm/ti/mspm0/g/mspm0g350x.dtsi index da514638e93f..d39d812161a7 100644 --- a/dts/arm/ti/mspm0/g/mspm0g350x.dtsi +++ b/dts/arm/ti/mspm0/g/mspm0g350x.dtsi @@ -8,6 +8,13 @@ / { soc { + dac0: dac@40018000 { + compatible = "ti,mspm0-dac"; + reg = <0x40018000 0x2000>; + status = "disabled"; + #io-channel-cells = <1>; + }; + comp0: comp@40008000 { compatible = "ti,mspm0-comparator"; reg = <0x40008000 0x2000>; diff --git a/dts/arm/ti/mspm0/g/mspm0gx51x.dtsi b/dts/arm/ti/mspm0/g/mspm0gx51x.dtsi index bbbde016b354..4435fa344060 100644 --- a/dts/arm/ti/mspm0/g/mspm0gx51x.dtsi +++ b/dts/arm/ti/mspm0/g/mspm0gx51x.dtsi @@ -8,6 +8,13 @@ / { soc { + dac0: dac@40018000 { + compatible = "ti,mspm0-dac"; + reg = <0x40018000 0x2000>; + status = "disabled"; + #io-channel-cells = <1>; + }; + comp0: comp@40008000 { compatible = "ti,mspm0-comparator"; reg = <0x40008000 0x2000>; From 19d26a53b46f96573c813caf5f29df74429c6a61 Mon Sep 17 00:00:00 2001 From: Santhosh Charles Date: Wed, 7 Oct 2026 15:03:10 +0530 Subject: [PATCH 04/16] UPSTREAM: boards: ti: lp_mspm0g3507: enable DAC support commit e70a0ed731e59e63419964a6841019916bebc43b upstream. Enable DAC peripheral and add dac to the list of supported hardware in board YAML. Signed-off-by: Santhosh Charles --- boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts | 4 ++++ boards/ti/lp_mspm0g3507/lp_mspm0g3507.yaml | 1 + 2 files changed, 5 insertions(+) diff --git a/boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts b/boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts index d253d0d4d950..967a833e7ec9 100644 --- a/boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts +++ b/boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts @@ -134,6 +134,10 @@ pinctrl-names = "default"; }; +&dac0 { + status = "okay"; +}; + &vref0 { status = "okay"; pinctrl-0 = <&analog_pa23>; diff --git a/boards/ti/lp_mspm0g3507/lp_mspm0g3507.yaml b/boards/ti/lp_mspm0g3507/lp_mspm0g3507.yaml index e60175a52833..a3c222caf92b 100644 --- a/boards/ti/lp_mspm0g3507/lp_mspm0g3507.yaml +++ b/boards/ti/lp_mspm0g3507/lp_mspm0g3507.yaml @@ -13,6 +13,7 @@ supported: - uart - gpio - can + - dac - vref - dma - trng From 8cbd777b7326abb1f99ceb6c522468eb3a53ef7b Mon Sep 17 00:00:00 2001 From: Santhosh Charles Date: Wed, 7 Oct 2026 15:04:30 +0530 Subject: [PATCH 05/16] UPSTREAM: boards: ti: lp_mspm0g3519: enable DAC support commit f7a4352fb43ff289bfa38ebb600b74e973f2008c upstream. Enable DAC peripheral and add dac to the list of supported hardware in board YAML. Signed-off-by: Santhosh Charles --- boards/ti/lp_mspm0g3519/lp_mspm0g3519.dts | 4 ++++ boards/ti/lp_mspm0g3519/lp_mspm0g3519.yaml | 1 + 2 files changed, 5 insertions(+) diff --git a/boards/ti/lp_mspm0g3519/lp_mspm0g3519.dts b/boards/ti/lp_mspm0g3519/lp_mspm0g3519.dts index 8068b09acfa8..784c5a1dbedb 100644 --- a/boards/ti/lp_mspm0g3519/lp_mspm0g3519.dts +++ b/boards/ti/lp_mspm0g3519/lp_mspm0g3519.dts @@ -124,6 +124,10 @@ pinctrl-names = "default"; }; +&dac0 { + status = "okay"; +}; + &vref0 { status = "okay"; pinctrl-0 = <&analog_pa23>; diff --git a/boards/ti/lp_mspm0g3519/lp_mspm0g3519.yaml b/boards/ti/lp_mspm0g3519/lp_mspm0g3519.yaml index cf8ab53c372f..593074095191 100644 --- a/boards/ti/lp_mspm0g3519/lp_mspm0g3519.yaml +++ b/boards/ti/lp_mspm0g3519/lp_mspm0g3519.yaml @@ -13,6 +13,7 @@ supported: - uart - gpio - can + - dac - vref - dma - trng From 242aa7b03bf1f9735cb68eb63d14010a2565084d Mon Sep 17 00:00:00 2001 From: Santhosh Charles Date: Wed, 7 Oct 2026 15:04:45 +0530 Subject: [PATCH 06/16] UPSTREAM: tests: drivers: dac: dac_api: add support for MSPM0G series commit 52a551e37306ff746d7ea984572391d1af13cbf8 upstream. Add lp_mspm0g3507 and lp_mspm0g3519 to the dac0_channel0 test configuration in testcase.yaml. Signed-off-by: Santhosh Charles --- tests/drivers/dac/dac_api/testcase.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/drivers/dac/dac_api/testcase.yaml b/tests/drivers/dac/dac_api/testcase.yaml index 4e21f19129fb..fcf29ed4bdca 100644 --- a/tests/drivers/dac/dac_api/testcase.yaml +++ b/tests/drivers/dac/dac_api/testcase.yaml @@ -59,6 +59,8 @@ tests: - bl652_dvk - bl653_dvk - bl5340_dvk/nrf5340/cpuapp + - lp_mspm0g3507 + - lp_mspm0g3519 drivers.dac.api.dac1_channel1: extra_args: - EXTRA_DTC_OVERLAY_FILE="dac1-channel1.overlay" From c7a19886ee4417dd35faa761fd558aa56a7cb288 Mon Sep 17 00:00:00 2001 From: Tejas Garg Date: Thu, 8 Oct 2026 14:32:43 +0530 Subject: [PATCH 07/16] UPSTREAM-PEND: drivers: dac: ti: mspm0: fix inverted output enable logic PR: 115925 When the DAC output is configured as internal, the output enable bit was being set instead of cleared, and vice versa for external output. Swap the enable/disable assignments to match the intended behavior. Signed-off-by: Tejas Garg --- drivers/dac/dac_mspm0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dac/dac_mspm0.c b/drivers/dac/dac_mspm0.c index cbdbe61aacfd..e1cf989c64e2 100644 --- a/drivers/dac/dac_mspm0.c +++ b/drivers/dac/dac_mspm0.c @@ -75,9 +75,9 @@ static int dac_mspm0_channel_setup(const struct device *dev, * and the external DAC_OUT pin. HW does not allow separate control. */ if (channel_cfg->internal) { - DL_DAC12_enableOutputPin(regs); - } else { DL_DAC12_disableOutputPin(regs); + } else { + DL_DAC12_enableOutputPin(regs); } DL_DAC12_enable(regs); From 34802e87ce8633013481d2265b878b04271de902 Mon Sep 17 00:00:00 2001 From: Tejas Garg Date: Thu, 8 Oct 2026 14:32:43 +0530 Subject: [PATCH 08/16] UPSTREAM-PEND: driver: dac: ti: mspm0: Convert to native register access PR: 115925 Replace all the Driverlib calls to direct register writes, removing dependency on Driverlib. The DAC12_Regs struct and all register constants are defined locally. Signed-off-by: Tejas Garg --- drivers/dac/Kconfig.mspm0 | 2 +- drivers/dac/dac_mspm0.c | 219 +++++++++++++++++++++++++++++++------- 2 files changed, 181 insertions(+), 40 deletions(-) diff --git a/drivers/dac/Kconfig.mspm0 b/drivers/dac/Kconfig.mspm0 index 15336a39d659..8365a1bceb4f 100644 --- a/drivers/dac/Kconfig.mspm0 +++ b/drivers/dac/Kconfig.mspm0 @@ -1,13 +1,13 @@ # TI MSPM0 DAC Driver Configuration # Copyright (c) 2026 Linumiz +# Copyright (c) 2026 Texas Instruments Incorporated # SPDX-License-Identifier: Apache-2.0 config DAC_MSPM0 bool "TI MSPM0 Digital To Analog Converter (DAC) Driver" default y depends on DT_HAS_TI_MSPM0_DAC_ENABLED - select USE_MSPM0_DL_DAC12 help Enable support for the DAC (Digital-to-Analog Converter) peripheral driver for Texas Instruments MSPM0 G-Series MCUs. diff --git a/drivers/dac/dac_mspm0.c b/drivers/dac/dac_mspm0.c index e1cf989c64e2..3cb9a3db3c78 100644 --- a/drivers/dac/dac_mspm0.c +++ b/drivers/dac/dac_mspm0.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2026 Linumiz + * Copyright (c) 2026 Texas Instruments Incorporated * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,9 +11,134 @@ #include #include #include +#include + +struct dac12_gen_event_regs { + volatile uint32_t iidx; /* !< (@ 0x00001050) Interrupt index */ + uint32_t reserved0; /* !< Reserved*/ + volatile uint32_t imask; /* !< (@ 0x00001058) Interrupt mask */ + uint32_t reserved1; /* !< Reserved*/ + volatile uint32_t ris; /* !< (@ 0x00001060) Raw interrupt status */ + uint32_t reserved2; /* !< Reserved*/ + volatile uint32_t mis; /* !< (@ 0x00001068) Masked interrupt status */ + uint32_t reserved3; /* !< Reserved*/ + volatile uint32_t iset; /* !< (@ 0x00001070) Interrupt set */ + uint32_t reserved4; /* !< Reserved*/ + volatile uint32_t iclr; /* !< (@ 0x00001078) Interrupt clear */ +}; + +struct dac12_cpu_init_regs { + volatile uint32_t iidx; /* !< (@ 0x00001020) Interrupt index */ + uint32_t reserved0; /* !< Reserved*/ + volatile uint32_t imask; /* !< (@ 0x00001028) Interrupt mask */ + uint32_t reserved1; /* !< Reserved*/ + volatile uint32_t ris; /* !< (@ 0x00001030) Raw interrupt status */ + uint32_t reserved2; /* !< Reserved*/ + volatile uint32_t mis; /* !< (@ 0x00001038) Masked interrupt status */ + uint32_t reserved3; /* !< Reserved*/ + volatile uint32_t iset; /* !< (@ 0x00001040) Interrupt set */ + uint32_t reserved4; /* !< Reserved*/ + volatile uint32_t iclr; /* !< (@ 0x00001048) Interrupt clear */ +}; -/* TI Driverlib includes */ -#include +struct dac12_gprcm_regs { + volatile uint32_t pwren; /* !< (@ 0x00000800) Power enable */ + volatile uint32_t rstctl; /* !< (@ 0x00000804) Reset Control */ + uint32_t reserved0[3]; /* !< Reserved*/ + volatile uint32_t stat; /* !< (@ 0x00000814) Status Register */ +}; + +struct dac12_regs { + uint32_t reserved0[256]; + volatile uint32_t fsub_0; /* !< (@ 0x00000400) Subscriber Port 0 */ + uint32_t reserved1[16]; /* !< Reserved*/ + volatile uint32_t fpub_1; /* !< (@ 0x00000444) Publisher port 1 */ + uint32_t reserved2[238]; /* !< Reserved*/ + struct dac12_gprcm_regs gprcm; /* !< (@ 0x00000800) */ + uint32_t reserved3[514]; /* !< Reserved*/ + struct dac12_cpu_init_regs cpu_int; /* !< (@ 0x00001020) */ + uint32_t reserved4; /* !< Reserved*/ + struct dac12_gen_event_regs gen_event; /* !< (@ 0x00001050) */ + uint32_t reserved5[25]; /* !< Reserved*/ + volatile uint32_t evt_mode; /* !< (@ 0x000010E0) Event Mode */ + uint32_t reserved6[6]; /* !< Reserved*/ + volatile uint32_t desc; /* !< (@ 0x000010FC) Module Description */ + volatile uint32_t ctl0; /* !< (@ 0x00001100) Control 0 */ + uint32_t reserved7[3]; /* !< Reserved*/ + volatile uint32_t ctl1; /* !< (@ 0x00001110) Control 1 */ + uint32_t reserved8[3]; /* !< Reserved*/ + volatile uint32_t ctl2; /* !< (@ 0x00001120) Control 2 */ + uint32_t reserved9[3]; /* !< Reserved*/ + volatile uint32_t ctl3; /* !< (@ 0x00001130) Control 3 */ + uint32_t reserved10[3]; /* !< Reserved*/ + volatile uint32_t calctl; /* !< (@ 0x00001140) Calibration control */ + uint32_t reserved11[7]; /* !< Reserved*/ + volatile uint32_t caldata; /* !< (@ 0x00001160) Calibration data */ + uint32_t reserved12[39]; /* !< Reserved*/ + volatile uint32_t data0; /* !< (@ 0x00001200) Data 0 */ +}; + +/* + * Compile-time checks + */ +BUILD_ASSERT(offsetof(struct dac12_regs, gprcm) == 0x0800U); +BUILD_ASSERT(offsetof(struct dac12_regs, cpu_int) == 0x1020U); +BUILD_ASSERT(offsetof(struct dac12_regs, gen_event) == 0x1050U); +BUILD_ASSERT(offsetof(struct dac12_regs, ctl0) == 0x1100U); +BUILD_ASSERT(offsetof(struct dac12_regs, ctl1) == 0x1110U); +BUILD_ASSERT(offsetof(struct dac12_regs, calctl) == 0x1140U); +BUILD_ASSERT(offsetof(struct dac12_regs, data0) == 0x1200U); + +/* + * Bit-field constants + */ + +#ifndef CONFIG_HAS_MSPM0_SDK +/* DAC12_RSTCTL Bits */ +#define DAC12_RSTCTL_RESETSTKYCLR_CLR BIT(1) /* !< Clear reset sticky bit */ +#define DAC12_RSTCTL_RESETASSERT_ASSERT BIT(0) /* !< Assert reset */ +#define DAC12_RSTCTL_KEY_UNLOCK_W 0xB1000000U /* !< KEY to allow write access */ + +/* GPRCM.PWREN — writing the unlock key + enable bit powers the peripheral on */ +#define DAC12_PWREN_KEY_UNLOCK_W 0x26000000U +#define DAC12_PWREN_ENABLE_ENABLE BIT(0) + +/* CTL0 — main DAC enable/disable, resolution, and data format */ +#define DAC12_CTL0_ENABLE_SET BIT(0) /* bit 0: DAC on */ +#define DAC12_CTL0_ENABLE_MASK BIT(0) +#define DAC12_CTL0_RES_MASK BIT(8) /* bit 8: resolution select */ +#define DAC12_CTL0_RES__8BITS FIELD_PREP(DAC12_CTL0_RES_MASK, 0) +#define DAC12_CTL0_RES__12BITS FIELD_PREP(DAC12_CTL0_RES_MASK, 1) +#define DAC12_CTL0_DFM_MASK BIT(16) /* bit 16: data format (binary vs 2s-comp) */ +#define DAC12_CTL0_DFM_BINARY FIELD_PREP(DAC12_CTL0_DFM_MASK, 0) + +/* CTL1 — output amplifier, voltage reference, and output pin routing */ +#define DAC12_CTL1_AMPEN_MASK BIT(0) +#define DAC12_CTL1_AMPEN_ENABLE FIELD_PREP(DAC12_CTL1_AMPEN_MASK, 1) /* bit 0: amp enable */ +#define DAC12_CTL1_AMPHIZ_MASK BIT(1) /* bit 1: amp-off output state */ +#define DAC12_CTL1_AMPHIZ_PULLDOWN \ + FIELD_PREP(DAC12_CTL1_AMPHIZ_MASK, 1) /* pull DAC_OUT to 0 V when amp is off */ +#define DAC12_CTL1_REFSP_MASK BIT(8) /* bit 8: positive reference select */ +#define DAC12_CTL1_REFSP_VDDA FIELD_PREP(DAC12_CTL1_REFSP_MASK, 0) /* use VDDA as VR+ */ +#define DAC12_CTL1_REFSP_VEREFP FIELD_PREP(DAC12_CTL1_REFSP_MASK, 1) /* use VEREFP pin as VR+ */ +#define DAC12_CTL1_REFSN_MASK BIT(9) /* bit 9: negative reference select */ +#define DAC12_CTL1_REFSN_VEREFN FIELD_PREP(DAC12_CTL1_REFSN_MASK, 0) /* use VEREFN pin as VR- */ +#define DAC12_CTL1_REFSN_VSSA FIELD_PREP(DAC12_CTL1_REFSP_MASK, 1) /* use VSSA as VR- */ +#define DAC12_CTL1_OPS_MASK BIT(24) /* bit 24: output pin select */ +#define DAC12_CTL1_OPS_OUT0 FIELD_PREP(DAC12_CTL1_OPS_MASK, 1) /* route output to DAC_OUT pin */ + +/* CALCTL — self-calibration trigger and trim source select */ +#define DAC12_CALCTL_CALON_MASK BIT(0) /* bit 0: calibration state bit */ +#define DAC12_CALCTL_CALON_ACTIVE \ + FIELD_PREP(DAC12_CALCTL_CALON_MASK, 1) /* bit 0: calibration running */ +#define DAC12_CALCTL_CALSEL_SELFCALIBRATIONTRIM BIT(1) /* bit 1: use self-cal trim */ + +/* GEN_EVENT.RIS — raw interrupt status flags */ +#define DAC12_GEN_EVENT_RIS_MODRDYIFG_SET BIT(1) /* bit 1: DAC core is ready */ + +/* DATA0 — the value written here appears on the DAC output */ +#define DAC12_DATA0_DATA_VALUE_MASK GENMASK(11, 0) /* bits [11:0]: 12-bit data field */ +#endif #define DAC_RESOLUTION_8BIT 8 #define DAC_RESOLUTION_12BIT 12 @@ -23,9 +149,15 @@ #define DAC_PRIMARY_CHANNEL_ID 0 #define DAC_READY_TIMEOUT_US 1000 +#define DAC12_VREF_SOURCE_VEREFP_VEREFN (DAC12_CTL1_REFSP_VEREFP | DAC12_CTL1_REFSN_VEREFN) +#define DAC12_VREF_SOURCE_VDDA_VSSA (DAC12_CTL1_REFSP_VDDA | DAC12_CTL1_REFSN_VSSA) + +/* Startup delay in cycles */ +#define POWER_STARTUP_DELAY 16 + struct dac_mspm0_config { DEVICE_MMIO_ROM; - DL_DAC12_VREF_SOURCE dac_vref_src; + uint32_t vref_ctl1_bits; }; struct dac_mspm0_data { @@ -34,9 +166,9 @@ struct dac_mspm0_data { uint8_t resolution; }; -static inline DAC12_Regs *dac_mspm0_regs(const struct device *dev) +static inline struct dac12_regs *dac_mspm0_regs(const struct device *dev) { - return (DAC12_Regs *)DEVICE_MMIO_GET(dev); + return (struct dac12_regs *)DEVICE_MMIO_GET(dev); } static int dac_mspm0_channel_setup(const struct device *dev, @@ -44,7 +176,7 @@ static int dac_mspm0_channel_setup(const struct device *dev, { const struct dac_mspm0_config *config = dev->config; struct dac_mspm0_data *data = dev->data; - DAC12_Regs *regs = dac_mspm0_regs(dev); + struct dac12_regs *regs = dac_mspm0_regs(dev); if (channel_cfg->channel_id != DAC_PRIMARY_CHANNEL_ID) { return -EINVAL; @@ -57,43 +189,49 @@ static int dac_mspm0_channel_setup(const struct device *dev, k_mutex_lock(&data->lock, K_FOREVER); - /* DAC must be disabled before configuration */ - DL_DAC12_disable(regs); + /* disable DAC before reconfiguring */ + regs->ctl0 &= ~DAC12_CTL0_ENABLE_MASK; - DL_DAC12_configDataFormat(regs, DL_DAC12_REPRESENTATION_BINARY, - (channel_cfg->resolution == DAC_RESOLUTION_12BIT) ? - DL_DAC12_RESOLUTION_12BIT : DL_DAC12_RESOLUTION_8BIT); + /* set data format (binary) and resolution in ctl0 */ + uint32_t res_bits = (channel_cfg->resolution == DAC_RESOLUTION_12BIT) + ? DAC12_CTL0_RES__12BITS + : DAC12_CTL0_RES__8BITS; - /* buffered must be true to enable amplifier for output drive */ - DL_DAC12_setAmplifier(regs, - (channel_cfg->buffered) ? DL_DAC12_AMP_ON : DL_DAC12_AMP_OFF_0V); + regs->ctl0 = + (regs->ctl0 & ~(DAC12_CTL0_DFM_MASK | DAC12_CTL0_RES_MASK)) | + ((DAC12_CTL0_DFM_BINARY | res_bits) & (DAC12_CTL0_DFM_MASK | DAC12_CTL0_RES_MASK)); - DL_DAC12_setReferenceVoltageSource(regs, config->dac_vref_src); + /* configure amplifier, voltage reference, and output routing in ctl1 */ + uint32_t amp_bits = + channel_cfg->buffered ? DAC12_CTL1_AMPEN_ENABLE : DAC12_CTL1_AMPHIZ_PULLDOWN; + uint32_t ops_bits = channel_cfg->internal ? 0U : DAC12_CTL1_OPS_OUT0; + uint32_t ctl1_mask = DAC12_CTL1_AMPEN_MASK | DAC12_CTL1_AMPHIZ_MASK | + DAC12_CTL1_REFSP_MASK | DAC12_CTL1_REFSN_MASK | DAC12_CTL1_OPS_MASK; - /* - * CTL1.OPS controls output to both internal modules (OPA, ADC, COMP) - * and the external DAC_OUT pin. HW does not allow separate control. - */ - if (channel_cfg->internal) { - DL_DAC12_disableOutputPin(regs); - } else { - DL_DAC12_enableOutputPin(regs); - } + regs->ctl1 = (regs->ctl1 & ~ctl1_mask) | + ((amp_bits | config->vref_ctl1_bits | ops_bits) & ctl1_mask); - DL_DAC12_enable(regs); + /* re-enable the DAC */ + regs->ctl0 |= DAC12_CTL0_ENABLE_SET; - /* Wait for DAC core and output buffer to settle */ - if (!WAIT_FOR(DL_DAC12_getInterruptStatus(regs, - DL_DAC12_INTERRUPT_MODULE_READY), - DAC_READY_TIMEOUT_US, k_busy_wait(1))) { + /* Wait for the DAC core and amplifier to settle */ + if (!WAIT_FOR(regs->gen_event.ris & DAC12_GEN_EVENT_RIS_MODRDYIFG_SET, DAC_READY_TIMEOUT_US, + k_busy_wait(1))) { k_mutex_unlock(&data->lock); return -ETIMEDOUT; } data->resolution = channel_cfg->resolution; + /* self-calibrate offset error if amplifier is active */ if (channel_cfg->buffered) { - DL_DAC12_performSelfCalibrationBlocking(regs); + regs->calctl = DAC12_CALCTL_CALON_ACTIVE | DAC12_CALCTL_CALSEL_SELFCALIBRATIONTRIM; + if (!WAIT_FOR((!(regs->calctl & DAC12_CALCTL_CALON_MASK)) & + DAC12_CALCTL_CALON_ACTIVE, + DAC_READY_TIMEOUT_US, k_busy_wait(1))) { + k_mutex_unlock(&data->lock); + return -ETIMEDOUT; + } } k_mutex_unlock(&data->lock); @@ -104,7 +242,7 @@ static int dac_mspm0_channel_setup(const struct device *dev, static int dac_mspm0_write_value(const struct device *dev, uint8_t channel, uint32_t value) { struct dac_mspm0_data *data = dev->data; - DAC12_Regs *regs = dac_mspm0_regs(dev); + struct dac12_regs *regs = dac_mspm0_regs(dev); int ret = 0; k_mutex_lock(&data->lock, K_FOREVER); @@ -120,14 +258,13 @@ static int dac_mspm0_write_value(const struct device *dev, uint8_t channel, uint ret = -EINVAL; goto unlock; } - DL_DAC12_output12(regs, value); - + regs->data0 = value & DAC12_DATA0_DATA_VALUE_MASK; } else { if (value > DAC8_MAX_VALUE) { ret = -EINVAL; goto unlock; } - DL_DAC12_output8(regs, (uint8_t)value); + regs->data0 = (uint8_t)value; } unlock: @@ -139,8 +276,12 @@ static int dac_mspm0_init(const struct device *dev) { DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); - DL_DAC12_enablePower(dac_mspm0_regs(dev)); - delay_cycles(CONFIG_MSPM0_PERIPH_STARTUP_DELAY); + struct dac12_regs *regs = dac_mspm0_regs(dev); + + regs->gprcm.rstctl = DAC12_RSTCTL_KEY_UNLOCK_W | DAC12_RSTCTL_RESETSTKYCLR_CLR | + DAC12_RSTCTL_RESETASSERT_ASSERT; + + regs->gprcm.pwren = DAC12_PWREN_KEY_UNLOCK_W | DAC12_PWREN_ENABLE_ENABLE; return 0; } @@ -154,9 +295,9 @@ static DEVICE_API(dac, dac_mspm0_driver_api) = { \ static const struct dac_mspm0_config dac_mspm0_config_##id = { \ DEVICE_MMIO_ROM_INIT(DT_DRV_INST(id)), \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(id, vref), \ - (.dac_vref_src = DL_DAC12_VREF_SOURCE_VEREFP_VEREFN), \ - (.dac_vref_src = DL_DAC12_VREF_SOURCE_VDDA_VSSA)), \ + .vref_ctl1_bits = COND_CODE_1(DT_INST_NODE_HAS_PROP(id, vref), \ + DAC12_VREF_SOURCE_VEREFP_VEREFN, \ + DAC12_VREF_SOURCE_VDDA_VSSA), \ }; \ \ static struct dac_mspm0_data dac_mspm0_data_##id = { \ From 99e8b272029f6887c8fd32deedbf240c5fa3607b Mon Sep 17 00:00:00 2001 From: Tejas Garg Date: Thu, 8 Oct 2026 14:32:43 +0530 Subject: [PATCH 09/16] UPSTREAM-PEND: boards: ti: Add boards level changes for dac and adc perp... PR: 115925 Adding board dts and yaml changes for DAC and ADC to enable DAC samples and tests Signed-off-by: Tejas Garg --- boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts | 6 ++++++ boards/ti/lp_mspm0g3519/lp_mspm0g3519.dts | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts b/boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts index 967a833e7ec9..5269be3214ae 100644 --- a/boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts +++ b/boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts @@ -48,6 +48,12 @@ pwms = <&pwma0 0 PWM_MSEC(100) PWM_POLARITY_NORMAL>; }; }; + + zephyr,user { + dac = <&dac0>; + dac-channel-id = <0>; + dac-resolution = <12>; + }; }; &cpu0 { diff --git a/boards/ti/lp_mspm0g3519/lp_mspm0g3519.dts b/boards/ti/lp_mspm0g3519/lp_mspm0g3519.dts index 784c5a1dbedb..b48384795591 100644 --- a/boards/ti/lp_mspm0g3519/lp_mspm0g3519.dts +++ b/boards/ti/lp_mspm0g3519/lp_mspm0g3519.dts @@ -63,6 +63,12 @@ zephyr,code = ; }; }; + + zephyr,user { + dac = <&dac0>; + dac-channel-id = <0>; + dac-resolution = <12>; + }; }; &cpu0 { From 02ac92e32fee95a7cddb93d6a167fa11d5e50d08 Mon Sep 17 00:00:00 2001 From: Tejas Garg Date: Thu, 8 Oct 2026 14:32:43 +0530 Subject: [PATCH 10/16] UPSTREAM-PEND: tests: drivers: dac: Add test scenario for mspm0g3507/351... PR: 115925 The following commit adds the required test scenario as well as corresponding overlay file, which maps io channels (dac0, channel0) and (adc0, channel4) to what the test expects (dac1) and (adc1) under the zephyr,user node. The scenario overlay files are created such that they serve as common overlay for multiple SOCs. Signed-off-by: Tejas Garg --- .../dac_api/dac0-channel0-buffered.overlay | 23 ++++++++++ tests/drivers/dac/dac_api/testcase.yaml | 4 ++ tests/drivers/dac/dac_loopback/testcase.yaml | 6 +++ .../ti-dac0-channel0-adc0-channel4.overlay | 45 +++++++++++++++++++ 4 files changed, 78 insertions(+) create mode 100644 tests/drivers/dac/dac_api/dac0-channel0-buffered.overlay create mode 100644 tests/drivers/dac/dac_loopback/ti-dac0-channel0-adc0-channel4.overlay diff --git a/tests/drivers/dac/dac_api/dac0-channel0-buffered.overlay b/tests/drivers/dac/dac_api/dac0-channel0-buffered.overlay new file mode 100644 index 000000000000..3d18827df636 --- /dev/null +++ b/tests/drivers/dac/dac_api/dac0-channel0-buffered.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2026 Texas Instruments Incorporated + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + zephyr,user { + io-channels = <&dac0 0>; + io-channel-names = "dac1"; + }; +}; + +&dac0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,resolution = <12>; + zephyr,buffered; + }; +}; diff --git a/tests/drivers/dac/dac_api/testcase.yaml b/tests/drivers/dac/dac_api/testcase.yaml index fcf29ed4bdca..f21ccc7163ee 100644 --- a/tests/drivers/dac/dac_api/testcase.yaml +++ b/tests/drivers/dac/dac_api/testcase.yaml @@ -59,6 +59,10 @@ tests: - bl652_dvk - bl653_dvk - bl5340_dvk/nrf5340/cpuapp + drivers.dac.api.dac0_channel0_buffered: + extra_args: + - EXTRA_DTC_OVERLAY_FILE="dac0-channel0-buffered.overlay" + platform_allow: - lp_mspm0g3507 - lp_mspm0g3519 drivers.dac.api.dac1_channel1: diff --git a/tests/drivers/dac/dac_loopback/testcase.yaml b/tests/drivers/dac/dac_loopback/testcase.yaml index 64113bc73cf7..182b0f091dbe 100644 --- a/tests/drivers/dac/dac_loopback/testcase.yaml +++ b/tests/drivers/dac/dac_loopback/testcase.yaml @@ -39,6 +39,12 @@ tests: - frdm_k22f - frdm_k64f - twr_ke18f + drivers.dac.loopback.ti_dac0_chan0_adc0_chan4: + extra_args: + - EXTRA_DTC_OVERLAY_FILE="ti-dac0-channel0-adc0-channel4.overlay" + platform_allow: + - lp_mspm0g3507 + - lp_mspm0g3519 drivers.dac.loopback.blxxx_dvk: extra_args: - EXTRA_DTC_OVERLAY_FILE="blxxx_dvk.overlay" diff --git a/tests/drivers/dac/dac_loopback/ti-dac0-channel0-adc0-channel4.overlay b/tests/drivers/dac/dac_loopback/ti-dac0-channel0-adc0-channel4.overlay new file mode 100644 index 000000000000..fc7838f00369 --- /dev/null +++ b/tests/drivers/dac/dac_loopback/ti-dac0-channel0-adc0-channel4.overlay @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2026 Texas Instruments Incorporated + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + zephyr,user { + io-channels = <&dac0 0 &adc0 4>; + io-channel-names = "dac1", "adc1"; + }; +}; + +&dac0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,resolution = <12>; + zephyr,buffered; + }; +}; + +&adc0 { + clocks = <&ckm MSPM0_CLOCK_ULPCLK>; + ti,clk-divider = <1>; + ti,clk-range = <6>; + max-result-reg = <12>; + pinctrl-0 = <&analog_pb25>; + pinctrl-names = "default"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + channel@4 { + reg = <4>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_VDD_1"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; From b74bb234286740e155553719df31724fcd2cfa3f Mon Sep 17 00:00:00 2001 From: Tejas Garg Date: Thu, 8 Oct 2026 14:33:44 +0530 Subject: [PATCH 11/16] TI: tests: drivers: dac: Add adc changes to allign with adc changes The following commit modifies the tests overlay which configures the ADC dts node which lines up with adc changes Signed-off-by: Tejas Garg --- Reason: Currently in the upstream the ADC PR is not merged, requiring to keep the old dts structure in the dac-loopback to keep the test operational Once the following PR is merged these changes can be integrated with the dac_loopback test as well: PR 117293 --- .../dac_loopback/ti-dac0-channel0-adc0-channel4.overlay | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/drivers/dac/dac_loopback/ti-dac0-channel0-adc0-channel4.overlay b/tests/drivers/dac/dac_loopback/ti-dac0-channel0-adc0-channel4.overlay index fc7838f00369..174eb5fe3efd 100644 --- a/tests/drivers/dac/dac_loopback/ti-dac0-channel0-adc0-channel4.overlay +++ b/tests/drivers/dac/dac_loopback/ti-dac0-channel0-adc0-channel4.overlay @@ -25,10 +25,6 @@ }; &adc0 { - clocks = <&ckm MSPM0_CLOCK_ULPCLK>; - ti,clk-divider = <1>; - ti,clk-range = <6>; - max-result-reg = <12>; pinctrl-0 = <&analog_pb25>; pinctrl-names = "default"; status = "okay"; @@ -39,7 +35,8 @@ reg = <4>; zephyr,gain = "ADC_GAIN_1"; zephyr,reference = "ADC_REF_VDD_1"; - zephyr,acquisition-time = ; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; zephyr,resolution = <12>; }; }; From 2e0b2421259a137c28cb7b4eae88d014f8c09a16 Mon Sep 17 00:00:00 2001 From: Tejas Garg Date: Thu, 8 Oct 2026 14:35:03 +0530 Subject: [PATCH 12/16] UPSTREAM-PEND: dts: bindings: dac: Add dts binding for fifo functionality PR: 120826 The following commit adds dts bindings required for enabling fifo functionality for dac peripheral for mspm0 SOCs Signed-off-by: Tejas Garg --- dts/bindings/dac/ti,mspm0-dac.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dts/bindings/dac/ti,mspm0-dac.yaml b/dts/bindings/dac/ti,mspm0-dac.yaml index 443285207946..475fc0ab7f71 100644 --- a/dts/bindings/dac/ti,mspm0-dac.yaml +++ b/dts/bindings/dac/ti,mspm0-dac.yaml @@ -14,6 +14,20 @@ properties: vref: type: phandle + fifo-enable: + type: boolean + description: | + Enable the 4-slot hardware FIFO. When set, the sample time generator + clocks samples out of the FIFO at sample-rate-hz, decoupling DAC output + timing from CPU write timing. + + sample-rate-hz: + type: int + enum: [500, 1000, 2000, 4000, 8000, 16000, 100000, 200000, 500000, 1000000] + description: | + DAC output sample rate in Hz. Maps directly to the sample time generator + STIMCONFIG preset. Requires fifo-enable. + "#io-channel-cells": const: 1 From 0c96a3f5a9f3b44ca26470d0c562fd5d809b2bc5 Mon Sep 17 00:00:00 2001 From: Tejas Garg Date: Thu, 8 Oct 2026 14:35:03 +0530 Subject: [PATCH 13/16] UPSTREAM-PEND: dts: arm: ti: Adding interrupt property for dac peripheral PR: 120826 The following commit adds the interrupt dts node property, used by the dac driver Signed-off-by: Tejas Garg --- dts/arm/ti/mspm0/g/mspm0g350x.dtsi | 1 + dts/arm/ti/mspm0/g/mspm0gx51x.dtsi | 1 + 2 files changed, 2 insertions(+) diff --git a/dts/arm/ti/mspm0/g/mspm0g350x.dtsi b/dts/arm/ti/mspm0/g/mspm0g350x.dtsi index d39d812161a7..6b57dd0205c1 100644 --- a/dts/arm/ti/mspm0/g/mspm0g350x.dtsi +++ b/dts/arm/ti/mspm0/g/mspm0g350x.dtsi @@ -11,6 +11,7 @@ dac0: dac@40018000 { compatible = "ti,mspm0-dac"; reg = <0x40018000 0x2000>; + interrupts = <7 0>; status = "disabled"; #io-channel-cells = <1>; }; diff --git a/dts/arm/ti/mspm0/g/mspm0gx51x.dtsi b/dts/arm/ti/mspm0/g/mspm0gx51x.dtsi index 4435fa344060..df8ed8d218da 100644 --- a/dts/arm/ti/mspm0/g/mspm0gx51x.dtsi +++ b/dts/arm/ti/mspm0/g/mspm0gx51x.dtsi @@ -11,6 +11,7 @@ dac0: dac@40018000 { compatible = "ti,mspm0-dac"; reg = <0x40018000 0x2000>; + interrupts = <7 0>; status = "disabled"; #io-channel-cells = <1>; }; From be08247af89fed6513ff0e6deee34d8f348f9638 Mon Sep 17 00:00:00 2001 From: Tejas Garg Date: Thu, 8 Oct 2026 14:35:03 +0530 Subject: [PATCH 14/16] UPSTREAM-PEND: drivers: dac: Update dac driver to add fifo functionality PR: 120826 The following commit updates the mspm0 dac driver to add fifo functionality to the driver Signed-off-by: Tejas Garg --- drivers/dac/dac_mspm0.c | 134 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 1 deletion(-) diff --git a/drivers/dac/dac_mspm0.c b/drivers/dac/dac_mspm0.c index 3cb9a3db3c78..1d6f06698e82 100644 --- a/drivers/dac/dac_mspm0.c +++ b/drivers/dac/dac_mspm0.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -127,6 +128,33 @@ BUILD_ASSERT(offsetof(struct dac12_regs, data0) == 0x1200U); #define DAC12_CTL1_OPS_MASK BIT(24) /* bit 24: output pin select */ #define DAC12_CTL1_OPS_OUT0 FIELD_PREP(DAC12_CTL1_OPS_MASK, 1) /* route output to DAC_OUT pin */ +/* CTL2 — FIFO control */ +#define DAC12_CTL2_FIFOEN_SET BIT(0) /* FIFO enabled */ +#define DAC12_CTL2_FIFOTRIGSEL_STIM 0x0 /* sample time generator trigger */ + +/* CTL3 — sample time generator */ +#define DAC12_CTL3_STIMEN_SET BIT(0) /* sample time generator enabled */ +#define DAC12_CTL3_STIMCONFIG__500SPS 0x0 +#define DAC12_CTL3_STIMCONFIG__1KSPS BIT(8) +#define DAC12_CTL3_STIMCONFIG__2KSPS BIT(9) +#define DAC12_CTL3_STIMCONFIG__4KSPS 0x300 +#define DAC12_CTL3_STIMCONFIG__8KSPS BIT(10) +#define DAC12_CTL3_STIMCONFIG__16KSPS 0x500 +#define DAC12_CTL3_STIMCONFIG__100KSPS 0x600 +#define DAC12_CTL3_STIMCONFIG__200KSPS 0x700 +#define DAC12_CTL3_STIMCONFIG__500KSPS BIT(11) +#define DAC12_CTL3_STIMCONFIG__1MSPS 0x900 + +/* CPU_INT — FIFO interrupt mask and clear */ +; +#define DAC12_CPU_INT_IMASK_FIFOEMPTYIFG_SET BIT(12) +#define DAC12_CPU_INT_MIS_FIFOEMPTYIFG_SET BIT(12) +#define DAC12_CPU_INT_ICLR_FIFOEMPTYIFG_CLR BIT(12) +#define DAC12_CPU_INT_IMASK_FIFOFULLIFG_SET BIT(8) +#define DAC12_CPU_INT_MIS_FIFOFULLIFG_SET BIT(8) +#define DAC12_CPU_INT_ICLR_FIFOFULLIFG_CLR BIT(8) +#define DAC12_CPU_INT_RIS_FIFOFULLIFG_MASK BIT(8) + /* CALCTL — self-calibration trigger and trim source select */ #define DAC12_CALCTL_CALON_MASK BIT(0) /* bit 0: calibration state bit */ #define DAC12_CALCTL_CALON_ACTIVE \ @@ -149,6 +177,8 @@ BUILD_ASSERT(offsetof(struct dac12_regs, data0) == 0x1200U); #define DAC_PRIMARY_CHANNEL_ID 0 #define DAC_READY_TIMEOUT_US 1000 +#define DAC_FIFO_DEPTH 4 + #define DAC12_VREF_SOURCE_VEREFP_VEREFN (DAC12_CTL1_REFSP_VEREFP | DAC12_CTL1_REFSN_VEREFN) #define DAC12_VREF_SOURCE_VDDA_VSSA (DAC12_CTL1_REFSP_VDDA | DAC12_CTL1_REFSN_VSSA) @@ -158,11 +188,14 @@ BUILD_ASSERT(offsetof(struct dac12_regs, data0) == 0x1200U); struct dac_mspm0_config { DEVICE_MMIO_ROM; uint32_t vref_ctl1_bits; + bool fifo_enabled; + uint32_t sample_rate_hz; }; struct dac_mspm0_data { DEVICE_MMIO_RAM; struct k_mutex lock; + struct k_sem fifo_sem; /* flow-control gate */ uint8_t resolution; }; @@ -171,6 +204,19 @@ static inline struct dac12_regs *dac_mspm0_regs(const struct device *dev) return (struct dac12_regs *)DEVICE_MMIO_GET(dev); } +static void dac_mspm0_isr(const struct device *dev) +{ + struct dac_mspm0_data *data = dev->data; + struct dac12_regs *regs = dac_mspm0_regs(dev); + uint32_t mis = regs->cpu_int.mis; + + if (mis & DAC12_CPU_INT_MIS_FIFOEMPTYIFG_SET) { + regs->cpu_int.imask &= ~(DAC12_CPU_INT_IMASK_FIFOEMPTYIFG_SET); + /* Release the gate — unblocks the thread waiting in write_value */ + k_sem_give(&data->fifo_sem); + } +} + static int dac_mspm0_channel_setup(const struct device *dev, const struct dac_channel_cfg *channel_cfg) { @@ -234,6 +280,61 @@ static int dac_mspm0_channel_setup(const struct device *dev, } } + if (config->fifo_enabled) { + uint32_t stimconfig; + + switch (config->sample_rate_hz) { + case 500: + stimconfig = DAC12_CTL3_STIMCONFIG__500SPS; + break; + case 1000: + stimconfig = DAC12_CTL3_STIMCONFIG__1KSPS; + break; + case 2000: + stimconfig = DAC12_CTL3_STIMCONFIG__2KSPS; + break; + case 4000: + stimconfig = DAC12_CTL3_STIMCONFIG__4KSPS; + break; + case 8000: + stimconfig = DAC12_CTL3_STIMCONFIG__8KSPS; + break; + case 16000: + stimconfig = DAC12_CTL3_STIMCONFIG__16KSPS; + break; + case 100000: + stimconfig = DAC12_CTL3_STIMCONFIG__100KSPS; + break; + case 200000: + stimconfig = DAC12_CTL3_STIMCONFIG__200KSPS; + break; + case 500000: + stimconfig = DAC12_CTL3_STIMCONFIG__500KSPS; + break; + case 1000000: + stimconfig = DAC12_CTL3_STIMCONFIG__1MSPS; + break; + default: + k_mutex_unlock(&data->lock); + return -EINVAL; + } + + /* enable sample time generator with selected rate */ + regs->ctl3 = DAC12_CTL3_STIMEN_SET | stimconfig; + + /* enable FIFO and select sample time generator trigger. + * FIFOTH is don't care in CPU mode; FIFO level is reported + * directly through the RIS interrupt flags. + */ + regs->ctl2 = DAC12_CTL2_FIFOEN_SET | DAC12_CTL2_FIFOTRIGSEL_STIM; + + regs->cpu_int.iclr = + DAC12_CPU_INT_ICLR_FIFOEMPTYIFG_CLR | DAC12_CPU_INT_ICLR_FIFOFULLIFG_CLR; + + /* Binary semaphore: count=0, limit=1 */ + k_sem_init(&data->fifo_sem, 0, 1); + } + k_mutex_unlock(&data->lock); return 0; @@ -241,10 +342,26 @@ static int dac_mspm0_channel_setup(const struct device *dev, static int dac_mspm0_write_value(const struct device *dev, uint8_t channel, uint32_t value) { + const struct dac_mspm0_config *config = dev->config; struct dac_mspm0_data *data = dev->data; struct dac12_regs *regs = dac_mspm0_regs(dev); int ret = 0; + /* + * Block here (without holding the mutex) if the FIFO-full ISR has + * closed the gate. The empty ISR will give the semaphore back, + * waking this thread when there is space to write again. + */ + if (config->fifo_enabled) { + if (regs->cpu_int.ris & DAC12_CPU_INT_RIS_FIFOFULLIFG_MASK) { + k_sem_reset(&data->fifo_sem); + regs->cpu_int.iclr |= DAC12_CPU_INT_ICLR_FIFOEMPTYIFG_CLR; + regs->cpu_int.imask |= DAC12_CPU_INT_IMASK_FIFOEMPTYIFG_SET; + k_sem_take(&data->fifo_sem, K_FOREVER); + regs->cpu_int.iclr |= DAC12_CPU_INT_ICLR_FIFOFULLIFG_CLR; + } + } + k_mutex_lock(&data->lock, K_FOREVER); /* Validate channel and resolution */ @@ -291,6 +408,11 @@ static DEVICE_API(dac, dac_mspm0_driver_api) = { .write_value = dac_mspm0_write_value }; +#define DAC_MSPM0_IRQ_INIT(id) \ + IRQ_CONNECT(DT_INST_IRQN(id), DT_INST_IRQ(id, priority), dac_mspm0_isr, \ + DEVICE_DT_INST_GET(id), 0); \ + irq_enable(DT_INST_IRQN(id)); + #define DAC_MSPM0_DEFINE(id) \ \ static const struct dac_mspm0_config dac_mspm0_config_##id = { \ @@ -298,13 +420,23 @@ static DEVICE_API(dac, dac_mspm0_driver_api) = { .vref_ctl1_bits = COND_CODE_1(DT_INST_NODE_HAS_PROP(id, vref), \ DAC12_VREF_SOURCE_VEREFP_VEREFN, \ DAC12_VREF_SOURCE_VDDA_VSSA), \ + .fifo_enabled = DT_INST_PROP(id, fifo_enable), \ + .sample_rate_hz = DT_INST_PROP_OR(id, sample_rate_hz, 0), \ }; \ \ static struct dac_mspm0_data dac_mspm0_data_##id = { \ .lock = Z_MUTEX_INITIALIZER(dac_mspm0_data_##id.lock), \ }; \ \ - DEVICE_DT_INST_DEFINE(id, &dac_mspm0_init, NULL, &dac_mspm0_data_##id, \ + static int dac_mspm0_init_##id(const struct device *dev) \ + { \ + dac_mspm0_init(dev); \ + IF_ENABLED(DT_INST_PROP(id, fifo_enable), \ + (DAC_MSPM0_IRQ_INIT(id))); \ + return 0; \ + } \ + \ + DEVICE_DT_INST_DEFINE(id, &dac_mspm0_init_##id, NULL, &dac_mspm0_data_##id, \ &dac_mspm0_config_##id, POST_KERNEL, CONFIG_DAC_INIT_PRIORITY, \ &dac_mspm0_driver_api); From 62e5531676ec460197bb078dd66527da1e2b9884 Mon Sep 17 00:00:00 2001 From: Tejas Garg Date: Thu, 8 Oct 2026 14:35:03 +0530 Subject: [PATCH 15/16] UPSTREAM-PEND: boards: ti: add board dts changes to enable fifo function... PR: 120826 The following commit adds board dts changes to enable fifo functionality on board level Signed-off-by: Tejas Garg --- boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts | 6 ++++++ boards/ti/lp_mspm0g3519/lp_mspm0g3519.dts | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts b/boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts index 5269be3214ae..52c0b0a7f6f7 100644 --- a/boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts +++ b/boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts @@ -74,6 +74,10 @@ status = "okay"; }; +&mfpclk { + status = "okay"; +}; + &canclk { clocks = <&syspll>; status = "okay"; @@ -142,6 +146,8 @@ &dac0 { status = "okay"; + fifo-enable; + sample-rate-hz = <1000>; }; &vref0 { diff --git a/boards/ti/lp_mspm0g3519/lp_mspm0g3519.dts b/boards/ti/lp_mspm0g3519/lp_mspm0g3519.dts index b48384795591..48e4cf2c890f 100644 --- a/boards/ti/lp_mspm0g3519/lp_mspm0g3519.dts +++ b/boards/ti/lp_mspm0g3519/lp_mspm0g3519.dts @@ -89,6 +89,10 @@ status = "okay"; }; +&mfpclk { + status = "okay"; +}; + &canclk { clocks = <&syspll>; status = "okay"; @@ -132,6 +136,8 @@ &dac0 { status = "okay"; + fifo-enable; + sample-rate-hz = <1000>; }; &vref0 { From 0eaa5e01151996ee5895bd0b17f8af4c4b0a6293 Mon Sep 17 00:00:00 2001 From: Tejas Garg Date: Thu, 8 Oct 2026 14:35:04 +0530 Subject: [PATCH 16/16] UPSTREAM-PEND: samples: drivers: dac: Modifying sample to add custom sle... PR: 120826 Currently the sample is restricted to sleep time dependent on dac resolution. Adding custom configuration option for sleep time, where the sleep time can be set via board conf file, while retaining the default behaviour if no custom configuration is given. Signed-off-by: Tejas Garg --- samples/drivers/dac/Kconfig | 9 ++++++++ samples/drivers/dac/boards/lp_mspm0g3507.conf | 1 + samples/drivers/dac/boards/lp_mspm0g3519.conf | 1 + samples/drivers/dac/src/main.c | 23 +++++++++++-------- 4 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 samples/drivers/dac/boards/lp_mspm0g3507.conf create mode 100644 samples/drivers/dac/boards/lp_mspm0g3519.conf diff --git a/samples/drivers/dac/Kconfig b/samples/drivers/dac/Kconfig index ce025e047cf4..1f81e1763c89 100644 --- a/samples/drivers/dac/Kconfig +++ b/samples/drivers/dac/Kconfig @@ -20,3 +20,12 @@ config DAC_BUFFER_NOT_SUPPORT bool "DAC on board/SoC does not support output buffer mode" help If this config is turned on, the sample will run with no output buffer enabled + +config DAC_SAMPLE_SLEEP_MS + int "Sleep between DAC writes in ms (-1 = auto from resolution, 0 = disabled)" + default -1 + help + Delay inserted between successive dac_write_value() calls. + -1: use the original computed value (4096 / dac_values, min 1 ms). + 0: disable sleep entirely (e.g. when FIFO flow control handles pacing). + >0: fixed delay in milliseconds. diff --git a/samples/drivers/dac/boards/lp_mspm0g3507.conf b/samples/drivers/dac/boards/lp_mspm0g3507.conf new file mode 100644 index 000000000000..08474070b7aa --- /dev/null +++ b/samples/drivers/dac/boards/lp_mspm0g3507.conf @@ -0,0 +1 @@ +CONFIG_DAC_SAMPLE_SLEEP_MS=0 diff --git a/samples/drivers/dac/boards/lp_mspm0g3519.conf b/samples/drivers/dac/boards/lp_mspm0g3519.conf new file mode 100644 index 000000000000..08474070b7aa --- /dev/null +++ b/samples/drivers/dac/boards/lp_mspm0g3519.conf @@ -0,0 +1 @@ +CONFIG_DAC_SAMPLE_SLEEP_MS=0 diff --git a/samples/drivers/dac/src/main.c b/samples/drivers/dac/src/main.c index 71657a193418..6be78448b76d 100644 --- a/samples/drivers/dac/src/main.c +++ b/samples/drivers/dac/src/main.c @@ -55,23 +55,26 @@ int main(void) /* Number of valid DAC values, e.g. 4096 for 12-bit DAC */ const int dac_values = 1U << DAC_RESOLUTION; - /* - * 1 msec sleep leads to about 4 sec signal period for 12-bit - * DACs. For DACs with lower resolution, sleep time needs to - * be increased. - * Make sure to sleep at least 1 msec even for future 16-bit - * DACs (lowering signal frequency). - */ - const int sleep_time = 4096 / dac_values > 0 ? - 4096 / dac_values : 1; - for (int i = 0; i < dac_values; i++) { ret = dac_write_value(dac_dev, DAC_CHANNEL_ID, i); if (ret != 0) { printk("dac_write_value() failed with code %d\n", ret); return 0; } +#if CONFIG_DAC_SAMPLE_SLEEP_MS == -1 + /* + * 1 msec sleep leads to about 4 sec signal period for 12-bit + * DACs. For DACs with lower resolution, sleep time needs to + * be increased. + * Make sure to sleep at least 1 msec even for future 16-bit + * DACs (lowering signal frequency). + */ + const int sleep_time = 4096 / dac_values > 0 ? + 4096 / dac_values : 1; k_sleep(K_MSEC(sleep_time)); +#elif CONFIG_DAC_SAMPLE_SLEEP_MS > 0 + k_sleep(K_MSEC(CONFIG_DAC_SAMPLE_SLEEP_MS)); +#endif } } return 0;