diff --git a/boards/microchip/sam/sam_e54_xpro/Kconfig.sam_e54_xpro b/boards/microchip/sam/sam_e54_xpro/Kconfig.sam_e54_xpro new file mode 100644 index 0000000000000..816c623df024e --- /dev/null +++ b/boards/microchip/sam/sam_e54_xpro/Kconfig.sam_e54_xpro @@ -0,0 +1,5 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_SAM_E54_XPRO + select SOC_ATSAME54P20A diff --git a/boards/microchip/sam/sam_e54_xpro/board.cmake b/boards/microchip/sam/sam_e54_xpro/board.cmake new file mode 100644 index 0000000000000..82216ececa08c --- /dev/null +++ b/boards/microchip/sam/sam_e54_xpro/board.cmake @@ -0,0 +1,4 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/microchip/sam/sam_e54_xpro/board.yml b/boards/microchip/sam/sam_e54_xpro/board.yml new file mode 100644 index 0000000000000..1007736ff6c53 --- /dev/null +++ b/boards/microchip/sam/sam_e54_xpro/board.yml @@ -0,0 +1,9 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +board: + name: sam_e54_xpro + full_name: SAM E54 Xplained Pro + vendor: microchip + socs: + - name: atsame54p20a diff --git a/boards/microchip/sam/sam_e54_xpro/doc/img/sam_e54_xpro.webp b/boards/microchip/sam/sam_e54_xpro/doc/img/sam_e54_xpro.webp new file mode 100644 index 0000000000000..bd40d45bb7eed Binary files /dev/null and b/boards/microchip/sam/sam_e54_xpro/doc/img/sam_e54_xpro.webp differ diff --git a/boards/microchip/sam/sam_e54_xpro/doc/index.rst b/boards/microchip/sam/sam_e54_xpro/doc/index.rst new file mode 100644 index 0000000000000..57c9b78478d04 --- /dev/null +++ b/boards/microchip/sam/sam_e54_xpro/doc/index.rst @@ -0,0 +1,94 @@ +.. zephyr:board:: sam_e54_xpro + +Overview +******** + +The SAM E54 Xplained Pro evaluation kit is ideal for evaluation and +prototyping with the SAM E54 Cortex®-M4F processor-based +microcontrollers. The kit includes Microchip’s Embedded Debugger (EDBG), +which provides a full debug interface without the need for additional +hardware. + +Hardware +******** + +- ATSAME54P20A ARM Cortex-M4F processor at 120 MHz +- 32.768 kHz crystal oscillator +- 12 MHz crystal oscillator +- 1024 KiB flash memory and 256 KiB of RAM +- One yellow user LED +- One mechanical user push button +- One reset button +- On-board USB based EDBG unit with serial console +- One QTouch® PTC button +- 32 MiB QSPI Flash +- ATECC508 CryptoAuthentication™ device +- AT24MAC402 serial EEPROM with EUI-48™ MAC address +- Ethernet + + - RJ45 connector with built-in magnetics + - KSZ8091RNA PHY + - 10Base-T/100Base-TX IEE 802.3 compliant Ethernet transceiver + +- USB interface, host, and device +- SD/SDIO card connector + +Supported Features +================== + +.. zephyr:board-supported-hw:: + +Connections and IOs +=================== + +The `SAM E54 Xplained Pro User Guide`_ has detailed information about board connections. + +Programming and Debugging +************************* + +The SAM E54 Xplained Pro features an on-board Microchip Embedded Debugger (EDBG), +which provides both a standard debug interface and a virtual serial port used as the Zephyr console. +SERCOM2 of the ATSAME54P20A MCU is configured as a USART for console output. + +#. Connect the board to your host machine using the debug USB port. + +#. Open a terminal and start a serial console on the corresponding port. + On Linux, this is typically ``/dev/ttyACM0``. For example: + + .. code-block:: console + + $ minicom -D /dev/ttyACM0 -o + + The -o option tells minicom not to send the modem initialization + string. Connection should be configured as follows: + + - Speed: 115200 + - Data: 8 bits + - Parity: None + - Stop bits: 1 + +#. Build and flash the Zephyr ``hello_world`` sample application: + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: sam_e54_xpro + :goals: flash + :compact: + +#. Observe output on the terminal. If everything is set up correctly, you should see: + + .. code-block:: console + + Hello World! same_54_xpro + +References +********** + +SAM E54 Product Page: + https://www.microchip.com/en-us/product/ATSAME54P20A + +SAM E54 Xplained Pro evaluation kit Page: + https://www.microchip.com/en-us/development-tool/ATSAME54-XPRO + +.. _SAM E54 Xplained Pro User Guide: + https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/UserGuides/70005321A.pdf diff --git a/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro-pinctrl.dtsi b/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro-pinctrl.dtsi new file mode 100644 index 0000000000000..05798b46d3ecd --- /dev/null +++ b/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro-pinctrl.dtsi @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + sercom2_uart_default: sercom2_uart_default { + group1 { + pinmux = , + ; + }; + }; +}; diff --git a/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.dts b/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.dts new file mode 100644 index 0000000000000..025d49b64e98a --- /dev/null +++ b/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.dts @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "sam_e54_xpro-pinctrl.dtsi" +#include + +/ { + model = "SAM E54 Xplained Pro"; + compatible = "same54,xpro", "microchip,atsame54p20a", "microchip,same54"; + + chosen { + zephyr,console = &sercom2; + zephyr,shell-uart = &sercom2; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* + * The final 16 KiB is reserved for the application. + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@fc000 { + label = "storage"; + reg = <0x000fc000 0x00004000>; + }; + }; +}; + +&cpu0 { + clock-frequency = <48000000>; +}; + +&sercom2 { + status = "okay"; + compatible = "microchip,sercom-g1-uart"; + #address-cells = <1>; + #size-cells = <0>; + + current-speed = <115200>; + data-bits = <8>; + parity = "none"; + stop-bits = "1"; + + rxpo = <1>; + txpo = <0>; + + pinctrl-0 = <&sercom2_uart_default>; + pinctrl-names = "default"; +}; diff --git a/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.yaml b/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.yaml new file mode 100644 index 0000000000000..d349dbd338489 --- /dev/null +++ b/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +identifier: sam_e54_xpro +name: SAM E54 Xplained Pro +type: mcu +arch: arm +toolchain: + - zephyr +flash: 1024 +ram: 256 +supported: + - pinctrl + - shell + - uart +vendor: microchip diff --git a/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro_defconfig b/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro_defconfig new file mode 100644 index 0000000000000..ce22ecc682df3 --- /dev/null +++ b/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro_defconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BUILD_OUTPUT_HEX=y + +CONFIG_ARM_MPU=y +CONFIG_HW_STACK_PROTECTION=y + +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y diff --git a/boards/microchip/sam/sam_e54_xpro/support/openocd.cfg b/boards/microchip/sam/sam_e54_xpro/support/openocd.cfg new file mode 100644 index 0000000000000..a4713f87dbd79 --- /dev/null +++ b/boards/microchip/sam/sam_e54_xpro/support/openocd.cfg @@ -0,0 +1,25 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 +source [find interface/cmsis-dap.cfg] +transport select swd + +# chip name +set CHIPNAME same54p20a +set ENDIAN little +set CPUTAPID 0x0bc11477 + +source [find target/atsame5x.cfg] + +reset_config none +cortex_m reset_config sysresetreq + +$_TARGETNAME configure -event gdb-attach { + echo "Debugger attaching: halting execution" + reset halt + gdb_breakpoint_override hard +} + +$_TARGETNAME configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 048f398d0976b..d5fbf1d5c483b 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -10,6 +10,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_FIXED_RATE_CLOCK clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_GD32 clock_control_gd32.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_LITEX clock_control_litex.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_LPC11U6X clock_control_lpc11u6x.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCHP_SAM_D5X_E5X clock_control_mchp_sam_d5x_e5x.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCHP_XEC clock_control_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_CCM clock_control_mcux_ccm.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_CCM_REV2 clock_control_mcux_ccm_rev2.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index 05a2a7fb8fa67..a2c338de764eb 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -114,4 +114,6 @@ source "drivers/clock_control/Kconfig.wch_rcc" source "drivers/clock_control/Kconfig.it51xxx" +source "drivers/clock_control/Kconfig.mchp" + endif # CLOCK_CONTROL diff --git a/drivers/clock_control/Kconfig.mchp b/drivers/clock_control/Kconfig.mchp new file mode 100644 index 0000000000000..60a9bf5467a36 --- /dev/null +++ b/drivers/clock_control/Kconfig.mchp @@ -0,0 +1,26 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_MCHP_COMMON + bool + help + Common options for Microchip clock control drivers. + +config CLOCK_CONTROL_MCHP_SAM_D5X_E5X + bool "Microchip SAM D5X/E5X clock controller Support" + depends on DT_HAS_MICROCHIP_SAM_D5X_E5X_CLOCK_ENABLED + default y + select CLOCK_CONTROL_MCHP_COMMON + help + Enable clock controller driver for Microchip SAM D5X/E5X SoC family. + +if CLOCK_CONTROL_MCHP_COMMON + +config CLOCK_CONTROL_MCHP_GET_RATE + bool "Get clock rate" + default y + help + Enable support for retrieving the clock rate. This may increase + code size, depending on the depth of clock source hierarchy. + +endif # CLOCK_CONTROL_MCHP_COMMON diff --git a/drivers/clock_control/clock_control_mchp_sam_d5x_e5x.c b/drivers/clock_control/clock_control_mchp_sam_d5x_e5x.c new file mode 100644 index 0000000000000..5e1c61403784f --- /dev/null +++ b/drivers/clock_control/clock_control_mchp_sam_d5x_e5x.c @@ -0,0 +1,713 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file clock_mchp_sam_d5x_e5x.c + * @brief Clock control driver for sam_d5x_e5x family devices. + */ + +#include +#include +#include +#include + +#include + +/****************************************************************************** + * @brief Devicetree definitions + *****************************************************************************/ +#define DT_DRV_COMPAT microchip_sam_d5x_e5x_clock + +/****************************************************************************** + * @brief Macro definitions + *****************************************************************************/ +LOG_MODULE_REGISTER(clock_mchp_sam_d5x_e5x, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +#define CLOCK_NODE DT_NODELABEL(clock) + +#define CLOCK_SUCCESS 0 + +#define FREQ_32KHZ 32768 +#define FREQ_1KHZ 1024 +#define FREQ_DFLL_48MHZ 48000000 + +/* gclk peripheral channel max, 0 - 47 */ +#define GPH_MAX 47 + +/* maximum value for mask bit position, 0 - 31 */ +#define MMASK_MAX 31 + +/* maximum value for div, when div_select is clock source frequency divided by 2^(N+1) */ +#define GCLKGEN_POWER_DIV_MAX 29 + +/* init iteration count, so that, the source clocks are initialized before executing init */ +#define CLOCK_INIT_ITERATION_COUNT 3 + +/* mclkbus Not Applicable for a clock subsystem ID */ +#define MBUS_NA (0x3f) + +/* mclkmaskbit Not Applicable for a clock subsystem ID */ +#define MMASK_NA (0x3f) + +/* gclkperiph Not Applicable for a clock subsystem ID */ +#define GPH_NA (0x3f) + +/* Clock subsystem Types */ +#define SUBSYS_TYPE_XOSC (0) +#define SUBSYS_TYPE_DFLL (1) +#define SUBSYS_TYPE_FDPLL (2) +#define SUBSYS_TYPE_RTC (3) +#define SUBSYS_TYPE_OSC32K (4) +#define SUBSYS_TYPE_GCLKGEN (5) +#define SUBSYS_TYPE_GCLKPERIPH (6) +#define SUBSYS_TYPE_MCLKCPU (7) +#define SUBSYS_TYPE_MCLKPERIPH (8) +#define SUBSYS_TYPE_MAX (8) + +/* mclk bus */ +#define MBUS_AHB (0) +#define MBUS_APBA (1) +#define MBUS_APBB (2) +#define MBUS_APBC (3) +#define MBUS_APBD (4) +#define MBUS_MAX (4) + +/* XOSC instances */ +#define INST_XOSC0 0 +#define INST_XOSC1 1 + +/* FDPLL instances */ +#define INST_FDPLL0 0 +#define INST_FDPLL1 1 + +/* OSC32K instances */ +#define INST_OSC32K_OSCULP1K 0 +#define INST_OSC32K_OSCULP32K 1 +#define INST_OSC32K_XOSC1K 2 +#define INST_OSC32K_XOSC32K 3 + +/****************************************************************************** + * @brief Data type definitions + *****************************************************************************/ +/** @brief Clock subsystem definition. + * + * Structure which can be used as a sys argument in the clock_control API. + * Encode clock type, mclk bus, mclk mask bit, gclk pch and instance number, + * to clock subsystem. + * + * - 00..07 (8 bits): inst + * - 08..13 (6 bits): gclkperiph + * - 14..19 (6 bits): mclkmaskbit + * - 20..25 (6 bits): mclkbus + * - 26..31 (6 bits): type + */ +typedef union { + uint32_t val; + struct { + uint32_t inst: 8; + uint32_t gclkperiph: 6; + uint32_t mclkmaskbit: 6; + uint32_t mclkbus: 6; + uint32_t type: 6; + } bits; +} clock_mchp_subsys_t; + +/** @brief clock driver configuration structure. */ +typedef struct { + oscctrl_registers_t *oscctrl_regs; + osc32kctrl_registers_t *osc32kctrl_regs; + gclk_registers_t *gclk_regs; + mclk_registers_t *mclk_regs; + + /* Timeout in milliseconds to wait for clock to turn on */ + uint32_t on_timeout_ms; +} clock_mchp_config_t; + +/* + * - 00..14 (15 bits): clock_mchp_gclkgen_t/clock_mchp_fdpll_src_clock_t + * - 15..23 (9 bits): CLOCK_MCHP_FDPLL_SRC_MAX+1+clock_mchp_gclk_src_clock_t + */ +typedef enum { + ON_BITPOS_GCLK0 = CLOCK_MCHP_FDPLL_SRC_GCLK0, + ON_BITPOS_GCLK1 = CLOCK_MCHP_FDPLL_SRC_GCLK1, + ON_BITPOS_GCLK2 = CLOCK_MCHP_FDPLL_SRC_GCLK2, + ON_BITPOS_GCLK3 = CLOCK_MCHP_FDPLL_SRC_GCLK3, + ON_BITPOS_GCLK4 = CLOCK_MCHP_FDPLL_SRC_GCLK4, + ON_BITPOS_GCLK5 = CLOCK_MCHP_FDPLL_SRC_GCLK5, + ON_BITPOS_GCLK6 = CLOCK_MCHP_FDPLL_SRC_GCLK6, + ON_BITPOS_GCLK7 = CLOCK_MCHP_FDPLL_SRC_GCLK7, + ON_BITPOS_GCLK8 = CLOCK_MCHP_FDPLL_SRC_GCLK8, + ON_BITPOS_GCLK9 = CLOCK_MCHP_FDPLL_SRC_GCLK9, + ON_BITPOS_GCLK10 = CLOCK_MCHP_FDPLL_SRC_GCLK10, + ON_BITPOS_GCLK11 = CLOCK_MCHP_FDPLL_SRC_GCLK11, + ON_BITPOS_XOSC32K_ = CLOCK_MCHP_FDPLL_SRC_XOSC32K, + ON_BITPOS_XOSC0_ = CLOCK_MCHP_FDPLL_SRC_XOSC0, + ON_BITPOS_XOSC1_ = CLOCK_MCHP_FDPLL_SRC_XOSC1, + ON_BITPOS_XOSC0 = CLOCK_MCHP_FDPLL_SRC_MAX + 1 + CLOCK_MCHP_GCLK_SRC_XOSC0, + ON_BITPOS_XOSC1 = CLOCK_MCHP_FDPLL_SRC_MAX + 1 + CLOCK_MCHP_GCLK_SRC_XOSC1, + ON_BITPOS_GCLKPIN = CLOCK_MCHP_FDPLL_SRC_MAX + 1 + CLOCK_MCHP_GCLK_SRC_GCLKPIN, + ON_BITPOS_GCLKGEN1 = CLOCK_MCHP_FDPLL_SRC_MAX + 1 + CLOCK_MCHP_GCLK_SRC_GCLKGEN1, + ON_BITPOS_OSCULP32K = CLOCK_MCHP_FDPLL_SRC_MAX + 1 + CLOCK_MCHP_GCLK_SRC_OSCULP32K, + ON_BITPOS_XOSC32K = CLOCK_MCHP_FDPLL_SRC_MAX + 1 + CLOCK_MCHP_GCLK_SRC_XOSC32K, + ON_BITPOS_DFLL = CLOCK_MCHP_FDPLL_SRC_MAX + 1 + CLOCK_MCHP_GCLK_SRC_DFLL, + ON_BITPOS_FDPLL0 = CLOCK_MCHP_FDPLL_SRC_MAX + 1 + CLOCK_MCHP_GCLK_SRC_FDPLL0, + ON_BITPOS_FDPLL1 = CLOCK_MCHP_FDPLL_SRC_MAX + 1 + CLOCK_MCHP_GCLK_SRC_FDPLL1 +} clock_mchp_on_bitpos_t; + +/** @brief clock driver data structure. */ +typedef struct { + /* + * - 00..14 (15 bits): clock_mchp_gclkgen_t/clock_mchp_fdpll_src_clock_t + * - 15..23 (9 bits): CLOCK_MCHP_FDPLL_SRC_MAX+1+clock_mchp_gclk_src_clock_t + */ + uint32_t src_on_status; +} clock_mchp_data_t; + +/****************************************************************************** + * @brief Function forward declarations + *****************************************************************************/ +#if CONFIG_CLOCK_CONTROL_MCHP_GET_RATE +static int clock_get_rate_dfll(const struct device *dev, uint32_t *freq); +#endif /* CONFIG_CLOCK_CONTROL_MCHP_GET_RATE */ + +static enum clock_control_status clock_mchp_get_status(const struct device *dev, + clock_control_subsys_t sys); + +/****************************************************************************** + * @brief Helper functions + *****************************************************************************/ +/** + * @brief check if subsystem type and id are valid. + */ +static int clock_check_subsys(clock_mchp_subsys_t subsys) +{ + int ret_val = -EINVAL; + uint32_t inst_max = 0, gclkperiph_max = GPH_NA, mclkbus_max = MBUS_NA, + mclkmaskbit_max = MMASK_NA; + + do { + /* Check if turning on all clocks is requested. */ + if (subsys.val == (uint32_t)CLOCK_CONTROL_SUBSYS_ALL) { + break; + } + + /* Check if the specified subsystem was found. */ + if (subsys.bits.type > SUBSYS_TYPE_MAX) { + break; + } + + switch (subsys.bits.type) { + case SUBSYS_TYPE_XOSC: + inst_max = CLOCK_MCHP_XOSC_ID_MAX; + break; + + case SUBSYS_TYPE_DFLL: + inst_max = CLOCK_MCHP_DFLL_MAX; + gclkperiph_max = CLOCK_MCHP_DFLL_MAX; + break; + + case SUBSYS_TYPE_FDPLL: + inst_max = CLOCK_MCHP_FDPLL_ID_MAX; + gclkperiph_max = CLOCK_MCHP_FDPLL_ID_MAX; + break; + + case SUBSYS_TYPE_RTC: + inst_max = CLOCK_MCHP_RTC_ID_MAX; + break; + + case SUBSYS_TYPE_OSC32K: + inst_max = CLOCK_MCHP_OSC32K_ID_MAX; + break; + + case SUBSYS_TYPE_GCLKGEN: + inst_max = CLOCK_MCHP_GCLKGEN_ID_MAX; + break; + + case SUBSYS_TYPE_GCLKPERIPH: + inst_max = CLOCK_MCHP_GCLKPERIPH_ID_MAX; + gclkperiph_max = GPH_MAX; + break; + + case SUBSYS_TYPE_MCLKCPU: + inst_max = CLOCK_MCHP_MCLKCPU_MAX; + break; + + case SUBSYS_TYPE_MCLKPERIPH: + inst_max = CLOCK_MCHP_MCLKPERIPH_ID_MAX; + mclkbus_max = MBUS_MAX; + mclkmaskbit_max = MMASK_MAX; + break; + + default: + LOG_ERR("Unsupported SUBSYS_TYPE"); + } + + /* Check if the specified id is valid. */ + if ((subsys.bits.inst > inst_max) || (subsys.bits.gclkperiph > gclkperiph_max) || + (subsys.bits.mclkbus > mclkbus_max) || + (subsys.bits.mclkmaskbit > mclkmaskbit_max)) { + break; + } + + ret_val = CLOCK_SUCCESS; + } while (0); + + return ret_val; +} + +/** + * @brief get the address of mclk mask register. + */ +__IO uint32_t *get_mclkbus_mask_reg(mclk_registers_t *mclk_regs, uint32_t bus) +{ + __IO uint32_t *reg32 = NULL; + + switch (bus) { + case MBUS_AHB: + reg32 = &mclk_regs->MCLK_AHBMASK; + break; + case MBUS_APBA: + reg32 = &mclk_regs->MCLK_APBAMASK; + break; + case MBUS_APBB: + reg32 = &mclk_regs->MCLK_APBBMASK; + break; + case MBUS_APBC: + reg32 = &mclk_regs->MCLK_APBCMASK; + break; + case MBUS_APBD: + reg32 = &mclk_regs->MCLK_APBDMASK; + break; + default: + LOG_ERR("Unsupported mclkbus"); + break; + } + + return reg32; +} + +/** + * @brief function to set/clear clock subsystem enable bit. + */ +static int clock_on_off(const clock_mchp_config_t *config, const clock_mchp_subsys_t subsys, + bool on) +{ + int ret_val = CLOCK_SUCCESS; + gclk_registers_t *gclk_regs = config->gclk_regs; + __IO uint32_t *reg32 = NULL; + uint32_t reg32_val = 0; + + switch (subsys.bits.type) { + case SUBSYS_TYPE_GCLKPERIPH: + reg32 = &gclk_regs->GCLK_PCHCTRL[subsys.bits.gclkperiph]; + reg32_val = GCLK_PCHCTRL_CHEN_Msk; + break; + case SUBSYS_TYPE_MCLKPERIPH: + reg32 = get_mclkbus_mask_reg(config->mclk_regs, subsys.bits.mclkbus); + reg32_val = 1 << subsys.bits.mclkmaskbit; + break; + default: + ret_val = -ENOTSUP; + break; + } + + if ((ret_val == CLOCK_SUCCESS) && (reg32 != NULL)) { + if (on == true) { + *reg32 |= reg32_val; + } else { + *reg32 &= ~reg32_val; + } + } + + return ret_val; +} + +#if CONFIG_CLOCK_CONTROL_MCHP_GET_RATE +/** + * @brief get rate of gclk generator in Hz. + */ +static int clock_get_rate_gclkgen(const struct device *dev, clock_mchp_gclkgen_t gclkgen_id, + clock_mchp_gclk_src_clock_t gclkgen_called_src, uint32_t *freq) +{ + int ret_val = CLOCK_SUCCESS; + const clock_mchp_config_t *config = dev->config; + gclk_registers_t *gclk_regs = config->gclk_regs; + clock_mchp_gclk_src_clock_t gclkgen_src; + uint32_t gclkgen_src_freq; + uint16_t gclkgen_div; + + bool power_div = (((gclk_regs->GCLK_GENCTRL[gclkgen_id] & GCLK_GENCTRL_DIVSEL_Msk) >> + GCLK_GENCTRL_DIVSEL_Pos) == GCLK_GENCTRL_DIVSEL_DIV1_Val) + ? false + : true; + + do { + /* Return rate as 0, if clock is not on */ + if (clock_mchp_get_status(dev, (clock_control_subsys_t)MCHP_CLOCK_DERIVE_ID( + SUBSYS_TYPE_GCLKGEN, MBUS_NA, MMASK_NA, + GPH_NA, gclkgen_id)) != + CLOCK_CONTROL_STATUS_ON) { + *freq = 0; + break; + } + + /* get source for gclk generator from gclkgen registers */ + gclkgen_src = (gclk_regs->GCLK_GENCTRL[gclkgen_id] & GCLK_GENCTRL_SRC_Msk) >> + GCLK_GENCTRL_SRC_Pos; + if (gclkgen_called_src == gclkgen_src) { + ret_val = -ENOTSUP; + break; + } + + if (gclkgen_src == CLOCK_MCHP_GCLK_SRC_DFLL) { + ret_val = clock_get_rate_dfll(dev, &gclkgen_src_freq); + } else { + ret_val = -ENOTSUP; + } + if (ret_val != CLOCK_SUCCESS) { + break; + } + + /* get gclk generator clock divider*/ + gclkgen_div = (gclk_regs->GCLK_GENCTRL[gclkgen_id] & GCLK_GENCTRL_DIV_Msk) >> + GCLK_GENCTRL_DIV_Pos; + + /* + * For gclk1, 8 division factor bits - DIV[7:0] + * others, 16 division factor bits - DIV[15:0] + */ + if (gclkgen_id != CLOCK_MCHP_GCLKGEN_GEN1) { + gclkgen_div = gclkgen_div & 0xFF; + } + + if (power_div == true) { + if (gclkgen_div > GCLKGEN_POWER_DIV_MAX) { + gclkgen_div = GCLKGEN_POWER_DIV_MAX; + } + gclkgen_div = 1 << (gclkgen_div + 1); + } else { + /* if DIV value is 0, has same effect as DIV value 1 */ + if (gclkgen_div == 0) { + gclkgen_div = 1; + } + } + *freq = gclkgen_src_freq / gclkgen_div; + } while (0); + + return ret_val; +} + +/** + * @brief get rate of DFLL in Hz. + */ +static int clock_get_rate_dfll(const struct device *dev, uint32_t *freq) +{ + int ret_val = CLOCK_SUCCESS; + const clock_mchp_config_t *config = dev->config; + oscctrl_registers_t *oscctrl_regs = config->oscctrl_regs; + + if ((oscctrl_regs->OSCCTRL_STATUS & OSCCTRL_STATUS_DFLLRDY_Msk) == 0) { + /* Return rate as 0, if clock is not on */ + *freq = 0; + } else if ((oscctrl_regs->OSCCTRL_DFLLCTRLB & OSCCTRL_DFLLCTRLB_MODE_Msk) == 0) { + /* in open loop mode*/ + *freq = FREQ_DFLL_48MHZ; + } else { + /* in closed loop mode*/ + ret_val = -ENOTSUP; + } + + return ret_val; +} +#endif /* CONFIG_CLOCK_CONTROL_MCHP_GET_RATE */ + +/****************************************************************************** + * @brief API functions + *****************************************************************************/ + +/** + * @brief Turn on the clock for a specified subsystem, can be blocking. + * + * @param dev Pointer to the clock device structure + * @param sys Clock subsystem + * + * @return 0 if the clock is successfully turned on + * @return -ENOTSUP If the requested operation is not supported. + * @return -ETIMEDOUT If the requested operation is timedout. + * @return -EALREADY If clock is already on. + */ +static int clock_mchp_on(const struct device *dev, clock_control_subsys_t sys) +{ + int ret_val = -ENOTSUP; + const clock_mchp_config_t *config = dev->config; + clock_mchp_subsys_t subsys = {.val = (uint32_t)sys}; + enum clock_control_status status; + bool is_wait = false; + uint32_t on_timeout_ms = 0; + + do { + /* Validate subsystem. */ + if (CLOCK_SUCCESS != clock_check_subsys(subsys)) { + break; + } + + status = clock_mchp_get_status(dev, sys); + if (status == CLOCK_CONTROL_STATUS_ON) { + /* clock is already on. */ + ret_val = -EALREADY; + break; + } + + /* Check if the clock on operation is successful. */ + if (clock_on_off(config, subsys, true) == CLOCK_SUCCESS) { + is_wait = true; + } + } while (0); + + /* Wait until the clock state becomes ON. */ + while (is_wait == true) { + status = clock_mchp_get_status(dev, sys); + if (status == CLOCK_CONTROL_STATUS_ON) { + /* Successfully turned on clock. */ + ret_val = CLOCK_SUCCESS; + break; + } + if (on_timeout_ms < config->on_timeout_ms) { + /* Thread is not available while booting. */ + if ((k_is_pre_kernel() == false) && (k_current_get() != NULL)) { + /* Sleep before checking again. */ + k_sleep(K_MSEC(1)); + on_timeout_ms++; + } + } else { + /* Clock on timeout occurred */ + ret_val = -ETIMEDOUT; + break; + } + } + + return ret_val; +} + +/** + * @brief Turn off the clock for a specified subsystem. + * + * @param dev Pointer to the clock device structure + * @param sys Clock subsystem + * + * @return 0 if the clock is successfully turned off + * @return -ENOTSUP If the requested operation is not supported. + * @return -EALREADY If clock is already off. + */ +static int clock_mchp_off(const struct device *dev, clock_control_subsys_t sys) +{ + int ret_val = -ENOTSUP; + const clock_mchp_config_t *config = dev->config; + clock_mchp_subsys_t subsys = {.val = (uint32_t)sys}; + + do { + /* Validate subsystem. */ + if (CLOCK_SUCCESS != clock_check_subsys(subsys)) { + break; + } + + ret_val = clock_on_off(config, subsys, false); + } while (0); + + return ret_val; +} + +/** + * @brief Get the status of clock, for a specified subsystem. + * + * This function retrieves the current status of the clock for a given subsystem. + * + * @param dev Pointer to the clock device structure. + * @param sys The clock subsystem. + * + * @return The current status of clock for the subsystem (e.g., off, on, starting, or unknown). + */ +static enum clock_control_status clock_mchp_get_status(const struct device *dev, + clock_control_subsys_t sys) +{ + enum clock_control_status ret_status = CLOCK_CONTROL_STATUS_UNKNOWN; + const clock_mchp_config_t *config = dev->config; + oscctrl_registers_t *oscctrl_regs = config->oscctrl_regs; + gclk_registers_t *gclk_regs = config->gclk_regs; + clock_mchp_subsys_t subsys = {.val = (uint32_t)sys}; + uint32_t mask; + uint8_t inst; + __IO uint32_t *reg32; + + do { + /* Validate subsystem. */ + if (CLOCK_SUCCESS != clock_check_subsys(subsys)) { + break; + } + + inst = subsys.bits.inst; + + switch (subsys.bits.type) { + case SUBSYS_TYPE_DFLL: + /* Check if DFLL is enabled */ + if ((oscctrl_regs->OSCCTRL_DFLLCTRLA & OSCCTRL_DFLLCTRLA_ENABLE_Msk) != 0) { + /* Check if sync is complete and ready bit is set */ + ret_status = ((oscctrl_regs->OSCCTRL_DFLLSYNC != 0) || + ((oscctrl_regs->OSCCTRL_STATUS & + OSCCTRL_STATUS_DFLLRDY_Msk) == 0)) + ? CLOCK_CONTROL_STATUS_STARTING + : CLOCK_CONTROL_STATUS_ON; + } else { + ret_status = CLOCK_CONTROL_STATUS_OFF; + } + + break; + case SUBSYS_TYPE_GCLKGEN: + ret_status = CLOCK_CONTROL_STATUS_OFF; + if ((gclk_regs->GCLK_GENCTRL[inst] & GCLK_GENCTRL_GENEN_Msk) != 0) { + /* Generator is on, check if it's starting or fully on */ + ret_status = ((gclk_regs->GCLK_SYNCBUSY & + (1 << (GCLK_SYNCBUSY_GENCTRL_Pos + inst))) != 0) + ? CLOCK_CONTROL_STATUS_STARTING + : CLOCK_CONTROL_STATUS_ON; + } + break; + case SUBSYS_TYPE_GCLKPERIPH: + /* Check if the peripheral clock is enabled */ + ret_status = ((gclk_regs->GCLK_PCHCTRL[subsys.bits.gclkperiph] & + GCLK_PCHCTRL_CHEN_Msk) != 0) + ? CLOCK_CONTROL_STATUS_ON + : CLOCK_CONTROL_STATUS_OFF; + break; + case SUBSYS_TYPE_MCLKCPU: + ret_status = CLOCK_CONTROL_STATUS_ON; + break; + case SUBSYS_TYPE_MCLKPERIPH: + reg32 = get_mclkbus_mask_reg(config->mclk_regs, subsys.bits.mclkbus); + mask = 1 << subsys.bits.mclkmaskbit; + ret_status = ((*reg32 & mask) != 0) ? CLOCK_CONTROL_STATUS_ON + : CLOCK_CONTROL_STATUS_OFF; + + break; + default: + break; + } + + } while (0); + + /* Return the status of the clock for the specified subsystem. */ + return ret_status; +} + +#if CONFIG_CLOCK_CONTROL_MCHP_GET_RATE +/** + * @brief Get the rate of the clock for a specified subsystem. + * + * This function retrieves the clock frequency (Hz) for the given subsystem. + * + * @param dev Pointer to clock device structure. + * @param sys The clock subsystem. + * @param frequency Pointer to store the retrieved clock rate. + * + * @return 0 if the rate is successfully retrieved. + * @return -ENOTSUP If the requested operation is not supported. + */ +static int clock_mchp_get_rate(const struct device *dev, clock_control_subsys_t sys, uint32_t *freq) +{ + int ret_val = CLOCK_SUCCESS; + const clock_mchp_config_t *config = dev->config; + clock_mchp_subsys_t subsys = {.val = (uint32_t)sys}; + uint8_t cpu_div; + uint32_t gclkgen_src_freq; + clock_mchp_gclkgen_t gclkperiph_src; + + do { + /* Validate subsystem. */ + if (CLOCK_SUCCESS != clock_check_subsys(subsys)) { + ret_val = -ENOTSUP; + break; + } + + /* Return rate as 0, if clock is not on */ + if (clock_mchp_get_status(dev, sys) != CLOCK_CONTROL_STATUS_ON) { + *freq = 0; + break; + } + + switch (subsys.bits.type) { + case SUBSYS_TYPE_GCLKPERIPH: + gclkperiph_src = (config->gclk_regs->GCLK_PCHCTRL[subsys.bits.gclkperiph] & + GCLK_PCHCTRL_GEN_Msk) >> + GCLK_PCHCTRL_GEN_Pos; + ret_val = clock_get_rate_gclkgen(dev, gclkperiph_src, + CLOCK_MCHP_GCLK_SRC_MAX + 1, freq); + break; + + case SUBSYS_TYPE_MCLKCPU: + case SUBSYS_TYPE_MCLKPERIPH: + /* source for mclk is always gclk0 */ + ret_val = clock_get_rate_gclkgen(dev, 0, CLOCK_MCHP_GCLK_SRC_MAX + 1, + &gclkgen_src_freq); + if (ret_val == CLOCK_SUCCESS) { + cpu_div = (config->mclk_regs->MCLK_CPUDIV & MCLK_CPUDIV_DIV_Msk) >> + MCLK_CPUDIV_DIV_Pos; + if (cpu_div != 0) { + *freq = gclkgen_src_freq / cpu_div; + } + } + break; + default: + ret_val = -ENOTSUP; + break; + } + + } while (0); + + return ret_val; +} + +#endif /* CONFIG_CLOCK_CONTROL_MCHP_GET_RATE */ + +/** + * @brief clock driver initialization function. + */ +static int clock_mchp_init(const struct device *dev) +{ + /* Return CLOCK_SUCCESS indicating successful initialization. */ + return CLOCK_SUCCESS; +} + +/****************************************************************************** + * @brief Zephyr driver instance creation + *****************************************************************************/ +static DEVICE_API(clock_control, clock_mchp_driver_api) = { + .on = clock_mchp_on, + .off = clock_mchp_off, + .get_status = clock_mchp_get_status, +#if CONFIG_CLOCK_CONTROL_MCHP_GET_RATE + .get_rate = clock_mchp_get_rate, +#endif /* CONFIG_CLOCK_CONTROL_MCHP_GET_RATE */ +}; + +#define CLOCK_MCHP_CONFIG_DEFN() \ + static const clock_mchp_config_t clock_mchp_config = { \ + .on_timeout_ms = DT_PROP_OR(CLOCK_NODE, on_timeout_ms, 5), \ + .mclk_regs = (mclk_registers_t *)DT_REG_ADDR_BY_NAME(CLOCK_NODE, mclk), \ + .oscctrl_regs = (oscctrl_registers_t *)DT_REG_ADDR_BY_NAME(CLOCK_NODE, oscctrl), \ + .osc32kctrl_regs = \ + (osc32kctrl_registers_t *)DT_REG_ADDR_BY_NAME(CLOCK_NODE, osc32kctrl), \ + .gclk_regs = (gclk_registers_t *)DT_REG_ADDR_BY_NAME(CLOCK_NODE, gclk)} + +#define CLOCK_MCHP_DATA_DEFN() static clock_mchp_data_t clock_mchp_data; + +#define CLOCK_MCHP_DEVICE_INIT(n) \ + CLOCK_MCHP_CONFIG_DEFN(); \ + CLOCK_MCHP_DATA_DEFN(); \ + DEVICE_DT_INST_DEFINE(n, clock_mchp_init, NULL, &clock_mchp_data, &clock_mchp_config, \ + PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \ + &clock_mchp_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(CLOCK_MCHP_DEVICE_INIT) diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 7346578e75d03..0c42011ddf8b4 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -23,6 +23,7 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_SAM0 pinctrl_sam0.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_SAM_PIO4 pinctrl_sam_pio4.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_STM32 pinctrl_stm32.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_NXP_PORT pinctrl_nxp_port.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_MCHP_PORT_G1 pinctrl_mchp_port_g1.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_MCHP_XEC pinctrl_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_IMX pinctrl_imx.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_SIFIVE pinctrl_sifive.c) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index e13c4e427ff71..28420beb29834 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -46,6 +46,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.mchp" source "drivers/pinctrl/Kconfig.mspm0" source "drivers/pinctrl/Kconfig.rpi_pico" source "drivers/pinctrl/Kconfig.sam" diff --git a/drivers/pinctrl/Kconfig.mchp b/drivers/pinctrl/Kconfig.mchp new file mode 100644 index 0000000000000..22334fde4c270 --- /dev/null +++ b/drivers/pinctrl/Kconfig.mchp @@ -0,0 +1,9 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_MCHP_PORT_G1 + bool "Microchip PORT G1 pin controller driver" + default y + depends on DT_HAS_MICROCHIP_PORT_G1_PINCTRL_ENABLED + help + This option enables PINCTRL driver for group (g1) of PORT peripherals. diff --git a/drivers/pinctrl/pinctrl_mchp_port_g1.c b/drivers/pinctrl/pinctrl_mchp_port_g1.c new file mode 100644 index 0000000000000..14357db5d3673 --- /dev/null +++ b/drivers/pinctrl/pinctrl_mchp_port_g1.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file pinctrl_mchp_port_g1.c + * @brief Pin control driver for Microchip devices. + * + * This file provides the implementation of pin control functions + * for Microchip-based systems. + */ + +#include +#include + +/** + * @brief Utility macro that expands to the PORT address if it exists. + * + * This macro checks if a node label exists in the device tree and, if it does, + * it expands to the register address of that node label. If the node label does + * not exist, it expands to nothing. + * + * @param nodelabel The node label to check in the device tree. + */ +/* clang-format off */ +#define MCHP_PORT_ADDR_OR_NONE(nodelabel) \ + IF_ENABLED(DT_NODE_EXISTS(DT_NODELABEL(nodelabel)), \ + (DT_REG_ADDR(DT_NODELABEL(nodelabel)))) +/* clang-format on */ + +/** + * @brief Array of port addresses for the MCHP SAMD5x_E5x series. + * + * This array contains the register addresses of the ports (PORTA, PORTB, PORTC, and PORTD) + * for the MCHP SAMD5x_E5x series microcontrollers. The addresses are obtained using the + * MCHP_PORT_ADDR_OR_NONE macro, which ensures that only existing ports are included. + * This can be updated for other devices using conditional comiplation directives + */ +static const uint32_t mchp_port_addrs[] = { + MCHP_PORT_ADDR_OR_NONE(porta), + MCHP_PORT_ADDR_OR_NONE(portb), + MCHP_PORT_ADDR_OR_NONE(portc), + MCHP_PORT_ADDR_OR_NONE(portd), +}; + +/** + * @brief Set pinmux registers using odd/even logic + * + * This function configures the pinmux registers for a given pin based on + * the provided pin control information. It determines whether the pin number + * is odd or even and sets the appropriate bits in the PORT_PMUX register. + * + * @param pin Pointer to the pin control information + * @param reg Pointer to the base address of the port group registers + */ +static void pinctrl_pinmux(const pinctrl_soc_pin_t *pin) +{ + port_group_registers_t *pRegister; + + uint8_t pin_num = MCHP_PINMUX_PIN_GET(pin->pinmux); + uint8_t port_id = MCHP_PINMUX_PORT_GET(pin->pinmux); + uint8_t pin_mux = MCHP_PINMUX_PERIPH_GET(pin->pinmux); + + bool is_odd = pin_num & 1; + uint32_t idx = pin_num / 2U; + + pRegister = (port_group_registers_t *)mchp_port_addrs[port_id]; + + if (pRegister != NULL) { + /* Each pinmux register holds the config for two pins. The + * even numbered pin goes in the bits 0..3 and the odd + * numbered pin in bits 4..7. + */ + if (is_odd == true) { + pRegister->PORT_PMUX[idx] |= PORT_PMUX_PMUXO(pin_mux); + } else { + pRegister->PORT_PMUX[idx] |= PORT_PMUX_PMUXE(pin_mux); + } + pRegister->PORT_PINCFG[pin_num] |= (uint8_t)PORT_PINCFG_PMUXEN_Msk; + } +} + +/** + * @brief Set all pin configuration registers by checking the flags + * + * This function configures various pin settings such as pull-up, pull-down, + * input enable, output enable, and drive strength based on the provided + * pin control information. + * + * @param pin Pointer to the pin control information + * @param reg Pointer to the base address of the port group registers + */ +static void pinctrl_set_flags(const pinctrl_soc_pin_t *pin) +{ + port_group_registers_t *pRegister; + + uint8_t pin_num = MCHP_PINMUX_PIN_GET(pin->pinmux); + uint8_t port_id = MCHP_PINMUX_PORT_GET(pin->pinmux); + + pRegister = (port_group_registers_t *)mchp_port_addrs[port_id]; + + if (pRegister != NULL) { + + /* Check if pull-up or pull-down resistors need to be configured */ + if (((pin->pinflag & MCHP_PINCTRL_PULLUP) != 0) || + ((pin->pinflag & MCHP_PINCTRL_PULLDOWN) != 0)) { + if ((pin->pinflag & MCHP_PINCTRL_PULLUP) != 0) { + /* If pull-up resistor enabled, + * set the corresponding bit in PORT_OUT reg + */ + pRegister->PORT_OUT |= (1 << pin_num); + } + pRegister->PORT_PINCFG[pin_num] |= PORT_PINCFG_PULLEN(1); + } else { + pRegister->PORT_PINCFG[pin_num] &= ~PORT_PINCFG_PULLEN(1); + } + + /* if input is enabled, set the corresponding bit in PORT_PINCFG register */ + if ((pin->pinflag & MCHP_PINCTRL_INPUTENABLE) != 0) { + pRegister->PORT_PINCFG[pin_num] |= PORT_PINCFG_INEN(1); + } else { + pRegister->PORT_PINCFG[pin_num] &= ~PORT_PINCFG_INEN(1); + } + + /* if output is enabled, set the corresponding bit in PORT_DIR register */ + if ((pin->pinflag & MCHP_PINCTRL_OUTPUTENABLE) != 0) { + pRegister->PORT_DIR |= (1 << pin_num); + } else { + pRegister->PORT_DIR &= ~(1 << pin_num); + } + + /* if drive strength is enabled, set the corresponding bit in PORT_PINCFG reg */ + if ((pin->pinflag & MCHP_PINCTRL_DRIVESTRENGTH) != 0) { + pRegister->PORT_PINCFG[pin_num] |= PORT_PINCFG_DRVSTR(1); + } else { + pRegister->PORT_PINCFG[pin_num] &= ~PORT_PINCFG_DRVSTR(1); + } + } +} + +/** + * @brief Configure a specific pin based on the provided pin configuration. + * + * This helper function configures a pin by determining its port function and then + * calling the appropriate functions to set the pinmux and other pin configurations. + * + * @param pin The pin configuration to be applied. This is of type pinctrl_soc_pin_t. + */ +static void pinctrl_configure_pin(pinctrl_soc_pin_t pin) +{ + uint8_t port_func = MCHP_PINMUX_FUNC_GET(pin.pinmux); + + /* call pinmux function if alternate function is configured */ + if (port_func == MCHP_PINMUX_FUNC_periph) { + pinctrl_pinmux(&pin); + } + + /* set all other pin configurations */ + pinctrl_set_flags(&pin); +} + +/** + * @brief Configure multiple pins. + * + * This function configures a set of pins based on the provided pin + * configuration array. + * + * @param pins Pointer to an array of pinctrl_soc_pin_t structures that + * define the pin configurations. + * @param pin_cnt Number of pins to configure. + * @param reg Unused parameter. + * + * @return 0 on success. + */ +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) +{ + ARG_UNUSED(reg); + + for (uint8_t i = 0U; i < pin_cnt; i++) { + pinctrl_configure_pin(*pins); + pins++; + } + + return 0; +} diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index d2e05081316d8..04f7f0a1e8845 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -47,6 +47,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_LITEX uart_litex.c) zephyr_library_sources_ifdef(CONFIG_UART_LPC11U6X uart_lpc11u6x.c) zephyr_library_sources_ifdef(CONFIG_UART_MAX32 uart_max32.c) zephyr_library_sources_ifdef(CONFIG_UART_MCHP_MEC5 uart_mchp_mec5.c) +zephyr_library_sources_ifdef(CONFIG_UART_MCHP_SERCOM_G1 uart_mchp_sercom_g1.c) zephyr_library_sources_ifdef(CONFIG_UART_MCUX uart_mcux.c) zephyr_library_sources_ifdef(CONFIG_UART_MCUX_FLEXCOMM uart_mcux_flexcomm.c) zephyr_library_sources_ifdef(CONFIG_UART_MCUX_IUART uart_mcux_iuart.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index ea3fbed123bac..7e3276f4dc22b 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -188,6 +188,7 @@ rsource "Kconfig.leuart_gecko" rsource "Kconfig.litex" rsource "Kconfig.lpc11u6x" rsource "Kconfig.max32" +rsource "Kconfig.mchp" rsource "Kconfig.mcux" rsource "Kconfig.mcux_flexcomm" rsource "Kconfig.mcux_iuart" diff --git a/drivers/serial/Kconfig.mchp b/drivers/serial/Kconfig.mchp new file mode 100644 index 0000000000000..f72b45ae0e5a3 --- /dev/null +++ b/drivers/serial/Kconfig.mchp @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config UART_MCHP_SERCOM_G1 + bool "Microchip SERCOM G1 UART driver" + default y + depends on DT_HAS_MICROCHIP_SERCOM_G1_UART_ENABLED + select SERIAL_HAS_DRIVER + select PINCTRL + help + This option enables UART driver for group (g1) of SERCOM peripherals. diff --git a/drivers/serial/uart_mchp_sercom_g1.c b/drivers/serial/uart_mchp_sercom_g1.c new file mode 100644 index 0000000000000..90f72e84d5ddb --- /dev/null +++ b/drivers/serial/uart_mchp_sercom_g1.c @@ -0,0 +1,763 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file uart_mchp_sercom_g1.c + * @brief UART driver implementation for Microchip devices. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/******************************************* + * Const and Macro Defines + ****************************************** + */ + +/* Define compatible string */ +#define DT_DRV_COMPAT microchip_sercom_g1_uart + +#define UART_SUCCESS 0 +#define BITSHIFT_FOR_BAUD_CALC 20 + +/* Do the peripheral clock related configuration */ + +/** + * @brief Clock configuration structure for the UART. + * + * This structure contains the clock configuration parameters for the UART + * peripheral. + */ +typedef struct mchp_uart_clock { + /* Clock driver */ + const struct device *clock_dev; + + /* Main clock subsystem. */ + clock_control_subsys_t mclk_sys; + + /* Generic clock subsystem. */ + clock_control_subsys_t gclk_sys; +} mchp_uart_clock_t; + +#define UART_MCHP_CLOCK_DEFN(n) \ + .uart_clock.clock_dev = DEVICE_DT_GET(DT_NODELABEL(clock)), \ + .uart_clock.mclk_sys = (void *)(DT_INST_CLOCKS_CELL_BY_NAME(n, mclk, subsystem)), \ + .uart_clock.gclk_sys = (void *)(DT_INST_CLOCKS_CELL_BY_NAME(n, gclk, subsystem)), + +/** + * @brief UART device constant configuration structure. + */ +typedef struct uart_mchp_dev_cfg { + /* Baud rate for UART communication */ + uint32_t baudrate; + uint8_t data_bits; + uint8_t parity; + uint8_t stop_bits; + + /* Pointer to the SERCOM registers. */ + sercom_registers_t *regs; + + /* Flag indicating if the clock is external. */ + bool clock_external; + + /* RX pinout configuration. */ + uint32_t rxpo; + + /* TX pinout configuration. */ + uint32_t txpo; + + /* Clock configuration */ + mchp_uart_clock_t uart_clock; + + /* Pin control configuration */ + const struct pinctrl_dev_config *pcfg; + +} uart_mchp_dev_cfg_t; + +/** + * @brief UART device runtime data structure. + */ +typedef struct uart_mchp_dev_data { + /* Cached UART configuration */ + struct uart_config config_cache; +} uart_mchp_dev_data_t; + +/** + * @brief Wait for synchronization of the UART. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + */ +static void uart_wait_sync(sercom_registers_t *regs, bool clock_external) +{ + if (clock_external == false) { + while ((regs->USART_INT.SERCOM_SYNCBUSY & SERCOM_USART_INT_SYNCBUSY_Msk) != 0) { + } + } else { + while ((regs->USART_EXT.SERCOM_SYNCBUSY & SERCOM_USART_EXT_SYNCBUSY_Msk) != 0) { + } + } +} + +/** + * @brief Disable UART interrupts. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + */ +static inline void uart_disable_interrupts(sercom_registers_t *regs, bool clock_external) +{ + if (clock_external == false) { + regs->USART_INT.SERCOM_INTENCLR = SERCOM_USART_INT_INTENCLR_Msk; + } else { + regs->USART_EXT.SERCOM_INTENCLR = SERCOM_USART_EXT_INTENCLR_Msk; + } +} + +/** + * @brief Configure the number of data bits for the UART. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + * @param count Number of data bits (5 to 9). + * @return 0 on success, -1 on invalid count. + */ +static int uart_config_data_bits(sercom_registers_t *regs, bool clock_external, unsigned int count) +{ + uint32_t value; + int retval = UART_SUCCESS; + + do { + if (clock_external == false) { + switch (count) { + case UART_CFG_DATA_BITS_5: + value = SERCOM_USART_INT_CTRLB_CHSIZE_5_BIT; + break; + case UART_CFG_DATA_BITS_6: + value = SERCOM_USART_INT_CTRLB_CHSIZE_6_BIT; + break; + case UART_CFG_DATA_BITS_7: + value = SERCOM_USART_INT_CTRLB_CHSIZE_7_BIT; + break; + case UART_CFG_DATA_BITS_8: + value = SERCOM_USART_INT_CTRLB_CHSIZE_8_BIT; + break; + case UART_CFG_DATA_BITS_9: + value = SERCOM_USART_INT_CTRLB_CHSIZE_9_BIT; + break; + default: + retval = -ENOTSUP; + } + } else { + switch (count) { + case UART_CFG_DATA_BITS_5: + value = SERCOM_USART_EXT_CTRLB_CHSIZE_5_BIT; + break; + case UART_CFG_DATA_BITS_6: + value = SERCOM_USART_EXT_CTRLB_CHSIZE_6_BIT; + break; + case UART_CFG_DATA_BITS_7: + value = SERCOM_USART_EXT_CTRLB_CHSIZE_7_BIT; + break; + case UART_CFG_DATA_BITS_8: + value = SERCOM_USART_EXT_CTRLB_CHSIZE_8_BIT; + break; + case UART_CFG_DATA_BITS_9: + value = SERCOM_USART_EXT_CTRLB_CHSIZE_9_BIT; + break; + default: + retval = -ENOTSUP; + } + } + if (retval != UART_SUCCESS) { + break; + } + + /* Writing to the CTRLB register requires synchronization */ + if (clock_external == false) { + regs->USART_INT.SERCOM_CTRLB &= ~SERCOM_USART_INT_CTRLB_CHSIZE_Msk; + regs->USART_INT.SERCOM_CTRLB |= value; + } else { + regs->USART_EXT.SERCOM_CTRLB &= ~SERCOM_USART_EXT_CTRLB_CHSIZE_Msk; + regs->USART_EXT.SERCOM_CTRLB |= value; + } + uart_wait_sync(regs, clock_external); + } while (0); + + return retval; +} + +/** + * @brief Configure the parity mode for the UART. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + * @param parity Parity mode to configure. + */ +static void uart_config_parity(sercom_registers_t *regs, bool clock_external, + enum uart_config_parity parity) +{ + if (clock_external == false) { + regs->USART_INT.SERCOM_CTRLA &= ~SERCOM_USART_INT_CTRLA_FORM_Msk; + switch (parity) { + case UART_CFG_PARITY_ODD: { + regs->USART_INT.SERCOM_CTRLA |= + SERCOM_USART_INT_CTRLA_FORM_USART_FRAME_WITH_PARITY; + + /* Writing to the CTRLB register requires synchronization */ + regs->USART_INT.SERCOM_CTRLB |= SERCOM_USART_INT_CTRLB_PMODE_Msk; + uart_wait_sync(regs, clock_external); + break; + } + case UART_CFG_PARITY_EVEN: { + regs->USART_INT.SERCOM_CTRLA |= + SERCOM_USART_INT_CTRLA_FORM_USART_FRAME_WITH_PARITY; + + /* Writing to the CTRLB register requires synchronization */ + regs->USART_INT.SERCOM_CTRLB &= ~SERCOM_USART_INT_CTRLB_PMODE_Msk; + uart_wait_sync(regs, clock_external); + break; + } + default: { + regs->USART_INT.SERCOM_CTRLA |= + SERCOM_USART_INT_CTRLA_FORM_USART_FRAME_NO_PARITY; + break; + } + } + } else { + regs->USART_EXT.SERCOM_CTRLA &= ~SERCOM_USART_EXT_CTRLA_FORM_Msk; + switch (parity) { + case UART_CFG_PARITY_ODD: { + regs->USART_EXT.SERCOM_CTRLA |= + SERCOM_USART_EXT_CTRLA_FORM_USART_FRAME_WITH_PARITY; + + /* Writing to the CTRLB register requires synchronization */ + regs->USART_EXT.SERCOM_CTRLB |= SERCOM_USART_EXT_CTRLB_PMODE_Msk; + uart_wait_sync(regs, clock_external); + break; + } + case UART_CFG_PARITY_EVEN: { + regs->USART_EXT.SERCOM_CTRLA |= + SERCOM_USART_EXT_CTRLA_FORM_USART_FRAME_WITH_PARITY; + + /* Writing to the CTRLB register requires synchronization */ + regs->USART_EXT.SERCOM_CTRLB &= ~SERCOM_USART_EXT_CTRLB_PMODE_Msk; + uart_wait_sync(regs, clock_external); + break; + } + default: { + regs->USART_EXT.SERCOM_CTRLA |= + SERCOM_USART_EXT_CTRLA_FORM_USART_FRAME_NO_PARITY; + break; + } + } + } +} + +/** + * @brief Configure the number of stop bits for the UART. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + * @param count Number of stop bits (1 or 2). + * @return 0 on success, -1 on invalid count. + */ +static int uart_config_stop_bits(sercom_registers_t *regs, bool clock_external, unsigned int count) +{ + int retval = UART_SUCCESS; + + do { + if (clock_external == false) { + if (count == UART_CFG_STOP_BITS_1) { + regs->USART_INT.SERCOM_CTRLB &= ~SERCOM_USART_INT_CTRLB_SBMODE_Msk; + } else if (count == UART_CFG_STOP_BITS_2) { + regs->USART_INT.SERCOM_CTRLB |= SERCOM_USART_INT_CTRLB_SBMODE_Msk; + } else { + retval = -ENOTSUP; + break; + } + } else { + if (count == UART_CFG_STOP_BITS_1) { + regs->USART_EXT.SERCOM_CTRLB &= ~SERCOM_USART_EXT_CTRLB_SBMODE_Msk; + } else if (count == UART_CFG_STOP_BITS_2) { + regs->USART_EXT.SERCOM_CTRLB |= SERCOM_USART_EXT_CTRLB_SBMODE_Msk; + } else { + retval = -ENOTSUP; + break; + } + } + uart_wait_sync(regs, clock_external); + } while (0); + + return retval; +} + +/** + * @brief Configure the UART pinout. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + */ +static void uart_config_pinout(const uart_mchp_dev_cfg_t *const cfg) +{ + uint32_t reg_value; + + sercom_registers_t *regs = cfg->regs; + uint32_t rxpo = cfg->rxpo; + uint32_t txpo = cfg->txpo; + + if (cfg->clock_external == false) { + reg_value = regs->USART_INT.SERCOM_CTRLA; + reg_value &= ~(SERCOM_USART_INT_CTRLA_RXPO_Msk | SERCOM_USART_INT_CTRLA_TXPO_Msk); + reg_value |= + (SERCOM_USART_INT_CTRLA_RXPO(rxpo) | SERCOM_USART_INT_CTRLA_TXPO(txpo)); + cfg->regs->USART_INT.SERCOM_CTRLA = reg_value; + } else { + reg_value = regs->USART_EXT.SERCOM_CTRLA; + reg_value &= ~(SERCOM_USART_EXT_CTRLA_RXPO_Msk | SERCOM_USART_EXT_CTRLA_TXPO_Msk); + reg_value |= + (SERCOM_USART_EXT_CTRLA_RXPO(rxpo) | SERCOM_USART_EXT_CTRLA_TXPO(txpo)); + regs->USART_EXT.SERCOM_CTRLA = reg_value; + } +} + +/** + * @brief Set clock polarity for UART. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + * @param tx_rising transmit on rising edge + */ +static void uart_set_clock_polarity(sercom_registers_t *regs, bool clock_external, bool tx_rising) +{ + if (clock_external == false) { + if (tx_rising == true) { + regs->USART_INT.SERCOM_CTRLA &= ~SERCOM_USART_INT_CTRLA_CPOL_Msk; + } else { + regs->USART_INT.SERCOM_CTRLA |= SERCOM_USART_INT_CTRLA_CPOL_Msk; + } + } else { + if (tx_rising == true) { + regs->USART_EXT.SERCOM_CTRLA &= ~SERCOM_USART_EXT_CTRLA_CPOL_Msk; + } else { + regs->USART_EXT.SERCOM_CTRLA |= SERCOM_USART_EXT_CTRLA_CPOL_Msk; + } + } +} + +/** + * @brief Set the clock source for the UART. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + */ +static void uart_set_clock_source(sercom_registers_t *regs, bool clock_external) +{ + uint32_t reg_value; + + reg_value = regs->USART_INT.SERCOM_CTRLA; + reg_value &= ~SERCOM_USART_INT_CTRLA_MODE_Msk; + + if (clock_external == true) { + regs->USART_INT.SERCOM_CTRLA = + reg_value | SERCOM_USART_INT_CTRLA_MODE_USART_EXT_CLK; + } else { + regs->USART_INT.SERCOM_CTRLA = + reg_value | SERCOM_USART_INT_CTRLA_MODE_USART_INT_CLK; + } +} + +/** + * @brief Set the data order for the UART. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + * @param lsb_first Boolean to set the data order. + */ +static void uart_set_lsb_first(sercom_registers_t *regs, bool clock_external, bool lsb_first) +{ + if (clock_external == false) { + if (lsb_first == true) { + regs->USART_INT.SERCOM_CTRLA |= SERCOM_USART_INT_CTRLA_DORD_Msk; + } else { + regs->USART_INT.SERCOM_CTRLA &= ~SERCOM_USART_INT_CTRLA_DORD_Msk; + } + } else { + if (lsb_first == true) { + regs->USART_EXT.SERCOM_CTRLA |= SERCOM_USART_EXT_CTRLA_DORD_Msk; + } else { + regs->USART_EXT.SERCOM_CTRLA &= ~SERCOM_USART_EXT_CTRLA_DORD_Msk; + } + } +} + +/** + * @brief Enable or disable the UART receiver. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + * @param enable Boolean to enable or disable the receiver. + */ +static void uart_rx_on_off(sercom_registers_t *regs, bool clock_external, bool enable) +{ + if (clock_external == false) { + if (enable == true) { + regs->USART_INT.SERCOM_CTRLB |= SERCOM_USART_INT_CTRLB_RXEN_Msk; + } else { + regs->USART_INT.SERCOM_CTRLB &= ~SERCOM_USART_INT_CTRLB_RXEN_Msk; + } + } else { + if (enable == true) { + regs->USART_EXT.SERCOM_CTRLB |= SERCOM_USART_EXT_CTRLB_RXEN_Msk; + } else { + regs->USART_EXT.SERCOM_CTRLB &= ~SERCOM_USART_EXT_CTRLB_RXEN_Msk; + } + } + + /* Writing to the CTRLB register requires synchronization */ + uart_wait_sync(regs, clock_external); +} + +/** + * @brief Enable or disable the UART transmitter. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + * @param enable Boolean to enable or disable the transmitter. + */ +static void uart_tx_on_off(sercom_registers_t *regs, bool clock_external, bool enable) +{ + if (clock_external == false) { + if (enable == true) { + regs->USART_INT.SERCOM_CTRLB |= SERCOM_USART_INT_CTRLB_TXEN_Msk; + } else { + regs->USART_INT.SERCOM_CTRLB &= ~SERCOM_USART_INT_CTRLB_TXEN_Msk; + } + } else { + if (enable == true) { + regs->USART_EXT.SERCOM_CTRLB |= SERCOM_USART_EXT_CTRLB_TXEN_Msk; + } else { + regs->USART_EXT.SERCOM_CTRLB &= ~SERCOM_USART_EXT_CTRLB_TXEN_Msk; + } + } + + /* Writing to the CTRLB register requires synchronization */ + uart_wait_sync(regs, clock_external); +} + +/** + * @brief Set the UART baud rate. + * + * This function sets the baud rate for the specified UART instance. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + * @param baudrate Desired baud rate. + * @param clk_freq_hz Clock frequency in Hz. + * @return 0 on success, -ERANGE if the calculated baud rate is out of range. + */ +static int uart_set_baudrate(sercom_registers_t *regs, bool clock_external, uint32_t baudrate, + uint32_t clk_freq_hz) +{ + uint64_t tmp; + uint16_t baud; + + int retval = UART_SUCCESS; + + do { + if (clk_freq_hz == 0) { + retval = -EINVAL; + break; + } + tmp = (uint64_t)baudrate << BITSHIFT_FOR_BAUD_CALC; + tmp = (tmp + (clk_freq_hz >> 1)) / clk_freq_hz; + + /* Verify that the calculated result is within range */ + if ((tmp < 1) || (tmp > UINT16_MAX)) { + retval = -ERANGE; + break; + } + + baud = (UINT16_MAX + 1) - (uint16_t)tmp; + + if (clock_external == false) { + regs->USART_INT.SERCOM_CTRLA &= ~SERCOM_USART_INT_CTRLA_SAMPR_Msk; + regs->USART_INT.SERCOM_BAUD = baud; + } else { + regs->USART_EXT.SERCOM_CTRLA &= ~SERCOM_USART_EXT_CTRLA_SAMPR_Msk; + regs->USART_EXT.SERCOM_BAUD = baud; + } + } while (0); + + return retval; +} + +/** + * @brief Enable or disable the UART. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + * @param enable Boolean to enable or disable the UART. + */ +static void uart_enable(sercom_registers_t *regs, bool clock_external, bool enable) +{ + if (clock_external == false) { + if (enable == true) { + regs->USART_INT.SERCOM_CTRLA |= SERCOM_USART_INT_CTRLA_RUNSTDBY_Msk; + regs->USART_INT.SERCOM_CTRLA |= SERCOM_USART_INT_CTRLA_ENABLE_Msk; + } else { + regs->USART_INT.SERCOM_CTRLA &= ~SERCOM_USART_INT_CTRLA_ENABLE_Msk; + } + } else { + if (enable == true) { + regs->USART_EXT.SERCOM_CTRLA |= SERCOM_USART_EXT_CTRLA_RUNSTDBY_Msk; + regs->USART_EXT.SERCOM_CTRLA |= SERCOM_USART_EXT_CTRLA_ENABLE_Msk; + } else { + regs->USART_EXT.SERCOM_CTRLA &= ~SERCOM_USART_EXT_CTRLA_ENABLE_Msk; + } + } + + /* Enabling and disabling the SERCOM (CTRLA.ENABLE) requires synchronization */ + uart_wait_sync(regs, clock_external); +} + +/** + * @brief Check if the UART receive is complete. + * + * This function checks if the receive operation is complete for the specified UART instance. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + * @return True if receive is complete, false otherwise. + */ +static inline bool uart_is_rx_complete(sercom_registers_t *regs, bool clock_external) +{ + bool retval; + + if (clock_external == false) { + retval = ((regs->USART_INT.SERCOM_INTFLAG & SERCOM_USART_INT_INTFLAG_RXC_Msk) != 0); + } else { + retval = ((regs->USART_EXT.SERCOM_INTFLAG & SERCOM_USART_EXT_INTFLAG_RXC_Msk) != 0); + } + + return retval; +} + +/** + * @brief Get the received character from the UART. + * + * This function retrieves the received character from the specified UART instance. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + * @return The received character. + */ +static inline unsigned char uart_get_received_char(sercom_registers_t *regs, bool clock_external) +{ + unsigned char retval; + + if (clock_external == false) { + retval = (unsigned char)regs->USART_INT.SERCOM_DATA; + } else { + retval = (unsigned char)regs->USART_EXT.SERCOM_DATA; + } + + return retval; +} + +/** + * @brief Check if the UART TX is ready. + * + * This function checks if the TX operation is ready for the specified UART instance. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + * @return True if TX is ready, false otherwise. + */ +static inline bool uart_is_tx_ready(sercom_registers_t *regs, bool clock_external) +{ + bool retval; + + if (clock_external == false) { + retval = ((regs->USART_INT.SERCOM_INTFLAG & SERCOM_USART_INT_INTFLAG_DRE_Msk) != 0); + } else { + retval = ((regs->USART_EXT.SERCOM_INTFLAG & SERCOM_USART_EXT_INTFLAG_DRE_Msk) != 0); + } + + return retval; +} + +/** + * @brief Transmit a character via UART. + * + * This function transmits a character via the specified UART instance. + * + * @param regs Pointer to the sercom_registers_t structure. + * @param clock_external Boolean to check external or internal clock + * @param data The character to transmit. + */ +static inline void uart_tx_char(sercom_registers_t *regs, bool clock_external, unsigned char data) +{ + if (clock_external == false) { + regs->USART_INT.SERCOM_DATA = data; + } else { + regs->USART_EXT.SERCOM_DATA = data; + } +} + +/** + * @brief Initialize the UART device. + * + * @param dev Device structure. + * @return 0 on success, negative error code on failure. + */ +static int uart_mchp_init(const struct device *dev) +{ + const uart_mchp_dev_cfg_t *const cfg = dev->config; + uart_mchp_dev_data_t *const dev_data = dev->data; + sercom_registers_t *regs = cfg->regs; + bool clock_external = cfg->clock_external; + int retval = UART_SUCCESS; + + do { + /* Enable the GCLK and MCLK*/ + retval = clock_control_on(cfg->uart_clock.clock_dev, cfg->uart_clock.gclk_sys); + if ((retval != UART_SUCCESS) && (retval != -EALREADY)) { + break; + } + retval = clock_control_on(cfg->uart_clock.clock_dev, cfg->uart_clock.mclk_sys); + if ((retval != UART_SUCCESS) && (retval != -EALREADY)) { + break; + } + + uart_disable_interrupts(regs, clock_external); + + dev_data->config_cache.flow_ctrl = UART_CFG_FLOW_CTRL_NONE; + + retval = uart_config_data_bits(regs, clock_external, cfg->data_bits); + if (retval != UART_SUCCESS) { + break; + } + dev_data->config_cache.data_bits = cfg->data_bits; + + uart_config_parity(regs, clock_external, cfg->parity); + dev_data->config_cache.parity = cfg->parity; + + retval = uart_config_stop_bits(regs, clock_external, cfg->stop_bits); + if (retval != UART_SUCCESS) { + break; + } + dev_data->config_cache.stop_bits = cfg->stop_bits; + + uart_config_pinout(cfg); + uart_set_clock_polarity(regs, clock_external, false); + uart_set_clock_source(regs, clock_external); + uart_set_lsb_first(regs, clock_external, true); + + /* Enable PINMUX based on PINCTRL */ + retval = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (retval != UART_SUCCESS) { + break; + } + + /* Enable receiver and transmitter */ + uart_rx_on_off(regs, clock_external, true); + uart_tx_on_off(regs, clock_external, true); + + uint32_t clock_rate; + + clock_control_get_rate(cfg->uart_clock.clock_dev, cfg->uart_clock.gclk_sys, + &clock_rate); + + retval = uart_set_baudrate(regs, clock_external, cfg->baudrate, clock_rate); + if (retval != UART_SUCCESS) { + break; + } + dev_data->config_cache.baudrate = cfg->baudrate; + + uart_enable(regs, clock_external, true); + } while (0); + + return retval; +} + +/** + * @brief Poll the UART device for input. + * + * @param dev Device structure. + * @param data Pointer to store the received data. + * @return 0 on success, negative error code on failure. + */ +static int uart_mchp_poll_in(const struct device *dev, unsigned char *data) +{ + const uart_mchp_dev_cfg_t *const cfg = dev->config; + sercom_registers_t *regs = cfg->regs; + bool clock_external = cfg->clock_external; + int retval = UART_SUCCESS; + + if (uart_is_rx_complete(regs, clock_external) == false) { + retval = -EBUSY; + } else { + *data = uart_get_received_char(regs, clock_external); + } + + return retval; +} + +/** + * @brief Output a character via UART. + * + * @param dev Device structure. + * @param data Character to send. + */ +static void uart_mchp_poll_out(const struct device *dev, unsigned char data) +{ + const uart_mchp_dev_cfg_t *const cfg = dev->config; + sercom_registers_t *regs = cfg->regs; + bool clock_external = cfg->clock_external; + + while (uart_is_tx_ready(regs, clock_external) == false) { + } + + /* send a character */ + uart_tx_char(regs, clock_external, data); +} + +static DEVICE_API(uart, uart_mchp_driver_api) = { + .poll_in = uart_mchp_poll_in, + .poll_out = uart_mchp_poll_out, +}; + +#define UART_MCHP_CONFIG_DEFN(n) \ + static const uart_mchp_dev_cfg_t uart_mchp_config_##n = { \ + .baudrate = DT_INST_PROP(n, current_speed), \ + .data_bits = DT_INST_ENUM_IDX_OR(n, data_bits, UART_CFG_DATA_BITS_8), \ + .parity = DT_INST_ENUM_IDX_OR(n, parity, UART_CFG_PARITY_NONE), \ + .stop_bits = DT_INST_ENUM_IDX_OR(n, stop_bits, UART_CFG_STOP_BITS_1), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .regs = (sercom_registers_t *)DT_INST_REG_ADDR(n), \ + .rxpo = (DT_INST_PROP(n, rxpo)), \ + .txpo = (DT_INST_PROP(n, txpo)), \ + .clock_external = DT_INST_PROP(n, clock_external), \ + UART_MCHP_CLOCK_DEFN(n)} + +#define UART_MCHP_DEVICE_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + UART_MCHP_CONFIG_DEFN(n); \ + static uart_mchp_dev_data_t uart_mchp_data_##n; \ + DEVICE_DT_INST_DEFINE(n, uart_mchp_init, NULL, &uart_mchp_data_##n, &uart_mchp_config_##n, \ + PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, &uart_mchp_driver_api) + +DT_INST_FOREACH_STATUS_OKAY(UART_MCHP_DEVICE_INIT) diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51g18a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51g18a.dtsi new file mode 100644 index 0000000000000..6af44b4bfb511 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51g18a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51g19a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51g19a.dtsi new file mode 100644 index 0000000000000..74bee592b56d8 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51g19a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51j18a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51j18a.dtsi new file mode 100644 index 0000000000000..6af44b4bfb511 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51j18a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51j19a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51j19a.dtsi new file mode 100644 index 0000000000000..74bee592b56d8 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51j19a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51j20a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51j20a.dtsi new file mode 100644 index 0000000000000..75c8389a1bf0b --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51j20a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51n19a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51n19a.dtsi new file mode 100644 index 0000000000000..74bee592b56d8 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51n19a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51n20a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51n20a.dtsi new file mode 100644 index 0000000000000..75c8389a1bf0b --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51n20a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51p19a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51p19a.dtsi new file mode 100644 index 0000000000000..74bee592b56d8 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51p19a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51p20a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51p20a.dtsi new file mode 100644 index 0000000000000..75c8389a1bf0b --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsamd51/atsamd51p20a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51g18a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51g18a.dtsi new file mode 100644 index 0000000000000..6af44b4bfb511 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51g18a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51g19a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51g19a.dtsi new file mode 100644 index 0000000000000..74bee592b56d8 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51g19a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51j18a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51j18a.dtsi new file mode 100644 index 0000000000000..6af44b4bfb511 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51j18a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51j19a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51j19a.dtsi new file mode 100644 index 0000000000000..74bee592b56d8 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51j19a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51j20a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51j20a.dtsi new file mode 100644 index 0000000000000..75c8389a1bf0b --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51j20a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51n19a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51n19a.dtsi new file mode 100644 index 0000000000000..74bee592b56d8 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51n19a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51n20a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51n20a.dtsi new file mode 100644 index 0000000000000..75c8389a1bf0b --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsame51/atsame51n20a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsame53/atsame53j18a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsame53/atsame53j18a.dtsi new file mode 100644 index 0000000000000..6af44b4bfb511 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsame53/atsame53j18a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsame53/atsame53j19a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsame53/atsame53j19a.dtsi new file mode 100644 index 0000000000000..74bee592b56d8 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsame53/atsame53j19a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsame53/atsame53j20a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsame53/atsame53j20a.dtsi new file mode 100644 index 0000000000000..75c8389a1bf0b --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsame53/atsame53j20a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsame53/atsame53n19a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsame53/atsame53n19a.dtsi new file mode 100644 index 0000000000000..74bee592b56d8 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsame53/atsame53n19a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsame53/atsame53n20a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsame53/atsame53n20a.dtsi new file mode 100644 index 0000000000000..75c8389a1bf0b --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsame53/atsame53n20a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsame54/atsame54n19a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsame54/atsame54n19a.dtsi new file mode 100644 index 0000000000000..74bee592b56d8 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsame54/atsame54n19a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsame54/atsame54n20a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsame54/atsame54n20a.dtsi new file mode 100644 index 0000000000000..75c8389a1bf0b --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsame54/atsame54n20a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsame54/atsame54p19a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsame54/atsame54p19a.dtsi new file mode 100644 index 0000000000000..74bee592b56d8 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsame54/atsame54p19a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/atsame54/atsame54p20a.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/atsame54/atsame54p20a.dtsi new file mode 100644 index 0000000000000..75c8389a1bf0b --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/atsame54/atsame54p20a.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x.dtsi new file mode 100644 index 0000000000000..d799321d5be4e --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x.dtsi @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-m4f"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + + mpu: mpu@e000ed90 { + compatible = "arm,armv7m-mpu"; + reg = <0xe000ed90 0x2c>; + }; + }; + }; + + soc { + flash0: flash@0 { + compatible = "soc-nv-flash"; + write-block-size = <8>; + }; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + }; + + clock: clock@40000800 { + compatible = "microchip,sam-d5x-e5x-clock"; + reg = <0x40000800 0x24>, <0x40001000 0x58>, + <0x40001400 0x20>, <0x40001c00 0x140>; + reg-names = "mclk", "oscctrl", + "osc32kctrl", "gclk"; + + gclkperiph: gclkperiph { + compatible = "microchip,sam-d5x-e5x-gclkperiph"; + #clock-cells = <1>; + }; + + mclkperiph: mclkperiph { + compatible = "microchip,sam-d5x-e5x-mclkperiph"; + #clock-cells = <1>; + }; + }; + + sercom0: sercom@40003000 { + compatible = "microchip,sercom-g1"; + status = "disabled"; + reg = <0x40003000 0x31>; + interrupts = <46 0>, <47 0>, <48 0>, <49 0>; + clocks = <&mclkperiph CLOCK_MCHP_MCLKPERIPH_ID_APBA_SERCOM0>, + <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_SERCOM0_CORE>; + clock-names = "mclk", "gclk"; + }; + + sercom1: sercom@40003400 { + compatible = "microchip,sercom-g1"; + status = "disabled"; + reg = <0x40003400 0x31>; + interrupts = <50 0>, <51 0>, <52 0>, <53 0>; + clocks = <&mclkperiph CLOCK_MCHP_MCLKPERIPH_ID_APBA_SERCOM1>, + <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_SERCOM1_CORE>; + clock-names = "mclk", "gclk"; + }; + + pinctrl: pinctrl@41008000 { + compatible = "microchip,port-g1-pinctrl"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x41008000 0x41008000 0x200>; + + porta: gpio@41008000 { + reg = <0x41008000 0x80>; + }; + + portb: gpio@41008080 { + reg = <0x41008080 0x80>; + }; + + portc: gpio@41008100 { + reg = <0x41008100 0x80>; + }; + + portd: gpio@41008180 { + reg = <0x41008180 0x80>; + }; + }; + + sercom2: sercom@41012000 { + compatible = "microchip,sercom-g1"; + status = "disabled"; + reg = <0x41012000 0x31>; + interrupts = <54 0>, <55 0>, <56 0>, <57 0>; + clocks = <&mclkperiph CLOCK_MCHP_MCLKPERIPH_ID_APBB_SERCOM2>, + <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_SERCOM2_CORE>; + clock-names = "mclk", "gclk"; + }; + + sercom3: sercom@41014000 { + compatible = "microchip,sercom-g1"; + status = "disabled"; + reg = <0x41014000 0x31>; + interrupts = <58 0>, <59 0>, <60 0>, <61 0>; + clocks = <&mclkperiph CLOCK_MCHP_MCLKPERIPH_ID_APBB_SERCOM3>, + <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_SERCOM3_CORE>; + clock-names = "mclk", "gclk"; + }; + + sercom4: sercom@43000000 { + compatible = "microchip,sercom-g1"; + status = "disabled"; + reg = <0x43000000 0x31>; + interrupts = <62 0>, <63 0>, <64 0>, <65 0>; + clocks = <&mclkperiph CLOCK_MCHP_MCLKPERIPH_ID_APBD_SERCOM4>, + <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_SERCOM4_CORE>; + clock-names = "mclk", "gclk"; + }; + + sercom5: sercom@43000400 { + compatible = "microchip,sercom-g1"; + status = "disabled"; + reg = <0x43000400 0x31>; + interrupts = <66 0>, <67 0>, <68 0>, <69 0>; + clocks = <&mclkperiph CLOCK_MCHP_MCLKPERIPH_ID_APBD_SERCOM5>, + <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_SERCOM5_CORE>; + clock-names = "mclk", "gclk"; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <3>; +}; diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_18.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_18.dtsi new file mode 100644 index 0000000000000..47eaed3e6a44b --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_18.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + soc { + flash0: flash@0 { + reg = <0x0 DT_SIZE_K(256)>; + }; + + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(128)>; + }; + }; +}; diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_19.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_19.dtsi new file mode 100644 index 0000000000000..ee586debb0339 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_19.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + soc { + flash0: flash@0 { + reg = <0x0 DT_SIZE_K(512)>; + }; + + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(192)>; + }; + }; +}; diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_20.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_20.dtsi new file mode 100644 index 0000000000000..d3cb3e7a8bb9f --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_20.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + soc { + flash0: flash@0 { + reg = <0x0 DT_SIZE_K(1024)>; + }; + + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(256)>; + }; + }; +}; diff --git a/dts/bindings/arm/microchip,sercom-g1.yaml b/dts/bindings/arm/microchip,sercom-g1.yaml new file mode 100644 index 0000000000000..2d8cb4acb9457 --- /dev/null +++ b/dts/bindings/arm/microchip,sercom-g1.yaml @@ -0,0 +1,21 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: Microchip SERCOM (Serial Communication) module + +description: | + Microchip SERCOM multi-protocol (UART, SPI, I2C) SERCOM unit, group g1 + +compatible: "microchip,sercom-g1" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + clocks: + required: true diff --git a/dts/bindings/clock/microchip,sam-d5x-e5x-clock.yaml b/dts/bindings/clock/microchip,sam-d5x-e5x-clock.yaml new file mode 100644 index 0000000000000..90815c95949f7 --- /dev/null +++ b/dts/bindings/clock/microchip,sam-d5x-e5x-clock.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: Microchip SAM_D5x_E5x SOC family clock + +description: | + Microchip SAM_D5x_E5x SOC family clock (OSCCTRL, OSC32KCTRL, GCLK, MCLK) + +include: + - name: base.yaml + - name: pinctrl-device.yaml + +compatible: "microchip,sam-d5x-e5x-clock" + +properties: + on-timeout-ms: + type: int + default: 5 + description: | + Timeout in milliseconds for clock to be on. + + Driver waits in clock on API to check if the clock is actually on, + so that the waiting time is not indefinite. diff --git a/dts/bindings/clock/microchip,sam-d5x-e5x-gclkperiph.yaml b/dts/bindings/clock/microchip,sam-d5x-e5x-gclkperiph.yaml new file mode 100644 index 0000000000000..c66569a9c5e99 --- /dev/null +++ b/dts/bindings/clock/microchip,sam-d5x-e5x-gclkperiph.yaml @@ -0,0 +1,26 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: Microchip GCLK (Generic Clock) peripheral + +description: | + peripheral channel gclk clock configuration. + +include: [base.yaml] + +compatible: "microchip,sam-d5x-e5x-gclkperiph" + +properties: + "#clock-cells": + const: 1 + type: int + description: | + The subsystem cell is to identify a clock controller sub-system. + + The subsystem can be referred from include\zephyr\dt-bindings\clock\mchp_sam_d5x_e5x_clock.h, + under the GCLKPERIPH_TYPE section of ids. + All clock control API use this value to specify the clock on which the API operates. + Since subsystem is opaque to the user, it can be accessed from the devicetree node and used. + +clock-cells: + - subsystem diff --git a/dts/bindings/clock/microchip,sam-d5x-e5x-mclkperiph.yaml b/dts/bindings/clock/microchip,sam-d5x-e5x-mclkperiph.yaml new file mode 100644 index 0000000000000..4385bb85044e8 --- /dev/null +++ b/dts/bindings/clock/microchip,sam-d5x-e5x-mclkperiph.yaml @@ -0,0 +1,26 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: Microchip MCLK (Main Clock) peripheral + +description: | + Main Clock (MCLK) configuration for peripheral AHB and APB clocks. + +include: [base.yaml] + +compatible: "microchip,sam-d5x-e5x-mclkperiph" + +properties: + "#clock-cells": + const: 1 + type: int + description: | + The subsystem cell is to identify a clock controller sub-system. + + The subsystem can be referred from include\zephyr\dt-bindings\clock\mchp_sam_d5x_e5x_clock.h, + under the MCLKPERIPH_TYPE section of ids. + All clock control API use this value to specify the clock on which the API operates. + Since subsystem is opaque to the user, it can be accessed from the devicetree node and used. + +clock-cells: + - subsystem diff --git a/dts/bindings/pinctrl/microchip,port-g1-pinctrl.yaml b/dts/bindings/pinctrl/microchip,port-g1-pinctrl.yaml new file mode 100644 index 0000000000000..634bab9fb8626 --- /dev/null +++ b/dts/bindings/pinctrl/microchip,port-g1-pinctrl.yaml @@ -0,0 +1,126 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: Microchip PORT Pinctrl container node + +description: | + Microchip port-g1 Pinctrl container node + + The Microchip port-g1 pin controller is a singleton node responsible for controlling + pin function selection and pin properties. For example, you can use this node + to route SERCOM0 as UART were RX to pin PAD1 and enable the pull-up resistor + on the pin. + + Group g1 PORT PINCTRL driver supports following hardware peripherals: + - module name="PORT" id="U2210" version="2.2.0" + + 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 shown in this example: + + /** You can put this in places like a -pinctrl.dtsi file in + * your board directory, or a devicetree overlay in your application. + */ + + /** include pre-defined combinations for the SoC variant used by the board */ + #include + + &pinctrl { + /* configuration for the usart0 "default" state */ + sercom0_uart_default: sercom0_uart_default { + /* group 1 */ + group1 { + /* configure PA6 as USART0 TX and PA8 as USART0 CTS */ + pinmux = , ; + }; + /* group 2 */ + group2 { + /* configure PA5 as USART0 RX and PA7 as USART0 RTS */ + pinmux = , ; + /* both PA5 and PA7 have pull-up enabled */ + bias-pull-up; + }; + }; + }; + + The 'usart0_default' child node encodes the pin configurations for a + particular state of a device; in this case, the default (that is, active) + state. + + As shown, pin configurations are organized in groups within each child node. + Each group can specify a list of pin function selections in the 'pinmux' + property. + + A group can also specify shared pin properties common to all the specified + pins, such as the 'bias-pull-up' property in group 2. Here is a list of + supported standard pin properties: + + - bias-pull-up: Enable pull-up resistor. + - bias-pull-down: Enable pull-down resistor. + - drive-strength: Increase sink current. + - input-enable: Enable input on pin. + - output-enable: Enable output on a pin without actively driving it. + + To link pin configurations with a device, use a pinctrl-N property for some + number N, like this example you could place in your board's DTS file: + + #include "board-pinctrl.dtsi" + + &usart0 { + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; + }; + +compatible: "microchip,port-g1-pinctrl" + +include: base.yaml + +properties: + "#address-cells": + required: true + const: 1 + "#size-cells": + required: true + const: 1 + +child-binding: + description: | + Each child node defines the configuration for a particular state. + child-binding: + description: | + The grandchild nodes group pins that share the same pin configuration. + + include: + - name: pincfg-node.yaml + property-allowlist: + - bias-pull-up + - bias-pull-down + - drive-strength + - input-enable + - output-enable + + properties: + pinmux: + required: true + type: array + description: | + An array of pins sharing the same group properties. The pins should + be defined using pre-defined macros or, alternatively, using the + SAM_PINMUX utility macros depending on the pinmux model used by the + SoC series. + drive-strength: + enum: + - 0 + - 1 + default: 0 + description: | + The drive strength controls the output driver strength of an I/O pin + configured as an output. + 0: Pin drive strength is set to normal drive strength. + 1: Pin drive strength is set to stronger drive strength. diff --git a/dts/bindings/serial/microchip,sercom-g1-uart.yaml b/dts/bindings/serial/microchip,sercom-g1-uart.yaml new file mode 100644 index 0000000000000..d0d1697b9f315 --- /dev/null +++ b/dts/bindings/serial/microchip,sercom-g1-uart.yaml @@ -0,0 +1,80 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: Microchip SERCOM UART controller + +description: | + Microchip SERCOM UART driver. + + Group g1 SERCOM UART driver supports following hardware peripherals: + - module name="SERCOM" id="U2201" version="5.0.0" + +compatible: "microchip,sercom-g1-uart" + +include: + - name: uart-controller.yaml + - name: pinctrl-device.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + clocks: + required: true + + clock-names: + required: true + + rxpo: + type: int + required: true + description: | + Define the receive data (RxD) pin configuration. + An enumeration with the following values: + + +-------+---------------+ + | Value | RX Pin | + +-------+---------------+ + | 0 | SERCOM_PAD[0] | + +-------+---------------+ + | 1 | SERCOM_PAD[1] | + +-------+---------------+ + | 2 | SERCOM_PAD[2] | + +-------+---------------+ + | 3 | SERCOM_PAD[3] | + +-------+---------------+ + + txpo: + type: int + required: true + description: | + Transmit Data Pinout. An enumeration with values that depend on the + hardware being used. This controls both the transmit pins and if + hardware flow control is used. + + SAMD5/E5: + + +-------+---------------+---------------+---------------+ + | Value | TX Pin | RTS | CTS | + +-------+---------------+---------------+---------------+ + | 0 | SERCOM_PAD[0] | N/A | N/A | + +-------+---------------+---------------+---------------+ + | 1 | Reserved | + +-------+---------------+---------------+---------------+ + | 2 | SERCOM_PAD[0] | SERCOM_PAD[2] | SERCOM_PAD[3] | + +-------+---------------+---------------+---------------+ + | 3 | SERCOM_PAD[0] | SERCOM_PAD[2] | N/A | + +-------+---------------+---------------+---------------+ + + clock-external: + type: boolean + description: | + select external clock for uart (external clock if true). + + collision-detection: + type: boolean + description: | + Enable collision detection for half-duplex mode. diff --git a/include/zephyr/drivers/clock_control/mchp_clock_control.h b/include/zephyr/drivers/clock_control/mchp_clock_control.h new file mode 100644 index 0000000000000..6f4b52efd6792 --- /dev/null +++ b/include/zephyr/drivers/clock_control/mchp_clock_control.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file mchp_clock_control.h + * @brief Clock control header file for Microchip soc devices. + * + * This file provides clock driver interface definitions and structures + * for microchip soc families + */ + +#ifndef INCLUDE_ZEPHYR_DRIVERS_CLOCK_CONTROL_MCHP_CLOCK_CONTROL_H_ +#define INCLUDE_ZEPHYR_DRIVERS_CLOCK_CONTROL_MCHP_CLOCK_CONTROL_H_ + +#include +#include + +#if CONFIG_CLOCK_CONTROL_MCHP_SAM_D5X_E5X +#include +#endif /* CLOCK_CONTROL_MCHP_SAM_D5X_E5X */ + +#endif /* INCLUDE_ZEPHYR_DRIVERS_CLOCK_CONTROL_MCHP_CLOCK_CONTROL_H_ */ diff --git a/include/zephyr/drivers/clock_control/mchp_clock_sam_d5x_e5x.h b/include/zephyr/drivers/clock_control/mchp_clock_sam_d5x_e5x.h new file mode 100644 index 0000000000000..cf656b87aedf7 --- /dev/null +++ b/include/zephyr/drivers/clock_control/mchp_clock_sam_d5x_e5x.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file mchp_clock_sam_d5x_e5x.h + * @brief Clock control header file for Microchip sam_d5x_e5x family. + * + * This file provides clock driver interface definitions and structures + * for sam_d5x_e5x family + */ + +#ifndef INCLUDE_ZEPHYR_DRIVERS_CLOCK_CONTROL_MCHP_CLOCK_SAM_D5X_E5X_H_ +#define INCLUDE_ZEPHYR_DRIVERS_CLOCK_CONTROL_MCHP_CLOCK_SAM_D5X_E5X_H_ + +#include + +typedef struct { + /** @brief configure oscillator to ON, when a peripheral is requesting it as a source */ + bool on_demand_en; + + /** @brief configure oscillator to ON in standby sleep mode, unless on_demand_en is set */ + bool run_in_standby_en; +} clock_mchp_subsys_xosc_config_t; + +/** @brief GCLK generator numbers + * @anchor clock_mchp_gclkgen_t + */ +typedef enum { + CLOCK_MCHP_GCLKGEN_GEN0, + CLOCK_MCHP_GCLKGEN_GEN1, + CLOCK_MCHP_GCLKGEN_GEN2, + CLOCK_MCHP_GCLKGEN_GEN3, + CLOCK_MCHP_GCLKGEN_GEN4, + CLOCK_MCHP_GCLKGEN_GEN5, + CLOCK_MCHP_GCLKGEN_GEN6, + CLOCK_MCHP_GCLKGEN_GEN7, + CLOCK_MCHP_GCLKGEN_GEN8, + CLOCK_MCHP_GCLKGEN_GEN9, + CLOCK_MCHP_GCLKGEN_GEN10, + CLOCK_MCHP_GCLKGEN_GEN11 +} clock_mchp_gclkgen_t; + +typedef struct { + /** @brief configure oscillator to ON, when a peripheral is requesting it as a source */ + bool on_demand_en; + + /** @brief configure oscillator to ON in standby sleep mode, unless on_demand_en is set */ + bool run_in_standby_en; + + /** @brief Enable closed-loop operation */ + bool closed_loop_en; + + /** @brief Reference source clock selection @see @ref clock_mchp_gclkgen_t */ + clock_mchp_gclkgen_t src; + + /** @brief Determines the ratio of the CLK_DFLL output frequency to the CLK_DFLL_REF input + * frequency (0 - 65535) + */ + uint32_t multiply_factor; +} clock_mchp_subsys_dfll_config_t; + +/** @brief FDPLL source clocks + * @anchor clock_mchp_fdpll_src_clock_t + */ +typedef enum { + CLOCK_MCHP_FDPLL_SRC_GCLK0, + CLOCK_MCHP_FDPLL_SRC_GCLK1, + CLOCK_MCHP_FDPLL_SRC_GCLK2, + CLOCK_MCHP_FDPLL_SRC_GCLK3, + CLOCK_MCHP_FDPLL_SRC_GCLK4, + CLOCK_MCHP_FDPLL_SRC_GCLK5, + CLOCK_MCHP_FDPLL_SRC_GCLK6, + CLOCK_MCHP_FDPLL_SRC_GCLK7, + CLOCK_MCHP_FDPLL_SRC_GCLK8, + CLOCK_MCHP_FDPLL_SRC_GCLK9, + CLOCK_MCHP_FDPLL_SRC_GCLK10, + CLOCK_MCHP_FDPLL_SRC_GCLK11, + CLOCK_MCHP_FDPLL_SRC_XOSC32K, + CLOCK_MCHP_FDPLL_SRC_XOSC0, + CLOCK_MCHP_FDPLL_SRC_XOSC1, + + CLOCK_MCHP_FDPLL_SRC_MAX = CLOCK_MCHP_FDPLL_SRC_XOSC1 +} clock_mchp_fdpll_src_clock_t; + +typedef struct { + /** @brief configure oscillator to ON, when a peripheral is requesting it as a source */ + bool on_demand_en; + + /** @brief configure oscillator to ON in standby sleep mode, unless on_demand_en is set */ + bool run_in_standby_en; + + /** @brief Reference source clock selection @see @ref clock_mchp_fdpll_src_clock_t */ + clock_mchp_fdpll_src_clock_t src; + + /** @brief Set the XOSC clock division factor (0 - 2047) */ + uint32_t xosc_clock_divider; + + /** @brief Set the integer part of the frequency multiplier. (0 - 4095) */ + uint32_t divider_ratio_int; + + /** @brief Set the fractional part of the frequency multiplier. (0 - 31) */ + uint32_t divider_ratio_frac; +} clock_mchp_subsys_fdpll_config_t; + +/** @brief RTC source clocks + * @anchor clock_mchp_rtc_src_clock_t + */ +typedef enum { + CLOCK_MCHP_RTC_SRC_ULP1K = OSC32KCTRL_RTCCTRL_RTCSEL_ULP1K, + CLOCK_MCHP_RTC_SRC_ULP32K = OSC32KCTRL_RTCCTRL_RTCSEL_ULP32K, + CLOCK_MCHP_RTC_SRC_XOSC1K = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC1K, + CLOCK_MCHP_RTC_SRC_XOSC32K = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC32K +} clock_mchp_rtc_src_clock_t; + +typedef struct { + /** @brief RTC source clock selection @see @ref clock_mchp_rtc_src_clock_t */ + clock_mchp_rtc_src_clock_t src; +} clock_mchp_subsys_rtc_config_t; + +typedef struct { + /** @brief configure oscillator to ON, when a peripheral is requesting it as a source */ + bool on_demand_en; + + /** @brief configure oscillator to ON in standby sleep mode, unless on_demand_en is set */ + bool run_in_standby_en; +} clock_mchp_subsys_osc32k_config_t; + +/** @brief Gclk Generator source clocks + * @anchor clock_mchp_gclk_src_clock_t + */ +typedef enum { + CLOCK_MCHP_GCLK_SRC_XOSC0, + CLOCK_MCHP_GCLK_SRC_XOSC1, + CLOCK_MCHP_GCLK_SRC_GCLKPIN, + CLOCK_MCHP_GCLK_SRC_GCLKGEN1, + CLOCK_MCHP_GCLK_SRC_OSCULP32K, + CLOCK_MCHP_GCLK_SRC_XOSC32K, + CLOCK_MCHP_GCLK_SRC_DFLL, + CLOCK_MCHP_GCLK_SRC_FDPLL0, + CLOCK_MCHP_GCLK_SRC_FDPLL1, + + CLOCK_MCHP_GCLK_SRC_MAX = CLOCK_MCHP_GCLK_SRC_FDPLL1 +} clock_mchp_gclk_src_clock_t; + +typedef struct { + /** @brief configure oscillator to ON in standby sleep mode, unless on_demand_en is set */ + bool run_in_standby_en; + + /** @brief Generator source clock selection @see @ref clock_mchp_gclk_src_clock_t */ + clock_mchp_gclk_src_clock_t src; + + /** @brief Represent a division value for the corresponding Generator. The actual division + * factor is dependent on the state of div_select (gclk1 0 - 65535, others 0 - 255) + */ + uint16_t div_factor; +} clock_mchp_subsys_gclkgen_config_t; + +typedef struct { + /** @brief gclk generator source of a peripheral clock @see @ref clock_mchp_gclkgen_t*/ + clock_mchp_gclkgen_t src; +} clock_mchp_subsys_gclkperiph_config_t; + +/** @brief division ratio of mclk prescaler for CPU + * @anchor clock_mchp_mclk_cpu_div_t + */ +typedef enum { + CLOCK_MCHP_MCLK_CPU_DIV_1 = 1, + CLOCK_MCHP_MCLK_CPU_DIV_2 = 2, + CLOCK_MCHP_MCLK_CPU_DIV_4 = 4, + CLOCK_MCHP_MCLK_CPU_DIV_8 = 8, + CLOCK_MCHP_MCLK_CPU_DIV_16 = 16, + CLOCK_MCHP_MCLK_CPU_DIV_32 = 32, + CLOCK_MCHP_MCLK_CPU_DIV_64 = 64, + CLOCK_MCHP_MCLK_CPU_DIV_128 = 128 +} clock_mchp_mclk_cpu_div_t; + +/** @brief MCLK configuration structure + * + * Used for CLOCK_MCHP_SUBSYS_TYPE_MCLKCPU + */ +typedef struct { + /** @brief division ratio of mclk prescaler for CPU @see @ref clock_mchp_mclk_cpu_div_t */ + clock_mchp_mclk_cpu_div_t division_factor; +} clock_mchp_subsys_mclkcpu_config_t; + +/** @brief clock rate datatype + * + * Used for setting a clock rate + */ +typedef uint32_t *clock_mchp_rate_t; + +#endif /* INCLUDE_ZEPHYR_DRIVERS_CLOCK_CONTROL_MCHP_CLOCK_SAM_D5X_E5X_H_ */ diff --git a/include/zephyr/dt-bindings/clock/mchp_sam_d5x_e5x_clock.h b/include/zephyr/dt-bindings/clock/mchp_sam_d5x_e5x_clock.h new file mode 100644 index 0000000000000..125ebbd128cc6 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/mchp_sam_d5x_e5x_clock.h @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file mchp_sam_d5x_e5x_clock.h + * @brief List clock subsystem IDs for sam_d5x_e5x family. + * + * Clock subsystem IDs. To be used in devicetree nodes, and as argument for clock API. + */ + +#ifndef INCLUDE_ZEPHYR_DT_BINDINGS_CLOCK_MCHP_SAM_D5X_E5X_CLOCK_H_ +#define INCLUDE_ZEPHYR_DT_BINDINGS_CLOCK_MCHP_SAM_D5X_E5X_CLOCK_H_ + +/** + * Encode clock type, mclk bus, mclk mask bit, gclk pch and instance number, + * to clock subsystem. + * + * - 00..07 (8 bits): inst + * + * - 08..13 (6 bits): gclkperiph + * (values from 0 to 47) + * + * - 14..19 (6 bits): mclkmaskbit + * (values from 0 to 31) + * + * - 20..25 (6 bits): mclkbus + * following values + * MBUS_AHB (0) + * MBUS_APBA (1) + * MBUS_APBB (2) + * MBUS_APBC (3) + * MBUS_APBD (4) + * + * - 26..31 (6 bits): type + * following values + * SUBSYS_TYPE_XOSC (0) + * SUBSYS_TYPE_DFLL (1) + * SUBSYS_TYPE_FDPLL (2) + * SUBSYS_TYPE_RTC (3) + * SUBSYS_TYPE_OSC32K (4) + * SUBSYS_TYPE_GCLKGEN (5) + * SUBSYS_TYPE_GCLKPERIPH (6) + * SUBSYS_TYPE_MCLKCPU (7) + * SUBSYS_TYPE_MCLKPERIPH (8) + * + * @param type clock subsystem type + * @param mclkbus select from the AHBx and the APBx buses + * @param mclkmaskbit select the module connected to AHBx or APBx bus (0 to 31) + * @param gclkperiph gclk peripheral channel number m in PCHTRLm (0 to 47) + * @param inst instance number of the specified clock type + */ +#define MCHP_CLOCK_DERIVE_ID(type, mclkbus, mclkmaskbit, gclkperiph, inst) \ + (((type) << 26) | ((mclkbus) << 20) | ((mclkmaskbit) << 14) | ((gclkperiph) << 8) | inst) + +/* XOSC_TYPE ids */ +#define CLOCK_MCHP_XOSC_ID_XOSC0 MCHP_CLOCK_DERIVE_ID(0, 0x3f, 0x3f, 0x3f, 0) +#define CLOCK_MCHP_XOSC_ID_XOSC1 MCHP_CLOCK_DERIVE_ID(0, 0x3f, 0x3f, 0x3f, 1) +#define CLOCK_MCHP_XOSC_ID_MAX (1) + +/* DFLL_TYPE ids */ +#define CLOCK_MCHP_DFLL_ID MCHP_CLOCK_DERIVE_ID(1, 0x3f, 0x3f, 0, 0) +#define CLOCK_MCHP_DFLL_MAX (0) + +/* FDPLL_TYPE id */ +#define CLOCK_MCHP_FDPLL_ID_FDPLL0 MCHP_CLOCK_DERIVE_ID(2, 0x3f, 0x3f, 1, 0) +#define CLOCK_MCHP_FDPLL_ID_FDPLL1 MCHP_CLOCK_DERIVE_ID(2, 0x3f, 0x3f, 2, 1) +#define CLOCK_MCHP_FDPLL_ID_MAX (1) + +/* RTC_TYPE ids */ +#define CLOCK_MCHP_RTC_ID MCHP_CLOCK_DERIVE_ID(3, 0x3f, 0x3f, 0x3f, 0) +#define CLOCK_MCHP_RTC_ID_MAX (0) + +/* OSC32K_TYPE ids */ +#define CLOCK_MCHP_OSC32K_ID_OSCULP1K MCHP_CLOCK_DERIVE_ID(4, 0x3f, 0x3f, 0x3f, 0) +#define CLOCK_MCHP_OSC32K_ID_OSCULP32K MCHP_CLOCK_DERIVE_ID(4, 0x3f, 0x3f, 0x3f, 1) +#define CLOCK_MCHP_OSC32K_ID_XOSC1K MCHP_CLOCK_DERIVE_ID(4, 0x3f, 0x3f, 0x3f, 2) +#define CLOCK_MCHP_OSC32K_ID_XOSC32K MCHP_CLOCK_DERIVE_ID(4, 0x3f, 0x3f, 0x3f, 3) +#define CLOCK_MCHP_OSC32K_ID_MAX (3) + +/* GCLKGEN_TYPE ids */ +#define CLOCK_MCHP_GCLKGEN_ID_GEN0 MCHP_CLOCK_DERIVE_ID(5, 0x3f, 0x3f, 0x3f, 0) +#define CLOCK_MCHP_GCLKGEN_ID_GEN1 MCHP_CLOCK_DERIVE_ID(5, 0x3f, 0x3f, 0x3f, 1) +#define CLOCK_MCHP_GCLKGEN_ID_GEN2 MCHP_CLOCK_DERIVE_ID(5, 0x3f, 0x3f, 0x3f, 2) +#define CLOCK_MCHP_GCLKGEN_ID_GEN3 MCHP_CLOCK_DERIVE_ID(5, 0x3f, 0x3f, 0x3f, 3) +#define CLOCK_MCHP_GCLKGEN_ID_GEN4 MCHP_CLOCK_DERIVE_ID(5, 0x3f, 0x3f, 0x3f, 4) +#define CLOCK_MCHP_GCLKGEN_ID_GEN5 MCHP_CLOCK_DERIVE_ID(5, 0x3f, 0x3f, 0x3f, 5) +#define CLOCK_MCHP_GCLKGEN_ID_GEN6 MCHP_CLOCK_DERIVE_ID(5, 0x3f, 0x3f, 0x3f, 6) +#define CLOCK_MCHP_GCLKGEN_ID_GEN7 MCHP_CLOCK_DERIVE_ID(5, 0x3f, 0x3f, 0x3f, 7) +#define CLOCK_MCHP_GCLKGEN_ID_GEN8 MCHP_CLOCK_DERIVE_ID(5, 0x3f, 0x3f, 0x3f, 8) +#define CLOCK_MCHP_GCLKGEN_ID_GEN9 MCHP_CLOCK_DERIVE_ID(5, 0x3f, 0x3f, 0x3f, 9) +#define CLOCK_MCHP_GCLKGEN_ID_GEN10 MCHP_CLOCK_DERIVE_ID(5, 0x3f, 0x3f, 0x3f, 10) +#define CLOCK_MCHP_GCLKGEN_ID_GEN11 MCHP_CLOCK_DERIVE_ID(5, 0x3f, 0x3f, 0x3f, 11) +#define CLOCK_MCHP_GCLKGEN_ID_MAX (11) + +/* GCLKPERIPH_TYPE ids */ +#define CLOCK_MCHP_GCLKPERIPH_ID_SDHC0_SLOW MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 3, 0) +#define CLOCK_MCHP_GCLKPERIPH_ID_SDHC1_SLOW MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 3, 1) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM0_SLOW MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 3, 2) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM1_SLOW MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 3, 3) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM2_SLOW MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 3, 4) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM3_SLOW MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 3, 5) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM4_SLOW MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 3, 6) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM5_SLOW MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 3, 7) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM6_SLOW MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 3, 8) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM7_SLOW MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 3, 9) +#define CLOCK_MCHP_GCLKPERIPH_ID_EIC MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 4, 10) +#define CLOCK_MCHP_GCLKPERIPH_ID_FREQM_MSR MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 5, 11) +#define CLOCK_MCHP_GCLKPERIPH_ID_FREQM_REF MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 6, 12) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM0_CORE MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 7, 13) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM1_CORE MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 8, 14) +#define CLOCK_MCHP_GCLKPERIPH_ID_TC0 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 9, 15) +#define CLOCK_MCHP_GCLKPERIPH_ID_TC1 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 9, 16) +#define CLOCK_MCHP_GCLKPERIPH_ID_USB MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 10, 17) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS0 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 11, 18) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS1 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 12, 19) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS2 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 13, 20) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS3 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 14, 21) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS4 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 15, 22) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS5 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 16, 23) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS6 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 17, 24) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS7 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 18, 25) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS8 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 19, 26) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS9 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 20, 27) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS10 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 21, 28) +#define CLOCK_MCHP_GCLKPERIPH_ID_EVSYS11 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 22, 29) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM2_CORE MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 23, 30) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM3_CORE MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 24, 31) +#define CLOCK_MCHP_GCLKPERIPH_ID_TCC0 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 25, 32) +#define CLOCK_MCHP_GCLKPERIPH_ID_TCC1 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 25, 33) +#define CLOCK_MCHP_GCLKPERIPH_ID_TC2 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 26, 34) +#define CLOCK_MCHP_GCLKPERIPH_ID_TC3 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 26, 35) +#define CLOCK_MCHP_GCLKPERIPH_ID_CAN0 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 27, 36) +#define CLOCK_MCHP_GCLKPERIPH_ID_CAN1 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 28, 37) +#define CLOCK_MCHP_GCLKPERIPH_ID_TCC2 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 29, 38) +#define CLOCK_MCHP_GCLKPERIPH_ID_TCC3 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 29, 39) +#define CLOCK_MCHP_GCLKPERIPH_ID_TC4 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 30, 40) +#define CLOCK_MCHP_GCLKPERIPH_ID_TC5 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 30, 41) +#define CLOCK_MCHP_GCLKPERIPH_ID_PDEC MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 31, 42) +#define CLOCK_MCHP_GCLKPERIPH_ID_AC MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 32, 43) +#define CLOCK_MCHP_GCLKPERIPH_ID_CCL MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 33, 44) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM4_CORE MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 34, 45) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM5_CORE MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 35, 46) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM6_CORE MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 36, 47) +#define CLOCK_MCHP_GCLKPERIPH_ID_SERCOM7_CORE MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 37, 48) +#define CLOCK_MCHP_GCLKPERIPH_ID_TCC4 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 38, 49) +#define CLOCK_MCHP_GCLKPERIPH_ID_TC6 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 39, 50) +#define CLOCK_MCHP_GCLKPERIPH_ID_TC7 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 39, 51) +#define CLOCK_MCHP_GCLKPERIPH_ID_ADC0 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 40, 52) +#define CLOCK_MCHP_GCLKPERIPH_ID_ADC1 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 41, 53) +#define CLOCK_MCHP_GCLKPERIPH_ID_DAC MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 42, 54) +#define CLOCK_MCHP_GCLKPERIPH_ID_I2S0 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 43, 55) +#define CLOCK_MCHP_GCLKPERIPH_ID_I2S1 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 44, 56) +#define CLOCK_MCHP_GCLKPERIPH_ID_SDHC0 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 45, 57) +#define CLOCK_MCHP_GCLKPERIPH_ID_SDHC1 MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 46, 58) +#define CLOCK_MCHP_GCLKPERIPH_ID_CM4_TRACE MCHP_CLOCK_DERIVE_ID(6, 0x3f, 0x3f, 47, 59) +#define CLOCK_MCHP_GCLKPERIPH_ID_MAX (59) + +/* MCLKCPU_TYPE ids */ +#define CLOCK_MCHP_MCLKCPU_ID MCHP_CLOCK_DERIVE_ID(7, 0x3f, 0x3f, 0x3f, 0) +#define CLOCK_MCHP_MCLKCPU_MAX (0) + +/* MCLKPERIPH_TYPE ids */ +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_HPB0 MCHP_CLOCK_DERIVE_ID(8, 0, 0, 0x3f, 0) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_HPB1 MCHP_CLOCK_DERIVE_ID(8, 0, 1, 0x3f, 1) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_HPB2 MCHP_CLOCK_DERIVE_ID(8, 0, 2, 0x3f, 2) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_HPB3 MCHP_CLOCK_DERIVE_ID(8, 0, 3, 0x3f, 3) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_DSU MCHP_CLOCK_DERIVE_ID(8, 0, 4, 0x3f, 4) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_NVMCTRL MCHP_CLOCK_DERIVE_ID(8, 0, 6, 0x3f, 5) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_CMCC MCHP_CLOCK_DERIVE_ID(8, 0, 8, 0x3f, 6) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_DMAC MCHP_CLOCK_DERIVE_ID(8, 0, 9, 0x3f, 7) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_USB MCHP_CLOCK_DERIVE_ID(8, 0, 10, 0x3f, 8) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_PAC MCHP_CLOCK_DERIVE_ID(8, 0, 12, 0x3f, 9) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_QSPI MCHP_CLOCK_DERIVE_ID(8, 0, 13, 0x3f, 10) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_GMAC MCHP_CLOCK_DERIVE_ID(8, 0, 14, 0x3f, 11) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_SDHC0 MCHP_CLOCK_DERIVE_ID(8, 0, 15, 0x3f, 12) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_SDHC1 MCHP_CLOCK_DERIVE_ID(8, 0, 16, 0x3f, 13) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_CAN0 MCHP_CLOCK_DERIVE_ID(8, 0, 17, 0x3f, 14) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_CAN1 MCHP_CLOCK_DERIVE_ID(8, 0, 18, 0x3f, 15) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_ICM MCHP_CLOCK_DERIVE_ID(8, 0, 19, 0x3f, 16) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_PUKCC MCHP_CLOCK_DERIVE_ID(8, 0, 20, 0x3f, 17) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_QSPI_2X MCHP_CLOCK_DERIVE_ID(8, 0, 21, 0x3f, 18) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_NVMCTRL_SMEEPROM MCHP_CLOCK_DERIVE_ID(8, 0, 22, 0x3f, 19) +#define CLOCK_MCHP_MCLKPERIPH_ID_AHB_NVMCTRL_CACHE MCHP_CLOCK_DERIVE_ID(8, 0, 23, 0x3f, 20) + +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_PAC MCHP_CLOCK_DERIVE_ID(8, 1, 0, 0x3f, 21) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_PM MCHP_CLOCK_DERIVE_ID(8, 1, 1, 0x3f, 22) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_MCLK MCHP_CLOCK_DERIVE_ID(8, 1, 2, 0x3f, 23) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_RSTC MCHP_CLOCK_DERIVE_ID(8, 1, 3, 0x3f, 24) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_OSCCTRL MCHP_CLOCK_DERIVE_ID(8, 1, 4, 0x3f, 25) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_OSC32KCTRL MCHP_CLOCK_DERIVE_ID(8, 1, 5, 0x3f, 26) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_SUPC MCHP_CLOCK_DERIVE_ID(8, 1, 6, 0x3f, 27) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_GCLK MCHP_CLOCK_DERIVE_ID(8, 1, 7, 0x3f, 28) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_WDT MCHP_CLOCK_DERIVE_ID(8, 1, 8, 0x3f, 29) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_RTC MCHP_CLOCK_DERIVE_ID(8, 1, 9, 0x3f, 30) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_EIC MCHP_CLOCK_DERIVE_ID(8, 1, 10, 0x3f, 31) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_FREQM MCHP_CLOCK_DERIVE_ID(8, 1, 11, 0x3f, 32) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_SERCOM0 MCHP_CLOCK_DERIVE_ID(8, 1, 12, 0x3f, 33) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_SERCOM1 MCHP_CLOCK_DERIVE_ID(8, 1, 13, 0x3f, 34) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_TC0 MCHP_CLOCK_DERIVE_ID(8, 1, 14, 0x3f, 35) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBA_TC1 MCHP_CLOCK_DERIVE_ID(8, 1, 15, 0x3f, 36) + +#define CLOCK_MCHP_MCLKPERIPH_ID_APBB_USB MCHP_CLOCK_DERIVE_ID(8, 2, 0, 0x3f, 37) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBB_DSU MCHP_CLOCK_DERIVE_ID(8, 2, 1, 0x3f, 38) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBB_NVMCTRL MCHP_CLOCK_DERIVE_ID(8, 2, 2, 0x3f, 39) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBB_PORT MCHP_CLOCK_DERIVE_ID(8, 2, 4, 0x3f, 40) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBB_EVSYS MCHP_CLOCK_DERIVE_ID(8, 2, 7, 0x3f, 41) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBB_SERCOM2 MCHP_CLOCK_DERIVE_ID(8, 2, 9, 0x3f, 42) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBB_SERCOM3 MCHP_CLOCK_DERIVE_ID(8, 2, 10, 0x3f, 43) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBB_TCC0 MCHP_CLOCK_DERIVE_ID(8, 2, 11, 0x3f, 44) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBB_TCC1 MCHP_CLOCK_DERIVE_ID(8, 2, 12, 0x3f, 45) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBB_TC2 MCHP_CLOCK_DERIVE_ID(8, 2, 13, 0x3f, 46) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBB_TC3 MCHP_CLOCK_DERIVE_ID(8, 2, 14, 0x3f, 47) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBB_RAMECC MCHP_CLOCK_DERIVE_ID(8, 2, 16, 0x3f, 48) + +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_GMAC MCHP_CLOCK_DERIVE_ID(8, 3, 2, 0x3f, 49) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_TCC2 MCHP_CLOCK_DERIVE_ID(8, 3, 3, 0x3f, 50) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_TCC3 MCHP_CLOCK_DERIVE_ID(8, 3, 4, 0x3f, 51) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_TC4 MCHP_CLOCK_DERIVE_ID(8, 3, 5, 0x3f, 52) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_TC5 MCHP_CLOCK_DERIVE_ID(8, 3, 6, 0x3f, 53) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_PDEC MCHP_CLOCK_DERIVE_ID(8, 3, 7, 0x3f, 54) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_AC MCHP_CLOCK_DERIVE_ID(8, 3, 8, 0x3f, 55) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_AES MCHP_CLOCK_DERIVE_ID(8, 3, 9, 0x3f, 56) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_TRNG MCHP_CLOCK_DERIVE_ID(8, 3, 10, 0x3f, 57) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_ICM MCHP_CLOCK_DERIVE_ID(8, 3, 11, 0x3f, 58) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_QSPI MCHP_CLOCK_DERIVE_ID(8, 3, 13, 0x3f, 59) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBC_CCL MCHP_CLOCK_DERIVE_ID(8, 3, 14, 0x3f, 60) + +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_SERCOM4 MCHP_CLOCK_DERIVE_ID(8, 4, 0, 0x3f, 61) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_SERCOM5 MCHP_CLOCK_DERIVE_ID(8, 4, 1, 0x3f, 62) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_SERCOM6 MCHP_CLOCK_DERIVE_ID(8, 4, 2, 0x3f, 63) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_SERCOM7 MCHP_CLOCK_DERIVE_ID(8, 4, 3, 0x3f, 64) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_TCC4 MCHP_CLOCK_DERIVE_ID(8, 4, 4, 0x3f, 65) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_TC6 MCHP_CLOCK_DERIVE_ID(8, 4, 5, 0x3f, 66) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_TC7 MCHP_CLOCK_DERIVE_ID(8, 4, 6, 0x3f, 67) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_ADC0 MCHP_CLOCK_DERIVE_ID(8, 4, 7, 0x3f, 68) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_ADC1 MCHP_CLOCK_DERIVE_ID(8, 4, 8, 0x3f, 69) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_DAC MCHP_CLOCK_DERIVE_ID(8, 4, 9, 0x3f, 70) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_I2S MCHP_CLOCK_DERIVE_ID(8, 4, 10, 0x3f, 71) +#define CLOCK_MCHP_MCLKPERIPH_ID_APBD_PCC MCHP_CLOCK_DERIVE_ID(8, 4, 11, 0x3f, 72) +#define CLOCK_MCHP_MCLKPERIPH_ID_MAX (72) + +#endif /* INCLUDE_ZEPHYR_DT_BINDINGS_CLOCK_MCHP_SAM_D5X_E5X_CLOCK_H_ */ diff --git a/soc/microchip/sam/sam_d5x_e5x/CMakeLists.txt b/soc/microchip/sam/sam_d5x_e5x/CMakeLists.txt new file mode 100644 index 0000000000000..d4ef0e635835c --- /dev/null +++ b/soc/microchip/sam/sam_d5x_e5x/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") + +zephyr_include_directories(common) +zephyr_include_directories(${SOC_SERIES}) diff --git a/soc/microchip/sam/sam_d5x_e5x/Kconfig b/soc/microchip/sam/sam_d5x_e5x/Kconfig new file mode 100644 index 0000000000000..38c46c9802f1b --- /dev/null +++ b/soc/microchip/sam/sam_d5x_e5x/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_MICROCHIP_SAM_D5X_E5X + select ARM + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_ARM_MPU + select CPU_HAS_FPU + select CLOCK_CONTROL + select HAS_CMSIS_CORE + select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE diff --git a/soc/microchip/sam/sam_d5x_e5x/Kconfig.defconfig b/soc/microchip/sam/sam_d5x_e5x/Kconfig.defconfig new file mode 100644 index 0000000000000..970e27ca30f03 --- /dev/null +++ b/soc/microchip/sam/sam_d5x_e5x/Kconfig.defconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_MICROCHIP_SAM_D5X_E5X + +config NUM_IRQS + default 137 + +config ROM_START_OFFSET + default 0x400 if BOOTLOADER_MCUBOOT + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) + +endif # SOC_FAMILY_MICROCHIP_SAM_D5X_E5X diff --git a/soc/microchip/sam/sam_d5x_e5x/Kconfig.soc b/soc/microchip/sam/sam_d5x_e5x/Kconfig.soc new file mode 100644 index 0000000000000..4f9dc8b4c57c1 --- /dev/null +++ b/soc/microchip/sam/sam_d5x_e5x/Kconfig.soc @@ -0,0 +1,27 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_MICROCHIP_SAM_D5X_E5X + bool + +config SOC_FAMILY + default "microchip_sam_d5x_e5x" if SOC_FAMILY_MICROCHIP_SAM_D5X_E5X + +# List of Peripheral IPs available in SOC_FAMILY_MICROCHIP_SAM_D5X_E5X family +if SOC_FAMILY_MICROCHIP_SAM_D5X_E5X + +config PINCTRL_MCHP_PORT_U2210_2_2_0 + bool + default y + help + Enable PORT pinctrl peripheral IP version 2.2.0 (U2210). + +config UART_MCHP_SERCOM_U2201_5_0_0 + bool + default y + help + Enable SERCOM UART peripheral IP version 5.0.0 (U2201). + +endif # SOC_FAMILY_MICROCHIP_SAM_D5X_E5X + +rsource "*/Kconfig.soc" diff --git a/soc/microchip/sam/sam_d5x_e5x/atsamd51/Kconfig.soc b/soc/microchip/sam/sam_d5x_e5x/atsamd51/Kconfig.soc new file mode 100644 index 0000000000000..ef9928677e870 --- /dev/null +++ b/soc/microchip/sam/sam_d5x_e5x/atsamd51/Kconfig.soc @@ -0,0 +1,58 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_ATSAMD51 + bool + select SOC_FAMILY_MICROCHIP_SAM_D5X_E5X + help + Enable support for Microchip SAMD51 Cortex-M4F microcontrollers. + +config SOC_SERIES + default "atsamd51" if SOC_SERIES_ATSAMD51 + +config SOC_ATSAMD51G18A + bool + select SOC_SERIES_ATSAMD51 + +config SOC_ATSAMD51G19A + bool + select SOC_SERIES_ATSAMD51 + +config SOC_ATSAMD51J18A + bool + select SOC_SERIES_ATSAMD51 + +config SOC_ATSAMD51J19A + bool + select SOC_SERIES_ATSAMD51 + +config SOC_ATSAMD51J20A + bool + select SOC_SERIES_ATSAMD51 + +config SOC_ATSAMD51N19A + bool + select SOC_SERIES_ATSAMD51 + +config SOC_ATSAMD51N20A + bool + select SOC_SERIES_ATSAMD51 + +config SOC_ATSAMD51P19A + bool + select SOC_SERIES_ATSAMD51 + +config SOC_ATSAMD51P20A + bool + select SOC_SERIES_ATSAMD51 + +config SOC + default "atsamd51g18a" if SOC_ATSAMD51G18A + default "atsamd51g19a" if SOC_ATSAMD51G19A + default "atsamd51j18a" if SOC_ATSAMD51J18A + default "atsamd51j19a" if SOC_ATSAMD51J19A + default "atsamd51j20a" if SOC_ATSAMD51J20A + default "atsamd51n19a" if SOC_ATSAMD51N19A + default "atsamd51n20a" if SOC_ATSAMD51N20A + default "atsamd51p19a" if SOC_ATSAMD51P19A + default "atsamd51p20a" if SOC_ATSAMD51P20A diff --git a/soc/microchip/sam/sam_d5x_e5x/atsamd51/soc.h b/soc/microchip/sam/sam_d5x_e5x/atsamd51/soc.h new file mode 100644 index 0000000000000..21d2621e1ee0f --- /dev/null +++ b/soc/microchip/sam/sam_d5x_e5x/atsamd51/soc.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_MICROCHIP_SAM_D5X_E5X_ATSAMD51_SOC_H_ +#define SOC_MICROCHIP_SAM_D5X_E5X_ATSAMD51_SOC_H_ + +#ifndef _ASMLANGUAGE + +#include + +#if defined(CONFIG_SOC_ATSAMD51G18A) +#include +#elif defined(CONFIG_SOC_ATSAMD51G19A) +#include +#elif defined(CONFIG_SOC_ATSAMD51J18A) +#include +#elif defined(CONFIG_SOC_ATSAMD51J19A) +#include +#elif defined(CONFIG_SOC_ATSAMD51J20A) +#include +#elif defined(CONFIG_SOC_ATSAMD51N19A) +#include +#elif defined(CONFIG_SOC_ATSAMD51N20A) +#include +#elif defined(CONFIG_SOC_ATSAMD51P19A) +#include +#elif defined(CONFIG_SOC_ATSAMD51P20A) +#include +#else +#error "Library does not support the specified device." +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* SOC_MICROCHIP_SAM_D5X_E5X_ATSAMD51_SOC_H_ */ diff --git a/soc/microchip/sam/sam_d5x_e5x/atsame51/Kconfig.soc b/soc/microchip/sam/sam_d5x_e5x/atsame51/Kconfig.soc new file mode 100644 index 0000000000000..abdab918695b2 --- /dev/null +++ b/soc/microchip/sam/sam_d5x_e5x/atsame51/Kconfig.soc @@ -0,0 +1,48 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_ATSAME51 + bool + select SOC_FAMILY_MICROCHIP_SAM_D5X_E5X + help + Enable support for Microchip SAME51 Cortex-M4F microcontrollers. + +config SOC_SERIES + default "atsame51" if SOC_SERIES_ATSAME51 + +config SOC_ATSAME51G18A + bool + select SOC_SERIES_ATSAME51 + +config SOC_ATSAME51G19A + bool + select SOC_SERIES_ATSAME51 + +config SOC_ATSAME51J18A + bool + select SOC_SERIES_ATSAME51 + +config SOC_ATSAME51J19A + bool + select SOC_SERIES_ATSAME51 + +config SOC_ATSAME51J20A + bool + select SOC_SERIES_ATSAME51 + +config SOC_ATSAME51N19A + bool + select SOC_SERIES_ATSAME51 + +config SOC_ATSAME51N20A + bool + select SOC_SERIES_ATSAME51 + +config SOC + default "atsame51g18a" if SOC_ATSAME51G18A + default "atsame51g19a" if SOC_ATSAME51G19A + default "atsame51j18a" if SOC_ATSAME51J18A + default "atsame51j19a" if SOC_ATSAME51J19A + default "atsame51j20a" if SOC_ATSAME51J20A + default "atsame51n19a" if SOC_ATSAME51N19A + default "atsame51n20a" if SOC_ATSAME51N20A diff --git a/soc/microchip/sam/sam_d5x_e5x/atsame51/soc.h b/soc/microchip/sam/sam_d5x_e5x/atsame51/soc.h new file mode 100644 index 0000000000000..d0c0cdb8b3746 --- /dev/null +++ b/soc/microchip/sam/sam_d5x_e5x/atsame51/soc.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_MICROCHIP_SAM_D5X_E5X_ATSAME51_SOC_H_ +#define SOC_MICROCHIP_SAM_D5X_E5X_ATSAME51_SOC_H_ + +#ifndef _ASMLANGUAGE + +#include + +#if defined(CONFIG_SOC_ATSAME51G18A) +#include +#elif defined(CONFIG_SOC_ATSAME51G19A) +#include +#elif defined(CONFIG_SOC_ATSAME51J18A) +#include +#elif defined(CONFIG_SOC_ATSAME51J19A) +#include +#elif defined(CONFIG_SOC_ATSAME51J20A) +#include +#elif defined(CONFIG_SOC_ATSAME51N19A) +#include +#elif defined(CONFIG_SOC_ATSAME51N20A) +#include +#else +#error "Library does not support the specified device." +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* SOC_MICROCHIP_SAM_D5X_E5X_ATSAME51_SOC_H_ */ diff --git a/soc/microchip/sam/sam_d5x_e5x/atsame53/Kconfig.soc b/soc/microchip/sam/sam_d5x_e5x/atsame53/Kconfig.soc new file mode 100644 index 0000000000000..cb54d2079b096 --- /dev/null +++ b/soc/microchip/sam/sam_d5x_e5x/atsame53/Kconfig.soc @@ -0,0 +1,38 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_ATSAME53 + bool + select SOC_FAMILY_MICROCHIP_SAM_D5X_E5X + help + Enable support for Microchip SAME53 Cortex-M4F microcontrollers. + +config SOC_SERIES + default "atsame53" if SOC_SERIES_ATSAME53 + +config SOC_ATSAME53J18A + bool + select SOC_SERIES_ATSAME53 + +config SOC_ATSAME53J19A + bool + select SOC_SERIES_ATSAME53 + +config SOC_ATSAME53J20A + bool + select SOC_SERIES_ATSAME53 + +config SOC_ATSAME53N19A + bool + select SOC_SERIES_ATSAME53 + +config SOC_ATSAME53N20A + bool + select SOC_SERIES_ATSAME53 + +config SOC + default "atsame53j18a" if SOC_ATSAME53J18A + default "atsame53j19a" if SOC_ATSAME53J19A + default "atsame53j20a" if SOC_ATSAME53J20A + default "atsame53n19a" if SOC_ATSAME53N19A + default "atsame53n20a" if SOC_ATSAME53N20A diff --git a/soc/microchip/sam/sam_d5x_e5x/atsame53/soc.h b/soc/microchip/sam/sam_d5x_e5x/atsame53/soc.h new file mode 100644 index 0000000000000..f71e208275230 --- /dev/null +++ b/soc/microchip/sam/sam_d5x_e5x/atsame53/soc.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_MICROCHIP_SAM_D5X_E5X_ATSAME53_SOC_H_ +#define SOC_MICROCHIP_SAM_D5X_E5X_ATSAME53_SOC_H_ + +#ifndef _ASMLANGUAGE + +#include + +#if defined(CONFIG_SOC_ATSAME53J18A) +#include +#elif defined(CONFIG_SOC_ATSAME53J19A) +#include +#elif defined(CONFIG_SOC_ATSAME53J20A) +#include +#elif defined(CONFIG_SOC_ATSAME53N19A) +#include +#elif defined(CONFIG_SOC_ATSAME53N20A) +#include +#else +#error "Library does not support the specified device." +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* SOC_MICROCHIP_SAM_D5X_E5X_ATSAME53_SOC_H_ */ diff --git a/soc/microchip/sam/sam_d5x_e5x/atsame54/Kconfig.soc b/soc/microchip/sam/sam_d5x_e5x/atsame54/Kconfig.soc new file mode 100644 index 0000000000000..b543dafed0fa5 --- /dev/null +++ b/soc/microchip/sam/sam_d5x_e5x/atsame54/Kconfig.soc @@ -0,0 +1,33 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_ATSAME54 + bool + select SOC_FAMILY_MICROCHIP_SAM_D5X_E5X + help + Enable support for Microchip SAME54 Cortex-M4F microcontrollers. + +config SOC_SERIES + default "atsame54" if SOC_SERIES_ATSAME54 + +config SOC_ATSAME54N19A + bool + select SOC_SERIES_ATSAME54 + +config SOC_ATSAME54N20A + bool + select SOC_SERIES_ATSAME54 + +config SOC_ATSAME54P19A + bool + select SOC_SERIES_ATSAME54 + +config SOC_ATSAME54P20A + bool + select SOC_SERIES_ATSAME54 + +config SOC + default "atsame54n19a" if SOC_ATSAME54N19A + default "atsame54n20a" if SOC_ATSAME54N20A + default "atsame54p19a" if SOC_ATSAME54P19A + default "atsame54p20a" if SOC_ATSAME54P20A diff --git a/soc/microchip/sam/sam_d5x_e5x/atsame54/soc.h b/soc/microchip/sam/sam_d5x_e5x/atsame54/soc.h new file mode 100644 index 0000000000000..dfc314423bbde --- /dev/null +++ b/soc/microchip/sam/sam_d5x_e5x/atsame54/soc.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_MICROCHIP_SAM_D5X_E5X_ATSAME54_SOC_H_ +#define SOC_MICROCHIP_SAM_D5X_E5X_ATSAME54_SOC_H_ + +#ifndef _ASMLANGUAGE + +#include + +#if defined(CONFIG_SOC_ATSAME54N19A) +#include +#elif defined(CONFIG_SOC_ATSAME54N20A) +#include +#elif defined(CONFIG_SOC_ATSAME54P19A) +#include +#elif defined(CONFIG_SOC_ATSAME54P20A) +#include +#else +#error "Library does not support the specified device." +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* SOC_MICROCHIP_SAM_D5X_E5X_ATSAME54_SOC_H_ */ diff --git a/soc/microchip/sam/sam_d5x_e5x/common/pinctrl_soc.h b/soc/microchip/sam/sam_d5x_e5x/common/pinctrl_soc.h new file mode 100644 index 0000000000000..007b167c8cc0a --- /dev/null +++ b/soc/microchip/sam/sam_d5x_e5x/common/pinctrl_soc.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_MICROCHIP_SAM_D5X_E5X_COMMON_PINCTRL_SOC_H_ +#define SOC_MICROCHIP_SAM_D5X_E5X_COMMON_PINCTRL_SOC_H_ + +#include +#include +#include "dt-bindings/sam/sam_d5x_e5x/common/mchp_pinctrl_pinmux_sam.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond INTERNAL_HIDDEN */ + +/** + * @brief Structure representing the pin control settings for a SOC pin. + * + * This structure is used to define the pinmux and pin configuration settings + * for a specific pin on the SOC. It includes information about the port, pin, + * function, bias, drive, and other configuration options. + */ +typedef struct pinctrl_soc_pin { + /** Pinmux settings (port, pin and function). */ + uint16_t pinmux; + /** Pin configuration (bias, drive etc). */ + uint16_t pinflag; +} pinctrl_soc_pin_t; + +/** + * @brief Utility macro to initialize pinmux field. + * + * @param node_id Node identifier. + */ +#define Z_PINCTRL_MCHP_PINMUX_INIT(node_id, prop, idx) DT_PROP_BY_IDX(node_id, prop, idx) + +/** + * @brief Utility macro to initialize each pin. + * + * @param node_id Node identifier. + * @param prop Property name. + * @param idx Property entry index. + */ +#define Z_PINCTRL_MCHP_PINFLAG_INIT(node_id, prop, idx) \ + ((DT_PROP(node_id, bias_pull_up) << MCHP_PINCTRL_PULLUP_POS) | \ + (DT_PROP(node_id, bias_pull_down) << MCHP_PINCTRL_PULLDOWN_POS) | \ + (DT_PROP(node_id, input_enable) << MCHP_PINCTRL_INPUTENABLE_POS) | \ + (DT_PROP(node_id, output_enable) << MCHP_PINCTRL_OUTPUTENABLE_POS) | \ + (DT_ENUM_IDX(node_id, drive_strength) << MCHP_PINCTRL_DRIVESTRENGTH_POS)), + +/** + * @brief Utility macro to initialize each pin. + * + * @param node_id Node identifier. + * @param prop Property name. + * @param idx Property entry index. + */ +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + {.pinmux = Z_PINCTRL_MCHP_PINMUX_INIT(node_id, prop, idx), \ + .pinflag = Z_PINCTRL_MCHP_PINFLAG_INIT(node_id, prop, idx)}, + +/** + * @brief Utility macro to initialize state pins contained in a given property. + * + * @param node_id Node identifier. + * @param prop Property name describing state pins. + */ +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + {DT_FOREACH_CHILD_VARGS(DT_PHANDLE(node_id, prop), DT_FOREACH_PROP_ELEM, pinmux, \ + Z_PINCTRL_STATE_PIN_INIT)} + +/** @endcond */ + +/** + * @brief Pin flags/attributes + * @anchor MCHP_PINFLAGS + * + * @{ + */ + +#define MCHP_PINCTRL_FLAGS_DEFAULT (0U) +#define MCHP_PINCTRL_FLAGS_POS (0U) +#define MCHP_PINCTRL_FLAGS_MASK (0x3F << MCHP_PINCTRL_FLAGS_POS) +#define MCHP_PINCTRL_FLAG_MASK (1U) +#define MCHP_PINCTRL_PULLUP_POS (MCHP_PINCTRL_FLAGS_POS) +#define MCHP_PINCTRL_PULLUP (1U << MCHP_PINCTRL_PULLUP_POS) +#define MCHP_PINCTRL_PULLDOWN_POS (MCHP_PINCTRL_PULLUP_POS + 1U) +#define MCHP_PINCTRL_PULLDOWN (1U << MCHP_PINCTRL_PULLDOWN_POS) +#define MCHP_PINCTRL_OPENDRAIN_POS (MCHP_PINCTRL_PULLDOWN_POS + 1U) +#define MCHP_PINCTRL_OPENDRAIN (1U << MCHP_PINCTRL_OPENDRAIN_POS) +#define MCHP_PINCTRL_INPUTENABLE_POS (MCHP_PINCTRL_OPENDRAIN_POS + 1U) +#define MCHP_PINCTRL_INPUTENABLE (1U << MCHP_PINCTRL_INPUTENABLE_POS) +#define MCHP_PINCTRL_OUTPUTENABLE_POS (MCHP_PINCTRL_INPUTENABLE_POS + 1U) +#define MCHP_PINCTRL_OUTPUTENABLE (1U << MCHP_PINCTRL_OUTPUTENABLE_POS) +#define MCHP_PINCTRL_DRIVESTRENGTH_POS (MCHP_PINCTRL_OUTPUTENABLE_POS + 1U) +#define MCHP_PINCTRL_DRIVESTRENGTH (1U << MCHP_PINCTRL_DRIVESTRENGTH_POS) + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* SOC_MICROCHIP_SAM_D5X_E5X_COMMON_PINCTRL_SOC_H_ */ diff --git a/soc/microchip/sam/sam_d5x_e5x/soc.yml b/soc/microchip/sam/sam_d5x_e5x/soc.yml new file mode 100644 index 0000000000000..e243333d486dd --- /dev/null +++ b/soc/microchip/sam/sam_d5x_e5x/soc.yml @@ -0,0 +1,39 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +family: +- name: microchip_sam_d5x_e5x + series: + - name: atsamd51 + socs: + - name: atsamd51g18a + - name: atsamd51g19a + - name: atsamd51j18a + - name: atsamd51j19a + - name: atsamd51j20a + - name: atsamd51n19a + - name: atsamd51n20a + - name: atsamd51p19a + - name: atsamd51p20a + - name: atsame51 + socs: + - name: atsame51g18a + - name: atsame51g19a + - name: atsame51j18a + - name: atsame51j19a + - name: atsame51j20a + - name: atsame51n19a + - name: atsame51n20a + - name: atsame53 + socs: + - name: atsame53j18a + - name: atsame53j19a + - name: atsame53j20a + - name: atsame53n19a + - name: atsame53n20a + - name: atsame54 + socs: + - name: atsame54n19a + - name: atsame54n20a + - name: atsame54p19a + - name: atsame54p20a diff --git a/west.yml b/west.yml index 753b3091c45ee..0c918c30915ee 100644 --- a/west.yml +++ b/west.yml @@ -195,7 +195,7 @@ manifest: groups: - hal - name: hal_microchip - revision: 415c92d3c8bd3d62db35980729df42be1f178023 + revision: 2c5eb6b7b9ef3a442ff9d9536fbc63b2028c2d0e path: modules/hal/microchip groups: - hal