diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index c77180172d2d1..be325242ddbd6 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -4302,6 +4302,20 @@ ITE Platforms: labels: - "platform: ITE" +TI MSPM0 Platforms: + status: maintained + maintainers: + - ssekar15 + files: + - soc/ti/mspm0/ + - boards/ti/lp_mspm0g3507/ + - dts/arm/ti/mspm0/ + - dts/bindings/*/*mspm0* + - drivers/*/*_mspm0* + - modules/Kconfig.mspm0 + labels: + - "platform: Texas Instruments MSPM0" + TI SimpleLink Platforms: status: maintained maintainers: diff --git a/boards/ti/lp_mspm0g3507/Kconfig.lp_mspm0g3507 b/boards/ti/lp_mspm0g3507/Kconfig.lp_mspm0g3507 new file mode 100644 index 0000000000000..1875699447165 --- /dev/null +++ b/boards/ti/lp_mspm0g3507/Kconfig.lp_mspm0g3507 @@ -0,0 +1,5 @@ +# Copyright (c) 2025 Texas Instruments +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_LP_MSPM0G3507 + select SOC_MSPM0G3507 diff --git a/boards/ti/lp_mspm0g3507/board.cmake b/boards/ti/lp_mspm0g3507/board.cmake new file mode 100644 index 0000000000000..2b2b64ba4f74b --- /dev/null +++ b/boards/ti/lp_mspm0g3507/board.cmake @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=MSPM0G3507" "--speed=4000") +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/ti/lp_mspm0g3507/board.yml b/boards/ti/lp_mspm0g3507/board.yml new file mode 100644 index 0000000000000..f2763be9b23e7 --- /dev/null +++ b/boards/ti/lp_mspm0g3507/board.yml @@ -0,0 +1,6 @@ +board: + name: lp_mspm0g3507 + full_name: MSPM0G3507 Launchpad + vendor: ti + socs: + - name: mspm0g3507 diff --git a/boards/ti/lp_mspm0g3507/doc/img/lp_mspm0g3507.webp b/boards/ti/lp_mspm0g3507/doc/img/lp_mspm0g3507.webp new file mode 100644 index 0000000000000..dba82b8bb9112 Binary files /dev/null and b/boards/ti/lp_mspm0g3507/doc/img/lp_mspm0g3507.webp differ diff --git a/boards/ti/lp_mspm0g3507/doc/index.rst b/boards/ti/lp_mspm0g3507/doc/index.rst new file mode 100644 index 0000000000000..db58807f21bf9 --- /dev/null +++ b/boards/ti/lp_mspm0g3507/doc/index.rst @@ -0,0 +1,160 @@ +.. zephyr:board:: lp_mspm0g3507 + +Overview +******** + +MSPM0G350x microcontrollers (MCUs) are part of the MSP highly integrated, ultra-low-power 32-bit MCU +family based on the enhanced Arm® Cortex®-M0+ 32-bit core platform operating at up to 80-MHz frequency. +These cost-optimized MCUs offer high-performance analog peripheral integration, support extended temperature +ranges from -40°C to 125°C, and operate with supply voltages ranging from 1.62 V to 3.6 V. + +The MSPM0G350x devices provide up to 128KB embedded flash program memory with built-in error correction +code (ECC) and up to 32KB SRAM with a hardware parity option. These MCUs also incorporate a +memory protection unit, 7-channel DMA, math accelerator, and a variety of peripherals including + +* Analog. + + * Two 12-bit 4-Msps ADCs. + + * Configurable internal shared voltage reference. + + * One 12-bit 1-Msps DAC. + + * Three high speed comparators with built-in reference DACs. + + * Two zero-drift zero-crossover op-amps with programmable gain. + +* Digital. + + * Two 16-bit advanced control timers. + + * Five general-purpose timers. + + * One 16-bit general-purpose timer for QEI interface. + + * One 32-bit high resolution general-purpose timer. + + * Two 16-bit timers with deadband support and up to 12 PWM Channels. + + * Two windowed-watchdog timers. + + * One RTC with alarm and calendar modes. + +* Data Integrity and Encryption. + + * One AES HW accelerator capable of CTR, CBC, and ECB modes. + + * One Cyclic Redundancy Check (CRC) accelerator. + + * One True Random Number Generator (TRNG). + +* Communication. + + * Four UARTs, one with support for advanced modes such as LIN and Manchester. + + * Two I2C supporting SMBUS/PMBUS and speeds up to FM+ (1Mbits/s). + + * Two SPI, one with max speed 32Mbits/s. + + * One CAN interface supporting CAN 2.0 A or B and CAN-FD. + +.. image:: img/lp_mspm0g3507.webp + :align: center + :alt: MSPM0G3507 LaunchPad development board + +Zephyr uses the ``lp_mspm0g3507`` board for building LP_MSPM0G3507 + +Features: +********* + +- Onboard XDS110 debug probe +- EnergyTrace technology available for ultra-low-power debugging +- 2 buttons, 1 LED and 1 RGB LED for user interaction +- Temperature sensor circuit +- Light sensor circuit +- External OPA2365 (default buffer mode) for ADC (up to 4 Msps) evaluation +- Onboard 32.768-kHz and 40-MHz crystals +- RC filter for ADC input (unpopulated by default) + +Details on the MSPM0G3507 LaunchPad can be found on the `TI LP_MSPM0G3507 Product Page`_. + +Supported Features +================== + +.. zephyr:board-supported-hw:: + +Building and Flashing +********************* + +Building +======== + +Follow the :ref:`getting_started` instructions for Zephyr application development. + +For example, to build the blinky application for the MSPM0G3507 LaunchPad: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: lp_mspm0g3507 + :goals: build + +The resulting ``zephyr.bin`` binary in the build directory can be flashed onto +MSPM0G3507 LaunchPad using the steps mentioned below. + +Flashing +======== + +Open OCD is used to program the flash memory on the devices. It may be necessary in +earlier versions to use a branch of open OCD onto the device. + +Before OpenOCD is public, one can clone `This Repo `_, +and then this can be built with + +``` +cd +./bootstrap (when building from the git repository) +./configure +make +sudo make install +``` + +Then after the build, it is possible to flash the device by passing additional arguments to the flash command + +``` +west flash --openocd /src/openocd --openocd-search /tcl +``` + +Flashing using JLINK + +``` +west flash --runner=jlink +``` + +Debugging +========= + +You can debug an application in the usual way. Here is an example for the +:zephyr:code-sample:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: lp_mspm0g3507 + :goals: debug + +References +********** + +TI MSPM0 MCU Page: + https://www.ti.com/microcontrollers-mcus-processors/arm-based-microcontrollers/arm-cortex-m0-mcus/overview.html + +TI MSPM0G3507 Product Page: + https://www.ti.com/product/MSPM0G3507 + +TI MSPM0 SDK: + https://www.ti.com/tool/MSPM0-SDK + +.. _MSPM0G3507 TRM: + https://www.ti.com/lit/slau846 + +.. _TI LP_MSPM0G3507 Product Page: + https://www.ti.com/tool/LP-MSPM0G3507 diff --git a/boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts b/boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts new file mode 100644 index 0000000000000..900bff2706400 --- /dev/null +++ b/boards/ti/lp_mspm0g3507/lp_mspm0g3507.dts @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2025 Texas Instruments + * Copyright (c) 2025 Linumiz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include +#include + +/ { + model = "TI LP_MSPM0G3507/MSPM0G3507"; + compatible = "ti,mspm0g3507"; + + aliases { + led0 = &led0; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,code-partition = &slot0_partition; + }; + + leds { + compatible = "gpio-leds"; + + led0: led_0 { + gpios = <&gpiob 22 GPIO_ACTIVE_HIGH>; + label = "Blue LED"; + }; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&ulpclk { + clock-frequency = ; + clk-div = <2>; +}; + +&mclk { + clock-frequency = ; + clocks = <&hsclk 0>; +}; + +&hsclk { + clocks = <&syspll2x 0>; + status = "okay"; +}; + +&syspll2x { + status = "okay"; +}; + +&flash0 { + status = "okay"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x8000>; + }; + + slot0_partition: partition@8000 { + label = "image-0"; + reg = <0x00008000 0xC000>; + }; + + slot1_partition: partition@14000 { + label = "image-1"; + reg = <0x00014000 0xC000>; + }; + }; +}; + +&pinctrl { + status = "okay"; +}; + +&gpioa { + status = "okay"; +}; + +&gpiob { + status = "okay"; +}; + +&uart0 { + status = "okay"; + + current-speed = <115200>; + pinctrl-0 = <&uart0_tx_pa10 &uart0_rx_pa11>; + pinctrl-names = "default"; +}; diff --git a/boards/ti/lp_mspm0g3507/lp_mspm0g3507.yaml b/boards/ti/lp_mspm0g3507/lp_mspm0g3507.yaml new file mode 100644 index 0000000000000..0847dde8f4050 --- /dev/null +++ b/boards/ti/lp_mspm0g3507/lp_mspm0g3507.yaml @@ -0,0 +1,14 @@ +identifier: lp_mspm0g3507 +name: TI MSPM0G3507 Launchpad +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 32 +flash: 128 +supported: + - uart + - gpio +vendor: ti diff --git a/boards/ti/lp_mspm0g3507/lp_mspm0g3507_defconfig b/boards/ti/lp_mspm0g3507/lp_mspm0g3507_defconfig new file mode 100644 index 0000000000000..b916bd908277d --- /dev/null +++ b/boards/ti/lp_mspm0g3507/lp_mspm0g3507_defconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +# Enable UART driver +CONFIG_SERIAL=y + +# Enable Console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +CONFIG_CLOCK_CONTROL=y diff --git a/boards/ti/lp_mspm0g3507/support/openocd.cfg b/boards/ti/lp_mspm0g3507/support/openocd.cfg new file mode 100644 index 0000000000000..0356c7705cf1b --- /dev/null +++ b/boards/ti/lp_mspm0g3507/support/openocd.cfg @@ -0,0 +1,4 @@ +source [find interface/xds110.cfg] +adapter speed 10000 + +source [find target/ti_mspm0.cfg] diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index e4a9609936c68..325ed9d281529 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -19,6 +19,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_SCG clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_SCG_K4 clock_control_mcux_scg_k4.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_SIM clock_control_mcux_sim.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_SYSCON clock_control_mcux_syscon.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MSPM0 clock_control_mspm0.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NPCM clock_control_npcm.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NPCX clock_control_npcx.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF clock_control_nrf.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index 16db5c77a151f..f528aa2dad327 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -50,6 +50,8 @@ source "drivers/clock_control/Kconfig.mcux_sim" source "drivers/clock_control/Kconfig.mcux_syscon" +source "drivers/clock_control/Kconfig.mspm0" + source "drivers/clock_control/Kconfig.npcm" source "drivers/clock_control/Kconfig.npcx" diff --git a/drivers/clock_control/Kconfig.mspm0 b/drivers/clock_control/Kconfig.mspm0 new file mode 100644 index 0000000000000..e21e3b305a550 --- /dev/null +++ b/drivers/clock_control/Kconfig.mspm0 @@ -0,0 +1,11 @@ +# TI MSPM0 Family + +# Copyright (c) 2025, Texas Instruments Inc. +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_MSPM0 + bool "TI MSPM0 clock" + default y + depends on SOC_FAMILY_TI_MSPM0 + help + This option enables the TI MSPM0 Clock Control Enabler diff --git a/drivers/clock_control/clock_control_mspm0.c b/drivers/clock_control/clock_control_mspm0.c new file mode 100644 index 0000000000000..9caa2be386f4e --- /dev/null +++ b/drivers/clock_control/clock_control_mspm0.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2025 Texas Instruments + * Copyright (c) 2025 Linumiz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +#define MSPM0_ULPCLK_DIV COND_CODE_1( \ + DT_NODE_HAS_PROP(DT_NODELABEL(ulpclk), clk_div), \ + (CONCAT(DL_SYSCTL_ULPCLK_DIV_, \ + DT_PROP(DT_NODELABEL(ulpclk), clk_div))), \ + (0)) + +#define MSPM0_MCLK_DIV COND_CODE_1( \ + DT_NODE_HAS_PROP(DT_NODELABEL(mclk), clk_div), \ + (CONCAT(DL_SYSCTL_MCLK_DIVIDER_, \ + DT_PROP(DT_NODELABEL(mclk), clk_div))), \ + (0)) + +#define MSPM0_MFPCLK_DIV COND_CODE_1( \ + DT_NODE_HAS_PROP(DT_NODELABEL(mfpclk), clk_div), \ + (CONCAT(DL_SYSCTL_HFCLK_MFPCLK_DIVIDER_, \ + DT_PROP(DT_NODELABEL(mfpclk), clk_div))), \ + (0)) + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(mfpclk), okay) +#define MSPM0_MFPCLK_ENABLED 1 +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pll), okay) +#define MSPM0_PLL_ENABLED 1 +#endif + +#define DT_MCLK_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(mclk)) +#define DT_LFCLK_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(lfclk)) +#define DT_HSCLK_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(hsclk)) +#define DT_HFCLK_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(hfclk)) +#define DT_MFPCLK_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(mfpclk)) +#define DT_PLL_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(pll)) + +struct mspm0_clk_cfg { + uint32_t clk_div; + uint32_t clk_freq; +}; + +static struct mspm0_clk_cfg mspm0_lfclk_cfg = { + .clk_freq = DT_PROP(DT_NODELABEL(lfclk), clock_frequency), +}; + +static struct mspm0_clk_cfg mspm0_ulpclk_cfg = { + .clk_freq = DT_PROP(DT_NODELABEL(ulpclk), clock_frequency), + .clk_div = MSPM0_ULPCLK_DIV, +}; + +static struct mspm0_clk_cfg mspm0_mclk_cfg = { + .clk_freq = DT_PROP(DT_NODELABEL(mclk), clock_frequency), + .clk_div = MSPM0_MCLK_DIV, +}; + +#if MSPM0_MFPCLK_ENABLED +static struct mspm0_clk_cfg mspm0_mfpclk_cfg = { + .clk_freq = DT_PROP(DT_NODELABEL(mfpclk), clock_frequency), + .clk_div = MSPM0_MFPCLK_DIV, +}; +#endif + +#if MSPM0_PLL_ENABLED +/* basic checks of the devicetree to follow */ +#if (DT_NODE_HAS_PROP(DT_NODELABEL(pll), clk2x_div) && \ + DT_NODE_HAS_PROP(DT_NODELABEL(pll), clk0_div)) +#error "Only CLK2X or CLK0 can be enabled at a time on the PLL" +#endif + +static DL_SYSCTL_SYSPLLConfig clock_mspm0_cfg_syspll = { + .inputFreq = DL_SYSCTL_SYSPLL_INPUT_FREQ_32_48_MHZ, + .sysPLLMCLK = DL_SYSCTL_SYSPLL_MCLK_CLK2X, + .sysPLLRef = DL_SYSCTL_SYSPLL_REF_SYSOSC, + .rDivClk2x = (DT_PROP_OR(DT_NODELABEL(pll), clk2x_div, 1) - 1), + .rDivClk1 = (DT_PROP_OR(DT_NODELABEL(pll), clk1_div, 1) - 1), + .rDivClk0 = (DT_PROP_OR(DT_NODELABEL(pll), clk0_div, 1) - 1), + .qDiv = (DT_PROP(DT_NODELABEL(pll), q_div) - 1), + .pDiv = CONCAT(DL_SYSCTL_SYSPLL_PDIV_, + DT_PROP(DT_NODELABEL(pll), p_div)), + .enableCLK2x = COND_CODE_1( + DT_NODE_HAS_PROP(DT_NODELABEL(pll), clk2x_div), + (DL_SYSCTL_SYSPLL_CLK2X_ENABLE), + (DL_SYSCTL_SYSPLL_CLK2X_DISABLE)), + .enableCLK1 = COND_CODE_1( + DT_NODE_HAS_PROP(DT_NODELABEL(pll), clk1_div), + (DL_SYSCTL_SYSPLL_CLK1_ENABLE), + (DL_SYSCTL_SYSPLL_CLK1_DISABLE)), + .enableCLK0 = COND_CODE_1( + DT_NODE_HAS_PROP(DT_NODELABEL(pll), clk0_div), + (DL_SYSCTL_SYSPLL_CLK0_ENABLE), + (DL_SYSCTL_SYSPLL_CLK0_DISABLE)), +}; +#endif + +static int clock_mspm0_on(const struct device *dev, clock_control_subsys_t sys) +{ + return 0; +} + +static int clock_mspm0_off(const struct device *dev, clock_control_subsys_t sys) +{ + return 0; +} + +static int clock_mspm0_get_rate(const struct device *dev, + clock_control_subsys_t sys, + uint32_t *rate) +{ + struct mspm0_sys_clock *sys_clock = (struct mspm0_sys_clock *)sys; + + switch (sys_clock->clk) { + case MSPM0_CLOCK_LFCLK: + *rate = mspm0_lfclk_cfg.clk_freq; + break; + + case MSPM0_CLOCK_ULPCLK: + *rate = mspm0_ulpclk_cfg.clk_freq; + break; + + case MSPM0_CLOCK_MCLK: + *rate = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC; + break; + +#if MSPM0_MFPCLK_ENABLED + case MSPM0_CLOCK_MFPCLK: + *rate = mspm0_mfpclk_cfg.clk_freq; + break; +#endif + + case MSPM0_CLOCK_MFCLK: + case MSPM0_CLOCK_CANCLK: + default: + return -ENOTSUP; + } + + return 0; +} + +static int clock_mspm0_init(const struct device *dev) +{ + /* setup clocks based on specific rates */ + DL_SYSCTL_setSYSOSCFreq(DL_SYSCTL_SYSOSC_FREQ_BASE); + + DL_SYSCTL_setMCLKDivider(mspm0_mclk_cfg.clk_div); + DL_SYSCTL_setULPCLKDivider(mspm0_ulpclk_cfg.clk_div); + +#if MSPM0_PLL_ENABLED +#if DT_SAME_NODE(DT_HSCLK_CLOCKS_CTRL, DT_NODELABEL(syspll0)) + clock_mspm0_cfg_syspll.sysPLLMCLK = DL_SYSCTL_SYSPLL_MCLK_CLK0; +#endif +#if DT_SAME_NODE(DT_PLL_CLOCKS_CTRL, DT_NODELABEL(hfclk)) + clock_mspm0_cfg_syspll.sysPLLRef = DL_SYSCTL_SYSPLL_REF_HFCLK; +#endif + DL_SYSCTL_configSYSPLL( + (DL_SYSCTL_SYSPLLConfig *)&clock_mspm0_cfg_syspll); +#endif + +#if DT_SAME_NODE(DT_HFCLK_CLOCKS_CTRL, DT_NODELABEL(hfxt)) + uint32_t hf_range; + uint32_t hfxt_freq = DT_PROP(DT_NODELABEL(hfxt), + clock_frequency) / MHZ(1); + uint32_t xtal_startup_delay = DT_PROP_OR(DT_NODELABEL(hfxt), + ti_xtal_startup_delay_us, 0); + + if (hfxt_freq >= 4 && + hfxt_freq <= 8) { + hf_range = DL_SYSCTL_HFXT_RANGE_4_8_MHZ; + } else if (hfxt_freq > 8 && + hfxt_freq <= 16) { + hf_range = DL_SYSCTL_HFXT_RANGE_8_16_MHZ; + } else if (hfxt_freq > 16 && + hfxt_freq <= 32) { + hf_range = DL_SYSCTL_HFXT_RANGE_16_32_MHZ; + } else if (hfxt_freq > 32 && + hfxt_freq <= 48) { + hf_range = DL_SYSCTL_HFXT_RANGE_32_48_MHZ; + } else { + return -EINVAL; + } + + /* startup time in 64us resolution */ + DL_SYSCTL_setHFCLKSourceHFXTParams(hf_range, + mspm0_hfclk_cfg.xtal_startup_delay / 64, + true); +#else + DL_SYSCTL_setHFCLKSourceHFCLKIN(); +#endif + +#if MSPM0_LFCLK_ENABLED +#if DT_SAME_NODE(DT_LFCLK_CLOCKS_CTRL, DT_NODELABEL(lfxt)) + DL_SYSCTL_LFCLKConfig config = {0}; + + DL_SYSCTL_setLFCLKSourceLFXT(&config); +#elif DT_SAME_NODE(DT_LFCLK_CLOCKS_CTRL, DT_NODELABEL(lfdig_in)) + DL_SYSCTL_setLFCLKSourceEXLF(); +#endif +#endif /* MSPM0_LFCLK_ENABLED */ + +#if DT_SAME_NODE(DT_MCLK_CLOCKS_CTRL, DT_NODELABEL(hsclk)) +#if DT_SAME_NODE(DT_HSCLK_CLOCKS_CTRL, DT_NODELABEL(hfclk)) + DL_SYSCTL_setMCLKSource(SYSOSC, HSCLK, + DL_SYSCTL_HSCLK_SOURCE_HFCLK); +#endif + +#if MSPM0_PLL_ENABLED +#if (DT_SAME_NODE(DT_HSCLK_CLOCKS_CTRL, DT_NODELABEL(syspll0)) || \ + DT_SAME_NODE(DT_HSCLK_CLOCKS_CTRL, DT_NODELABEL(syspll2x))) + DL_SYSCTL_setMCLKSource(SYSOSC, HSCLK, + DL_SYSCTL_HSCLK_SOURCE_SYSPLL); +#endif +#endif /* MSPM0_PLL_ENABLED */ + +#elif DT_SAME_NODE(DT_MCLK_CLOCKS_CTRL, DT_NODELABEL(lfclk)) + DL_SYSCTL_setMCLKSource(SYSOSC, LFCLK, false); +#endif /* DT_SAME_NODE(DT_MCLK_CLOCKS_CTRL, DT_NODELABEL(hsclk)) */ + +#if MSPM0_MFPCLK_ENABLED +#if DT_SAME_NODE(DT_MFPCLK_CLOCKS_CTRL, DT_NODELABEL(hfclk)) + DL_SYSCTL_setHFCLKDividerForMFPCLK(mspm0_mfpclk_cfg.clk_div); + DL_SYSCTL_setMFPCLKSource(DL_SYSCTL_MFPCLK_SOURCE_HFCLK); +#else + DL_SYSCTL_setMFPCLKSource(DL_SYSCTL_MFPCLK_SOURCE_SYSOSC); +#endif + DL_SYSCTL_enableMFPCLK(); +#endif /* MSPM0_MFPCLK_ENABLED */ + + return 0; +} + +static const struct clock_control_driver_api clock_mspm0_driver_api = { + .on = clock_mspm0_on, + .off = clock_mspm0_off, + .get_rate = clock_mspm0_get_rate, +}; + +DEVICE_DT_DEFINE(DT_NODELABEL(ckm), &clock_mspm0_init, NULL, NULL, NULL, + PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, + &clock_mspm0_driver_api); diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index c513f653f2356..728a883e1093c 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -61,6 +61,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_MCUX_LPC gpio_mcux_lpc.c) zephyr_library_sources_ifdef(CONFIG_GPIO_MCUX_RGPIO gpio_mcux_rgpio.c) zephyr_library_sources_ifdef(CONFIG_GPIO_MFXSTM32L152 gpio_mfxstm32l152.c) zephyr_library_sources_ifdef(CONFIG_GPIO_MMIO32 gpio_mmio32.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_MSPM0 gpio_mspm0.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NCT38XX gpio_nct38xx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NCT38XX gpio_nct38xx_port.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NCT38XX_ALERT gpio_nct38xx_alert.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 213ad2482336d..e95aded5613a8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -149,6 +149,7 @@ source "drivers/gpio/Kconfig.mcux_rgpio" source "drivers/gpio/Kconfig.mec5" source "drivers/gpio/Kconfig.mfxstm32l152" source "drivers/gpio/Kconfig.mmio32" +source "drivers/gpio/Kconfig.mspm0" source "drivers/gpio/Kconfig.nct38xx" source "drivers/gpio/Kconfig.neorv32" source "drivers/gpio/Kconfig.npcx" diff --git a/drivers/gpio/Kconfig.mspm0 b/drivers/gpio/Kconfig.mspm0 new file mode 100644 index 0000000000000..719b3511c7944 --- /dev/null +++ b/drivers/gpio/Kconfig.mspm0 @@ -0,0 +1,12 @@ +# TI MSPM0 GPIO configuration options + +# Copyright (c) 2025 Texas Instruments +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_MSPM0 + bool "TI MSPM0 GPIO driver" + default y + depends on DT_HAS_TI_MSPM0_GPIO_ENABLED + select USE_MSPM0_DL_GPIO + help + Enable the TI MSPM0 GPIO driver. diff --git a/drivers/gpio/gpio_mspm0.c b/drivers/gpio/gpio_mspm0.c new file mode 100644 index 0000000000000..87b9e429aa3c2 --- /dev/null +++ b/drivers/gpio/gpio_mspm0.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2025 Texas Instruments + * Copyright (c) 2025 Linumiz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_mspm0_gpio + +/* Zephyr includes */ +#include +#include +#include + +/* Driverlib includes */ +#include + +struct gpio_mspm0_config { + /* gpio_mspm0_config needs to be first (doesn't actually get used) */ + struct gpio_driver_config common; + /* port base address */ + GPIO_Regs *base; + /* port pincm lookup table */ + uint32_t *pincm_lut; +}; + +struct gpio_mspm0_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + sys_slist_t callbacks; /* List of interrupt callbacks */ +}; + +/* Two polarity registers and HAL api used for pins (0-15) and pins (16-32) */ +#define MSPM0_PINS_LOW_GROUP 16 + +/* GPIO defines */ +#define GPIOA_NODE DT_NODELABEL(gpioa) +#if DT_NODE_HAS_STATUS(GPIOA_NODE, okay) +#if CONFIG_SOC_SERIES_MSPM0G +#define NUM_GPIOA_PIN 32 +#define gpioa_pins NUM_GPIOA_PIN +static uint32_t gpioa_pincm_lut[NUM_GPIOA_PIN] = { + IOMUX_PINCM1, IOMUX_PINCM2, IOMUX_PINCM7, IOMUX_PINCM8, IOMUX_PINCM9, IOMUX_PINCM10, + IOMUX_PINCM11, IOMUX_PINCM14, IOMUX_PINCM19, IOMUX_PINCM20, IOMUX_PINCM21, IOMUX_PINCM22, + IOMUX_PINCM34, IOMUX_PINCM35, IOMUX_PINCM36, IOMUX_PINCM37, IOMUX_PINCM38, IOMUX_PINCM39, + IOMUX_PINCM40, IOMUX_PINCM41, IOMUX_PINCM42, IOMUX_PINCM46, IOMUX_PINCM47, IOMUX_PINCM53, + IOMUX_PINCM54, IOMUX_PINCM55, IOMUX_PINCM59, IOMUX_PINCM60, IOMUX_PINCM3, IOMUX_PINCM4, + IOMUX_PINCM5, IOMUX_PINCM6, +}; +#else +#error "Series lookup table not supported" +#endif /* if CONFIG_SOC_SERIES_MSPM0G */ +#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(gpioa), okay) */ + +#define GPIOB_NODE DT_NODELABEL(gpiob) +#if DT_NODE_HAS_STATUS(GPIOB_NODE, okay) +#ifdef CONFIG_SOC_SERIES_MSPM0G +#define NUM_GPIOB_PIN 28 +#define gpiob_pins NUM_GPIOB_PIN +static uint32_t gpiob_pincm_lut[NUM_GPIOB_PIN] = { + IOMUX_PINCM12, IOMUX_PINCM13, IOMUX_PINCM15, IOMUX_PINCM16, IOMUX_PINCM17, IOMUX_PINCM18, + IOMUX_PINCM23, IOMUX_PINCM24, IOMUX_PINCM25, IOMUX_PINCM26, IOMUX_PINCM27, IOMUX_PINCM28, + IOMUX_PINCM29, IOMUX_PINCM30, IOMUX_PINCM31, IOMUX_PINCM32, IOMUX_PINCM33, IOMUX_PINCM43, + IOMUX_PINCM44, IOMUX_PINCM45, IOMUX_PINCM48, IOMUX_PINCM49, IOMUX_PINCM50, IOMUX_PINCM51, + IOMUX_PINCM52, IOMUX_PINCM56, IOMUX_PINCM57, IOMUX_PINCM58, +}; +#endif /* CONFIG_SOC_SERIES_MSPM0G */ +#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(gpiob), okay) */ + +static int gpio_mspm0_port_get_raw(const struct device *port, uint32_t *value) +{ + const struct gpio_mspm0_config *config = port->config; + + /* Read entire port */ + *value = DL_GPIO_readPins(config->base, UINT32_MAX); + + return 0; +} + +static int gpio_mspm0_port_set_masked_raw(const struct device *port, + uint32_t mask, uint32_t value) +{ + const struct gpio_mspm0_config *config = port->config; + + DL_GPIO_writePinsVal(config->base, mask, value); + + return 0; +} + +static int gpio_mspm0_port_set_bits_raw(const struct device *port, + uint32_t mask) +{ + const struct gpio_mspm0_config *config = port->config; + + DL_GPIO_setPins(config->base, mask); + + return 0; +} + +static int gpio_mspm0_port_clear_bits_raw(const struct device *port, + uint32_t mask) +{ + const struct gpio_mspm0_config *config = port->config; + + DL_GPIO_clearPins(config->base, mask); + + return 0; +} + +static int gpio_mspm0_port_toggle_bits(const struct device *port, + uint32_t mask) +{ + const struct gpio_mspm0_config *config = port->config; + + DL_GPIO_togglePins(config->base, mask); + + return 0; +} + +static int gpio_mspm0_pin_configure(const struct device *port, + gpio_pin_t pin, + gpio_flags_t flags) +{ + const struct gpio_mspm0_config *config = port->config; + /* determine pull up resistor value based on flags */ + DL_GPIO_RESISTOR pull_res; + + if (flags & GPIO_PULL_UP) { + pull_res = DL_GPIO_RESISTOR_PULL_UP; + } else if (flags & GPIO_PULL_DOWN) { + pull_res = DL_GPIO_RESISTOR_PULL_DOWN; + } else { + pull_res = DL_GPIO_RESISTOR_NONE; + } + + /* Config pin based on flags */ + switch (flags & (GPIO_INPUT | GPIO_OUTPUT)) { + case GPIO_INPUT: + DL_GPIO_initDigitalInputFeatures(config->pincm_lut[pin], + DL_GPIO_INVERSION_DISABLE, + pull_res, + DL_GPIO_HYSTERESIS_DISABLE, + DL_GPIO_WAKEUP_DISABLE); + break; + case GPIO_OUTPUT: + DL_GPIO_initDigitalOutputFeatures(config->pincm_lut[pin], + DL_GPIO_INVERSION_DISABLE, + pull_res, + DL_GPIO_DRIVE_STRENGTH_LOW, + DL_GPIO_HIZ_DISABLE); + + /* Set initial state */ + if (flags & GPIO_OUTPUT_INIT_HIGH) { + gpio_mspm0_port_set_bits_raw(port, BIT(pin)); + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + gpio_mspm0_port_clear_bits_raw(port, BIT(pin)); + } + /* Enable output */ + DL_GPIO_enableOutput(config->base, BIT(pin)); + break; + case GPIO_DISCONNECTED: + DL_GPIO_disableOutput(config->base, BIT(pin)); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int gpio_mspm0_pin_interrupt_configure(const struct device *port, + gpio_pin_t pin, + enum gpio_int_mode mode, + enum gpio_int_trig trig) +{ + const struct gpio_mspm0_config *config = port->config; + + /* Config interrupt */ + switch (mode) { + case GPIO_INT_MODE_DISABLED: + DL_GPIO_clearInterruptStatus(config->base, BIT(pin)); + DL_GPIO_disableInterrupt(config->base, BIT(pin)); + break; + case GPIO_INT_MODE_EDGE: + uint32_t polarity = 0x00; + + if (trig & GPIO_INT_TRIG_LOW) { + polarity |= BIT(0); + } + + if (trig & GPIO_INT_TRIG_HIGH) { + polarity |= BIT(1); + } + + if (pin < MSPM0_PINS_LOW_GROUP) { + DL_GPIO_setLowerPinsPolarity(config->base, + polarity << (2 * pin)); + } else { + DL_GPIO_setUpperPinsPolarity(config->base, + polarity << (2 * (pin - MSPM0_PINS_LOW_GROUP))); + } + + DL_GPIO_clearInterruptStatus(config->base, BIT(pin)); + DL_GPIO_enableInterrupt(config->base, BIT(pin)); + break; + case GPIO_INT_MODE_LEVEL: + return -ENOTSUP; + } + + return 0; +} + +static int gpio_mspm0_manage_callback(const struct device *port, + struct gpio_callback *callback, + bool set) +{ + struct gpio_mspm0_data *data = port->data; + + return gpio_manage_callback(&data->callbacks, callback, set); +} + +static uint32_t gpio_mspm0_get_pending_int(const struct device *port) +{ + const struct gpio_mspm0_config *config = port->config; + + return DL_GPIO_getPendingInterrupt(config->base); +} + +static void gpio_mspm0_isr(const struct device *port) +{ + struct gpio_mspm0_data *data; + const struct gpio_mspm0_config *config; + const struct device *dev_list[] = { + DEVICE_DT_GET_OR_NULL(GPIOA_NODE), + DEVICE_DT_GET_OR_NULL(GPIOB_NODE), + }; + + for (uint8_t i = 0; i < ARRAY_SIZE(dev_list); i++) { + uint32_t status; + + if (dev_list[i] == NULL) { + continue; + } + + data = dev_list[i]->data; + config = dev_list[i]->config; + + status = DL_GPIO_getRawInterruptStatus(config->base, + 0xFFFFFFFF); + + DL_GPIO_clearInterruptStatus(config->base, status); + if (status != 0) { + gpio_fire_callbacks(&data->callbacks, + dev_list[i], status); + } + } +} + +static int gpio_mspm0_init(const struct device *dev) +{ + const struct gpio_mspm0_config *cfg = dev->config; + static bool init_irq = true; + + /* Reset and enable GPIO banks */ + DL_GPIO_reset(cfg->base); + DL_GPIO_enablePower(cfg->base); + + /* All the interrupt port share the same irq number, do it once */ + if (init_irq) { + init_irq = false; + + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), + gpio_mspm0_isr, DEVICE_DT_INST_GET(0), 0); + irq_enable(DT_INST_IRQN(0)); + } + + return 0; +} + +static const struct gpio_driver_api gpio_mspm0_driver_api = { + .pin_configure = gpio_mspm0_pin_configure, + .port_get_raw = gpio_mspm0_port_get_raw, + .port_set_masked_raw = gpio_mspm0_port_set_masked_raw, + .port_set_bits_raw = gpio_mspm0_port_set_bits_raw, + .port_clear_bits_raw = gpio_mspm0_port_clear_bits_raw, + .port_toggle_bits = gpio_mspm0_port_toggle_bits, + .pin_interrupt_configure = gpio_mspm0_pin_interrupt_configure, + .manage_callback = gpio_mspm0_manage_callback, + .get_pending_int = gpio_mspm0_get_pending_int, +}; + +#define GPIO_DEVICE_INIT(n, __suffix, __base_addr) \ + static const struct gpio_mspm0_config gpio_mspm0_cfg_##__suffix = { \ + .common = { .port_pin_mask = \ + GPIO_PORT_PIN_MASK_FROM_NGPIOS(gpio##__suffix##_pins), \ + }, \ + .base = (GPIO_Regs *)__base_addr, \ + .pincm_lut = gpio##__suffix##_pincm_lut, \ + }; \ + static struct gpio_mspm0_data gpio_mspm0_data_##__suffix; \ + DEVICE_DT_DEFINE(n, gpio_mspm0_init, NULL, &gpio_mspm0_data_##__suffix, \ + &gpio_mspm0_cfg_##__suffix, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \ + &gpio_mspm0_driver_api) + +#define GPIO_DEVICE_INIT_MSPM0(__suffix) \ + GPIO_DEVICE_INIT(DT_NODELABEL(gpio##__suffix), __suffix, \ + DT_REG_ADDR(DT_NODELABEL(gpio##__suffix))) + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpioa), okay) +GPIO_DEVICE_INIT_MSPM0(a); +#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(gpioa), okay) */ + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpiob), okay) +GPIO_DEVICE_INIT_MSPM0(b); +#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(gpiob), okay) */ diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 6e0747667a8d2..5efe0bd6abca6 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -16,6 +16,7 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_ITE_IT8XXX2 pinctrl_ite_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_NPCX pinctrl_npcx.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_NUMICRO pinctrl_numicro.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_NRF pinctrl_nrf.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_MSPM0 pinctrl_mspm0.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_RPI_PICO pinctrl_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_SAM pinctrl_sam.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_SAM0 pinctrl_sam0.c) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index df6ab582e0eba..a47c4392a78ad 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -45,6 +45,7 @@ source "drivers/pinctrl/Kconfig.it8xxx2" source "drivers/pinctrl/Kconfig.npcx" source "drivers/pinctrl/Kconfig.numicro" source "drivers/pinctrl/Kconfig.nrf" +source "drivers/pinctrl/Kconfig.mspm0" source "drivers/pinctrl/Kconfig.rpi_pico" source "drivers/pinctrl/Kconfig.sam" source "drivers/pinctrl/Kconfig.sam0" diff --git a/drivers/pinctrl/Kconfig.mspm0 b/drivers/pinctrl/Kconfig.mspm0 new file mode 100644 index 0000000000000..1bd21a1c60625 --- /dev/null +++ b/drivers/pinctrl/Kconfig.mspm0 @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2025 Texas Instruments + +config PINCTRL_MSPM0 + bool "TI pinctrl MSPM0 driver" + default y + depends on DT_HAS_TI_MSPM0_PINCTRL_ENABLED + help + Enable support for the PINCTRL on TI MSPM0 series. diff --git a/drivers/pinctrl/pinctrl_mspm0.c b/drivers/pinctrl/pinctrl_mspm0.c new file mode 100644 index 0000000000000..fc8055c196e4b --- /dev/null +++ b/drivers/pinctrl/pinctrl_mspm0.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 Texas Instruments + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define DT_DRV_COMPAT ti_mspm0_pinctrl + +#define MSPM0_PINCM(pinmux) (pinmux >> 0x10) +#define MSPM0_PIN_FUNCTION(pinmux) (pinmux & 0x3F) + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, + uint8_t pin_cnt, + uintptr_t reg) +{ + ARG_UNUSED(reg); + + uint8_t pin_function; + uint32_t pin_cm; + uint32_t iomux; + + for (int i = 0; i < pin_cnt; i++) { + pin_cm = MSPM0_PINCM(pins[i].pinmux); + pin_function = MSPM0_PIN_FUNCTION(pins[i].pinmux); + iomux = pins[i].iomux; + if (pin_function == 0x00) { + DL_GPIO_initPeripheralAnalogFunction(pin_cm); + } else { + DL_GPIO_initPeripheralFunction(pin_cm, + (iomux | pin_function)); + } + } + + return 0; +} diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index e627dd0a70d77..8d91c66b9252a 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -52,6 +52,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_MCUX_LPSCI uart_mcux_lpsci.c) zephyr_library_sources_ifdef(CONFIG_UART_MCUX_LPUART uart_mcux_lpuart.c) zephyr_library_sources_ifdef(CONFIG_UART_MIV uart_miv.c) zephyr_library_sources_ifdef(CONFIG_UART_MSP432P4XX uart_msp432p4xx.c) +zephyr_library_sources_ifdef(CONFIG_UART_MSPM0 uart_mspm0.c) zephyr_library_sources_ifdef(CONFIG_UART_NEORV32 uart_neorv32.c) zephyr_library_sources_ifdef(CONFIG_UART_NPCX uart_npcx.c) zephyr_library_sources_ifdef(CONFIG_UART_NRFX_UART uart_nrfx_uart.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index a90d6b04f4fc7..4dd075bffa02b 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -195,6 +195,7 @@ rsource "Kconfig.mcux_lpuart" rsource "Kconfig.mec5" rsource "Kconfig.miv" rsource "Kconfig.msp432p4xx" +rsource "Kconfig.mspm0" rsource "Kconfig.native_pty" rsource "Kconfig.native_tty" rsource "Kconfig.neorv32" diff --git a/drivers/serial/Kconfig.mspm0 b/drivers/serial/Kconfig.mspm0 new file mode 100644 index 0000000000000..dc72ef9d36d18 --- /dev/null +++ b/drivers/serial/Kconfig.mspm0 @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2025 Texas Instruments +# Copyright (c) 2025 Linumiz + +config UART_MSPM0 + bool "MSPM0 UART driver" + default y + depends on DT_HAS_TI_MSPM0_UART_ENABLED + select SERIAL_HAS_DRIVER + select USE_MSPM0_DL_UART + select PINCTRL + help + This option enables the TI MSPM0 UART driver. diff --git a/drivers/serial/uart_mspm0.c b/drivers/serial/uart_mspm0.c new file mode 100644 index 0000000000000..5622adf4f25cb --- /dev/null +++ b/drivers/serial/uart_mspm0.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2025 Texas Instruments + * Copyright (c) 2025 Linumiz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_mspm0_uart + +/* Zephyr includes */ +#include +#include +#include +#include +#include +#include + +/* Driverlib includes */ +#include + +struct uart_mspm0_config { + UART_Regs *regs; + uint32_t current_speed; + const struct mspm0_sys_clock *clock_subsys; + const struct pinctrl_dev_config *pinctrl; +}; + +struct uart_mspm0_data { + /* UART clock structure */ + DL_UART_Main_ClockConfig uart_clockconfig; + /* UART config structure */ + DL_UART_Main_Config uart_config; +}; + +static int uart_mspm0_init(const struct device *dev) +{ + const struct uart_mspm0_config *config = dev->config; + struct uart_mspm0_data *data = dev->data; + const struct device *clk_dev = DEVICE_DT_GET(DT_NODELABEL(ckm)); + uint32_t clock_rate; + int ret; + + /* Reset power */ + DL_UART_Main_reset(config->regs); + DL_UART_Main_enablePower(config->regs); + delay_cycles(CONFIG_MSPM0_PERIPH_STARTUP_DELAY); + + /* Init UART pins */ + ret = pinctrl_apply_state(config->pinctrl, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + + /* Set UART configs */ + DL_UART_Main_setClockConfig(config->regs, + &data->uart_clockconfig); + DL_UART_Main_init(config->regs, &data->uart_config); + + /* + * Configure baud rate by setting oversampling and baud rate divisor + * from the device tree data current-speed + */ + ret = clock_control_get_rate(clk_dev, + (struct mspm0_sys_clock *)config->clock_subsys, + &clock_rate); + if (ret < 0) { + return ret; + } + + DL_UART_Main_configBaudRate(config->regs, + clock_rate, + config->current_speed); + + /* Enable UART */ + DL_UART_Main_enable(config->regs); + + return 0; +} + +static int uart_mspm0_poll_in(const struct device *dev, unsigned char *c) +{ + const struct uart_mspm0_config *config = dev->config; + + if (DL_UART_Main_receiveDataCheck(config->regs, c) == false) { + return -1; + } + + return 0; +} + +static void uart_mspm0_poll_out(const struct device *dev, unsigned char c) +{ + const struct uart_mspm0_config *config = dev->config; + + DL_UART_Main_transmitDataBlocking(config->regs, c); +} + +static const struct uart_driver_api uart_mspm0_driver_api = { + .poll_in = uart_mspm0_poll_in, + .poll_out = uart_mspm0_poll_out, +}; + +#define MSPM0_MAIN_CLK_DIV(n) CONCAT(DL_UART_MAIN_CLOCK_DIVIDE_RATIO_, DT_INST_PROP(n, clk_div)) + +#define MSPM0_UART_INIT_FN(index) \ + \ + PINCTRL_DT_INST_DEFINE(index); \ + \ + static const struct mspm0_sys_clock mspm0_uart_sys_clock##index = \ + MSPM0_CLOCK_SUBSYS_FN(index); \ + \ + static const struct uart_mspm0_config uart_mspm0_cfg_##index = { \ + .regs = (UART_Regs *)DT_INST_REG_ADDR(index), \ + .current_speed = DT_INST_PROP(index, current_speed), \ + .pinctrl = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \ + .clock_subsys = &mspm0_uart_sys_clock##index, \ + }; \ + \ + static struct uart_mspm0_data uart_mspm0_data_##index = { \ + .uart_clockconfig = { \ + .clockSel = MSPM0_CLOCK_PERIPH_REG_MASK(DT_INST_CLOCKS_CELL(index, clk)), \ + .divideRatio = MSPM0_MAIN_CLK_DIV(index), \ + }, \ + .uart_config = {.mode = DL_UART_MAIN_MODE_NORMAL, \ + .direction = DL_UART_MAIN_DIRECTION_TX_RX, \ + .flowControl = (DT_INST_PROP(index, hw_flow_control) \ + ? DL_UART_MAIN_FLOW_CONTROL_RTS_CTS \ + : DL_UART_MAIN_FLOW_CONTROL_NONE), \ + .parity = DL_UART_MAIN_PARITY_NONE, \ + .wordLength = DL_UART_MAIN_WORD_LENGTH_8_BITS, \ + .stopBits = DL_UART_MAIN_STOP_BITS_ONE, \ + }, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(index, &uart_mspm0_init, NULL, &uart_mspm0_data_##index, \ + &uart_mspm0_cfg_##index, PRE_KERNEL_1, \ + CONFIG_SERIAL_INIT_PRIORITY, &uart_mspm0_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(MSPM0_UART_INIT_FN) diff --git a/dts/arm/ti/mspm0/g/mspm0g.dtsi b/dts/arm/ti/mspm0/g/mspm0g.dtsi new file mode 100644 index 0000000000000..dcf56287a293a --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g.dtsi @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 Texas Instruments + * Copyright (c) 2025 Linumiz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/{ + clocks: clocks { + pll: pll { + compatible = "ti,mspm0-pll"; + clocks = <&sysosc>; + p-div = <2>; + q-div = <5>; + clk1-div = <2>; + clk2x-div = <2>; + #clock-cells = <0>; + status = "okay"; + }; + + syspll2x: syspll2x { + #clock-cells = <1>; + compatible = "ti,mspm0-clk"; + status = "disabled"; + }; + }; +}; diff --git a/dts/arm/ti/mspm0/g/mspm0g1105.dtsi b/dts/arm/ti/mspm0/g/mspm0g1105.dtsi new file mode 100644 index 0000000000000..b0f16667f189e --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g1105.dtsi @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include + +/ { + soc { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(16)>; + }; + + flash0: serial-flash@0 { + reg = <0x0 DT_SIZE_K(32)>; + }; + }; +}; diff --git a/dts/arm/ti/mspm0/g/mspm0g1106.dtsi b/dts/arm/ti/mspm0/g/mspm0g1106.dtsi new file mode 100644 index 0000000000000..d26e979699da0 --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g1106.dtsi @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include + +/ { + soc { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(32)>; + }; + + flash0: serial-flash@0 { + reg = <0x0 DT_SIZE_K(64)>; + }; + }; +}; diff --git a/dts/arm/ti/mspm0/g/mspm0g1107.dtsi b/dts/arm/ti/mspm0/g/mspm0g1107.dtsi new file mode 100644 index 0000000000000..adffaaa172bce --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g1107.dtsi @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include + +/ { + soc { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(32)>; + }; + + flash0: serial-flash@0 { + reg = <0x0 DT_SIZE_K(128)>; + }; + }; +}; diff --git a/dts/arm/ti/mspm0/g/mspm0g110x.dtsi b/dts/arm/ti/mspm0/g/mspm0g110x.dtsi new file mode 100644 index 0000000000000..7662a074329d6 --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g110x.dtsi @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include diff --git a/dts/arm/ti/mspm0/g/mspm0g1505.dtsi b/dts/arm/ti/mspm0/g/mspm0g1505.dtsi new file mode 100644 index 0000000000000..8062934c46e32 --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g1505.dtsi @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include + +/ { + soc { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(16)>; + }; + + flash0: serial-flash@0 { + reg = <0x0 DT_SIZE_K(32)>; + }; + }; +}; diff --git a/dts/arm/ti/mspm0/g/mspm0g1506.dtsi b/dts/arm/ti/mspm0/g/mspm0g1506.dtsi new file mode 100644 index 0000000000000..255197fe824d4 --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g1506.dtsi @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include + +/ { + soc { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(32)>; + }; + + flash0: serial-flash@0 { + reg = <0x0 DT_SIZE_K(64)>; + }; + }; +}; diff --git a/dts/arm/ti/mspm0/g/mspm0g1507.dtsi b/dts/arm/ti/mspm0/g/mspm0g1507.dtsi new file mode 100644 index 0000000000000..ffe115b4ec8ee --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g1507.dtsi @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include + +/ { + soc { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(32)>; + }; + + flash0: serial-flash@0 { + reg = <0x0 DT_SIZE_K(128)>; + }; + }; +}; diff --git a/dts/arm/ti/mspm0/g/mspm0g150x.dtsi b/dts/arm/ti/mspm0/g/mspm0g150x.dtsi new file mode 100644 index 0000000000000..7662a074329d6 --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g150x.dtsi @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include diff --git a/dts/arm/ti/mspm0/g/mspm0g1519.dtsi b/dts/arm/ti/mspm0/g/mspm0g1519.dtsi new file mode 100644 index 0000000000000..8328ddd56272f --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g1519.dtsi @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include + +/ { + soc { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(128)>; + }; + + flash0: serial-flash@0 { + reg = <0x0 DT_SIZE_K(512)>; + }; + }; +}; diff --git a/dts/arm/ti/mspm0/g/mspm0g3105.dtsi b/dts/arm/ti/mspm0/g/mspm0g3105.dtsi new file mode 100644 index 0000000000000..18b57b196bcb6 --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g3105.dtsi @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include + +/ { + soc { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(16)>; + }; + + flash0: serial-flash@0 { + reg = <0x0 DT_SIZE_K(32)>; + }; + }; +}; diff --git a/dts/arm/ti/mspm0/g/mspm0g3106.dtsi b/dts/arm/ti/mspm0/g/mspm0g3106.dtsi new file mode 100644 index 0000000000000..6a85b27f43d5f --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g3106.dtsi @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include + +/ { + soc { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(32)>; + }; + + flash0: serial-flash@0 { + reg = <0x0 DT_SIZE_K(64)>; + }; + }; +}; diff --git a/dts/arm/ti/mspm0/g/mspm0g3107.dtsi b/dts/arm/ti/mspm0/g/mspm0g3107.dtsi new file mode 100644 index 0000000000000..18ac5646175df --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g3107.dtsi @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include + +/ { + soc { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(32)>; + }; + + flash0: serial-flash@0 { + reg = <0x0 DT_SIZE_K(128)>; + }; + }; +}; diff --git a/dts/arm/ti/mspm0/g/mspm0g310x.dtsi b/dts/arm/ti/mspm0/g/mspm0g310x.dtsi new file mode 100644 index 0000000000000..7662a074329d6 --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g310x.dtsi @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include diff --git a/dts/arm/ti/mspm0/g/mspm0g3505.dtsi b/dts/arm/ti/mspm0/g/mspm0g3505.dtsi new file mode 100644 index 0000000000000..6522bc6ad8f3b --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g3505.dtsi @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include + +/ { + soc { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(16)>; + }; + + flash0: serial-flash@0 { + reg = <0x0 DT_SIZE_K(32)>; + }; + }; +}; diff --git a/dts/arm/ti/mspm0/g/mspm0g3506.dtsi b/dts/arm/ti/mspm0/g/mspm0g3506.dtsi new file mode 100644 index 0000000000000..b960b996d6522 --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g3506.dtsi @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include + +/ { + soc { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(32)>; + }; + + flash0: serial-flash@0 { + reg = <0x0 DT_SIZE_K(64)>; + }; + }; +}; diff --git a/dts/arm/ti/mspm0/g/mspm0g3507.dtsi b/dts/arm/ti/mspm0/g/mspm0g3507.dtsi new file mode 100644 index 0000000000000..b9b7e6544d930 --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g3507.dtsi @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include + +/ { + soc { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(32)>; + }; + + flash0: serial-flash@0 { + reg = <0x0 DT_SIZE_K(128)>; + }; + }; +}; diff --git a/dts/arm/ti/mspm0/g/mspm0g350x.dtsi b/dts/arm/ti/mspm0/g/mspm0g350x.dtsi new file mode 100644 index 0000000000000..7662a074329d6 --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g350x.dtsi @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include diff --git a/dts/arm/ti/mspm0/g/mspm0g3519.dtsi b/dts/arm/ti/mspm0/g/mspm0g3519.dtsi new file mode 100644 index 0000000000000..8328ddd56272f --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0g3519.dtsi @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include + +/ { + soc { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(128)>; + }; + + flash0: serial-flash@0 { + reg = <0x0 DT_SIZE_K(512)>; + }; + }; +}; diff --git a/dts/arm/ti/mspm0/g/mspm0gx51x.dtsi b/dts/arm/ti/mspm0/g/mspm0gx51x.dtsi new file mode 100644 index 0000000000000..7662a074329d6 --- /dev/null +++ b/dts/arm/ti/mspm0/g/mspm0gx51x.dtsi @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include diff --git a/dts/arm/ti/mspm0/mspm0.dtsi b/dts/arm/ti/mspm0/mspm0.dtsi new file mode 100644 index 0000000000000..0b3fba586cd97 --- /dev/null +++ b/dts/arm/ti/mspm0/mspm0.dtsi @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2025 Texas Instruments + * Copyright (c) 2025 Linumiz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/{ + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-m0+"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + }; + }; + + ckm: clock-module { + compatible = "ti,mspm0-clk"; + #clock-cells = <1>; + }; + + clocks: clocks { + hfclk: hfclk { + #clock-cells = <1>; + compatible = "ti,mspm0-clk"; + status = "disabled"; + }; + + lfclk: lfclk { + #clock-cells = <1>; + compatible = "ti,mspm0-clk"; + clock-frequency = <32768>; + clocks = <&lfosc>; + }; + + hsclk: hsclk { + #clock-cells = <1>; + compatible = "ti,mspm0-clk"; + clocks = <&sysosc>; + }; + + ulpclk: ulpclk { + #clock-cells = <1>; + compatible = "ti,mspm0-clk"; + clock-frequency = ; + }; + + mclk: mclk { + #clock-cells = <1>; + compatible = "ti,mspm0-clk"; + clock-frequency = ; + clocks = <&sysosc>; + }; + + mfpclk: mfpclk { + #clock-cells = <1>; + compatible = "ti,mspm0-clk"; + clock-frequency = ; + clocks = <&sysosc>; + status = "disabled"; + }; + }; + + oscillators: oscialltors { + hfxt: hfxt { + #clock-cells = <0>; + compatible = "ti,mspm0-osc"; + clock-frequency = ; + status = "disabled"; + }; + + lfxt: lfxt { + #clock-cells = <0>; + compatible = "ti,mspm0-osc"; + clock-frequency = ; + status = "disabled"; + }; + + lfosc: lfosc { + #clock-cells = <0>; + compatible = "ti,mspm0-osc"; + clock-frequency = <32768>; + }; + + sysosc: sysosc { + #clock-cells = <0>; + compatible = "ti,mspm0-osc"; + clock-frequency = ; + }; + }; + + soc { + sram0: memory@20000000 { + compatible = "mmio-sram"; + }; + + flash0: serial-flash@0 { + compatible = "serial-flash"; + }; + + pinctrl: pin-controller@400a0000 { + compatible = "ti,mspm0-pinctrl"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x400a0000 0x4000>; + + gpioa: gpio@400a0000 { + compatible = "ti,mspm0-gpio"; + reg = <0x400a0000 0x2000>; + interrupts = <1 0>; + status = "disabled"; + gpio-controller; + #gpio-cells = <2>; + }; + + gpiob: gpio@400a2000 { + compatible = "ti,mspm0-gpio"; + reg = <0x400a2000 0x2000>; + interrupts = <1 0>; + status = "disabled"; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + uart0: uart@40108000 { + compatible = "ti,mspm0-uart"; + reg = <0x40108000 0x2000>; + current-speed = <115200>; + clocks = <&ckm MSPM0_CLOCK_ULPCLK>; + clk-div = <1>; + status = "disabled"; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <2>; +}; diff --git a/dts/bindings/clock/ti,mspm0-clk.yaml b/dts/bindings/clock/ti,mspm0-clk.yaml new file mode 100644 index 0000000000000..c450398ac3c6c --- /dev/null +++ b/dts/bindings/clock/ti,mspm0-clk.yaml @@ -0,0 +1,30 @@ +# Copyright (c) 2025 Texas Instruments Inc. +# Copyright (c) 2025 Linumiz +# SPDX-License-Identifier: Apache-2.0 + +description: TI MSPM0 Clock + +compatible: "ti,mspm0-clk" + +include: [clock-controller.yaml, base.yaml] + +properties: + "#clock-cells": + const: 1 + + clocks: + description: | + Clock reference source + + clock-frequency: + type: int + description: | + Output clock frequency in Hz. + + clk-div: + type: int + description: | + Clock divider selction value. Valid range [2 ... 16]. + +clock-cells: + - clk diff --git a/dts/bindings/clock/ti,mspm0-osc.yaml b/dts/bindings/clock/ti,mspm0-osc.yaml new file mode 100644 index 0000000000000..c5a68981f34ea --- /dev/null +++ b/dts/bindings/clock/ti,mspm0-osc.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2025 Texas Instruments Inc. +# Copyright (c) 2025 Linumiz +# SPDX-License-Identifier: Apache-2.0 + +description: TI MSPM0 oscillator + +compatible: "ti,mspm0-osc" + +include: [fixed-clock.yaml, base.yaml] + +properties: + "#clock-cells": + const: 0 + + ti,xtal-startup-delay-us: + type: int + description: | + Crystal Oscillator startup delay in micro seconds. + + ti,low-cap: + type: boolean + description: | + Specifies if capacitance is less than 3pF to reduce power consumption. diff --git a/dts/bindings/clock/ti,mspm0-pll.yaml b/dts/bindings/clock/ti,mspm0-pll.yaml new file mode 100644 index 0000000000000..e31768a8f8a71 --- /dev/null +++ b/dts/bindings/clock/ti,mspm0-pll.yaml @@ -0,0 +1,56 @@ +# Copyright (c) 2024 Texas Instruments Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: TI MSPM0 Phase Locked Loop + +compatible: "ti,mspm0-pll" + +include: [clock-controller.yaml, base.yaml] + +properties: + clocks: + required: true + description: | + Clock reference source + + "#clock-cells": + const: 0 + + p-div: + type: int + required: true + enum: + - 1 + - 2 + - 4 + - 8 + description: | + pdiv is the pre-divider of the output. ref_in / pdiv * qdiv = VCO + + q-div: + type: int + required: true + description: | + qdiv functions as a multiplier value for the ref_in / pdiv * qdiv = VCO + Valid Range: 2 - 128 + + clk0-div: + type: int + description: | + CLK0 PLL output is only enabled if the divider is present. Use CLK0 on + the MSPM0 to output to the MCLK, UCLK, and CPUCLK + Valid Range: 1 - 16 + + clk1-div: + type: int + description: | + CLK1 PLL output is only enabled if the divider is present. Use CLK1 on + the MSPM0 to output to the CANCLK, FCC, or output via EXCLK + Valid Range: 1 - 16 + + clk2x-div: + type: int + description: | + CLK2X PLL output is only enabled if the divider is present. Use CLK2X on + the MSPM0 to output to the MCLK, UCLK, and CPUCLK instead of CLK0 + Valid Range: 1 - 16 diff --git a/dts/bindings/gpio/ti,mspm0-gpio.yaml b/dts/bindings/gpio/ti,mspm0-gpio.yaml new file mode 100644 index 0000000000000..a08a432e4cff5 --- /dev/null +++ b/dts/bindings/gpio/ti,mspm0-gpio.yaml @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: Apache-2.0 + +description: TI MSPM0 GPIO + +compatible: "ti,mspm0-gpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/pinctrl/ti,mspm0-pinctrl.yaml b/dts/bindings/pinctrl/ti,mspm0-pinctrl.yaml new file mode 100644 index 0000000000000..68c632c5cd8da --- /dev/null +++ b/dts/bindings/pinctrl/ti,mspm0-pinctrl.yaml @@ -0,0 +1,122 @@ +# Copyright (c) 2025 Texas Instruments +# Copyright (c) 2025 Linumiz +# SPDX-License-Identifier: Apache-2.0 + +description: | + TI MSPM0 pinctrl node. + + Device pin configuration should be placed in the child nodes of this node. + Populate the 'pinmux' field with a pair consisting of a pin number and its + IO functions. + + The node has the 'pinctrl' node label set in your SoC's devicetree, + so you can modify it like this: + + &pinctrl { + /* your modifications go here */ + }; + + All device pin configurations should be placed in child nodes of the + 'pinctrl' node, as in the i2c0 example shown at the end. + + Here is a list of + supported standard pin properties: + + - bias-disable: Disable pull-up/down. + - bias-pull-down: Enable pull-down resistor. + - bias-pull-up: Enable pull-up resistor. + - drive-open-drain: Output driver is open-drain. + - drive-open-drain: Output driver is open-source. + - drive-strength: Maximum current that can be sourced from the pin. + - input-enable: enable input. + - ti,invert: enable logical inversion of a digital input or output + - ti,hysteresis: enable hysteresis control on open-drain pins + + An example for MSPM0 family, include the chip level pinctrl + DTSI file in the board level DTS: + + #include + + We want to configure the I2C pins to open drain, with pullup enabled + and input enabled. + + To change a pin's pinctrl default properties add a reference to the + pin in the board's DTS file or in the project overlay and set the + properties. + + &i2c1 { + pinctrl-0 = <&i2c1_scl_pb2_pull_up &i2c1_sda_pb3_pull_up>; + pinctrl-names = "default"; + } + + The i2c1_scl_pb2_pull_up corresponds to the following pin configuration in + the board dts file: + + &pinctrl { + i2c1_scl_pb2_pull_up: i2c1_scl_pb2_pull_up { + pinmux = ; + input-enable; + bias-pull-up; + drive-open-drain; + }; + }; + + Pin pb2 refers to the device pin name that one would see printed on the + launchpad, and the number 15 in the pinmux define refers to the PINCMx. + + These are obtained from the device-specific datasheet. + +compatible: "ti,mspm0-pinctrl" + +include: base.yaml + +properties: + reg: + required: true + +child-binding: + description: | + This binding gives a base representation of the MSPM0 + pins configuration. + + include: + - name: pincfg-node.yaml + property-allowlist: + - bias-disable + - bias-pull-down + - bias-pull-up + - bias-high-impedance + - drive-open-drain + - drive-open-source + - drive-strength + - input-enable + + properties: + pinmux: + required: true + type: int + description: | + MSPM0 pin's configuration (IO pin, IO function). + + drive-strength: + enum: + - 6 + - 20 + default: 6 + description: | + The drive strength controls the maximum output drive strength sunk or + sourced by an I/O pin. + 6: max 6 mA (SoC default) + 20: max 20 mA on high-drive capable IOs only (HDIO). + + ti,invert: + type: boolean + description: | + Enables inversion of the input or output using the internal + inversion capability of the GPIO + + ti,hysteresis: + type: boolean + description: | + Enables the hysteresis control for access to CMOS logic + (on open-drain capable pins) diff --git a/dts/bindings/serial/ti,mspm0-uart.yaml b/dts/bindings/serial/ti,mspm0-uart.yaml new file mode 100644 index 0000000000000..9660bac137df1 --- /dev/null +++ b/dts/bindings/serial/ti,mspm0-uart.yaml @@ -0,0 +1,30 @@ +description: TI MSPM0 UART + +compatible: "ti,mspm0-uart" + +include: [uart-controller.yaml, pinctrl-device.yaml, base.yaml] + +properties: + reg: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + clk-div: + type: int + default: 1 + enum: + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + description: | + Clock divider selction value. diff --git a/include/zephyr/drivers/clock_control/mspm0_clock_control.h b/include/zephyr/drivers/clock_control/mspm0_clock_control.h new file mode 100644 index 0000000000000..e0028e235475f --- /dev/null +++ b/include/zephyr/drivers/clock_control/mspm0_clock_control.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 Texas Instruments Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MSPM0_CLOCK_CONTROL +#define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MSPM0_CLOCK_CONTROL + +#include + +struct mspm0_sys_clock { + uint32_t clk; +}; + +#define MSPM0_CLOCK_SUBSYS_FN(index) {.clk = DT_INST_CLOCKS_CELL(index, clk)} + +#endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MSPM0_CLOCK_CONTROL */ diff --git a/include/zephyr/dt-bindings/clock/mspm0_clock.h b/include/zephyr/dt-bindings/clock/mspm0_clock.h new file mode 100644 index 0000000000000..be3cd42ac3d2b --- /dev/null +++ b/include/zephyr/dt-bindings/clock/mspm0_clock.h @@ -0,0 +1,27 @@ +/* + * Copyright 2025 Texas Instruments Inc. + * Copyright 2025 Linumiz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MSPM0_CLOCK_H +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MSPM0_CLOCK_H + +#define MSPM0_CLOCK(clk, bit) ((clk << 8) | bit) + +/* Peripheral clock source selection register mask */ +#define MSPM0_CLOCK_PERIPH_REG_MASK(X) (X & 0xFF) + +/* Clock references */ +#define MSPM0_CLOCK_SYSOSC MSPM0_CLOCK(0x0, 0x0) +#define MSPM0_CLOCK_LFCLK MSPM0_CLOCK(0x1, 0x2) +#define MSPM0_CLOCK_MFCLK MSPM0_CLOCK(0x2, 0x4) +#define MSPM0_CLOCK_BUSCLK MSPM0_CLOCK(0x3, 0x8) +#define MSPM0_CLOCK_ULPCLK MSPM0_CLOCK(0x4, 0x8) +#define MSPM0_CLOCK_MCLK MSPM0_CLOCK(0x5, 0x8) +#define MSPM0_CLOCK_MFPCLK MSPM0_CLOCK(0x6, 0x0) +#define MSPM0_CLOCK_CANCLK MSPM0_CLOCK(0x7, 0x0) +#define MSPM0_CLOCK_CLK_OUT MSPM0_CLOCK(0x8, 0x0) + +#endif diff --git a/include/zephyr/dt-bindings/pinctrl/mspm0-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/mspm0-pinctrl.h new file mode 100644 index 0000000000000..e2ec3d3335a46 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/mspm0-pinctrl.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 Texas Instruments + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _MSPM0_DT_BINDINGS_PINCTRL_H_ +#define _MSPM0_DT_BINDINGS_PINCTRL_H_ + +#define MSP_PORT_INDEX_BY_NAME(x) ((x == "PORTA") ? 0 : 1) + +#define MSPM0_PIN_FUNCTION_ANALOG (0x00000000) +#define MSPM0_PIN_FUNCTION_GPIO (0x00000001) +#define MSPM0_PIN_FUNCTION_2 (0x00000002) +#define MSPM0_PIN_FUNCTION_3 (0x00000003) +#define MSPM0_PIN_FUNCTION_4 (0x00000004) +#define MSPM0_PIN_FUNCTION_5 (0x00000005) +#define MSPM0_PIN_FUNCTION_6 (0x00000006) +#define MSPM0_PIN_FUNCTION_7 (0x00000007) +#define MSPM0_PIN_FUNCTION_8 (0x00000008) +#define MSPM0_PIN_FUNCTION_9 (0x00000009) +#define MSPM0_PIN_FUNCTION_10 (0x0000000A) + +/* Creates a concatenation of the correct pin function based on the pin control + * management register offset and the function suffix. + */ +#define MSP_PINMUX(pincm, function) (((pincm - 1) << 0x10) | function) + +#endif diff --git a/modules/Kconfig b/modules/Kconfig index 7d32d1ff818ef..786df9716a6bb 100644 --- a/modules/Kconfig +++ b/modules/Kconfig @@ -30,6 +30,7 @@ source "modules/Kconfig.infineon" source "modules/Kconfig.libmetal" source "modules/lvgl/Kconfig" source "modules/Kconfig.microchip" +source "modules/Kconfig.mspm0" source "modules/Kconfig.nuvoton" source "modules/Kconfig.open-amp" source "modules/Kconfig.picolibc" diff --git a/modules/Kconfig.mspm0 b/modules/Kconfig.mspm0 new file mode 100644 index 0000000000000..97ec56c445477 --- /dev/null +++ b/modules/Kconfig.mspm0 @@ -0,0 +1,13 @@ +# MSPM0 SDK configuration + +# Copyright (c) 2025 Texas Instruments +# SPDX-License-Identifier: Apache-2.0 + +config HAS_MSPM0_SDK + bool + +config USE_MSPM0_DL_GPIO + bool + +config USE_MSPM0_DL_UART + bool diff --git a/soc/ti/mspm0/CMakeLists.txt b/soc/ti/mspm0/CMakeLists.txt new file mode 100644 index 0000000000000..c5487db524647 --- /dev/null +++ b/soc/ti/mspm0/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "SoC Linker Script") + +add_subdirectory(${SOC_SERIES}) + +if(CONFIG_SOC_FAMILY_TI_MSPM0) + string(TOUPPER ${CONFIG_SOC} SDK_SOC_SELECT) + zephyr_compile_definitions(-D__${SDK_SOC_SELECT}__) +endif() diff --git a/soc/ti/mspm0/Kconfig b/soc/ti/mspm0/Kconfig new file mode 100644 index 0000000000000..3c1293fb9eb0f --- /dev/null +++ b/soc/ti/mspm0/Kconfig @@ -0,0 +1,18 @@ +# Texas Instruments MSPM0 Family +# Copyright (c) 2025 Texas Instruments +# Copyright (c) 2025 Linumiz +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_TI_MSPM0 + +rsource "*/Kconfig" + +# Per TRM Section 2.2.7 Peripheral Power Enable Control: wait at least 4 ULPCLK +# clock cycles before accessing the peripheral's memory-mapped registers. +# ULPCLK will either be equivalent or half of the main MCLK and CPUCLK, +# yielding the delay time of 8 cycles +config MSPM0_PERIPH_STARTUP_DELAY + int + default 8 + +endif # SOC_FAMILY_TI_MSPM0 diff --git a/soc/ti/mspm0/Kconfig.defconfig b/soc/ti/mspm0/Kconfig.defconfig new file mode 100644 index 0000000000000..335a9596b1ab0 --- /dev/null +++ b/soc/ti/mspm0/Kconfig.defconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2025 Texas Instruments +# Copyright (c) 2025 Linumiz + +if SOC_FAMILY_TI_MSPM0 + +rsource "*/Kconfig.defconfig" + +DT_MSPM0_MCLK_PATH := $(dt_nodelabel_path,mclk) +DT_MSPM0_MCLK_CPU_FREQ := $(dt_node_int_prop_int,$(DT_MSPM0_MCLK_PATH),clock-frequency) + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default "$(DT_MSPM0_MCLK_CPU_FREQ)" if "$(dt_nodelabel_enabled,mclk)" + +endif # SOC_FAMILY_TI_MSPM0 diff --git a/soc/ti/mspm0/Kconfig.soc b/soc/ti/mspm0/Kconfig.soc new file mode 100644 index 0000000000000..9aaaf8daa0ce9 --- /dev/null +++ b/soc/ti/mspm0/Kconfig.soc @@ -0,0 +1,13 @@ +# Texas Instruments MSPM0 Family + +# Copyright (c) 2025 Texas Instruments +# Copyright (c) 2025 Linumiz +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_TI_MSPM0 + bool + +config SOC_FAMILY + default "ti_mspm0" if SOC_FAMILY_TI_MSPM0 + +rsource "*/Kconfig.soc" diff --git a/soc/ti/mspm0/mspm0g/CMakeLists.txt b/soc/ti/mspm0/mspm0g/CMakeLists.txt new file mode 100644 index 0000000000000..956e8a013950c --- /dev/null +++ b/soc/ti/mspm0/mspm0g/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources(soc.c) +zephyr_include_directories(.) diff --git a/soc/ti/mspm0/mspm0g/Kconfig b/soc/ti/mspm0/mspm0g/Kconfig new file mode 100644 index 0000000000000..8a0241246d41c --- /dev/null +++ b/soc/ti/mspm0/mspm0g/Kconfig @@ -0,0 +1,17 @@ +# TI MSPM0G + +# Copyright (c) 2025 Texas Instruments +# Copyright (c) 2025 Linumiz +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_MSPM0G + select ARM + select CPU_CORTEX_M0PLUS + select CPU_CORTEX_M_HAS_VTOR + select CPU_HAS_ARM_MPU + select CPU_CORTEX_M_HAS_SYSTICK + select BUILD_OUTPUT_BIN + select BUILD_OUTPUT_HEX + select HAS_MSPM0_SDK + select CLOCK_CONTROL + select SOC_EARLY_INIT_HOOK diff --git a/soc/ti/mspm0/mspm0g/Kconfig.defconfig b/soc/ti/mspm0/mspm0g/Kconfig.defconfig new file mode 100644 index 0000000000000..17828deb55ac2 --- /dev/null +++ b/soc/ti/mspm0/mspm0g/Kconfig.defconfig @@ -0,0 +1,20 @@ +# TI MSPM0G series + +# Copyright (c) 2025 Texas Instruments +# Copyright (c) 2025 Linumiz +# SPDX-License-Identifier: Apache-2.0 + +DT_CHOSEN_Z_FLASH := zephyr,flash + +config FLASH_SIZE + default $(dt_chosen_reg_size_int,$(DT_CHOSEN_Z_FLASH),0,K) + +config FLASH_BASE_ADDRESS + default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_FLASH)) + +if SOC_SERIES_MSPM0G + +config NUM_IRQS + default 32 + +endif # SOC_SERIES_MSPM0G diff --git a/soc/ti/mspm0/mspm0g/Kconfig.soc b/soc/ti/mspm0/mspm0g/Kconfig.soc new file mode 100644 index 0000000000000..6bf4f51cdaea9 --- /dev/null +++ b/soc/ti/mspm0/mspm0g/Kconfig.soc @@ -0,0 +1,84 @@ +# Copyright (c) 2024 Texas Instruments +# Copyright (c) 2025 Linumiz +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_MSPM0G + bool + select SOC_FAMILY_TI_MSPM0 + help + Enable support for TI MSPM0G series SoCs + +config SOC_MSPM0G1105 + bool + select SOC_SERIES_MSPM0G + +config SOC_MSPM0G1106 + bool + select SOC_SERIES_MSPM0G + +config SOC_MSPM0G1107 + bool + select SOC_SERIES_MSPM0G + +config SOC_MSPM0G1505 + bool + select SOC_SERIES_MSPM0G + +config SOC_MSPM0G1506 + bool + select SOC_SERIES_MSPM0G + +config SOC_MSPM0G1507 + bool + select SOC_SERIES_MSPM0G + +config SOC_MSPM0G1519 + bool + select SOC_SERIES_MSPM0G + +config SOC_MSPM0G3105 + bool + select SOC_SERIES_MSPM0G + +config SOC_MSPM0G3106 + bool + select SOC_SERIES_MSPM0G + +config SOC_MSPM0G3107 + bool + select SOC_SERIES_MSPM0G + +config SOC_MSPM0G3505 + bool + select SOC_SERIES_MSPM0G + +config SOC_MSPM0G3506 + bool + select SOC_SERIES_MSPM0G + +config SOC_MSPM0G3507 + bool + select SOC_SERIES_MSPM0G + +config SOC_MSPM0G3519 + bool + select SOC_SERIES_MSPM0G + +config SOC_SERIES + default "mspm0g" if SOC_SERIES_MSPM0G + +config SOC + default "mspm0g1105" if SOC_MSPM0G1105 + default "mspm0g1106" if SOC_MSPM0G1106 + default "mspm0g1107" if SOC_MSPM0G1107 + default "mspm0g1505" if SOC_MSPM0G1505 + default "mspm0g1506" if SOC_MSPM0G1506 + default "mspm0g1507" if SOC_MSPM0G1507 + default "mspm0g1519" if SOC_MSPM0G1519 + default "mspm0g3105" if SOC_MSPM0G3105 + default "mspm0g3106" if SOC_MSPM0G3106 + default "mspm0g3107" if SOC_MSPM0G3107 + default "mspm0g3505" if SOC_MSPM0G3505 + default "mspm0g3506" if SOC_MSPM0G3506 + default "mspm0g3507" if SOC_MSPM0G3507 + default "mspm0g3519" if SOC_MSPM0G3519 diff --git a/soc/ti/mspm0/mspm0g/pinctrl_soc.h b/soc/ti/mspm0/mspm0g/pinctrl_soc.h new file mode 100644 index 0000000000000..0433f07260406 --- /dev/null +++ b/soc/ti/mspm0/mspm0g/pinctrl_soc.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025 Texas Instruments + * Copyright (c) 2025 Linumiz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ZEPHYR_SOC_ARM_TI_MSPM0_M0G_PINCTRL_SOC_H__ +#define __ZEPHYR_SOC_ARM_TI_MSPM0_M0G_PINCTRL_SOC_H__ + +#include +#include +#include + +#define MSP_GPIO_RESISTOR_PULL_DOWN (16) +#define MSP_GPIO_RESISTOR_PULL_UP (17) +#define MSP_GPIO_INPUT_ENABLE (18) +#define MSP_GPIO_HYSTERESIS_ENABLED (19) +#define MSP_GPIO_HIGH_DRIVE (20) +#define MSP_GPIO_OPEN_DRAIN_OUTPUT (25) +#define MSP_GPIO_INVERSION_ENABLED (26) + +#define MSP_PINMUX_INIT(node_id) DT_PROP(node_id, pinmux) + +#define MSP_PIN_CONTROL_IOMUX_INIT(node_id) \ + ((DT_PROP(node_id, bias_pull_up) << MSP_GPIO_RESISTOR_PULL_UP) | \ + (DT_PROP(node_id, bias_pull_down) << MSP_GPIO_RESISTOR_PULL_DOWN) | \ + (DT_PROP(node_id, drive_open_drain) << MSP_GPIO_OPEN_DRAIN_OUTPUT) | \ + (DT_ENUM_IDX(node_id, drive_strength) << MSP_GPIO_HIGH_DRIVE) | \ + (DT_PROP(node_id, ti_hysteresis) << MSP_GPIO_HYSTERESIS_ENABLED) | \ + (DT_PROP(node_id, ti_invert) << MSP_GPIO_INVERSION_ENABLED) | \ + (DT_PROP(node_id, input_enable) << MSP_GPIO_INPUT_ENABLE)) + +typedef struct pinctrl_soc_pin { + /* PINCM register index and pin function */ + uint32_t pinmux; + /* IOMUX Pin Control Management (direction, inversion, pullups) */ + uint32_t iomux; +} pinctrl_soc_pin_t; + +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + {.pinmux = MSP_PINMUX_INIT(DT_PROP_BY_IDX(node_id, prop, idx)), \ + .iomux = MSP_PIN_CONTROL_IOMUX_INIT(DT_PROP_BY_IDX(node_id, prop, idx))}, + +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + { \ + DT_FOREACH_PROP_ELEM(node_id, prop, Z_PINCTRL_STATE_PIN_INIT) \ + } + +#endif /* __ZEPHYR_SOC_ARM_TI_MSPM0_M0G_PINCTRL_SOC_H__ */ diff --git a/soc/ti/mspm0/mspm0g/soc.c b/soc/ti/mspm0/mspm0g/soc.c new file mode 100644 index 0000000000000..7dd0a95a0dc61 --- /dev/null +++ b/soc/ti/mspm0/mspm0g/soc.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Texas Instruments + * Copyright (c) 2025 Linumiz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +void soc_early_init_hook(void) +{ + /* Low Power Mode is configured to be SLEEP0 */ + DL_SYSCTL_setBORThreshold(DL_SYSCTL_BOR_THRESHOLD_LEVEL_0); +} diff --git a/soc/ti/mspm0/mspm0g/soc.h b/soc/ti/mspm0/mspm0g/soc.h new file mode 100644 index 0000000000000..3737f99073162 --- /dev/null +++ b/soc/ti/mspm0/mspm0g/soc.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2025 Texas Instruments + * Copyright (c) 2025 Linumiz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _MSPM0_SOC_H +#define _MSPM0_SOC_H + +#include +#include + +#endif /* _MSPM0_SOC_H */ diff --git a/soc/ti/mspm0/soc.yml b/soc/ti/mspm0/soc.yml new file mode 100644 index 0000000000000..fa02fa7ea57b9 --- /dev/null +++ b/soc/ti/mspm0/soc.yml @@ -0,0 +1,19 @@ +family: +- name: ti_mspm0 + series: + - name: mspm0g + socs: + - name: mspm0g1105 + - name: mspm0g1106 + - name: mspm0g1107 + - name: mspm0g1505 + - name: mspm0g1506 + - name: mspm0g1507 + - name: mspm0g1519 + - name: mspm0g3105 + - name: mspm0g3106 + - name: mspm0g3107 + - name: mspm0g3505 + - name: mspm0g3506 + - name: mspm0g3507 + - name: mspm0g3519 diff --git a/west.yml b/west.yml index 2e4c62339c872..55d30c99621a4 100644 --- a/west.yml +++ b/west.yml @@ -260,7 +260,7 @@ manifest: groups: - hal - name: hal_ti - revision: 258652a3ac5d7df68ba8df20e4705c3bd98ede38 + revision: bc8e7b99bb668cc51a3aa384448a48c48a33f8e2 path: modules/hal/ti groups: - hal