diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index dd5b101317e1..24df43e36d96 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -291,6 +291,21 @@ Ambiq Platforms: labels: - "platform: Ambiq" +AndesTech Platforms: + status: maintained + maintainers: + - jimmyzhe + collaborators: + - kevinwang821020 + files: + - boards/andestech/ + - drivers/*/*andes* + - dts/bindings/*/*andestech* + - dts/riscv/andes/ + - soc/andestech/ + labels: + - "platform: Andes Technology" + BeagleBoard Platforms: status: maintained maintainers: @@ -1050,8 +1065,8 @@ Documentation Infrastructure: Release Notes: status: maintained maintainers: - - fabiobaltieri - - kartben + - danieldegrasse + - dkalowsk collaborators: - kartben files: diff --git a/boards/ct/ctcc/ctcc_nrf9161-pinctrl.dtsi b/boards/ct/ctcc/ctcc_nrf9161-pinctrl.dtsi index c48b2987b85d..10eece2fd56e 100644 --- a/boards/ct/ctcc/ctcc_nrf9161-pinctrl.dtsi +++ b/boards/ct/ctcc/ctcc_nrf9161-pinctrl.dtsi @@ -25,28 +25,6 @@ }; }; - uart1_default: uart1_default { - group1 { - psels = , - ; - }; - group2 { - psels = , - ; - bias-pull-up; - }; - }; - - uart1_sleep: uart1_sleep { - group1 { - psels = , - , - , - ; - low-power-enable; - }; - }; - spi3_default: spi3_default { group1 { psels = , diff --git a/boards/ct/ctcc/ctcc_nrf9161_common.dtsi b/boards/ct/ctcc/ctcc_nrf9161_common.dtsi index 92a2a757c55a..00e53a5262ce 100644 --- a/boards/ct/ctcc/ctcc_nrf9161_common.dtsi +++ b/boards/ct/ctcc/ctcc_nrf9161_common.dtsi @@ -39,10 +39,6 @@ }; }; -&adc { - status = "okay"; -}; - &gpiote { status = "okay"; }; @@ -59,14 +55,6 @@ pinctrl-names = "default", "sleep"; }; -&uart1 { - status = "okay"; - current-speed = <115200>; - pinctrl-0 = <&uart1_default>; - pinctrl-1 = <&uart1_sleep>; - pinctrl-names = "default", "sleep"; -}; - &spi3 { compatible = "nordic,nrf-spim"; status = "okay"; diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts index 65515b1dd4e8..c9c6603950fb 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts @@ -257,7 +257,7 @@ ipc0: &cpuapp_cpurad_ipc { status = "okay"; mx25uw63: mx25uw6345g@0 { - compatible = "jedec,mspi-nor"; + compatible = "mxicy,mx25u", "jedec,mspi-nor"; status = "disabled"; reg = <0>; jedec-id = [c2 84 37]; diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron.dts b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron.dts index 79fea7a01c57..54e3014adeaf 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron.dts +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron.dts @@ -8,7 +8,6 @@ /delete-node/&cpurad_rx_partitions; /delete-node/&cpuapp_rx_partitions; -/delete-node/&cpusec_cpuapp_ipc; /* This is not yet an exhaustive memory map, and contain only a minimum required to boot * the application core. diff --git a/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.dts b/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.dts index 31502189d3f8..bbd09a534c23 100644 --- a/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.dts +++ b/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.dts @@ -248,7 +248,7 @@ ipc0: &cpuapp_cpurad_ipc { status = "okay"; mx25uw63: mx25uw6345g@0 { - compatible = "jedec,mspi-nor"; + compatible = "mxicy,mx25u", "jedec,mspi-nor"; status = "disabled"; reg = <0>; jedec-id = [c2 84 37]; diff --git a/boards/nxp/frdm_mcxa153/frdm_mcxa153-pinctrl.dtsi b/boards/nxp/frdm_mcxa153/frdm_mcxa153-pinctrl.dtsi index 97f195b9c5cf..65419589b86f 100644 --- a/boards/nxp/frdm_mcxa153/frdm_mcxa153-pinctrl.dtsi +++ b/boards/nxp/frdm_mcxa153/frdm_mcxa153-pinctrl.dtsi @@ -7,6 +7,15 @@ #include &pinctrl { + pinmux_flexpwm0_pwm0: pinmux_flexpwm0_pwm0 { + group0 { + pinmux = , + ; + slew-rate = "fast"; + drive-strength = "low"; + }; + }; + pinmux_lpuart0: pinmux_lpuart0 { group0 { pinmux = , diff --git a/boards/nxp/frdm_mcxa153/frdm_mcxa153.dts b/boards/nxp/frdm_mcxa153/frdm_mcxa153.dts index 3ab90983c24a..d2d96daf79eb 100644 --- a/boards/nxp/frdm_mcxa153/frdm_mcxa153.dts +++ b/boards/nxp/frdm_mcxa153/frdm_mcxa153.dts @@ -20,6 +20,7 @@ led2 = &blue_led; sw0 = &user_button_2; sw1 = &user_button_3; + pwm-0 = &flexpwm0_pwm0; }; chosen { @@ -93,6 +94,12 @@ }; }; +&flexpwm0_pwm0 { + status = "okay"; + pinctrl-0 = <&pinmux_flexpwm0_pwm0>; + pinctrl-names = "default"; +}; + &gpio0 { status = "okay"; }; diff --git a/boards/nxp/frdm_mcxa153/frdm_mcxa153.yaml b/boards/nxp/frdm_mcxa153/frdm_mcxa153.yaml index f607a093f63c..ae838f08d706 100644 --- a/boards/nxp/frdm_mcxa153/frdm_mcxa153.yaml +++ b/boards/nxp/frdm_mcxa153/frdm_mcxa153.yaml @@ -17,5 +17,6 @@ supported: - dma - flash - gpio + - pwm - uart vendor: nxp diff --git a/boards/realtek/rts5912_evb/rts5912_evb.dts b/boards/realtek/rts5912_evb/rts5912_evb.dts index 15d3b5357f1d..f58d75e36da0 100644 --- a/boards/realtek/rts5912_evb/rts5912_evb.dts +++ b/boards/realtek/rts5912_evb/rts5912_evb.dts @@ -20,6 +20,17 @@ }; }; +&adc0 { + status = "okay"; + pinctrl-0 = <&adc0_gpio074 &adc1_gpio075 + &adc2_gpio076 &adc3_gpio077 + &adc4_gpio078 &adc5_gpio079 + &adc6_gpio080 &adc7_gpio081 + &adc8_gpio082 &adc9_gpio054 + &adc10_gpio098 &adc11_gpio024>; + pinctrl-names = "default"; +}; + &uart0 { status = "okay"; current-speed = <115200>; diff --git a/boards/realtek/rts5912_evb/rts5912_evb.yaml b/boards/realtek/rts5912_evb/rts5912_evb.yaml index e81e170e7d62..e781df48992a 100644 --- a/boards/realtek/rts5912_evb/rts5912_evb.yaml +++ b/boards/realtek/rts5912_evb/rts5912_evb.yaml @@ -15,4 +15,5 @@ flash: 320 supported: - gpio - pinmux + - adc vendor: realtek diff --git a/boards/realtek/rts5912_evb/rts5912_evb_defconfig b/boards/realtek/rts5912_evb/rts5912_evb_defconfig index d821f0279dd5..a454f6a87a02 100644 --- a/boards/realtek/rts5912_evb/rts5912_evb_defconfig +++ b/boards/realtek/rts5912_evb/rts5912_evb_defconfig @@ -20,3 +20,6 @@ CONFIG_GPIO=y # Input Driver CONFIG_INPUT=y + +# Enable ADC +CONFIG_ADC=y diff --git a/boards/st/disco_l475_iot1/arduino_r3_connector.dtsi b/boards/st/disco_l475_iot1/arduino_r3_connector.dtsi index b48af67e2a16..05228c5ccb80 100644 --- a/boards/st/disco_l475_iot1/arduino_r3_connector.dtsi +++ b/boards/st/disco_l475_iot1/arduino_r3_connector.dtsi @@ -35,6 +35,6 @@ }; }; -arduino_i2c: &i2c3 {}; +arduino_i2c: &i2c1 {}; arduino_spi: &spi1 {}; arduino_serial: &uart4 {}; diff --git a/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi b/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi index 45df3911f4f7..b249d2ab8477 100644 --- a/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi +++ b/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi @@ -68,9 +68,18 @@ }; &pll1 { - clocks = <&clk_hsi>; - div-m = <4>; - mul-n = <75>; + clocks = <&clk_hse>; + div-m = <3>; + mul-n = <150>; + div-p1 = <1>; + div-p2 = <1>; + status = "okay"; +}; + +&pll3 { + clocks = <&clk_hse>; + div-m = <3>; + mul-n = <125>; div-p1 = <1>; div-p2 = <1>; status = "okay"; @@ -78,18 +87,24 @@ &ic1 { pll-src = <1>; - ic-div = <2>; + ic-div = <3>; status = "okay"; }; &ic2 { pll-src = <1>; - ic-div = <3>; + ic-div = <6>; status = "okay"; }; -&ic6 { +&ic3 { pll-src = <1>; + ic-div = <6>; + status = "okay"; +}; + +&ic6 { + pll-src = <3>; ic-div = <2>; status = "okay"; }; @@ -107,7 +122,7 @@ &cpusw { clocks = <&rcc STM32_SRC_IC1 CPU_SEL(3)>; - clock-frequency = ; + clock-frequency = ; status = "okay"; }; @@ -116,10 +131,7 @@ clocks = <&ic2>; clock-frequency = ; ahb-prescaler = <2>; - apb1-prescaler = <1>; - apb2-prescaler = <1>; - apb4-prescaler = <1>; - apb5-prescaler = <1>; + timg-prescaler = <2>; }; &adc1 { @@ -218,6 +230,9 @@ zephyr_udc0: &usbotg_hs1 { &xspim_p2_io3_pn5 &xspim_p2_io4_pn8 &xspim_p2_io5_pn9 &xspim_p2_io6_pn10 &xspim_p2_io7_pn11>; pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK(AHB5, 12)>, + <&rcc STM32_SRC_IC3 XSPI1_SEL(2)>, + <&rcc STM32_CLOCK(AHB5, 13)>; status = "okay"; mx25um51245g: ospi-nor-flash@70000000 { diff --git a/boards/st/stm32n6570_dk/Kconfig.defconfig b/boards/st/stm32n6570_dk/Kconfig.defconfig index 0196c3c0b854..2d792ba9657f 100644 --- a/boards/st/stm32n6570_dk/Kconfig.defconfig +++ b/boards/st/stm32n6570_dk/Kconfig.defconfig @@ -12,4 +12,13 @@ config NET_L2_ETHERNET endif # NETWORKING +if DISPLAY + +# MEMC needs to be enabled in order to store +# display frame buffer to external PSRAM +config MEMC + default y + +endif # DISPLAY + endif # BOARD_STM32N6570_DK diff --git a/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi b/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi index 1e4f59dcfda5..48ee7e4a22aa 100644 --- a/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi +++ b/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi @@ -6,8 +6,10 @@ #include #include +#include "zephyr/dt-bindings/display/panel.h" #include #include +#include #include "arduino_r3_connector.dtsi" / { @@ -16,6 +18,7 @@ zephyr,shell-uart = &usart1; zephyr,sram = &axisram2; zephyr,canbus = &fdcan1; + zephyr,display = <dc; spi-flash0 = &mx66uw1g45g; }; @@ -57,43 +60,67 @@ }; &pll1 { - clocks = <&clk_hsi>; - div-m = <4>; - mul-n = <75>; + clocks = <&clk_hse>; + div-m = <3>; + mul-n = <150>; div-p1 = <1>; div-p2 = <1>; status = "okay"; }; &pll2 { + clocks = <&clk_hsi>; + div-m = <2>; + mul-n = <48>; + div-p1 = <1>; + div-p2 = <1>; + status = "okay"; +}; + +&pll3 { + clocks = <&clk_hse>; + div-m = <3>; + mul-n = <125>; + div-p1 = <1>; + div-p2 = <1>; + status = "okay"; +}; + +&pll4 { clocks = <&clk_hsi>; div-m = <4>; - mul-n = <24>; - div-p1 = <2>; - div-p2 = <2>; + mul-n = <75>; + div-p1 = <1>; + div-p2 = <1>; status = "okay"; }; &ic1 { pll-src = <1>; - ic-div = <2>; + ic-div = <3>; status = "okay"; }; &ic2 { pll-src = <1>; - ic-div = <3>; + ic-div = <6>; + status = "okay"; +}; + +&ic3 { + pll-src = <1>; + ic-div = <6>; status = "okay"; }; &ic4 { pll-src = <2>; - ic-div = <2>; + ic-div = <32>; status = "okay"; }; &ic6 { - pll-src = <1>; + pll-src = <3>; ic-div = <2>; status = "okay"; }; @@ -104,6 +131,12 @@ status = "okay"; }; +&ic16 { + pll-src = <4>; + ic-div = <60>; + status = "okay"; +}; + &perck { clocks = <&rcc STM32_SRC_HSI PER_SEL(0)>; status = "okay"; @@ -111,7 +144,7 @@ &cpusw { clocks = <&rcc STM32_SRC_IC1 CPU_SEL(3)>; - clock-frequency = ; + clock-frequency = ; status = "okay"; }; @@ -120,10 +153,7 @@ clocks = <&ic2>; clock-frequency = ; ahb-prescaler = <2>; - apb1-prescaler = <1>; - apb2-prescaler = <1>; - apb4-prescaler = <1>; - apb5-prescaler = <1>; + timg-prescaler = <2>; }; &adc1 { @@ -170,7 +200,7 @@ &sdmmc2_ck_pc2 &sdmmc2_cmd_pc3>; pinctrl-names = "default"; bus-width = <4>; - cd-gpios = <&gpion 8 GPIO_ACTIVE_HIGH>; + cd-gpios = <&gpion 12 GPIO_ACTIVE_HIGH>; pwr-gpios = <&gpioq 7 GPIO_ACTIVE_HIGH>; }; @@ -214,6 +244,9 @@ zephyr_udc0: &usbotg_hs1 { &xspim_p1_io12_pp12 &xspim_p1_io13_pp13 &xspim_p1_io14_pp14 &xspim_p1_io15_pp15>; pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK(AHB5, 5)>, + <&rcc STM32_SRC_IC3 XSPI1_SEL(2)>, + <&rcc STM32_CLOCK(AHB5, 13)>; status = "okay"; memc: aps256xxn_obr: memory@90000000 { @@ -234,6 +267,9 @@ zephyr_udc0: &usbotg_hs1 { &xspim_p2_io3_pn5 &xspim_p2_io4_pn8 &xspim_p2_io5_pn9 &xspim_p2_io6_pn10 &xspim_p2_io7_pn11>; pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK(AHB5, 12)>, + <&rcc STM32_SRC_IC3 XSPI1_SEL(2)>, + <&rcc STM32_CLOCK(AHB5, 13)>; status = "okay"; mx66uw1g45g: ospi-nor-flash@70000000 { @@ -289,3 +325,42 @@ zephyr_udc0: &usbotg_hs1 { reg = <0x0>; }; }; + +<dc { + clocks = <&rcc STM32_CLOCK(APB5, 1)>, + <&rcc STM32_SRC_IC16 LTDC_SEL(2)>; + pinctrl-0 = <<dc_r0_pg0 <dc_r1_pd9 <dc_r2_pd15 <dc_r3_pb4 + <dc_r4_ph4 <dc_r5_pa15 <dc_r6_pg11 <dc_r7_pd8 + <dc_g0_pg12 <dc_g1_pg1 <dc_g2_pa1 <dc_g3_pa0 + <dc_g4_pb15 <dc_g5_pb12 <dc_g6_pb11 <dc_g7_pg8 + <dc_b0_pg15 <dc_b1_pa7 <dc_b2_pb2 <dc_b3_pg6 + <dc_b4_ph3 <dc_b5_ph6 <dc_b6_pa8 <dc_b7_pa2 + <dc_de_pg13 <dc_clk_pb13 <dc_hsync_pb14 <dc_vsync_pe11>; + pinctrl-names = "default"; + disp-on-gpios = <&gpioq 3 GPIO_ACTIVE_HIGH>; + bl-ctrl-gpios = <&gpioq 6 GPIO_ACTIVE_HIGH>; + + ext-sdram = <&psram>; + + status = "okay"; + + width = <800>; + height = <480>; + pixel-format = ; + display-timings { + compatible = "zephyr,panel-timing"; + de-active = <0>; + pixelclk-active = <0>; + hsync-active = <0>; + vsync-active = <0>; + hsync-len = <4>; + vsync-len = <4>; + hback-porch = <8>; + vback-porch = <8>; + hfront-porch = <8>; + vfront-porch = <8>; + }; + def-back-color-red = <0xFF>; + def-back-color-green = <0xFF>; + def-back-color-blue = <0xFF>; +}; diff --git a/doc/_doxygen/groups.dox b/doc/_doxygen/groups.dox index 20b58037c571..6365dd4c63b1 100644 --- a/doc/_doxygen/groups.dox +++ b/doc/_doxygen/groups.dox @@ -85,14 +85,4 @@ @{ @} -@brief Tests -@defgroup all_tests Tests -@{ -@} - -@defgroup kernel_memprotect_tests Memory Protection -@ingroup all_tests -@{ -@} - */ diff --git a/doc/connectivity/networking/api/zperf.rst b/doc/connectivity/networking/api/zperf.rst index fe09823c0575..058f816cf3bc 100644 --- a/doc/connectivity/networking/api/zperf.rst +++ b/doc/connectivity/networking/api/zperf.rst @@ -13,13 +13,8 @@ Overview zperf is a shell utility which allows to generate network traffic in Zephyr. The tool may be used to evaluate network bandwidth. -zperf is compatible with iPerf_2.0.5. Note that in newer iPerf versions, -an error message like this is printed and the server reported statistics -are missing. - -.. code-block:: console - - LAST PACKET NOT RECEIVED!!! +zperf is compatible with iPerf 2.0.10 and newer. For compatability with older versions, +enable :kconfig:option:`CONFIG_NET_ZPERF_LEGACY_HEADER_COMPAT`. zperf can be enabled in any application, a dedicated sample is also present in Zephyr. See :zephyr:code-sample:`zperf sample application ` for details. diff --git a/doc/releases/release-notes-4.2.rst b/doc/releases/release-notes-4.2.rst index c2188a4aa02a..c13f31d9171e 100644 --- a/doc/releases/release-notes-4.2.rst +++ b/doc/releases/release-notes-4.2.rst @@ -163,6 +163,11 @@ New APIs and options * :kconfig:option:`CONFIG_NET_SOCKETS_INET_RAW` +* Sensor + + * :c:func:`sensor_value_to_deci` + * :c:func:`sensor_value_to_centi` + * Stepper * :c:func:`stepper_stop()` @@ -572,3 +577,6 @@ Other notable changes * Updated Mbed TLS to version 3.6.3 (from 3.6.2). The release notes can be found at: https://github.com/Mbed-TLS/mbedtls/releases/tag/mbedtls-3.6.3 + +* Updated TF-M to version 2.1.2 (from 2.1.1). The release notes can be found at: + https://trustedfirmware-m.readthedocs.io/en/tf-mv2.1.2/releases/2.1.2.html diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index e20cced556f7..b5ae6b9f26dc 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -61,3 +61,4 @@ zephyr_library_sources_ifdef(CONFIG_ADC_AD4114 adc_ad4114.c) zephyr_library_sources_ifdef(CONFIG_ADC_AD7124 adc_ad7124.c) zephyr_library_sources_ifdef(CONFIG_ADC_AD405X adc_ad405x.c) zephyr_library_sources_ifdef(CONFIG_ADC_AD4130 adc_ad4130.c) +zephyr_library_sources_ifdef(CONFIG_ADC_REALTEK_RTS5912 adc_realtek_rts5912.c) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 32b4e4175e10..a8a21ceeb3cd 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -146,4 +146,6 @@ source "drivers/adc/Kconfig.ad405x" source "drivers/adc/Kconfig.ad4130" +source "drivers/adc/Kconfig.rts5912" + endif # ADC diff --git a/drivers/adc/Kconfig.rts5912 b/drivers/adc/Kconfig.rts5912 new file mode 100644 index 000000000000..fdceea6f43a1 --- /dev/null +++ b/drivers/adc/Kconfig.rts5912 @@ -0,0 +1,10 @@ +# Copyright (c) 2025, Realtek, SIBG-SD7 +# SPDX-License-Identifier: Apache-2.0 + +config ADC_REALTEK_RTS5912 + bool "Realtek RTS5912 ADC drivers" + default y + depends on DT_HAS_REALTEK_RTS5912_ADC_ENABLED + select PINCTRL + help + This option enables the ADC driver for Realtek RTS5912 of processors. diff --git a/drivers/adc/adc_realtek_rts5912.c b/drivers/adc/adc_realtek_rts5912.c new file mode 100644 index 000000000000..5f517209a7b7 --- /dev/null +++ b/drivers/adc/adc_realtek_rts5912.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2025 Realtek, SIBG-SD7 + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT realtek_rts5912_adc + +#include +#include +#include +#include + +#include "reg/reg_adc.h" + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" + +#include +LOG_MODULE_REGISTER(adc_rts5912, CONFIG_ADC_LOG_LEVEL); + +#define RTS5912_ADC_MAX_CHAN 12 +#define RTS5912_ADC_POLLING_TIME_MS 1 +#define RTS5912_ADC_ENABLE_TIMEOUT 100 + +struct adc_rts5912_config { + volatile struct adc_regs *regs; + const struct pinctrl_dev_config *pcfg; +#ifdef CONFIG_CLOCK_CONTROL + const struct device *clk_dev; + struct rts5912_sccon_subsys sccon_cfg; +#endif +}; + +struct adc_rts5912_data { + struct adc_context ctx; + const struct device *adc_dev; + volatile uint16_t *buffer; + volatile uint16_t *repeat_buffer; + uint32_t channels; +}; + +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct adc_rts5912_data *data = CONTAINER_OF(ctx, struct adc_rts5912_data, ctx); + const struct device *adc_dev = data->adc_dev; + const struct adc_rts5912_config *const cfg = adc_dev->config; + volatile struct adc_regs *regs = cfg->regs; + + data->repeat_buffer = data->buffer; + + regs->ctrl |= ADC_CTRL_SGLDNINTEN; + regs->ctrl |= ADC_CTRL_START; +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat_sampling) +{ + struct adc_rts5912_data *data = CONTAINER_OF(ctx, struct adc_rts5912_data, ctx); + + if (repeat_sampling) { + data->buffer = data->repeat_buffer; + } +} + +static int adc_rts5912_channel_setup(const struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + const struct adc_rts5912_config *const cfg = dev->config; + volatile struct adc_regs *regs = cfg->regs; + + if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { + LOG_ERR("Conversion time not supported!"); + return -EINVAL; + } + + if (channel_cfg->channel_id >= RTS5912_ADC_MAX_CHAN) { + LOG_ERR("Channel %d not supported!", channel_cfg->channel_id); + return -EINVAL; + } + + if (channel_cfg->gain != ADC_GAIN_1) { + LOG_ERR("ADC gain not supported!"); + return -EINVAL; + } + + uint8_t channel_id = channel_cfg->channel_id; + + regs->chctrl |= ((0x01ul << channel_id) | (ADC_CHCTRL_LPFBP << channel_id)); + LOG_DBG("CHCTRL = 0x%08x", regs->chctrl); + + return 0; +} + +static bool adc_rts5912_validate_buffer_size(const struct adc_sequence *sequence) +{ + int chan_count = 0; + size_t buff_need; + uint32_t chan_mask; + + for (chan_mask = 0x80; chan_mask != 0; chan_mask >>= 1) { + if (chan_mask & sequence->channels) { + chan_count++; + } + } + + buff_need = chan_count * sizeof(uint16_t); + + if (sequence->options) { + buff_need *= 1 + sequence->options->extra_samplings; + } + + if (buff_need > sequence->buffer_size) { + return false; + } + + return true; +} + +static int adc_rts5912_enable(const struct device *dev) +{ + const struct adc_rts5912_config *const cfg = dev->config; + volatile struct adc_regs *regs = cfg->regs; + int64_t st = k_uptime_get(); + + regs->ctrl |= ADC_CTRL_EN; + while ((k_uptime_get() - st) < RTS5912_ADC_ENABLE_TIMEOUT) { + if (regs->sts & ADC_STS_RDY) { + return 0; + } + k_msleep(RTS5912_ADC_POLLING_TIME_MS); + } + + LOG_ERR("ADC enable timeout"); + regs->ctrl &= ~ADC_CTRL_EN; + + return -EIO; +} + +static int adc_rts5912_start_read(const struct device *dev, const struct adc_sequence *sequence) +{ + struct adc_rts5912_data *const data = dev->data; + + if (sequence->channels & ~BIT_MASK(RTS5912_ADC_MAX_CHAN)) { + LOG_ERR("Incorrect channels, bitmask 0x%x", sequence->channels); + return -EINVAL; + } + + if (sequence->channels == 0UL) { + LOG_ERR("No channel selected"); + return -EINVAL; + } + + if (!adc_rts5912_validate_buffer_size(sequence)) { + LOG_ERR("Incorrect buffer size"); + return -ENOMEM; + } + + data->channels = sequence->channels; + data->buffer = sequence->buffer; + + if (adc_rts5912_enable(dev) < 0) { + return -EIO; + } + + adc_context_start_read(&data->ctx, sequence); + + return adc_context_wait_for_completion(&data->ctx); +} + +static int adc_rts5912_read(const struct device *dev, const struct adc_sequence *sequence) +{ + struct adc_rts5912_data *const data = dev->data; + int error; + + adc_context_lock(&data->ctx, false, NULL); + error = adc_rts5912_start_read(dev, sequence); + adc_context_release(&data->ctx, error); + + return error; +} + +static void rts5912_adc_get_sample(const struct device *dev) +{ + const struct adc_rts5912_config *const cfg = dev->config; + volatile struct adc_regs *regs = cfg->regs; + struct adc_rts5912_data *const data = dev->data; + uint32_t idx; + uint32_t channels = data->channels; + uint32_t bit; + + /* + * Using the enabled channel bit set, from + * lowest channel number to highest, find out + * which channel is enabled and copy the ADC + * values from hardware registers to the data + * buffer. + */ + bit = find_lsb_set(channels); + + while (bit != 0) { + idx = bit - 1; + + *data->buffer = ((uint16_t)regs->chdata[idx] & ADC_CHDATA_RESULT_Msk); + data->buffer++; + + LOG_DBG("idx=%d, data=%x", idx, regs->chdata[idx]); + + channels &= ~BIT(idx); + bit = find_lsb_set(channels); + } +} + +static void adc_rts5912_single_isr(const struct device *dev) +{ + const struct adc_rts5912_config *const cfg = dev->config; + volatile struct adc_regs *regs = cfg->regs; + struct adc_rts5912_data *const data = dev->data; + + if (regs->sts & ADC_STS_SGLDN) { + LOG_DBG("single done interrupt triggered."); + + regs->ctrl &= ~(ADC_CTRL_SGLDNINTEN); + regs->sts &= regs->sts; + + rts5912_adc_get_sample(dev); + + regs->ctrl &= ~ADC_CTRL_EN; + adc_context_on_sampling_done(&data->ctx, dev); + } +} + +static int adc_rts5912_init(const struct device *dev) +{ + const struct adc_rts5912_config *const cfg = dev->config; + struct adc_rts5912_data *const data = dev->data; + volatile struct adc_regs *regs = cfg->regs; + + int ret; + + data->adc_dev = dev; + + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret != 0) { + LOG_ERR("rts5912 ADC pinctrl setup failed (%d)", ret); + return ret; + } + +#ifdef CONFIG_CLOCK_CONTROL + if (!device_is_ready(cfg->clk_dev)) { + LOG_ERR("clock \"%s\" device not ready", cfg->clk_dev->name); + return -ENODEV; + } + + ret = clock_control_on(cfg->clk_dev, (clock_control_subsys_t)&cfg->sccon_cfg); + if (ret != 0) { + LOG_ERR("clock power on fail"); + return ret; + } +#endif + + regs->ctrl = ADC_CTRL_RST; + + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), adc_rts5912_single_isr, + DEVICE_DT_INST_GET(0), 0); + irq_enable(DT_INST_IRQN(0)); + + adc_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +#define DEV_CONFIG_CLK_DEV_INIT(n) \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .sccon_cfg = { \ + .clk_grp = DT_INST_CLOCKS_CELL(n, clk_grp), \ + .clk_idx = DT_INST_CLOCKS_CELL(n, clk_idx), \ + } + +#define ADC_RTS5912_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + \ + static DEVICE_API(adc, adc_rts5912_api_##n) = { \ + .channel_setup = adc_rts5912_channel_setup, \ + .read = adc_rts5912_read, \ + .ref_internal = DT_INST_PROP(n, vref_mv), \ + }; \ + \ + static struct adc_rts5912_config adc_rts5912_dev_cfg_##n = { \ + .regs = (struct adc_regs *)(DT_INST_REG_ADDR(n)), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + DEV_CONFIG_CLK_DEV_INIT(n)}; \ + \ + static struct adc_rts5912_data adc_rts5912_dev_data_##n = { \ + ADC_CONTEXT_INIT_TIMER(adc_rts5912_dev_data_##n, ctx), \ + ADC_CONTEXT_INIT_LOCK(adc_rts5912_dev_data_##n, ctx), \ + ADC_CONTEXT_INIT_SYNC(adc_rts5912_dev_data_##n, ctx), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, adc_rts5912_init, NULL, &adc_rts5912_dev_data_##n, \ + &adc_rts5912_dev_cfg_##n, PRE_KERNEL_1, CONFIG_ADC_INIT_PRIORITY, \ + &adc_rts5912_api_##n); + +DT_INST_FOREACH_STATUS_OKAY(ADC_RTS5912_INIT) diff --git a/drivers/clock_control/clock_stm32_ll_h7.c b/drivers/clock_control/clock_stm32_ll_h7.c index e99ea44452a9..5d6bcb72fa99 100644 --- a/drivers/clock_control/clock_stm32_ll_h7.c +++ b/drivers/clock_control/clock_stm32_ll_h7.c @@ -406,6 +406,11 @@ static int stm32_clock_control_configure(const struct device *dev, return err; } + if (pclken->enr == NO_SEL) { + /* Domain clock is fixed. Nothing to set. Exit */ + return 0; + } + z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); sys_clear_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr), diff --git a/drivers/console/uart_mcumgr.c b/drivers/console/uart_mcumgr.c index 2b068e6810c4..b162f0bc27d2 100644 --- a/drivers/console/uart_mcumgr.c +++ b/drivers/console/uart_mcumgr.c @@ -19,7 +19,7 @@ static const struct device *const uart_mcumgr_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_uart_mcumgr)); /** Callback to execute when a valid fragment has been received. */ -static uart_mcumgr_recv_fn *uart_mgumgr_recv_cb; +static uart_mcumgr_recv_fn *uart_mcumgr_recv_cb; /** Contains the fragment currently being received. */ static struct uart_mcumgr_rx_buf *uart_mcumgr_cur_buf; @@ -140,7 +140,7 @@ static void uart_mcumgr_async(const struct device *dev, struct uart_event *evt, for (int i = 0; i < len; i++) { rx_buf = uart_mcumgr_rx_byte(p[i]); if (rx_buf != NULL) { - uart_mgumgr_recv_cb(rx_buf); + uart_mcumgr_recv_cb(rx_buf); } } break; @@ -190,7 +190,7 @@ static void uart_mcumgr_isr(const struct device *unused, void *user_data) for (i = 0; i < chunk_len; i++) { rx_buf = uart_mcumgr_rx_byte(buf[i]); if (rx_buf != NULL) { - uart_mgumgr_recv_cb(rx_buf); + uart_mcumgr_recv_cb(rx_buf); } } } @@ -239,7 +239,7 @@ static void uart_mcumgr_setup(const struct device *uart) void uart_mcumgr_register(uart_mcumgr_recv_fn *cb) { - uart_mgumgr_recv_cb = cb; + uart_mcumgr_recv_cb = cb; if (device_is_ready(uart_mcumgr_dev)) { uart_mcumgr_setup(uart_mcumgr_dev); diff --git a/drivers/counter/CMakeLists.txt b/drivers/counter/CMakeLists.txt index 13b12340b646..b2c636522806 100644 --- a/drivers/counter/CMakeLists.txt +++ b/drivers/counter/CMakeLists.txt @@ -56,3 +56,4 @@ zephyr_library_sources_ifdef(CONFIG_COUNTER_NXP_MRT counter_nxp_mrt. zephyr_library_sources_ifdef(CONFIG_COUNTER_RA_AGT counter_renesas_ra_agt.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_RENESAS_RZ_GTM counter_renesas_rz_gtm.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_REALTEK_RTS5912_SLWTMR counter_realtek_rts5912_slwtmr.c) +zephyr_library_sources_ifdef(CONFIG_COUNTER_REALTEK_RTS5912 counter_realtek_rts5912.c) diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index 0bc67ab8ff3e..2cff7c5f51e0 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -110,4 +110,6 @@ source "drivers/counter/Kconfig.renesas_rz" source "drivers/counter/Kconfig.rts5912_slwtmr" +source "drivers/counter/Kconfig.rts5912" + endif # COUNTER diff --git a/drivers/counter/Kconfig.rts5912 b/drivers/counter/Kconfig.rts5912 new file mode 100644 index 000000000000..da025e964506 --- /dev/null +++ b/drivers/counter/Kconfig.rts5912 @@ -0,0 +1,12 @@ +# Realtek counter configuration options + +# Copyright (c) 2025 Realtek Corporation +# SPDX-License-Identifier: Apache-2.0 + +config COUNTER_REALTEK_RTS5912 + bool "Realtek rts5912 series counter driver" + default y + depends on DT_HAS_REALTEK_RTS5912_TIMER_ENABLED + help + Enable counter driver for Realtek RTS5912 MCU series. Such driver + will expose the basic timer devices present on the MCU. diff --git a/drivers/counter/counter_realtek_rts5912.c b/drivers/counter/counter_realtek_rts5912.c new file mode 100644 index 000000000000..40505d661327 --- /dev/null +++ b/drivers/counter/counter_realtek_rts5912.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2025 Realtek Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT realtek_rts5912_timer + +/** + * @file + * @brief Realtek RTS5912 Counter driver + * + * This is the driver for the 32-bit counters on the Realtek SoCs. + * + * Notes: + * - The counters are running in down counting mode. + * - Interrupts are triggered (if enabled) when the counter + * reaches zero. + * - These are not free running counters where there are separate + * compare values for interrupts. When setting single shot alarms, + * the counter values are changed so that interrupts are triggered + * when the counters reach zero. + */ + +#include +#include +#include +#include +#include "reg/reg_timer.h" +#include +LOG_MODULE_REGISTER(counter_realtek_rts5912, CONFIG_COUNTER_LOG_LEVEL); +struct counter_rts5912_config { + struct counter_config_info info; + void (*config_func)(void); + volatile struct timer32_type *base_address; + uint16_t prescaler; + uint32_t clk_grp; + uint32_t clk_idx; + const struct device *clk_dev; +}; + +struct counter_rts5912_data { + counter_alarm_callback_t alarm_cb; + counter_top_callback_t top_cb; + void *user_data; +}; + +#define COUNTER_RTS5912_REG_BASE(_dev) \ + ((const struct counter_rts5912_config *const)_dev->config)->base_address + +static int counter_rts5912_start(const struct device *dev) +{ + const struct counter_rts5912_config *config = dev->config; + volatile struct timer32_type *counter = config->base_address; + + if (counter->ctrl & TIMER32_CTRL_EN) { + return 0; + } + + counter->ctrl |= (TIMER32_CTRL_EN); + + LOG_DBG("%p Counter started", dev); + + return 0; +} + +static int counter_rts5912_stop(const struct device *dev) +{ + const struct counter_rts5912_config *config = dev->config; + volatile struct timer32_type *counter = config->base_address; + + if (!(counter->ctrl & TIMER32_CTRL_EN)) { + /* Already stopped, nothing to do */ + return 0; + } + /* disable timer and disable interrupt. */ + counter->ctrl = TIMER32_CTRL_INTEN_DIS; + counter->cnt = counter->ldcnt; + /* w1c interrupt pending status */ + counter->intclr |= TIMER32_INTCLR_INTCLR; + + LOG_DBG("%p Counter stopped", dev); + + return 0; +} + +static int counter_rts5912_get_value(const struct device *dev, uint32_t *ticks) +{ + const struct counter_rts5912_config *config = dev->config; + volatile struct timer32_type *counter = config->base_address; + + *ticks = counter->cnt + 1; + return 0; +} + +static int counter_rts5912_set_alarm(const struct device *dev, uint8_t chan_id, + const struct counter_alarm_cfg *alarm_cfg) +{ + struct counter_rts5912_data *data = dev->data; + const struct counter_rts5912_config *counter_cfg = dev->config; + volatile struct timer32_type *counter = counter_cfg->base_address; + uint32_t value; + + if (chan_id != 0) { + LOG_ERR("Invalid channel id %u", chan_id); + return -ENOTSUP; + } + + /* Interrupts are only triggered when the counter reaches 0. + * So only relative alarms are supported. + */ + if (alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) { + return -ENOTSUP; + } + + if (data->alarm_cb != NULL) { + return -EBUSY; + } + + if (!alarm_cfg->callback) { + return -EINVAL; + } + + if (alarm_cfg->ticks > counter_cfg->info.max_top_value) { + return -EINVAL; + } + /* disable timer */ + counter->ctrl &= ~TIMER32_CTRL_EN; + /* disable interrupt */ + counter->ctrl |= TIMER32_CTRL_INTEN_DIS; + /* set in one-shot mode */ + counter->ctrl &= ~TIMER32_CTRL_MDSELS_PERIOD; + /* set load counter */ + counter->ldcnt = alarm_cfg->ticks; + + data->alarm_cb = alarm_cfg->callback; + data->user_data = alarm_cfg->user_data; + /* w1c interrupt status */ + counter->intclr |= TIMER32_INTCLR_INTCLR; + /* enable interrupt */ + counter->ctrl &= ~TIMER32_CTRL_INTEN_DIS; + + LOG_DBG("%p Counter alarm set to %u ticks", dev, alarm_cfg->ticks); + /* enable timer and re-load PRCNT to CNT */ + counter->ctrl |= TIMER32_CTRL_EN; + /* read count value to update register */ + value = counter->cnt; + + return 0; +} + +static int counter_rts5912_cancel_alarm(const struct device *dev, uint8_t chan_id) +{ + struct counter_rts5912_data *data = dev->data; + const struct counter_rts5912_config *config = dev->config; + volatile struct timer32_type *counter = config->base_address; + + if (chan_id != 0) { + LOG_ERR("Invalid channel id %u", chan_id); + return -ENOTSUP; + } + + counter->ctrl = 0; + + data->alarm_cb = NULL; + data->user_data = NULL; + + LOG_DBG("%p Counter alarm canceled", dev); + + return 0; +} + +static uint32_t counter_rts5912_get_pending_int(const struct device *dev) +{ + const struct counter_rts5912_config *config = dev->config; + volatile struct timer32_type *counter = config->base_address; + + return counter->intsts; +} + +static uint32_t counter_rts5912_get_top_value(const struct device *dev) +{ + const struct counter_rts5912_config *config = dev->config; + volatile struct timer32_type *counter = config->base_address; + + return counter->ldcnt; +} + +static int counter_rts5912_set_top_value(const struct device *dev, + const struct counter_top_cfg *cfg) +{ + const struct counter_rts5912_config *counter_cfg = dev->config; + struct counter_rts5912_data *data = dev->data; + volatile struct timer32_type *counter = counter_cfg->base_address; + uint32_t value; + int ret = 0; + + if (data->alarm_cb) { + return -EBUSY; + } + + if (cfg->ticks > counter_cfg->info.max_top_value) { + return -EINVAL; + } + + counter->ctrl &= ~TIMER32_CTRL_EN; + counter->ctrl |= TIMER32_CTRL_INTEN_DIS; + + counter->ldcnt = cfg->ticks; + + data->top_cb = cfg->callback; + data->user_data = cfg->user_data; + + if (data->top_cb) { + /* w1c interrupt status */ + counter->intclr |= TIMER32_INTCLR_INTCLR; + /* enable interrupt */ + counter->ctrl &= ~TIMER32_CTRL_INTEN_DIS; + /* enable periodic alarm mode */ + counter->ctrl |= TIMER32_CTRL_MDSELS_PERIOD; + } else { + counter->ctrl = TIMER32_CTRL_INTEN_DIS; + } + + LOG_DBG("%p Counter top value was set to %u", dev, cfg->ticks); + + counter->ctrl |= TIMER32_CTRL_EN; + /* read count value to update register */ + value = counter->cnt; + + return ret; +} + +static void counter_rts5912_isr(const struct device *dev) +{ + struct counter_rts5912_data *data = dev->data; + const struct counter_rts5912_config *config = dev->config; + volatile struct timer32_type *counter = config->base_address; + counter_alarm_callback_t alarm_cb; + void *user_data; + uint32_t value; + + /* disable timer */ + counter->ctrl &= ~TIMER32_CTRL_EN; + /* disable interrupt */ + counter->ctrl |= TIMER32_CTRL_INTEN_DIS; + /* clear interrupt pending status */ + counter->intclr |= TIMER32_INTCLR_INTCLR; + + LOG_DBG("%p Counter ISR", dev); + + if (data->alarm_cb) { + /* Alarm is one-shot, so disable callback */ + alarm_cb = data->alarm_cb; + data->alarm_cb = NULL; + user_data = data->user_data; + + alarm_cb(dev, 0, counter->cnt + 1, user_data); + } else if (data->top_cb) { + data->top_cb(dev, data->user_data); + /* periodic alarm mode, enable interrupt */ + counter->ctrl &= ~TIMER32_CTRL_INTEN_DIS; + /* enable timer again */ + counter->ctrl |= TIMER32_CTRL_EN; + /* read count value to update register */ + value = counter->cnt; + } +} + +static uint32_t counter_rts5912_get_freq(const struct device *dev) +{ + const struct counter_rts5912_config *counter_cfg = dev->config; + + return counter_cfg->info.freq; +} + +static DEVICE_API(counter, counter_rts5912_api) = { + .start = counter_rts5912_start, + .stop = counter_rts5912_stop, + .get_value = counter_rts5912_get_value, + .set_alarm = counter_rts5912_set_alarm, + .cancel_alarm = counter_rts5912_cancel_alarm, + .set_top_value = counter_rts5912_set_top_value, + .get_pending_int = counter_rts5912_get_pending_int, + .get_top_value = counter_rts5912_get_top_value, + .get_freq = counter_rts5912_get_freq, +}; + +static int counter_rts5912_init(const struct device *dev) +{ + const struct counter_rts5912_config *counter_cfg = dev->config; + volatile struct timer32_type *counter = counter_cfg->base_address; + int rc; + struct rts5912_sccon_subsys sccon_subsys = { + .clk_grp = counter_cfg->clk_grp, + .clk_idx = counter_cfg->clk_idx, + }; + + if (!device_is_ready(counter_cfg->clk_dev)) { + LOG_ERR("device is not ready"); + return -ENODEV; + } + + rc = clock_control_on(counter_cfg->clk_dev, (clock_control_subsys_t)&sccon_subsys); + if (rc != 0) { + LOG_ERR("clock power on fail"); + return rc; + } + + counter_rts5912_stop(dev); + + /* Set preload and actually pre-load the counter */ + counter->ldcnt = counter_cfg->info.max_top_value; + counter->cnt = counter_cfg->info.max_top_value; + + counter_cfg->config_func(); + LOG_DBG("Init complete!"); + return 0; +} + +#define DEV_CONFIG_CLK_DEV_INIT(n) \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .clk_grp = DT_INST_CLOCKS_CELL_BY_NAME(n, tmr32, clk_grp), \ + .clk_idx = DT_INST_CLOCKS_CELL_BY_NAME(n, tmr32, clk_idx), + +#define COUNTER_RTS5912_INIT(inst) \ + static void counter_rts5912_irq_config_##inst(void); \ + \ + static struct counter_rts5912_data counter_rts5912_dev_data_##inst; \ + \ + static struct counter_rts5912_config counter_rts5912_dev_config_##inst = { \ + .info = \ + { \ + .max_top_value = DT_INST_PROP(inst, max_value), \ + .freq = DT_INST_PROP(inst, clock_frequency) / \ + (1 << DT_INST_PROP(inst, prescaler)), \ + .flags = 0, \ + .channels = 1, \ + }, \ + \ + .config_func = counter_rts5912_irq_config_##inst, \ + .base_address = (struct timer32_type *)DT_INST_REG_ADDR(inst), \ + .prescaler = DT_INST_PROP(inst, prescaler), \ + DEV_CONFIG_CLK_DEV_INIT(inst)}; \ + \ + DEVICE_DT_INST_DEFINE(inst, counter_rts5912_init, NULL, &counter_rts5912_dev_data_##inst, \ + &counter_rts5912_dev_config_##inst, PRE_KERNEL_1, \ + CONFIG_COUNTER_INIT_PRIORITY, &counter_rts5912_api); \ + \ + static void counter_rts5912_irq_config_##inst(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), counter_rts5912_isr, \ + DEVICE_DT_INST_GET(inst), 0); \ + irq_enable(DT_INST_IRQN(inst)); \ + } + +DT_INST_FOREACH_STATUS_OKAY(COUNTER_RTS5912_INIT) diff --git a/drivers/display/Kconfig.stm32_ltdc b/drivers/display/Kconfig.stm32_ltdc index 135986ca967e..6b74d3d0e794 100644 --- a/drivers/display/Kconfig.stm32_ltdc +++ b/drivers/display/Kconfig.stm32_ltdc @@ -8,6 +8,7 @@ menuconfig STM32_LTDC default y depends on DT_HAS_ST_STM32_LTDC_ENABLED select USE_STM32_HAL_LTDC + select USE_STM32_HAL_RIF if SOC_SERIES_STM32N6X select CACHE_MANAGEMENT if CPU_HAS_DCACHE select PINCTRL help diff --git a/drivers/display/display_stm32_ltdc.c b/drivers/display/display_stm32_ltdc.c index 200cd286eac8..2de41651fd9e 100644 --- a/drivers/display/display_stm32_ltdc.c +++ b/drivers/display/display_stm32_ltdc.c @@ -76,7 +76,8 @@ struct display_stm32_ltdc_config { uint32_t height; struct gpio_dt_spec disp_on_gpio; struct gpio_dt_spec bl_ctrl_gpio; - struct stm32_pclken pclken; + const struct stm32_pclken *pclken; + size_t pclk_len; const struct reset_dt_spec reset; const struct pinctrl_dev_config *pctrl; void (*irq_config_func)(const struct device *dev); @@ -297,11 +298,22 @@ static int stm32_ltdc_display_blanking_on(const struct device *dev) return display_blanking_on(display_dev); } +/* This symbol takes the value 1 if one of the device instances */ +/* is configured in dts with a domain clock */ +#if STM32_DT_INST_DEV_DOMAIN_CLOCK_SUPPORT +#define STM32_LTDC_DOMAIN_CLOCK_SUPPORT 1 +#else +#define STM32_LTDC_DOMAIN_CLOCK_SUPPORT 0 +#endif + static int stm32_ltdc_init(const struct device *dev) { int err; const struct display_stm32_ltdc_config *config = dev->config; struct display_stm32_ltdc_data *data = dev->data; +#if defined(CONFIG_SOC_SERIES_STM32N6X) + RIMC_MasterConfig_t rimc = {0}; +#endif /* Configure and set display on/off GPIO */ if (config->disp_on_gpio.port) { @@ -337,12 +349,23 @@ static int stm32_ltdc_init(const struct device *dev) /* Turn on LTDC peripheral clock */ err = clock_control_on(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), - (clock_control_subsys_t) &config->pclken); + (clock_control_subsys_t) &config->pclken[0]); if (err < 0) { LOG_ERR("Could not enable LTDC peripheral clock"); return err; } + if (IS_ENABLED(STM32_LTDC_DOMAIN_CLOCK_SUPPORT) && (config->pclk_len > 1)) { + /* Enable LTDC clock source */ + err = clock_control_configure(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t) &config->pclken[1], + NULL); + if (err < 0) { + LOG_ERR("Could not configure LTDC peripheral clock"); + return err; + } + } + #if defined(CONFIG_SOC_SERIES_STM32F4X) LL_RCC_PLLSAI_Disable(); LL_RCC_PLLSAI_ConfigDomain_LTDC(LL_RCC_PLLSOURCE_HSE, @@ -416,6 +439,15 @@ static int stm32_ltdc_init(const struct device *dev) return err; } +#if defined(CONFIG_SOC_SERIES_STM32N6X) + /* Configure RIF for LTDC layer 1 */ + rimc.MasterCID = RIF_CID_1; + rimc.SecPriv = RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV; + HAL_RIF_RIMC_ConfigMasterAttributes(RIF_MASTER_INDEX_LTDC1 , &rimc); + HAL_RIF_RISC_SetSlaveSecureAttributes(RIF_RISC_PERIPH_INDEX_LTDCL1, + RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV); +#endif + /* Disable layer 2, since it not used */ __HAL_LTDC_LAYER_DISABLE(&data->hltdc, LTDC_LAYER_2); @@ -455,7 +487,7 @@ static int stm32_ltdc_suspend(const struct device *dev) /* Turn off LTDC peripheral clock */ err = clock_control_off(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), - (clock_control_subsys_t) &config->pclken); + (clock_control_subsys_t) &config->pclken[0]); return err; } @@ -501,8 +533,10 @@ static DEVICE_API(display, stm32_ltdc_display_api) = { #define FRAME_BUFFER_SECTION __stm32_sdram1_section #elif DT_SAME_NODE(DT_INST_PHANDLE(0, ext_sdram), DT_NODELABEL(sdram2)) #define FRAME_BUFFER_SECTION __stm32_sdram2_section +#elif DT_SAME_NODE(DT_INST_PHANDLE(0, ext_sdram), DT_NODELABEL(psram)) +#define FRAME_BUFFER_SECTION __stm32_psram_section #else -#error "LTDC ext-sdram property in device tree does not reference SDRAM1 or SDRAM2 node" +#error "LTDC ext-sdram property in device tree does not reference SDRAM1 or SDRAM2 node or PSRAM node" #define FRAME_BUFFER_SECTION #endif /* DT_SAME_NODE(DT_INST_PHANDLE(0, ext_sdram), DT_NODELABEL(sdram1)) */ @@ -632,6 +666,9 @@ static DEVICE_API(display, stm32_ltdc_display_api) = { }, \ }, \ }; \ + static const struct stm32_pclken pclken_##inst[] = \ + STM32_DT_INST_CLOCKS(inst); \ + \ static const struct display_stm32_ltdc_config stm32_ltdc_config_##inst = { \ .width = DT_INST_PROP(inst, width), \ .height = DT_INST_PROP(inst, height), \ @@ -640,10 +677,8 @@ static DEVICE_API(display, stm32_ltdc_display_api) = { .bl_ctrl_gpio = COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, bl_ctrl_gpios), \ (GPIO_DT_SPEC_INST_GET(inst, bl_ctrl_gpios)), ({ 0 })), \ .reset = RESET_DT_SPEC_INST_GET(0), \ - .pclken = { \ - .enr = DT_INST_CLOCKS_CELL(inst, bits), \ - .bus = DT_INST_CLOCKS_CELL(inst, bus) \ - }, \ + .pclken = pclken_##inst, \ + .pclk_len = DT_INST_NUM_CLOCKS(inst), \ .pctrl = STM32_LTDC_DEVICE_PINCTRL_GET(inst), \ .irq_config_func = stm32_ltdc_irq_config_func_##inst, \ .display_controller = DEVICE_DT_GET_OR_NULL( \ diff --git a/drivers/flash/flash_mspi_nor.c b/drivers/flash/flash_mspi_nor.c index a5ced1e00703..e297b01f5d98 100644 --- a/drivers/flash/flash_mspi_nor.c +++ b/drivers/flash/flash_mspi_nor.c @@ -6,47 +6,56 @@ #define DT_DRV_COMPAT jedec_mspi_nor -#include #include -#include #include #include #include -#include "jesd216.h" -#include "spi_nor.h" +#include "flash_mspi_nor.h" +#include "flash_mspi_nor_quirks.h" LOG_MODULE_REGISTER(flash_mspi_nor, CONFIG_FLASH_LOG_LEVEL); -#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios) -#define WITH_RESET_GPIO 1 -#endif +void flash_mspi_command_set(const struct device *dev, const struct flash_mspi_nor_cmd *cmd) +{ + struct flash_mspi_nor_data *dev_data = dev->data; + const struct flash_mspi_nor_config *dev_config = dev->config; -struct flash_mspi_nor_data { - struct k_sem acquired; - struct mspi_xfer_packet packet; - struct mspi_xfer xfer; -}; + memset(&dev_data->xfer, 0, sizeof(dev_data->xfer)); + memset(&dev_data->packet, 0, sizeof(dev_data->packet)); -struct flash_mspi_nor_config { - const struct device *bus; - uint32_t flash_size; - struct mspi_dev_id mspi_id; - struct mspi_dev_cfg mspi_cfg; - enum mspi_dev_cfg_mask mspi_cfg_mask; -#if defined(CONFIG_MSPI_XIP) - struct mspi_xip_cfg xip_cfg; -#endif -#if defined(WITH_RESET_GPIO) - struct gpio_dt_spec reset; - uint32_t reset_pulse_us; - uint32_t reset_recovery_us; -#endif -#if defined(CONFIG_FLASH_PAGE_LAYOUT) - struct flash_pages_layout layout; -#endif - uint8_t jedec_id[SPI_NOR_MAX_ID_LEN]; -}; + dev_data->xfer.xfer_mode = MSPI_PIO; + dev_data->xfer.packets = &dev_data->packet; + dev_data->xfer.num_packet = 1; + dev_data->xfer.timeout = 10; + + dev_data->xfer.cmd_length = cmd->cmd_length; + dev_data->xfer.addr_length = cmd->addr_length; + dev_data->xfer.tx_dummy = (cmd->dir == MSPI_TX) ? + cmd->tx_dummy : dev_config->mspi_nor_cfg.tx_dummy; + dev_data->xfer.rx_dummy = (cmd->dir == MSPI_RX) ? + cmd->rx_dummy : dev_config->mspi_nor_cfg.rx_dummy; + + dev_data->packet.dir = cmd->dir; + dev_data->packet.cmd = cmd->cmd; +} + +static int dev_cfg_apply(const struct device *dev, const struct mspi_dev_cfg *cfg) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + struct flash_mspi_nor_data *dev_data = dev->data; + + if (dev_data->curr_cfg == cfg) { + return 0; + } + + int rc = mspi_dev_config(dev_config->bus, &dev_config->mspi_id, + MSPI_DEVICE_CONFIG_ALL, cfg); + if (rc < 0) { + LOG_ERR("Failed to set device config: %p error: %d", cfg, rc); + } + return rc; +} static int acquire(const struct device *dev) { @@ -64,8 +73,8 @@ static int acquire(const struct device *dev) * if needed for the flash device. */ rc = mspi_dev_config(dev_config->bus, &dev_config->mspi_id, - dev_config->mspi_cfg_mask, - &dev_config->mspi_cfg); + dev_config->mspi_nor_cfg_mask, + &dev_config->mspi_nor_cfg); if (rc < 0) { LOG_ERR("mspi_dev_config() failed: %d", rc); } else { @@ -125,12 +134,18 @@ static int api_read(const struct device *dev, off_t addr, void *dest, return rc; } + if (dev_config->jedec_cmds->read.force_single) { + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_init_cfg); + } else { + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_cfg); + } + + if (rc < 0) { + return rc; + } + /* TODO: get rid of all these hard-coded values for MX25Ux chips */ - dev_data->xfer.cmd_length = 2; - dev_data->xfer.addr_length = 4; - dev_data->xfer.rx_dummy = 20; - dev_data->packet.dir = MSPI_RX; - dev_data->packet.cmd = SPI_NOR_OCMD_RD; + flash_mspi_command_set(dev, &dev_config->jedec_cmds->read); dev_data->packet.address = addr; dev_data->packet.data_buf = dest; dev_data->packet.num_bytes = size; @@ -140,35 +155,58 @@ static int api_read(const struct device *dev, off_t addr, void *dest, release(dev); if (rc < 0) { - LOG_ERR("SPI_NOR_OCMD_RD xfer failed: %d", rc); + LOG_ERR("Read xfer failed: %d", rc); return rc; } return 0; } -static int wait_until_ready(const struct device *dev, k_timeout_t poll_period) +static int status_get(const struct device *dev, uint8_t *status) { const struct flash_mspi_nor_config *dev_config = dev->config; struct flash_mspi_nor_data *dev_data = dev->data; - uint8_t status_reg; int rc; + /* Enter command mode */ + if (dev_config->jedec_cmds->status.force_single) { + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_init_cfg); + } else { + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_cfg); + } + + if (rc < 0) { + LOG_ERR("Switching to dev_cfg failed: %d", rc); + return rc; + } + + flash_mspi_command_set(dev, &dev_config->jedec_cmds->status); + dev_data->packet.data_buf = status; + dev_data->packet.num_bytes = sizeof(uint8_t); + + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer); + + if (rc < 0) { + LOG_ERR("Status xfer failed: %d", rc); + return rc; + } + + return rc; +} + +static int wait_until_ready(const struct device *dev, k_timeout_t poll_period) +{ + int rc; + uint8_t status_reg; + while (true) { - dev_data->xfer.cmd_length = 2; - dev_data->xfer.addr_length = 4; - dev_data->xfer.rx_dummy = 4; - dev_data->packet.dir = MSPI_RX; - dev_data->packet.cmd = SPI_NOR_OCMD_RDSR; - dev_data->packet.address = 0; - dev_data->packet.data_buf = &status_reg; - dev_data->packet.num_bytes = sizeof(status_reg); - rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, - &dev_data->xfer); + rc = status_get(dev, &status_reg); + if (rc < 0) { - LOG_ERR("SPI_NOR_OCMD_RDSR xfer failed: %d", rc); + LOG_ERR("Wait until ready - status xfer failed: %d", rc); return rc; } + if (!(status_reg & SPI_NOR_WIP_BIT)) { break; } @@ -179,6 +217,26 @@ static int wait_until_ready(const struct device *dev, k_timeout_t poll_period) return 0; } +static int write_enable(const struct device *dev) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + struct flash_mspi_nor_data *dev_data = dev->data; + int rc; + + if (dev_config->jedec_cmds->write_en.force_single) { + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_init_cfg); + } else { + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_cfg); + } + + if (rc < 0) { + return rc; + } + + flash_mspi_command_set(dev, &dev_config->jedec_cmds->write_en); + return mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer); +} + static int api_write(const struct device *dev, off_t addr, const void *src, size_t size) { @@ -207,29 +265,29 @@ static int api_write(const struct device *dev, off_t addr, const void *src, uint16_t page_left = page_size - page_offset; uint16_t to_write = (uint16_t)MIN(size, page_left); - dev_data->xfer.cmd_length = 2; - dev_data->xfer.tx_dummy = 0; - dev_data->packet.dir = MSPI_TX; + if (write_enable(dev) < 0) { + LOG_ERR("Write enable xfer failed: %d", rc); + break; + } + + if (dev_config->jedec_cmds->page_program.force_single) { + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_init_cfg); + } else { + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_cfg); + } - dev_data->xfer.addr_length = 0; - dev_data->packet.cmd = SPI_NOR_OCMD_WREN; - dev_data->packet.num_bytes = 0; - rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, - &dev_data->xfer); if (rc < 0) { - LOG_ERR("SPI_NOR_OCMD_WREN xfer failed: %d", rc); - break; + return rc; } - dev_data->xfer.addr_length = 4; - dev_data->packet.cmd = SPI_NOR_OCMD_PAGE_PRG; + flash_mspi_command_set(dev, &dev_config->jedec_cmds->page_program); dev_data->packet.address = addr; dev_data->packet.data_buf = (uint8_t *)src; dev_data->packet.num_bytes = to_write; rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer); if (rc < 0) { - LOG_ERR("SPI_NOR_OCMD_PAGE_PRG xfer failed: %d", rc); + LOG_ERR("Page program xfer failed: %d", rc); break; } @@ -273,32 +331,40 @@ static int api_erase(const struct device *dev, off_t addr, size_t size) } while (size > 0) { - dev_data->xfer.cmd_length = 2; - dev_data->xfer.tx_dummy = 0; - dev_data->packet.dir = MSPI_TX; - dev_data->packet.num_bytes = 0; - - dev_data->xfer.addr_length = 0; - dev_data->packet.cmd = SPI_NOR_OCMD_WREN; - rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, - &dev_data->xfer); + rc = write_enable(dev); if (rc < 0) { - LOG_ERR("SPI_NOR_OCMD_WREN xfer failed: %d", rc); + LOG_ERR("Write enable failed."); break; } if (size == flash_size) { /* Chip erase. */ - dev_data->xfer.addr_length = 0; - dev_data->packet.cmd = SPI_NOR_OCMD_CE; + if (dev_config->jedec_cmds->chip_erase.force_single) { + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_init_cfg); + } else { + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_cfg); + } + if (rc < 0) { + return rc; + } + + flash_mspi_command_set(dev, &dev_config->jedec_cmds->chip_erase); size -= flash_size; } else { /* Sector erase. */ - dev_data->xfer.addr_length = 4; - dev_data->packet.cmd = SPI_NOR_OCMD_SE; - dev_data->packet.address = addr; - + if (dev_config->jedec_cmds->sector_erase.force_single) { + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_init_cfg); + } else { + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_cfg); + } + + if (rc < 0) { + return rc; + } + + flash_mspi_command_set(dev, &dev_config->jedec_cmds->sector_erase); + dev_data->packet.address = addr; addr += SPI_NOR_SECTOR_SIZE; size -= SPI_NOR_SECTOR_SIZE; } @@ -340,19 +406,24 @@ static int read_jedec_id(const struct device *dev, uint8_t *id) struct flash_mspi_nor_data *dev_data = dev->data; int rc; - dev_data->xfer.cmd_length = 2; - dev_data->xfer.addr_length = 4; - dev_data->xfer.rx_dummy = 4; - dev_data->packet.dir = MSPI_RX; - dev_data->packet.cmd = JESD216_OCMD_READ_ID; - dev_data->packet.address = 0; + if (dev_config->jedec_cmds->id.force_single) { + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_init_cfg); + } else { + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_cfg); + } + + if (rc < 0) { + return rc; + } + + flash_mspi_command_set(dev, &dev_config->jedec_cmds->id); dev_data->packet.data_buf = id; dev_data->packet.num_bytes = JESD216_READ_ID_LEN; + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer); if (rc < 0) { - printk("mspi_transceive() failed: %d\n", rc); - return rc; + LOG_ERR("Read JEDEC ID failed: %d\n", rc); } return rc; @@ -387,18 +458,24 @@ static int api_sfdp_read(const struct device *dev, off_t addr, void *dest, return rc; } - dev_data->xfer.cmd_length = 2; - dev_data->xfer.addr_length = 4; - dev_data->xfer.rx_dummy = 20; - dev_data->packet.dir = MSPI_RX; - dev_data->packet.cmd = JESD216_OCMD_READ_SFDP; + if (dev_config->jedec_cmds->sfdp.force_single) { + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_init_cfg); + } else { + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_cfg); + } + + if (rc < 0) { + return rc; + } + + flash_mspi_command_set(dev, &dev_config->jedec_cmds->sfdp); dev_data->packet.address = addr; dev_data->packet.data_buf = dest; dev_data->packet.num_bytes = size; rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer); if (rc < 0) { - printk("JESD216_OCMD_READ_SFDP xfer failed: %d\n", rc); + printk("Read SFDP xfer failed: %d\n", rc); return rc; } @@ -409,9 +486,7 @@ static int api_sfdp_read(const struct device *dev, off_t addr, void *dest, static int api_read_jedec_id(const struct device *dev, uint8_t *id) { - int rc = 0; - - rc = acquire(dev); + int rc = acquire(dev); if (rc < 0) { return rc; } @@ -439,87 +514,193 @@ static int dev_pm_action_cb(const struct device *dev, return 0; } -static int flash_chip_init(const struct device *dev) +static int quad_enable_set(const struct device *dev, bool enable) { const struct flash_mspi_nor_config *dev_config = dev->config; struct flash_mspi_nor_data *dev_data = dev->data; - struct mspi_dev_cfg init_dev_cfg = dev_config->mspi_cfg; - uint8_t id[JESD216_READ_ID_LEN] = {0}; int rc; - init_dev_cfg.freq = MHZ(1); - init_dev_cfg.io_mode = MSPI_IO_MODE_SINGLE; + flash_mspi_command_set(dev, &commands_single.write_en); + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, + &dev_data->xfer); + if (rc < 0) { + LOG_ERR("Failed to set write enable: %d", rc); + return rc; + } + + if (dev_config->dw15_qer == JESD216_DW15_QER_VAL_S1B6) { + const struct flash_mspi_nor_cmd cmd_status = { + .dir = MSPI_TX, + .cmd = SPI_NOR_CMD_WRSR, + .cmd_length = 1, + }; + uint8_t mode_payload = enable ? BIT(6) : 0; + + flash_mspi_command_set(dev, &cmd_status); + dev_data->packet.data_buf = &mode_payload; + dev_data->packet.num_bytes = sizeof(mode_payload); + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer); + + if (rc < 0) { + LOG_ERR("Failed to enable/disable quad mode: %d", rc); + return rc; + } + } else { + /* TODO: handle all DW15 QER values */ + return -ENOTSUP; + } + + rc = wait_until_ready(dev, K_USEC(1)); - rc = mspi_dev_config(dev_config->bus, &dev_config->mspi_id, - MSPI_DEVICE_CONFIG_ALL, &init_dev_cfg); if (rc < 0) { - LOG_ERR("Failed to set initial device config: %d", rc); + LOG_ERR("Failed waiting until device ready after enabling quad: %d", rc); return rc; } - dev_data->xfer.xfer_mode = MSPI_PIO; - dev_data->xfer.packets = &dev_data->packet; - dev_data->xfer.num_packet = 1; - dev_data->xfer.timeout = 10; + return 0; +} - dev_data->xfer.cmd_length = 1; - dev_data->xfer.addr_length = 0; - dev_data->xfer.tx_dummy = 0; - dev_data->xfer.rx_dummy = 0; - dev_data->packet.dir = MSPI_RX; - dev_data->packet.cmd = JESD216_CMD_READ_ID; - dev_data->packet.data_buf = id; - dev_data->packet.num_bytes = sizeof(id); - rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, - &dev_data->xfer); +static int default_io_mode(const struct device *dev) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + enum mspi_io_mode io_mode = dev_config->mspi_nor_cfg.io_mode; + int rc = 0; + + /* For Quad 1-1-4 and 1-4-4, entering or leaving mode is defined in JEDEC216 BFP DW15 QER */ + if (io_mode == MSPI_IO_MODE_SINGLE) { + rc = quad_enable_set(dev, false); + } else if ((io_mode == MSPI_IO_MODE_QUAD_1_1_4) || (io_mode == MSPI_IO_MODE_QUAD_1_4_4)) { + rc = quad_enable_set(dev, true); + } + + if (rc < 0) { + LOG_ERR("Failed to modify Quad Enable bit: %d", rc); + } + + if ((dev_config->quirks != NULL) && (dev_config->quirks->post_switch_mode != NULL)) { + rc = dev_config->quirks->post_switch_mode(dev); + } + + if (rc < 0) { + LOG_ERR("Failed to change IO mode: %d\n", rc); + return rc; + } + + return dev_cfg_apply(dev, &dev_config->mspi_nor_cfg); +} + +#if defined(WITH_RESET_GPIO) +static int gpio_reset(const struct device *dev) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + int rc; + + if (dev_config->reset.port) { + if (!gpio_is_ready_dt(&dev_config->reset)) { + LOG_ERR("Device %s is not ready", + dev_config->reset.port->name); + return -ENODEV; + } + + rc = gpio_pin_configure_dt(&dev_config->reset, + GPIO_OUTPUT_ACTIVE); + if (rc < 0) { + LOG_ERR("Failed to activate RESET: %d", rc); + return -EIO; + } + + if (dev_config->reset_pulse_us != 0) { + k_busy_wait(dev_config->reset_pulse_us); + } + + rc = gpio_pin_set_dt(&dev_config->reset, 0); + if (rc < 0) { + LOG_ERR("Failed to deactivate RESET: %d", rc); + return -EIO; + } + + if (dev_config->reset_recovery_us != 0) { + k_busy_wait(dev_config->reset_recovery_us); + } + } + + return 0; +} +#endif + +static int flash_chip_init(const struct device *dev) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + struct flash_mspi_nor_data *dev_data = dev->data; + enum mspi_io_mode io_mode = dev_config->mspi_nor_cfg.io_mode; + uint8_t id[JESD216_READ_ID_LEN] = {0}; + int rc; + + rc = dev_cfg_apply(dev, &dev_config->mspi_nor_init_cfg); + if (rc < 0) { - LOG_ERR("Failed to read JEDEC ID in single line mode: %d", rc); return rc; } - /* - * If the read ID does not match the one from DTS, assume the flash - * is already in the Octa I/O mode, so switching it is not needed. + /* Some chips reuse RESET pin for data in Quad modes: + * force single line mode before resetting. */ - if (memcmp(id, dev_config->jedec_id, sizeof(id)) == 0) { - static const uint8_t enable_sopi[] = { 0x01 }; + if ((io_mode == MSPI_IO_MODE_SINGLE) || (io_mode == MSPI_IO_MODE_QUAD_1_1_4) || + (io_mode == MSPI_IO_MODE_QUAD_1_4_4)) { + rc = quad_enable_set(dev, false); - dev_data->packet.dir = MSPI_TX; - dev_data->packet.cmd = SPI_NOR_CMD_WREN; - dev_data->packet.num_bytes = 0; - rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, - &dev_data->xfer); if (rc < 0) { - LOG_ERR("SPI_NOR_CMD_WREN xfer failed: %d", rc); + LOG_ERR("Failed to switch to single line mode: %d", rc); return rc; } - dev_data->xfer.addr_length = 4; - dev_data->packet.cmd = SPI_NOR_CMD_WR_CFGREG2; - dev_data->packet.address = 0; - dev_data->packet.data_buf = (uint8_t *)&enable_sopi; - dev_data->packet.num_bytes = sizeof(enable_sopi); - rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, - &dev_data->xfer); + rc = wait_until_ready(dev, K_USEC(1)); + if (rc < 0) { - printk("SPI_NOR_CMD_WR_CFGREG2 xfer failed: %d\n", rc); + LOG_ERR("Failed waiting for device after switch to single line: %d", rc); return rc; } } - rc = mspi_dev_config(dev_config->bus, &dev_config->mspi_id, - MSPI_DEVICE_CONFIG_ALL, &dev_config->mspi_cfg); +#if defined(WITH_RESET_GPIO) + rc = gpio_reset(dev); + if (rc < 0) { - LOG_ERR("Failed to set device config: %d", rc); + LOG_ERR("Failed to reset with GPIO: %d", rc); return rc; } +#endif + + flash_mspi_command_set(dev, &commands_single.id); + dev_data->packet.data_buf = id; + dev_data->packet.num_bytes = sizeof(id); + + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, + &dev_data->xfer); + if (rc < 0) { + LOG_ERR("Failed to read JEDEC ID in initial line mode: %d", rc); + return rc; + } + + rc = default_io_mode(dev); - rc = read_jedec_id(dev, id); if (rc < 0) { + LOG_ERR("Failed to switch to default io mode: %d", rc); return rc; } + /* Reading JEDEC ID for mode that forces single lane would be redundant, + * since it switches back to single lane mode. Use ID from previous read. + */ + if (!dev_config->jedec_cmds->id.force_single) { + rc = read_jedec_id(dev, id); + if (rc < 0) { + LOG_ERR("Failed to read JEDEC ID in final line mode: %d", rc); + return rc; + } + } + if (memcmp(id, dev_config->jedec_id, sizeof(id)) != 0) { LOG_ERR("JEDEC ID mismatch, read: %02x %02x %02x, " "expected: %02x %02x %02x", @@ -555,37 +736,6 @@ static int drv_init(const struct device *dev) return -ENODEV; } -#if defined(WITH_RESET_GPIO) - if (dev_config->reset.port) { - if (!gpio_is_ready_dt(&dev_config->reset)) { - LOG_ERR("Device %s is not ready", - dev_config->reset.port->name); - return -ENODEV; - } - - rc = gpio_pin_configure_dt(&dev_config->reset, - GPIO_OUTPUT_ACTIVE); - if (rc < 0) { - LOG_ERR("Failed to activate RESET: %d", rc); - return -EIO; - } - - if (dev_config->reset_pulse_us != 0) { - k_busy_wait(dev_config->reset_pulse_us); - } - - rc = gpio_pin_set_dt(&dev_config->reset, 0); - if (rc < 0) { - LOG_ERR("Failed to deactivate RESET: %d", rc); - return -EIO; - } - - if (dev_config->reset_recovery_us != 0) { - k_busy_wait(dev_config->reset_recovery_us); - } - } -#endif - rc = pm_device_runtime_get(dev_config->bus); if (rc < 0) { LOG_ERR("pm_device_runtime_get() failed: %d", rc); @@ -624,8 +774,60 @@ static DEVICE_API(flash, drv_api) = { #endif }; +#define FLASH_INITIAL_CONFIG(inst) \ +{ \ + .ce_num = DT_INST_PROP_OR(inst, mspi_hardware_ce_num, 0), \ + .freq = MIN(DT_INST_PROP(inst, mspi_max_frequency), MHZ(50)), \ + .io_mode = MSPI_IO_MODE_SINGLE, \ + .data_rate = MSPI_DATA_RATE_SINGLE, \ + .cpp = MSPI_CPP_MODE_0, \ + .endian = MSPI_XFER_BIG_ENDIAN, \ + .ce_polarity = MSPI_CE_ACTIVE_LOW, \ + .dqs_enable = false, \ +} + #define FLASH_SIZE_INST(inst) (DT_INST_PROP(inst, size) / 8) +/* Define copies of mspi_io_mode enum values, so they can be used inside + * the COND_CODE_1 macros. + */ +#define _MSPI_IO_MODE_SINGLE 0 +#define _MSPI_IO_MODE_QUAD_1_4_4 6 +#define _MSPI_IO_MODE_OCTAL 7 +BUILD_ASSERT(_MSPI_IO_MODE_SINGLE == MSPI_IO_MODE_SINGLE, + "Please align _MSPI_IO_MODE_SINGLE macro value"); +BUILD_ASSERT(_MSPI_IO_MODE_QUAD_1_4_4 == MSPI_IO_MODE_QUAD_1_4_4, + "Please align _MSPI_IO_MODE_QUAD_1_4_4 macro value"); +BUILD_ASSERT(_MSPI_IO_MODE_OCTAL == MSPI_IO_MODE_OCTAL, + "Please align _MSPI_IO_MODE_OCTAL macro value"); + +/* Define a non-existing extern symbol to get an understandable compile-time error + * if the IO mode is not supported by the driver. + */ +extern const struct flash_mspi_nor_cmds mspi_io_mode_not_supported; + +#define FLASH_CMDS(inst) COND_CODE_1( \ + IS_EQ(DT_INST_ENUM_IDX(inst, mspi_io_mode), _MSPI_IO_MODE_SINGLE), \ + (&commands_single), \ + (COND_CODE_1( \ + IS_EQ(DT_INST_ENUM_IDX(inst, mspi_io_mode), _MSPI_IO_MODE_QUAD_1_4_4), \ + (&commands_quad_1_4_4), \ + (COND_CODE_1( \ + IS_EQ(DT_INST_ENUM_IDX(inst, mspi_io_mode), _MSPI_IO_MODE_OCTAL), \ + (&commands_octal), \ + (&mspi_io_mode_not_supported) \ + )) \ + )) \ +) + +#define FLASH_QUIRKS(inst) FLASH_MSPI_QUIRKS_GET(DT_DRV_INST(inst)) + +#define FLASH_DW15_QER_VAL(inst) _CONCAT(JESD216_DW15_QER_VAL_, \ + DT_INST_STRING_TOKEN(inst, quad_enable_requirements)) +#define FLASH_DW15_QER(inst) COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, quad_enable_requirements), \ + (FLASH_DW15_QER_VAL(inst)), (JESD216_DW15_QER_VAL_NONE)) + + #if defined(CONFIG_FLASH_PAGE_LAYOUT) BUILD_ASSERT((CONFIG_FLASH_MSPI_NOR_LAYOUT_PAGE_SIZE % 4096) == 0, "MSPI_NOR_FLASH_LAYOUT_PAGE_SIZE must be multiple of 4096"); @@ -651,17 +853,22 @@ BUILD_ASSERT((FLASH_SIZE_INST(inst) % CONFIG_FLASH_MSPI_NOR_LAYOUT_PAGE_SIZE) == #endif #define FLASH_MSPI_NOR_INST(inst) \ - BUILD_ASSERT(DT_INST_ENUM_IDX(inst, mspi_io_mode) == \ - MSPI_IO_MODE_OCTAL, \ - "Only Octal I/O mode is supported for now"); \ + BUILD_ASSERT((DT_INST_ENUM_IDX(inst, mspi_io_mode) == \ + MSPI_IO_MODE_SINGLE) || \ + (DT_INST_ENUM_IDX(inst, mspi_io_mode) == \ + MSPI_IO_MODE_QUAD_1_4_4) || \ + (DT_INST_ENUM_IDX(inst, mspi_io_mode) == \ + MSPI_IO_MODE_OCTAL), \ + "Only 1x, 1-4-4 and 8x I/O modes are supported for now"); \ PM_DEVICE_DT_INST_DEFINE(inst, dev_pm_action_cb); \ static struct flash_mspi_nor_data dev##inst##_data; \ static const struct flash_mspi_nor_config dev##inst##_config = { \ .bus = DEVICE_DT_GET(DT_INST_BUS(inst)), \ .flash_size = FLASH_SIZE_INST(inst), \ .mspi_id = MSPI_DEVICE_ID_DT_INST(inst), \ - .mspi_cfg = MSPI_DEVICE_CONFIG_DT_INST(inst), \ - .mspi_cfg_mask = DT_PROP(DT_INST_BUS(inst), \ + .mspi_nor_cfg = MSPI_DEVICE_CONFIG_DT_INST(inst), \ + .mspi_nor_init_cfg = FLASH_INITIAL_CONFIG(inst), \ + .mspi_nor_cfg_mask = DT_PROP(DT_INST_BUS(inst), \ software_multiperipheral) \ ? MSPI_DEVICE_CONFIG_ALL \ : MSPI_DEVICE_CONFIG_NONE, \ @@ -675,6 +882,9 @@ BUILD_ASSERT((FLASH_SIZE_INST(inst) % CONFIG_FLASH_MSPI_NOR_LAYOUT_PAGE_SIZE) == / 1000,)) \ FLASH_PAGE_LAYOUT_DEFINE(inst) \ .jedec_id = DT_INST_PROP(inst, jedec_id), \ + .jedec_cmds = FLASH_CMDS(inst), \ + .quirks = FLASH_QUIRKS(inst), \ + .dw15_qer = FLASH_DW15_QER(inst), \ }; \ FLASH_PAGE_LAYOUT_CHECK(inst) \ DEVICE_DT_INST_DEFINE(inst, \ diff --git a/drivers/flash/flash_mspi_nor.h b/drivers/flash/flash_mspi_nor.h new file mode 100644 index 000000000000..35a0bff4c215 --- /dev/null +++ b/drivers/flash/flash_mspi_nor.h @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __FLASH_MSPI_NOR_H__ +#define __FLASH_MSPI_NOR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "jesd216.h" +#include "spi_nor.h" + +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios) +#define WITH_RESET_GPIO 1 +#endif + +struct flash_mspi_nor_config { + const struct device *bus; + uint32_t flash_size; + struct mspi_dev_id mspi_id; + struct mspi_dev_cfg mspi_nor_cfg; + struct mspi_dev_cfg mspi_nor_init_cfg; + enum mspi_dev_cfg_mask mspi_nor_cfg_mask; +#if defined(CONFIG_MSPI_XIP) + struct mspi_xip_cfg xip_cfg; +#endif +#if defined(WITH_RESET_GPIO) + struct gpio_dt_spec reset; + uint32_t reset_pulse_us; + uint32_t reset_recovery_us; +#endif +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + struct flash_pages_layout layout; +#endif + uint8_t jedec_id[SPI_NOR_MAX_ID_LEN]; + const struct flash_mspi_nor_cmds *jedec_cmds; + struct flash_mspi_nor_quirks *quirks; + uint8_t dw15_qer; +}; + +struct flash_mspi_nor_data { + struct k_sem acquired; + struct mspi_xfer_packet packet; + struct mspi_xfer xfer; + struct mspi_dev_cfg *curr_cfg; +}; + +struct flash_mspi_nor_cmd { + enum mspi_xfer_direction dir; + uint32_t cmd; + uint16_t tx_dummy; + uint16_t rx_dummy; + uint8_t cmd_length; + uint8_t addr_length; + bool force_single; +}; + +struct flash_mspi_nor_cmds { + struct flash_mspi_nor_cmd id; + struct flash_mspi_nor_cmd write_en; + struct flash_mspi_nor_cmd read; + struct flash_mspi_nor_cmd status; + struct flash_mspi_nor_cmd config; + struct flash_mspi_nor_cmd page_program; + struct flash_mspi_nor_cmd sector_erase; + struct flash_mspi_nor_cmd chip_erase; + struct flash_mspi_nor_cmd sfdp; +}; + +const struct flash_mspi_nor_cmds commands_single = { + .id = { + .dir = MSPI_RX, + .cmd = JESD216_CMD_READ_ID, + .cmd_length = 1, + }, + .write_en = { + .dir = MSPI_TX, + .cmd = SPI_NOR_CMD_WREN, + .cmd_length = 1, + }, + .read = { + .dir = MSPI_RX, + .cmd = SPI_NOR_CMD_READ_FAST, + .cmd_length = 1, + .addr_length = 3, + .rx_dummy = 8, + }, + .status = { + .dir = MSPI_RX, + .cmd = SPI_NOR_CMD_RDSR, + .cmd_length = 1, + }, + .config = { + .dir = MSPI_RX, + .cmd = SPI_NOR_CMD_RDCR, + .cmd_length = 1, + }, + .page_program = { + .dir = MSPI_TX, + .cmd = SPI_NOR_CMD_PP, + .cmd_length = 1, + .addr_length = 3, + }, + .sector_erase = { + .dir = MSPI_TX, + .cmd = SPI_NOR_CMD_SE, + .cmd_length = 1, + .addr_length = 3, + }, + .chip_erase = { + .dir = MSPI_TX, + .cmd = SPI_NOR_CMD_CE, + .cmd_length = 1, + }, + .sfdp = { + .dir = MSPI_RX, + .cmd = JESD216_CMD_READ_SFDP, + .cmd_length = 1, + .addr_length = 3, + .rx_dummy = 8, + }, +}; + +const struct flash_mspi_nor_cmds commands_quad_1_4_4 = { + .id = { + .dir = MSPI_RX, + .cmd = JESD216_CMD_READ_ID, + .cmd_length = 1, + .force_single = true, + }, + .write_en = { + .dir = MSPI_TX, + .cmd = SPI_NOR_CMD_WREN, + .cmd_length = 1, + }, + .read = { + .dir = MSPI_RX, + .cmd = SPI_NOR_CMD_4READ, + .cmd_length = 1, + .addr_length = 3, + .rx_dummy = 6, + }, + .status = { + .dir = MSPI_RX, + .cmd = SPI_NOR_CMD_RDSR, + .cmd_length = 1, + .force_single = true, + }, + .config = { + .dir = MSPI_RX, + .cmd = SPI_NOR_CMD_RDCR, + .cmd_length = 1, + .force_single = true, + }, + .page_program = { + .dir = MSPI_TX, + .cmd = SPI_NOR_CMD_PP_1_4_4, + .cmd_length = 1, + .addr_length = 3, + }, + .sector_erase = { + .dir = MSPI_TX, + .cmd = SPI_NOR_CMD_SE, + .cmd_length = 1, + .addr_length = 3, + .force_single = true, + }, + .chip_erase = { + .dir = MSPI_TX, + .cmd = SPI_NOR_CMD_CE, + .cmd_length = 1, + }, + .sfdp = { + .dir = MSPI_RX, + .cmd = JESD216_CMD_READ_SFDP, + .cmd_length = 1, + .addr_length = 3, + .rx_dummy = 8, + .force_single = true, + }, +}; + +const struct flash_mspi_nor_cmds commands_octal = { + .id = { + .dir = MSPI_RX, + .cmd = JESD216_OCMD_READ_ID, + .cmd_length = 2, + .addr_length = 4, + .rx_dummy = 4 + }, + .write_en = { + .dir = MSPI_TX, + .cmd = SPI_NOR_OCMD_WREN, + .cmd_length = 2, + }, + .read = { + .dir = MSPI_RX, + .cmd = SPI_NOR_OCMD_RD, + .cmd_length = 2, + .addr_length = 4, + .rx_dummy = 20, + }, + .status = { + .dir = MSPI_RX, + .cmd = SPI_NOR_OCMD_RDSR, + .cmd_length = 2, + .addr_length = 4, + .rx_dummy = 4, + }, + .page_program = { + .dir = MSPI_TX, + .cmd = SPI_NOR_OCMD_PAGE_PRG, + .cmd_length = 2, + .addr_length = 4, + }, + .sector_erase = { + .dir = MSPI_TX, + .cmd = SPI_NOR_OCMD_SE, + .cmd_length = 2, + .addr_length = 4, + }, + .chip_erase = { + .dir = MSPI_TX, + .cmd = SPI_NOR_OCMD_CE, + .cmd_length = 2, + }, + .sfdp = { + .dir = MSPI_RX, + .cmd = JESD216_OCMD_READ_SFDP, + .cmd_length = 2, + .addr_length = 4, + .rx_dummy = 20, + }, +}; + +void flash_mspi_command_set(const struct device *dev, const struct flash_mspi_nor_cmd *cmd); + +#ifdef __cplusplus +} +#endif + +#endif /*__FLASH_MSPI_NOR_H__*/ diff --git a/drivers/flash/flash_mspi_nor_quirks.h b/drivers/flash/flash_mspi_nor_quirks.h new file mode 100644 index 000000000000..eb40ad1938aa --- /dev/null +++ b/drivers/flash/flash_mspi_nor_quirks.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __FLASH_MSPI_NOR_QUIRKS_H__ +#define __FLASH_MSPI_NOR_QUIRKS_H__ + +/* Flash chip specific quirks */ +struct flash_mspi_nor_quirks { + /* Called after switching to default IO mode. */ + int (*post_switch_mode)(const struct device *dev); +}; + +/* Extend this macro when adding new flash chip with quirks */ +#define FLASH_MSPI_QUIRKS_GET(node) \ + COND_CODE_1(DT_NODE_HAS_COMPAT_STATUS(node, mxicy_mx25r, okay), \ + (&flash_quirks_mxicy_mx25r), \ + (COND_CODE_1(DT_NODE_HAS_COMPAT_STATUS(node, mxicy_mx25u, okay), \ + (&flash_quirks_mxicy_mx25u), \ + (NULL)))) + +#if DT_HAS_COMPAT_STATUS_OKAY(mxicy_mx25r) + +#define MXICY_MX25R_LH_MASK BIT(1) +#define MXICY_MX25R_QE_MASK BIT(6) +#define MXICY_MX25R_REGS_LEN 3 + +static uint8_t mxicy_mx25r_hp_payload[MXICY_MX25R_REGS_LEN] = { + MXICY_MX25R_QE_MASK, 0x0, MXICY_MX25R_LH_MASK +}; + +/* For quad io mode above 8 MHz and single io mode above 33 MHz, + * high performance mode needs to be enabled. + */ +static inline bool needs_hp(enum mspi_io_mode io_mode, uint32_t freq) +{ + if ((io_mode == MSPI_IO_MODE_QUAD_1_1_4) || (io_mode == MSPI_IO_MODE_QUAD_1_4_4)) { + if (freq > MHZ(8)) { + return true; + } + } else if (io_mode == MSPI_IO_MODE_SINGLE) { + if (freq > MHZ(33)) { + return true; + } + } + + return false; +} + +static inline int mxicy_mx25r_post_switch_mode(const struct device *dev) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + struct flash_mspi_nor_data *dev_data = dev->data; + enum mspi_io_mode io_mode = dev_config->mspi_nor_cfg.io_mode; + uint32_t freq = dev_config->mspi_nor_cfg.freq; + int rc; + uint8_t status; + uint8_t config[MXICY_MX25R_REGS_LEN - 1]; + + if (!needs_hp(io_mode, freq)) { + return 0; + } + + /* Wait for previous write to finish */ + do { + flash_mspi_command_set(dev, &dev_config->jedec_cmds->status); + dev_data->packet.data_buf = &status; + dev_data->packet.num_bytes = sizeof(status); + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer); + if (rc < 0) { + return rc; + } + } while (status & SPI_NOR_WIP_BIT); + + /* Write enable */ + flash_mspi_command_set(dev, &commands_single.write_en); + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, + &dev_data->xfer); + if (rc < 0) { + return rc; + } + + /* Write status and config registers */ + const struct flash_mspi_nor_cmd cmd_status = { + .dir = MSPI_TX, + .cmd = SPI_NOR_CMD_WRSR, + .cmd_length = 1, + }; + + flash_mspi_command_set(dev, &cmd_status); + dev_data->packet.data_buf = mxicy_mx25r_hp_payload; + dev_data->packet.num_bytes = sizeof(mxicy_mx25r_hp_payload); + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer); + if (rc < 0) { + return rc; + } + + /* Wait for write to end and verify status register */ + do { + flash_mspi_command_set(dev, &dev_config->jedec_cmds->status); + dev_data->packet.data_buf = &status; + dev_data->packet.num_bytes = sizeof(status); + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer); + if (rc < 0) { + return rc; + } + } while (status & SPI_NOR_WIP_BIT); + + if (status != mxicy_mx25r_hp_payload[0]) { + return -EIO; + } + + /* Verify configuration registers */ + flash_mspi_command_set(dev, &dev_config->jedec_cmds->config); + dev_data->packet.data_buf = config; + dev_data->packet.num_bytes = sizeof(config); + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer); + if (rc < 0) { + return rc; + } + + for (uint8_t i = 0; i < MXICY_MX25R_REGS_LEN - 1; i++) { + if (config[i] != mxicy_mx25r_hp_payload[i + 1]) { + return -EIO; + } + } + + return 0; +} + +struct flash_mspi_nor_quirks flash_quirks_mxicy_mx25r = { + .post_switch_mode = mxicy_mx25r_post_switch_mode, +}; + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(mxicy_mx25r) */ + +#if DT_HAS_COMPAT_STATUS_OKAY(mxicy_mx25u) + +#define MXICY_MX25R_OE_MASK BIT(0) + +static uint8_t mxicy_mx25u_oe_payload = MXICY_MX25R_OE_MASK; + +static inline int mxicy_mx25u_post_switch_mode(const struct device *dev) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + struct flash_mspi_nor_data *dev_data = dev->data; + enum mspi_io_mode io_mode = dev_config->mspi_nor_cfg.io_mode; + int rc; + + if (io_mode != MSPI_IO_MODE_OCTAL) { + return 0; + } + + /* Write enable */ + flash_mspi_command_set(dev, &commands_single.write_en); + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, + &dev_data->xfer); + if (rc < 0) { + return rc; + } + + /* Write config register 2 */ + const struct flash_mspi_nor_cmd cmd_status = { + .dir = MSPI_TX, + .cmd = SPI_NOR_CMD_WR_CFGREG2, + .cmd_length = 1, + .addr_length = 4, + }; + + flash_mspi_command_set(dev, &cmd_status); + dev_data->packet.data_buf = &mxicy_mx25u_oe_payload; + dev_data->packet.num_bytes = sizeof(mxicy_mx25u_oe_payload); + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, &dev_data->xfer); + return rc; +} + +struct flash_mspi_nor_quirks flash_quirks_mxicy_mx25u = { + .post_switch_mode = mxicy_mx25u_post_switch_mode, +}; + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(mxicy_mx25u) */ + +#endif /*__FLASH_MSPI_NOR_QUIRKS_H__*/ diff --git a/drivers/i2c/i2c_ene_kb1200.c b/drivers/i2c/i2c_ene_kb1200.c index 359f99793e42..e6853d38c7cd 100644 --- a/drivers/i2c/i2c_ene_kb1200.c +++ b/drivers/i2c/i2c_ene_kb1200.c @@ -12,13 +12,20 @@ #include #include +#include +LOG_MODULE_REGISTER(i2c_ene, CONFIG_I2C_LOG_LEVEL); + +#include "i2c-priv.h" + struct i2c_kb1200_config { struct fsmbm_regs *fsmbm; + uint32_t clock_freq; const struct pinctrl_dev_config *pcfg; }; struct i2c_kb1200_data { - struct k_sem mutex; + struct k_sem lock; + struct k_sem wait; volatile uint8_t *msg_buf; volatile uint32_t msg_len; volatile uint8_t msg_flags; @@ -39,6 +46,7 @@ static void i2c_kb1200_isr(const struct device *dev) uint32_t remain = data->msg_len - data->index; uint32_t send_bytes = remain > FSMBM_BUFFER_SIZE ? FSMBM_BUFFER_SIZE : remain; + memcpy((void *)&config->fsmbm->FSMBMDAT[0], (void *)&data->msg_buf[data->index], send_bytes); data->index += send_bytes; @@ -52,7 +60,7 @@ static void i2c_kb1200_isr(const struct device *dev) } else if (config->fsmbm->FSMBMPF & FSMBM_COMPLETE_EVENT) { /* complete */ if (((config->fsmbm->FSMBMSTS & FSMBM_STS_MASK) == FSMBM_SMBUS_BUSY) && - ((config->fsmbm->FSMBMFRT & ___STOP) == ___NONE)) { + ((config->fsmbm->FSMBMFRT & FRT_STOP) == FRT_NONE)) { /* while packet finish without STOP, the error message is * FSMBM_SMBUS_BUSY */ @@ -61,10 +69,12 @@ static void i2c_kb1200_isr(const struct device *dev) data->err_code = config->fsmbm->FSMBMSTS & FSMBM_STS_MASK; } data->state = STATE_COMPLETE; + k_sem_give(&data->wait); config->fsmbm->FSMBMPF = FSMBM_COMPLETE_EVENT; } else { data->err_code = config->fsmbm->FSMBMSTS & FSMBM_STS_MASK; data->state = STATE_COMPLETE; + k_sem_give(&data->wait); } } else if (data->state == STATE_RECEIVING) { uint32_t remain = data->msg_len - data->index; @@ -89,7 +99,7 @@ static void i2c_kb1200_isr(const struct device *dev) } else if (config->fsmbm->FSMBMPF & FSMBM_COMPLETE_EVENT) { /* complete */ if (((config->fsmbm->FSMBMSTS & FSMBM_STS_MASK) == FSMBM_SMBUS_BUSY) && - ((config->fsmbm->FSMBMFRT & ___STOP) == ___NONE)) { + ((config->fsmbm->FSMBMFRT & FRT_STOP) == FRT_NONE)) { /* while packet finish without STOP, the error message is * FSMBM_SMBUS_BUSY */ @@ -98,13 +108,16 @@ static void i2c_kb1200_isr(const struct device *dev) data->err_code = config->fsmbm->FSMBMSTS & FSMBM_STS_MASK; } data->state = STATE_COMPLETE; + k_sem_give(&data->wait); config->fsmbm->FSMBMPF = FSMBM_COMPLETE_EVENT; } else { data->err_code = config->fsmbm->FSMBMSTS & FSMBM_STS_MASK; data->state = STATE_COMPLETE; + k_sem_give(&data->wait); } } else if (data->state == STATE_COMPLETE) { config->fsmbm->FSMBMPF = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT); + k_sem_give(&data->wait); } } @@ -112,14 +125,16 @@ static int i2c_kb1200_poll_write(const struct device *dev, struct i2c_msg msg, u { const struct i2c_kb1200_config *config = dev->config; struct i2c_kb1200_data *data = dev->data; - uint8_t send_bytes; + uint32_t send_bytes; + int ret; + k_sem_reset(&data->wait); if (msg.flags & I2C_MSG_STOP) { /* No CMD, No CNT, No PEC, with STOP*/ - config->fsmbm->FSMBMFRT = ___STOP; + config->fsmbm->FSMBMFRT = FRT_STOP; } else { /* No CMD, No CNT, No PEC, no STOP*/ - config->fsmbm->FSMBMFRT = ___NONE; + config->fsmbm->FSMBMFRT = FRT_NONE; } data->msg_len = msg.len; data->msg_buf = msg.buf; @@ -135,7 +150,7 @@ static int i2c_kb1200_poll_write(const struct device *dev, struct i2c_msg msg, u data->state = STATE_SENDING; config->fsmbm->FSMBMCMD = 0; - config->fsmbm->FSMBMADR = (addr & ~BIT(0)) | FSMBM_WRITE; + config->fsmbm->FSMBMADR = (addr << 1) | FSMBM_WRITE; config->fsmbm->FSMBMPF = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT); /* If data over bufferSize increase 1 to force continue transmit */ if (msg.len >= (FSMBM_BUFFER_SIZE + 1)) { @@ -145,15 +160,19 @@ static int i2c_kb1200_poll_write(const struct device *dev, struct i2c_msg msg, u } config->fsmbm->FSMBMIE = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT); config->fsmbm->FSMBMPRTC_P = FLEXIBLE_PROTOCOL; - while (data->state != STATE_COMPLETE) { - ; + + /* Wait until ISR or timeout */ + ret = k_sem_take(&data->wait, K_MSEC(FSMBM_MAX_TIMEOUT)); + if (ret == -EAGAIN) { + data->err_code |= FSMBM_SDA_TIMEOUT; } data->state = STATE_IDLE; - if (data->err_code != 0) { + if (data->err_code) { /* reset HW */ config->fsmbm->FSMBMCFG |= FSMBM_HW_RESET; return data->err_code; } + return 0; } @@ -161,13 +180,18 @@ static int i2c_kb1200_poll_read(const struct device *dev, struct i2c_msg msg, ui { const struct i2c_kb1200_config *config = dev->config; struct i2c_kb1200_data *data = dev->data; + int ret; + k_sem_reset(&data->wait); + if ((msg.flags & I2C_MSG_RESTART) && !(msg.flags & I2C_MSG_STOP)) { + LOG_ERR("ENE i2c format not support."); + } if (msg.flags & I2C_MSG_STOP) { /* No CMD, No CNT, No PEC, with STOP*/ - config->fsmbm->FSMBMFRT = ___STOP; + config->fsmbm->FSMBMFRT = FRT_STOP; } else { /* No CMD, No CNT, No PEC, no STOP*/ - config->fsmbm->FSMBMFRT = ___NONE; + config->fsmbm->FSMBMFRT = FRT_NONE; } data->msg_len = msg.len; data->msg_buf = msg.buf; @@ -178,7 +202,7 @@ static int i2c_kb1200_poll_read(const struct device *dev, struct i2c_msg msg, ui data->state = STATE_RECEIVING; config->fsmbm->FSMBMCMD = 0; - config->fsmbm->FSMBMADR = (addr & ~BIT(0)) | FSMBM_READ; + config->fsmbm->FSMBMADR = (addr << 1) | FSMBM_READ; config->fsmbm->FSMBMPF = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT); /* If data over bufferSize increase 1 to force continue receive */ if (msg.len >= (FSMBM_BUFFER_SIZE + 1)) { @@ -188,15 +212,20 @@ static int i2c_kb1200_poll_read(const struct device *dev, struct i2c_msg msg, ui } config->fsmbm->FSMBMIE = (FSMBM_COMPLETE_EVENT | FSMBM_BLOCK_FINISH_EVENT); config->fsmbm->FSMBMPRTC_P = FLEXIBLE_PROTOCOL; - while (data->state != STATE_COMPLETE) { - ; + + /* Wait until ISR or timeout */ + ret = k_sem_take(&data->wait, K_MSEC(FSMBM_MAX_TIMEOUT)); + if (ret == -EAGAIN) { + data->err_code |= FSMBM_SDA_TIMEOUT; } data->state = STATE_IDLE; - if (data->err_code != 0) { + + if (data->err_code) { /* reset HW */ config->fsmbm->FSMBMCFG |= FSMBM_HW_RESET; return data->err_code; } + return 0; } @@ -204,6 +233,7 @@ static int i2c_kb1200_poll_read(const struct device *dev, struct i2c_msg msg, ui static int i2c_kb1200_configure(const struct device *dev, uint32_t dev_config) { const struct i2c_kb1200_config *config = dev->config; + uint32_t speed; if (!(dev_config & I2C_MODE_CONTROLLER)) { return -ENOTSUP; @@ -213,7 +243,7 @@ static int i2c_kb1200_configure(const struct device *dev, uint32_t dev_config) return -ENOTSUP; } - uint32_t speed = I2C_SPEED_GET(dev_config); + speed = I2C_SPEED_GET(dev_config); switch (speed) { case I2C_SPEED_STANDARD: @@ -242,7 +272,7 @@ static int i2c_kb1200_get_config(const struct device *dev, uint32_t *dev_config) const struct i2c_kb1200_config *config = dev->config; if ((config->fsmbm->FSMBMCFG & FSMBM_FUNCTION_ENABLE) == 0x00) { - printk("Cannot find i2c controller on 0x%p!\n", config->fsmbm); + LOG_ERR("Cannot find i2c controller on 0x%p!", config->fsmbm); return -EIO; } @@ -251,6 +281,8 @@ static int i2c_kb1200_get_config(const struct device *dev, uint32_t *dev_config) *dev_config = I2C_MODE_CONTROLLER | I2C_SPEED_SET(I2C_SPEED_STANDARD); break; case FSMBM_CLK_400K: + case FSMBM_CLK_500K: + case FSMBM_CLK_666K: *dev_config = I2C_MODE_CONTROLLER | I2C_SPEED_SET(I2C_SPEED_FAST); break; case FSMBM_CLK_1M: @@ -267,27 +299,27 @@ static int i2c_kb1200_transfer(const struct device *dev, struct i2c_msg *msgs, u uint16_t addr) { struct i2c_kb1200_data *data = dev->data; - int ret; + int ret = 0; - /* get the mutex */ - k_sem_take(&data->mutex, K_FOREVER); + /* lock */ + k_sem_take(&data->lock, K_FOREVER); for (int i = 0U; i < num_msgs; i++) { if ((msgs[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) { ret = i2c_kb1200_poll_write(dev, msgs[i], addr); if (ret) { - printk("%s Write error: 0x%X\n", dev->name, ret); + ret = -EIO; break; } } else { ret = i2c_kb1200_poll_read(dev, msgs[i], addr); if (ret) { - printk("%s Read error: 0x%X\n", dev->name, ret); + ret = -EIO; break; } } } - /* release the mutex */ - k_sem_give(&data->mutex); + /* release the lock */ + k_sem_give(&data->lock); return ret; } @@ -332,14 +364,23 @@ static int i2c_kb1200_init(const struct device *dev) int ret; const struct i2c_kb1200_config *config = dev->config; struct i2c_kb1200_data *data = dev->data; + uint32_t bitrate_cfg; ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); if (ret != 0) { return ret; } - /* init mutex */ - k_sem_init(&data->mutex, 1, 1); + bitrate_cfg = i2c_map_dt_bitrate(config->clock_freq); + if (!bitrate_cfg) { + return -EINVAL; + } + + i2c_kb1200_configure(dev, bitrate_cfg | I2C_MODE_CONTROLLER); + + k_sem_init(&data->wait, 0, 1); + /* init lock */ + k_sem_init(&data->lock, 1, 1); kb1200_fsmbm_irq_init(); return 0; @@ -350,10 +391,11 @@ static int i2c_kb1200_init(const struct device *dev) static struct i2c_kb1200_data i2c_kb1200_data_##inst; \ static const struct i2c_kb1200_config i2c_kb1200_config_##inst = { \ .fsmbm = (struct fsmbm_regs *)DT_INST_REG_ADDR(inst), \ + .clock_freq = DT_INST_PROP(inst, clock_frequency), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ }; \ I2C_DEVICE_DT_INST_DEFINE(inst, &i2c_kb1200_init, NULL, &i2c_kb1200_data_##inst, \ - &i2c_kb1200_config_##inst, PRE_KERNEL_1, \ - CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &i2c_kb1200_api); + &i2c_kb1200_config_##inst, PRE_KERNEL_1, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &i2c_kb1200_api); DT_INST_FOREACH_STATUS_OKAY(I2C_KB1200_DEVICE) diff --git a/drivers/i2c/i2c_ll_stm32.c b/drivers/i2c/i2c_ll_stm32.c index 315c522da7d4..15809dabc9f0 100644 --- a/drivers/i2c/i2c_ll_stm32.c +++ b/drivers/i2c/i2c_ll_stm32.c @@ -587,15 +587,62 @@ static void i2c_stm32_irq_config_func_##index(const struct device *dev) \ #ifdef CONFIG_I2C_STM32_V2_DMA -#define I2C_DMA_INIT(index, dir) \ - .dir##_dma = {.dev_dma = COND_CODE_1(DT_INST_DMAS_HAS_NAME(index, dir), \ - (DEVICE_DT_GET(STM32_DMA_CTLR(index, dir))), (NULL)), \ - .dma_channel = COND_CODE_1(DT_INST_DMAS_HAS_NAME(index, dir), \ - (DT_INST_DMAS_CELL_BY_NAME(index, dir, channel)), (-1))}, +#define I2C_DMA_INIT(index, dir) \ + .dir##_dma = { \ + .dev_dma = COND_CODE_1(DT_INST_DMAS_HAS_NAME(index, dir),\ + (DEVICE_DT_GET(STM32_DMA_CTLR(index, dir))), (NULL)),\ + .dma_channel = COND_CODE_1(DT_INST_DMAS_HAS_NAME(index, dir),\ + (DT_INST_DMAS_CELL_BY_NAME(index, dir, channel)), (-1)),\ + }, + +void i2c_stm32_dma_tx_cb(const struct device *dma_dev, void *user_data, + uint32_t channel, int status) +{ + ARG_UNUSED(dma_dev); + ARG_UNUSED(user_data); + ARG_UNUSED(channel); + + /* log DMA TX error */ + if (status != 0) { + LOG_ERR("DMA error %d", status); + } +} + +void i2c_stm32_dma_rx_cb(const struct device *dma_dev, void *user_data, + uint32_t channel, int status) +{ + ARG_UNUSED(dma_dev); + ARG_UNUSED(user_data); + ARG_UNUSED(channel); + + /* log DMA RX error */ + if (status != 0) { + LOG_ERR("DMA error %d", status); + } +} + +#define I2C_DMA_DATA_INIT(index, dir, src, dest) \ + .dma_##dir##_cfg = { \ + .dma_slot = STM32_DMA_SLOT(index, dir, slot), \ + .channel_direction = STM32_DMA_CONFIG_DIRECTION( \ + STM32_DMA_CHANNEL_CONFIG(index, dir)),\ + .cyclic = STM32_DMA_CONFIG_CYCLIC( \ + STM32_DMA_CHANNEL_CONFIG(index, dir)), \ + .channel_priority = STM32_DMA_CONFIG_PRIORITY( \ + STM32_DMA_CHANNEL_CONFIG(index, dir)), \ + .source_data_size = STM32_DMA_CONFIG_##src##_DATA_SIZE( \ + STM32_DMA_CHANNEL_CONFIG(index, dir)),\ + .dest_data_size = STM32_DMA_CONFIG_##dest##_DATA_SIZE( \ + STM32_DMA_CHANNEL_CONFIG(index, dir)), \ + .source_burst_length = 1, \ + .dest_burst_length = 1, \ + .dma_callback = i2c_stm32_dma_##dir##_cb, \ + }, \ #else #define I2C_DMA_INIT(index, dir) +#define I2C_DMA_DATA_INIT(index, dir, src, dest) #endif /* CONFIG_I2C_STM32_V2_DMA */ @@ -624,11 +671,14 @@ static const struct i2c_stm32_config i2c_stm32_cfg_##index = { \ IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2), \ (.timings = (const struct i2c_config_timing *) i2c_timings_##index,\ .n_timings = ARRAY_SIZE(i2c_timings_##index),)) \ - I2C_DMA_INIT(index, tx) \ - I2C_DMA_INIT(index, rx) \ + I2C_DMA_INIT(index, tx) \ + I2C_DMA_INIT(index, rx) \ }; \ \ -static struct i2c_stm32_data i2c_stm32_dev_data_##index; \ +static struct i2c_stm32_data i2c_stm32_dev_data_##index = { \ + I2C_DMA_DATA_INIT(index, tx, MEMORY, PERIPHERAL) \ + I2C_DMA_DATA_INIT(index, rx, PERIPHERAL, MEMORY) \ +}; \ \ PM_DEVICE_DT_INST_DEFINE(index, i2c_stm32_pm_action); \ \ diff --git a/drivers/i2c/i2c_ll_stm32.h b/drivers/i2c/i2c_ll_stm32.h index e22aeff26202..962492400e5c 100644 --- a/drivers/i2c/i2c_ll_stm32.h +++ b/drivers/i2c/i2c_ll_stm32.h @@ -105,7 +105,8 @@ struct i2c_stm32_data { const struct device *smbalert_cb_dev; #endif #ifdef CONFIG_I2C_STM32_V2_DMA - struct dma_config dma_cfg; + struct dma_config dma_tx_cfg; + struct dma_config dma_rx_cfg; struct dma_block_config dma_blk_cfg; #endif /* CONFIG_I2C_STM32_V2_DMA */ }; diff --git a/drivers/i2c/i2c_ll_stm32_v2.c b/drivers/i2c/i2c_ll_stm32_v2.c index 56a11b7a602e..367d15cef2ad 100644 --- a/drivers/i2c/i2c_ll_stm32_v2.c +++ b/drivers/i2c/i2c_ll_stm32_v2.c @@ -193,10 +193,12 @@ static inline void msg_init(const struct device *dev, struct i2c_msg *msg, /* Configure RX DMA */ data->dma_blk_cfg.source_address = LL_I2C_DMA_GetRegAddr( cfg->i2c, LL_I2C_DMA_REG_DATA_RECEIVE); + data->dma_blk_cfg.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; data->dma_blk_cfg.dest_address = (uint32_t)msg->buf; + data->dma_blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT; data->dma_blk_cfg.block_size = msg->len; - if (configure_dma(&cfg->rx_dma, &data->dma_cfg, + if (configure_dma(&cfg->rx_dma, &data->dma_rx_cfg, &data->dma_blk_cfg) != 0) { LOG_ERR("Problem setting up RX DMA"); return; @@ -209,10 +211,13 @@ static inline void msg_init(const struct device *dev, struct i2c_msg *msg, /* Configure TX DMA */ data->dma_blk_cfg.source_address = (uint32_t)data->current.buf; + data->dma_blk_cfg.source_addr_adj = DMA_ADDR_ADJ_INCREMENT; data->dma_blk_cfg.dest_address = LL_I2C_DMA_GetRegAddr( cfg->i2c, LL_I2C_DMA_REG_DATA_TRANSMIT); + data->dma_blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; data->dma_blk_cfg.block_size = msg->len; - if (configure_dma(&cfg->tx_dma, &data->dma_cfg, + + if (configure_dma(&cfg->tx_dma, &data->dma_tx_cfg, &data->dma_blk_cfg) != 0) { LOG_ERR("Problem setting up TX DMA"); return; diff --git a/drivers/i2c/i2c_max32.c b/drivers/i2c/i2c_max32.c index db370b9955b7..d23910b416c1 100644 --- a/drivers/i2c/i2c_max32.c +++ b/drivers/i2c/i2c_max32.c @@ -100,7 +100,7 @@ static int api_configure(const struct device *dev, uint32_t dev_cfg) return -ENOTSUP; } - return ret; + return ((ret > 0) ? 0 : -EIO); } #ifdef CONFIG_I2C_TARGET @@ -532,11 +532,19 @@ static int i2c_max32_transfer(const struct device *dev, struct i2c_msg *msgs, ui ret = data->err; } else { if (data->flags & I2C_MSG_STOP) { - /* Wait for busy flag to be cleared */ - while (i2c->status & ADI_MAX32_I2C_STATUS_MASTER_BUSY) { + /* 0 length transactions are needed for I2C SCANs */ + if ((req->tx_len == req->rx_len) && (req->tx_len == 0)) { + MXC_I2C_ClearFlags(i2c, ADI_MAX32_I2C_INT_FL0_MASK, + ADI_MAX32_I2C_INT_FL1_MASK); + } else { + /* Wait for busy flag to be cleared for clock stetching + * use-cases + */ + while (i2c->status & ADI_MAX32_I2C_STATUS_MASTER_BUSY) { + } + MXC_I2C_ClearFlags(i2c, ADI_MAX32_I2C_INT_FL0_MASK, + ADI_MAX32_I2C_INT_FL1_MASK); } - MXC_I2C_ClearFlags(i2c, ADI_MAX32_I2C_INT_FL0_MASK, - ADI_MAX32_I2C_INT_FL1_MASK); } } if (ret) { @@ -755,6 +763,12 @@ static void i2c_max32_isr_controller(const struct device *dev, mxc_i2c_regs_t *i MXC_I2C_EnableInt( i2c, ADI_MAX32_I2C_INT_EN0_RX_THD | ADI_MAX32_I2C_INT_EN0_DONE, 0); } + /* 0-length transactions are needed for I2C scans. + * In these cases, just give up the semaphore. + */ + else if ((req->tx_len == req->rx_len) && (req->tx_len == 0)) { + k_sem_give(&data->xfer); + } } if (req->tx_len && diff --git a/drivers/i2c/i2c_max32_rtio.c b/drivers/i2c/i2c_max32_rtio.c index 40ceeffdd413..411044bef2f4 100644 --- a/drivers/i2c/i2c_max32_rtio.c +++ b/drivers/i2c/i2c_max32_rtio.c @@ -97,7 +97,7 @@ static int max32_do_configure(const struct device *dev, uint32_t dev_cfg) return -ENOTSUP; } - return ret; + return ((ret > 0) ? 0 : -EIO); } static void max32_complete(const struct device *dev, int status); @@ -199,6 +199,7 @@ static void i2c_max32_isr_controller(const struct device *dev, mxc_i2c_regs_t *i if (int_fl0 & ADI_MAX32_I2C_INT_FL0_ERR) { data->err = -EIO; Wrap_MXC_I2C_SetIntEn(i2c, 0, 0); + max32_complete(dev, data->err); return; } @@ -303,7 +304,6 @@ static void max32_complete(const struct device *dev, int status) struct max32_i2c_data *data = dev->data; struct i2c_rtio *const ctx = data->ctx; const struct max32_i2c_config *const cfg = dev->config; - int ret = 0; if (cfg->regs->clkhi == I2C_STANDAR_BITRATE_CLKHI) { /* When I2C is configured in Standard Bitrate 100KHz @@ -319,9 +319,12 @@ static void max32_complete(const struct device *dev, int status) LOG_ERR("For Standard speed HW needs more time to run"); return; } - if (i2c_rtio_complete(ctx, ret)) { + + if (i2c_rtio_complete(ctx, status)) { data->second_msg_flag = 1; max32_start(dev); + } else { + data->second_msg_flag = 0; } } diff --git a/drivers/mdio/mdio_shell.c b/drivers/mdio/mdio_shell.c index 61bc39f4d502..e29d96e60a51 100644 --- a/drivers/mdio/mdio_shell.c +++ b/drivers/mdio/mdio_shell.c @@ -15,48 +15,37 @@ #include LOG_MODULE_REGISTER(mdio_shell, CONFIG_LOG_DEFAULT_LEVEL); -#if DT_HAS_COMPAT_STATUS_OKAY(atmel_sam_mdio) -#define DT_DRV_COMPAT atmel_sam_mdio -#elif DT_HAS_COMPAT_STATUS_OKAY(espressif_esp32_mdio) -#define DT_DRV_COMPAT espressif_esp32_mdio -#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_imx_netc_emdio) -#define DT_DRV_COMPAT nxp_imx_netc_emdio -#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_s32_netc_emdio) -#define DT_DRV_COMPAT nxp_s32_netc_emdio -#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_s32_gmac_mdio) -#define DT_DRV_COMPAT nxp_s32_gmac_mdio -#elif DT_HAS_COMPAT_STATUS_OKAY(adi_adin2111_mdio) -#define DT_DRV_COMPAT adi_adin2111_mdio -#elif DT_HAS_COMPAT_STATUS_OKAY(smsc_lan91c111_mdio) -#define DT_DRV_COMPAT smsc_lan91c111_mdio -#elif DT_HAS_COMPAT_STATUS_OKAY(zephyr_mdio_gpio) -#define DT_DRV_COMPAT zephyr_mdio_gpio -#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_enet_mdio) -#define DT_DRV_COMPAT nxp_enet_mdio -#elif DT_HAS_COMPAT_STATUS_OKAY(infineon_xmc4xxx_mdio) -#define DT_DRV_COMPAT infineon_xmc4xxx_mdio -#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_enet_qos_mdio) -#define DT_DRV_COMPAT nxp_enet_qos_mdio -#elif DT_HAS_COMPAT_STATUS_OKAY(litex_liteeth_mdio) -#define DT_DRV_COMPAT litex_liteeth_mdio -#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_mdio) -#define DT_DRV_COMPAT st_stm32_mdio -#elif DT_HAS_COMPAT_STATUS_OKAY(snps_dwcxgmac_mdio) -#define DT_DRV_COMPAT snps_dwcxgmac_mdio -#elif DT_HAS_COMPAT_STATUS_OKAY(sensry_sy1xx_mdio) -#define DT_DRV_COMPAT sensry_sy1xx_mdio -#elif DT_HAS_COMPAT_STATUS_OKAY(xlnx_axi_ethernet_1_00_a_mdio) -#define DT_DRV_COMPAT xlnx_axi_ethernet_1_00_a_mdio -#else -#error "No known devicetree compatible match for MDIO shell" -#endif - -#define MDIO_NODE_ID DT_COMPAT_GET_ANY_STATUS_OKAY(DT_DRV_COMPAT) +static bool device_is_mdio(const struct device *dev) +{ + return DEVICE_API_IS(mdio, dev); +} + +static void device_name_get(size_t idx, struct shell_static_entry *entry) +{ + const struct device *dev = shell_device_filter(idx, device_is_mdio); + + entry->syntax = (dev != NULL) ? dev->name : NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = NULL; +} + +SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get); + +static int parse_device_arg(const struct shell *sh, char **argv, const struct device **dev) +{ + *dev = shell_device_get_binding(argv[1]); + if (!*dev) { + shell_error(sh, "device %s not found", argv[1]); + return -ENODEV; + } + return 0; +} /* * Scan the entire 5-bit address space of the MDIO bus * - * scan [] + * scan [] */ static int cmd_mdio_scan(const struct shell *sh, size_t argc, char **argv) { @@ -64,16 +53,15 @@ static int cmd_mdio_scan(const struct shell *sh, size_t argc, char **argv) int cnt; uint16_t data; uint16_t reg_addr; + int ret; - dev = DEVICE_DT_GET(MDIO_NODE_ID); - if (!device_is_ready(dev)) { - shell_error(sh, "MDIO: Device driver %s is not ready.", dev->name); - - return -ENODEV; + ret = parse_device_arg(sh, argv, &dev); + if (ret < 0) { + return ret; } if (argc >= 2) { - reg_addr = strtol(argv[1], NULL, 16); + reg_addr = strtol(argv[2], NULL, 16); } else { reg_addr = 0; } @@ -101,24 +89,23 @@ static int cmd_mdio_scan(const struct shell *sh, size_t argc, char **argv) return 0; } -/* mdio write */ +/* mdio write */ static int cmd_mdio_write(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; uint16_t data; uint16_t reg_addr; uint16_t port_addr; + int ret; - dev = DEVICE_DT_GET(MDIO_NODE_ID); - if (!device_is_ready(dev)) { - shell_error(sh, "MDIO: Device driver %s is not ready.", dev->name); - - return -ENODEV; + ret = parse_device_arg(sh, argv, &dev); + if (ret < 0) { + return ret; } - port_addr = strtol(argv[1], NULL, 16); - reg_addr = strtol(argv[2], NULL, 16); - data = strtol(argv[3], NULL, 16); + port_addr = strtol(argv[2], NULL, 16); + reg_addr = strtol(argv[3], NULL, 16); + data = strtol(argv[4], NULL, 16); mdio_bus_enable(dev); @@ -134,23 +121,22 @@ static int cmd_mdio_write(const struct shell *sh, size_t argc, char **argv) return 0; } -/* mdio read */ +/* mdio read */ static int cmd_mdio_read(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; uint16_t data; uint16_t reg_addr; uint16_t port_addr; + int ret; - dev = DEVICE_DT_GET(MDIO_NODE_ID); - if (!device_is_ready(dev)) { - shell_error(sh, "MDIO: Device driver %s is not ready.", dev->name); - - return -ENODEV; + ret = parse_device_arg(sh, argv, &dev); + if (ret < 0) { + return ret; } - port_addr = strtol(argv[1], NULL, 16); - reg_addr = strtol(argv[2], NULL, 16); + port_addr = strtol(argv[2], NULL, 16); + reg_addr = strtol(argv[3], NULL, 16); mdio_bus_enable(dev); @@ -168,7 +154,7 @@ static int cmd_mdio_read(const struct shell *sh, size_t argc, char **argv) return 0; } -/* mdio write_c45 */ +/* mdio write_c45 */ static int cmd_mdio_write_45(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; @@ -176,18 +162,17 @@ static int cmd_mdio_write_45(const struct shell *sh, size_t argc, char **argv) uint16_t reg_addr; uint8_t dev_addr; uint8_t port_addr; + int ret; - dev = DEVICE_DT_GET(MDIO_NODE_ID); - if (!device_is_ready(dev)) { - shell_error(sh, "MDIO: Device driver %s is not ready.", dev->name); - - return -ENODEV; + ret = parse_device_arg(sh, argv, &dev); + if (ret < 0) { + return ret; } - port_addr = strtol(argv[1], NULL, 16); - dev_addr = strtol(argv[2], NULL, 16); - reg_addr = strtol(argv[3], NULL, 16); - data = strtol(argv[4], NULL, 16); + port_addr = strtol(argv[2], NULL, 16); + dev_addr = strtol(argv[3], NULL, 16); + reg_addr = strtol(argv[4], NULL, 16); + data = strtol(argv[5], NULL, 16); mdio_bus_enable(dev); @@ -203,7 +188,7 @@ static int cmd_mdio_write_45(const struct shell *sh, size_t argc, char **argv) return 0; } -/* mdio read_c45 */ +/* mdio read_c45 */ static int cmd_mdio_read_c45(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; @@ -211,17 +196,16 @@ static int cmd_mdio_read_c45(const struct shell *sh, size_t argc, char **argv) uint16_t reg_addr; uint8_t dev_addr; uint8_t port_addr; + int ret; - dev = DEVICE_DT_GET(MDIO_NODE_ID); - if (!device_is_ready(dev)) { - shell_error(sh, "MDIO: Device driver %s is not ready.", dev->name); - - return -ENODEV; + ret = parse_device_arg(sh, argv, &dev); + if (ret < 0) { + return ret; } - port_addr = strtol(argv[1], NULL, 16); - dev_addr = strtol(argv[2], NULL, 16); - reg_addr = strtol(argv[3], NULL, 16); + port_addr = strtol(argv[2], NULL, 16); + dev_addr = strtol(argv[3], NULL, 16); + reg_addr = strtol(argv[4], NULL, 16); mdio_bus_enable(dev); @@ -240,23 +224,23 @@ static int cmd_mdio_read_c45(const struct shell *sh, size_t argc, char **argv) } SHELL_STATIC_SUBCMD_SET_CREATE(sub_mdio_cmds, - SHELL_CMD_ARG(scan, NULL, - "Scan MDIO bus for devices: scan []", - cmd_mdio_scan, 0, 1), - SHELL_CMD_ARG(read, NULL, - "Read from MDIO device: read ", - cmd_mdio_read, 3, 0), - SHELL_CMD_ARG(write, NULL, - "Write to MDIO device: write ", - cmd_mdio_write, 4, 0), - SHELL_CMD_ARG(read_c45, NULL, + SHELL_CMD_ARG(scan, &dsub_device_name, + "Scan MDIO bus for devices: scan []", + cmd_mdio_scan, 1, 1), + SHELL_CMD_ARG(read, &dsub_device_name, + "Read from MDIO device: read ", + cmd_mdio_read, 4, 0), + SHELL_CMD_ARG(write, &dsub_device_name, + "Write to MDIO device: write ", + cmd_mdio_write, 5, 0), + SHELL_CMD_ARG(read_c45, &dsub_device_name, "Read from MDIO Clause 45 device: " - "read_c45 ", - cmd_mdio_read_c45, 4, 0), - SHELL_CMD_ARG(write_c45, NULL, + "read_c45 ", + cmd_mdio_read_c45, 5, 0), + SHELL_CMD_ARG(write_c45, &dsub_device_name, "Write to MDIO Clause 45 device: " - "write_c45 ", - cmd_mdio_write_45, 5, 0), + "write_c45 ", + cmd_mdio_write_45, 6, 0), SHELL_SUBCMD_SET_END /* Array terminated. */ ); diff --git a/drivers/memc/CMakeLists.txt b/drivers/memc/CMakeLists.txt index 188a40dfcd6a..afd05f4ecf1b 100644 --- a/drivers/memc/CMakeLists.txt +++ b/drivers/memc/CMakeLists.txt @@ -7,6 +7,7 @@ zephyr_library_sources_ifdef(CONFIG_MEMC_STM32_SDRAM memc_stm32_sdram.c) zephyr_linker_sources_ifdef(CONFIG_MEMC_STM32_SDRAM SECTIONS memc_stm32_sdram.ld) zephyr_library_sources_ifdef(CONFIG_MEMC_STM32_NOR_PSRAM memc_stm32_nor_psram.c) zephyr_library_sources_ifdef(CONFIG_MEMC_STM32_XSPI_PSRAM memc_stm32_xspi_psram.c) +zephyr_linker_sources_ifdef(CONFIG_MEMC_STM32_XSPI_PSRAM SECTIONS memc_stm32_xspi_psram.ld) zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI memc_mcux_flexspi.c) zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_W956A8MBYA memc_mcux_flexspi_w956a8mbya.c) diff --git a/drivers/memc/memc_stm32_xspi_psram.ld b/drivers/memc/memc_stm32_xspi_psram.ld new file mode 100644 index 000000000000..6ef15da28415 --- /dev/null +++ b/drivers/memc/memc_stm32_xspi_psram.ld @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#if DT_NODE_HAS_STATUS(DT_NODELABEL(psram), okay) +GROUP_START(PSRAM) + + SECTION_PROLOGUE(_STM32_PSRAM_SECTION_NAME, (NOLOAD),) + { + *(.stm32_psram) + *(".stm32_psram.*") + } GROUP_LINK_IN(PSRAM) + +GROUP_END(PSRAM) +#endif diff --git a/drivers/pinctrl/pinctrl_ambiq.c b/drivers/pinctrl/pinctrl_ambiq.c index 68acc9954668..b6c3e9ff676b 100644 --- a/drivers/pinctrl/pinctrl_ambiq.c +++ b/drivers/pinctrl/pinctrl_ambiq.c @@ -45,6 +45,17 @@ static void pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) pin_config.GP.cfg_b.eDriveStrength = pin->drive_strength; #if defined(CONFIG_SOC_SERIES_APOLLO4X) pin_config.GP.cfg_b.uSlewRate = pin->slew_rate; + switch (pin->sdif_cdwp) { + case 1: + am_hal_gpio_cd_pin_config(pin->pin_num); + break; + case 2: + am_hal_gpio_wp_pin_config(pin->pin_num); + break; + default: + /* not a sdif pin */ + break; + } #else switch (pin->sdif_cdwp) { case 1: diff --git a/drivers/sensor/pixart/CMakeLists.txt b/drivers/sensor/pixart/CMakeLists.txt index 010b153254b8..73f358386081 100644 --- a/drivers/sensor/pixart/CMakeLists.txt +++ b/drivers/sensor/pixart/CMakeLists.txt @@ -1,6 +1,10 @@ # Copyright (c) 2025 Croxel Inc. # Copyright (c) 2025 CogniPilot Foundation +# Copyright (c) 2025 Paul Timke # SPDX-License-Identifier: Apache-2.0 +# zephyr-keep-sorted-start add_subdirectory_ifdef(CONFIG_PAA3905 paa3905) +add_subdirectory_ifdef(CONFIG_PAJ7620 paj7620) add_subdirectory_ifdef(CONFIG_PAT9136 pat9136) +# zephyr-keep-sorted-stop diff --git a/drivers/sensor/pixart/Kconfig b/drivers/sensor/pixart/Kconfig index 68d521e26001..14db51f6f52a 100644 --- a/drivers/sensor/pixart/Kconfig +++ b/drivers/sensor/pixart/Kconfig @@ -1,8 +1,10 @@ # Copyright (c) 2025 Croxel Inc. # Copyright (c) 2025 CogniPilot Foundation +# Copyright (c) 2025 Paul Timke # SPDX-License-Identifier: Apache-2.0 # zephyr-keep-sorted-start source "drivers/sensor/pixart/paa3905/Kconfig" +source "drivers/sensor/pixart/paj7620/Kconfig" source "drivers/sensor/pixart/pat9136/Kconfig" # zephyr-keep-sorted-stop diff --git a/drivers/sensor/pixart/paj7620/CMakeLists.txt b/drivers/sensor/pixart/paj7620/CMakeLists.txt new file mode 100644 index 000000000000..b115ffef01c2 --- /dev/null +++ b/drivers/sensor/pixart/paj7620/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2025 Paul Timke +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(paj7620.c) +zephyr_library_sources_ifdef(CONFIG_PAJ7620_TRIGGER paj7620_trigger.c) diff --git a/drivers/sensor/pixart/paj7620/Kconfig b/drivers/sensor/pixart/paj7620/Kconfig new file mode 100644 index 000000000000..6dca4e7ab15b --- /dev/null +++ b/drivers/sensor/pixart/paj7620/Kconfig @@ -0,0 +1,21 @@ +# PAJ7620 gesture sensor configuration options + +# Copyright (c) 2025 Paul Timke +# SPDX-License-Identifier: Apache-2.0 + +menuconfig PAJ7620 + bool "PAJ7620 gesture sensor driver" + default y + depends on DT_HAS_PIXART_PAJ7620_ENABLED + select I2C + help + Enable driver for the PAJ7620 gesture sensor + +if PAJ7620 + +module = PAJ7620 +thread_priority = 10 +thread_stack_size = 1024 +source "drivers/sensor/Kconfig.trigger_template" + +endif # PAJ7620 diff --git a/drivers/sensor/pixart/paj7620/paj7620.c b/drivers/sensor/pixart/paj7620/paj7620.c new file mode 100644 index 000000000000..d729fe75bf9a --- /dev/null +++ b/drivers/sensor/pixart/paj7620/paj7620.c @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2025 Paul Timke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT pixart_paj7620 + +#include +#include +#include +#include +#include +#include +#include + +#include "paj7620.h" +#include "paj7620_reg.h" + +LOG_MODULE_REGISTER(paj7620, CONFIG_SENSOR_LOG_LEVEL); + +static int paj7620_select_register_bank(const struct device *dev, enum paj7620_mem_bank bank) +{ + int ret; + uint8_t bank_selection; + const struct paj7620_config *config = dev->config; + + switch (bank) { + case PAJ7620_MEMBANK_0: + bank_selection = PAJ7620_VAL_BANK_SEL_BANK_0; + break; + case PAJ7620_MEMBANK_1: + bank_selection = PAJ7620_VAL_BANK_SEL_BANK_1; + break; + default: + LOG_ERR("Nonexistent memory bank %d", (int)bank); + return -EINVAL; + } + + ret = i2c_reg_write_byte_dt(&config->i2c, PAJ7620_REG_BANK_SEL, bank_selection); + if (ret < 0) { + LOG_ERR("Failed to change memory bank"); + return ret; + } + + return 0; +} + +static int paj7620_get_hw_id(const struct device *dev, uint16_t *result) +{ + uint8_t ret; + uint8_t hw_id[2]; + const struct paj7620_config *config = dev->config; + + /* Part ID is stored in bank 0 */ + ret = paj7620_select_register_bank(dev, PAJ7620_MEMBANK_0); + if (ret < 0) { + return ret; + } + + ret = i2c_reg_read_byte_dt(&config->i2c, PAJ7620_REG_PART_ID_LSB, &hw_id[0]); + if (ret < 0) { + LOG_ERR("Failed to read hardware ID"); + return ret; + } + + ret = i2c_reg_read_byte_dt(&config->i2c, PAJ7620_REG_PART_ID_MSB, &hw_id[1]); + if (ret < 0) { + LOG_ERR("Failed to read hardware ID"); + return ret; + } + + *result = sys_get_le16(hw_id); + LOG_DBG("Obtained hardware ID 0x%04x", *result); + + return 0; +} + +static int paj7620_write_initial_reg_settings(const struct device *dev) +{ + int ret; + uint8_t reg_addr; + uint8_t value; + const struct paj7620_config *config = dev->config; + + /** + * Initializes registers with default values according to section 8.1 + * from Datasheet v1.5: + * https://files.seeedstudio.com/wiki/Grove_Gesture_V_1.0/res/PAJ7620U2_DS_v1.5_05012022_Confidential.pdf + */ + + for (int i = 0; i < ARRAY_SIZE(initial_register_array); i++) { + reg_addr = initial_register_array[i][0]; + value = initial_register_array[i][1]; + + ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, value); + if (ret < 0) { + return ret; + } + } + + return ret; +} + +static int paj7620_set_sampling_rate(const struct device *dev, const struct sensor_value *val) +{ + int ret; + int fps; + const struct paj7620_config *config = dev->config; + int64_t uval = val->val1 * 1000000 + val->val2; + + if (uval <= 120000000) { + fps = PAJ7620_NORMAL_SPEED; + } else if (uval <= 240000000) { + fps = PAJ7620_GAME_SPEED; + } else { + LOG_ERR("Unsupported sample rate"); + return -ENOTSUP; + } + + ret = paj7620_select_register_bank(dev, PAJ7620_MEMBANK_1); + if (ret < 0) { + return ret; + } + + ret = i2c_reg_write_byte_dt(&config->i2c, PAJ7620_REG_R_IDLE_TIME_LSB, fps); + if (ret < 0) { + LOG_ERR("Failed to set sample rate"); + return ret; + } + + ret = paj7620_select_register_bank(dev, PAJ7620_MEMBANK_0); + if (ret < 0) { + return ret; + } + + LOG_DBG("Sample rate set to %s mode", fps == PAJ7620_GAME_SPEED ? "game" : "normal"); + + return 0; +} + +static int paj7620_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + int ret; + struct paj7620_data *data = dev->data; + const struct paj7620_config *config = dev->config; + uint8_t gest_data[2]; + + if (chan != SENSOR_CHAN_ALL + && ((enum sensor_channel_paj7620)chan != SENSOR_CHAN_PAJ7620_GESTURES)) { + return -ENOTSUP; + } + + /* We read from REG_INT_FLAG_1 and REG_INT_FLAG_2 even on polling mode + * (without using interrupts) because that's where the gesture + * detection flags are set. + * NOTE: A set bit means that the corresponding gesture has been detected + */ + + ret = i2c_burst_read_dt(&config->i2c, PAJ7620_REG_INT_FLAG_1, gest_data, sizeof(gest_data)); + if (ret < 0) { + LOG_ERR("Failed to read gesture data"); + return ret; + } + + data->gesture_flags = sys_get_le16(gest_data); + + return 0; +} + +static int paj7620_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct paj7620_data *data = dev->data; + + switch ((uint32_t)chan) { + case SENSOR_CHAN_PAJ7620_GESTURES: + val->val1 = data->gesture_flags; + val->val2 = 0; + break; + default: + LOG_ERR("Unsupported sensor channel"); + return -ENOTSUP; + } + + return 0; +} + +static int paj7620_attr_set(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + int ret; + + if (chan != SENSOR_CHAN_ALL + && ((enum sensor_channel_paj7620)chan != SENSOR_CHAN_PAJ7620_GESTURES)) { + return -ENOTSUP; + } + + switch ((uint32_t)attr) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: + ret = paj7620_set_sampling_rate(dev, val); + break; + + default: + return -ENOTSUP; + } + + return ret; +} + +static int paj7620_init(const struct device *dev) +{ + int ret; + uint16_t hw_id; + const struct paj7620_config *config = dev->config; + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("I2C bus device not ready"); + return -ENODEV; + } + + /** + * According to the datasheet section 8.1, we must wait this amount + * of time for sensor to stabilize after power up + */ + k_usleep(PAJ7620_POWERUP_STABILIZATION_TIME_US); + + /** + * Make a write to the sensor to wake it up. After waking it, the + * the sensor still needs some time to be ready to listen. Without it, + * it may NACK subsequent transactions. + */ + (void)paj7620_select_register_bank(dev, PAJ7620_MEMBANK_0); + k_usleep(PAJ7620_WAKEUP_TIME_US); + + /** Verify this is not some other sensor with the same address */ + ret = paj7620_get_hw_id(dev, &hw_id); + if (ret < 0) { + return ret; + } + + if (hw_id != PAJ7620_PART_ID) { + LOG_ERR("Hardware ID 0x%04x does not match for PAJ7620", hw_id); + return -ENOTSUP; + } + + /** Initialize settings (it defaults to gesture mode) */ + ret = paj7620_write_initial_reg_settings(dev); + if (ret < 0) { + LOG_ERR("Failed to initialize device registers"); + return ret; + } + + if (IS_ENABLED(CONFIG_PAJ7620_TRIGGER)) { + ret = paj7620_trigger_init(dev); + if (ret < 0) { + LOG_ERR("Failed to enable interrupts"); + return ret; + } + } + + return 0; +} + +static DEVICE_API(sensor, paj7620_driver_api) = { + .sample_fetch = paj7620_sample_fetch, + .channel_get = paj7620_channel_get, + .attr_set = paj7620_attr_set, +#if CONFIG_PAJ7620_TRIGGER + .trigger_set = paj7620_trigger_set, +#endif +}; + +#define PAJ7620_INIT(n) \ + static const struct paj7620_config paj7620_config_##n = { \ + .i2c = I2C_DT_SPEC_INST_GET(n), \ + IF_ENABLED(CONFIG_PAJ7620_TRIGGER, \ + (.int_gpio = GPIO_DT_SPEC_INST_GET_OR(n, int_gpios, {0}))) \ + }; \ + \ + static struct paj7620_data paj7620_data_##n; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(n, \ + paj7620_init, \ + NULL, \ + &paj7620_data_##n, \ + &paj7620_config_##n, \ + POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, \ + &paj7620_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(PAJ7620_INIT); diff --git a/drivers/sensor/pixart/paj7620/paj7620.h b/drivers/sensor/pixart/paj7620/paj7620.h new file mode 100644 index 000000000000..688bf0ad86b3 --- /dev/null +++ b/drivers/sensor/pixart/paj7620/paj7620.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025 Paul Timke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_PAJ7620_H_ +#define ZEPHYR_DRIVERS_SENSOR_PAJ7620_H_ + +#include +#include +#include +#include +#include + +/** Sensor hardcoded Part ID */ +#define PAJ7620_PART_ID ((PAJ7620_VAL_PART_ID_MSB << 8) | (PAJ7620_VAL_PART_ID_LSB & 0x00FF)) + +/** Sensor FPS values */ +#define PAJ7620_NORMAL_SPEED 0xAC /* Normal speed 120 fps */ +#define PAJ7620_GAME_SPEED 0x30 /* Game mode speed 240 fps */ + +/** Sensor stabilization time microseconds (us) */ +#define PAJ7620_POWERUP_STABILIZATION_TIME_US 700 + +/** Sensor stabilization time after I2C wakeup (us). + * PAJ7620 still needs some time to wake up after waking it + * with an I2C write. This value was obtained experimentally + */ +#define PAJ7620_WAKEUP_TIME_US 200 + +enum paj7620_mem_bank { + PAJ7620_MEMBANK_0 = 0, + PAJ7620_MEMBANK_1, +}; + +struct paj7620_config { + const struct i2c_dt_spec i2c; +#if CONFIG_PAJ7620_TRIGGER + struct gpio_dt_spec int_gpio; +#endif +}; + +struct paj7620_data { + struct k_sem sem; + uint16_t gesture_flags; + +#ifdef CONFIG_PAJ7620_TRIGGER + const struct device *dev; + struct gpio_callback gpio_cb; + sensor_trigger_handler_t motion_handler; + const struct sensor_trigger *motion_trig; +#endif +#ifdef CONFIG_PAJ7620_TRIGGER_OWN_THREAD + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_PAJ7620_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem trig_sem; +#endif +#ifdef CONFIG_PAJ7620_TRIGGER_GLOBAL_THREAD + struct k_work work; +#endif +}; + +int paj7620_trigger_init(const struct device *dev); +int paj7620_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +#endif /* ZEPHYR_DRIVERS_SENSOR_PAJ7620_H_ */ diff --git a/drivers/sensor/pixart/paj7620/paj7620_reg.h b/drivers/sensor/pixart/paj7620/paj7620_reg.h new file mode 100644 index 000000000000..b4a4e6672551 --- /dev/null +++ b/drivers/sensor/pixart/paj7620/paj7620_reg.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2025 Paul Timke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_PAJ7620_REG_H_ +#define ZEPHYR_DRIVERS_SENSOR_PAJ7620_REG_H_ + +#include + +/** + * @file + * @brief PAJ7620 Register addresses and values. Not all registers from the + * data sheet are listed here, only the ones directly used by the driver. + * For more information about the registers, refer to: + * https://files.seeedstudio.com/wiki/Grove_Gesture_V_1.0/res/PAJ7620U2_DS_v1.5_05012022_Confidential.pdf + */ + +/** + * BANK 0 REGISTER ADDRESSES + */ + +/* Chip / Version ID */ +#define PAJ7620_REG_PART_ID_LSB 0x00 +#define PAJ7620_REG_PART_ID_MSB 0x01 + +/** Register bank select */ +#define PAJ7620_REG_BANK_SEL 0xEF + +/** Interrupt Controls */ +/* Note: If the corresponding bit is 1, the corresponding interrupt is enabled */ +#define PAJ7620_REG_MCU_INT_CTRL 0x40 /* Configure auto clean and active high/low */ +#define PAJ7620_REG_INT_1_EN 0x41 /* Enable int 1 interrupts */ +#define PAJ7620_REG_INT_2_EN 0x42 /* Enable int 2 interrupts */ +#define PAJ7620_REG_INT_FLAG_1 0x43 /* Gesture detection results */ +#define PAJ7620_REG_INT_FLAG_2 0x44 /* Gesture detection results (wave and others) */ + +/** + * BANK 0 REGISTER VALUES AND MASKS + */ +#define PAJ7620_VAL_PART_ID_LSB 0x20 +#define PAJ7620_VAL_PART_ID_MSB 0x76 + +/** Register bank select values */ +#define PAJ7620_VAL_BANK_SEL_BANK_0 0x00 +#define PAJ7620_VAL_BANK_SEL_BANK_1 0x01 + +/** Interrupt controls masks and values */ +#define PAJ7620_MASK_MCU_INT_FLAG_GCLR BIT(1) +#define PAJ7620_VAL_MCU_INT_FLAG_AUTO_CLEAN_DISABLE 0x00 +#define PAJ7620_VAL_MCU_INT_FLAG_AUTO_CLEAN_ENABLE 0x01 + +#define PAJ7620_MASK_MCU_INT_FLAG_INV BIT(4) +#define PAJ7620_VAL_MCU_INT_FLAG_PIN_ACTIVE_LOW 0x00 +#define PAJ7620_VAL_MCU_INT_FLAG_PIN_ACTIVE_HIGH 0x01 + +#define PAJ7620_MASK_ALL_GESTURE_INTS_ENABLE 0xFF +#define PAJ7620_MASK_ALL_GESTURE_INTS_DISABLE 0x00 + +/** + * BANK 1 REGISTER ADDRESSES + */ +#define PAJ7620_REG_R_IDLE_TIME_LSB 0x65 +#define PAJ7620_REG_R_IDLE_TIME_MSB 0x66 + +/** + * INITIALIZATION ARRAYS + * The following 'initial_register_array' is taken 'as is' from Section 8 + * (Firmware Guides) of the PAJ7620 datasheet v1.5. + * It encodes pairs of register addresses and values for those registers + * needed to initialize the sensor or change its operation mode + * + * Reference: + * https://files.seeedstudio.com/wiki/Grove_Gesture_V_1.0/res/PAJ7620U2_DS_v1.5_05012022_Confidential.pdf + */ + +static const uint8_t initial_register_array[][2] = { + {0xEF, 0x00}, /* Select memory bank 0 */ + {0x41, 0xFF}, /* Enable gesture interrupts */ + {0x42, 0x01}, + {0x46, 0x2D}, + {0x47, 0x0F}, + {0x48, 0x80}, + {0x49, 0x00}, + {0x4A, 0x40}, + {0x4B, 0x00}, + {0x4C, 0x20}, + {0x4D, 0x00}, + {0x51, 0x10}, + {0x5C, 0x02}, + {0x5E, 0x10}, + {0x80, 0x41}, + {0x81, 0x44}, + {0x82, 0x0C}, + {0x83, 0x20}, + {0x84, 0x20}, + {0x85, 0x00}, + {0x86, 0x10}, + {0x87, 0x00}, + {0x8B, 0x01}, + {0x8D, 0x00}, + {0x90, 0x0C}, + {0x91, 0x0C}, + {0x93, 0x0D}, + {0x94, 0x0A}, + {0x95, 0x0A}, + {0x96, 0x0C}, + {0x97, 0x05}, + {0x9A, 0x14}, + {0x9C, 0x3F}, + {0x9F, 0xF9}, + {0xA0, 0x48}, + {0xA5, 0x19}, + {0xCC, 0x19}, + {0xCD, 0x0B}, + {0xCE, 0x13}, + {0xCF, 0x62}, + {0xD0, 0x21}, + {0xEF, 0x01}, /* Select memory bank 1 */ + {0x00, 0x1E}, + {0x01, 0x1E}, + {0x02, 0x0F}, + {0x03, 0x0F}, + {0x04, 0x02}, + {0x25, 0x01}, + {0x26, 0x00}, + {0x27, 0x39}, + {0x28, 0x7F}, + {0x29, 0x08}, + {0x30, 0x03}, + {0x3E, 0xFF}, + {0x5E, 0x3D}, + {0x65, 0xAC}, /* Set fps to 'normal' mode */ + {0x66, 0x00}, + {0x67, 0x97}, + {0x68, 0x01}, + {0x69, 0xCD}, + {0x6A, 0x01}, + {0x6B, 0xB0}, + {0x6C, 0x04}, + {0x6D, 0x2C}, + {0x6E, 0x01}, + {0x72, 0x01}, + {0x73, 0x35}, + {0x74, 0x00}, /* Set to gesture mode */ + {0x77, 0x01}, + {0xEF, 0x00}, /* Reselect memory bank 0 */ +}; + +#endif /* ZEPHYR_DRIVERS_SENSOR_PAJ7620_REG_H_ */ diff --git a/drivers/sensor/pixart/paj7620/paj7620_trigger.c b/drivers/sensor/pixart/paj7620/paj7620_trigger.c new file mode 100644 index 000000000000..b5388ac5ea9b --- /dev/null +++ b/drivers/sensor/pixart/paj7620/paj7620_trigger.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2025 Paul Timke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT pixart_paj7620 + +#include "paj7620.h" +#include +#include + +LOG_MODULE_REGISTER(paj7620, CONFIG_SENSOR_LOG_LEVEL); + +static void paj7620_gpio_callback(const struct device *dev, + struct gpio_callback *cb, + uint32_t pin_mask) +{ + struct paj7620_data *data = + CONTAINER_OF(cb, struct paj7620_data, gpio_cb); + const struct paj7620_config *config = data->dev->config; + + if ((pin_mask & BIT(config->int_gpio.pin)) == 0U) { + return; + } + +#ifdef CONFIG_PAJ7620_TRIGGER_OWN_THREAD + k_sem_give(&data->trig_sem); +#elif CONFIG_PAJ7620_TRIGGER_GLOBAL_THREAD + k_work_submit(&data->work); +#endif +} + +static void paj7620_handle_int(const struct device *dev) +{ + struct paj7620_data *data = dev->data; + + if (data->motion_handler) { + data->motion_handler(dev, data->motion_trig); + } +} + +#ifdef CONFIG_PAJ7620_TRIGGER_OWN_THREAD +static void paj7620_thread_main(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p1); + ARG_UNUSED(p2); + + struct paj7620_data *data = p1; + + while (1) { + k_sem_take(&data->trig_sem, K_FOREVER); + paj7620_handle_int(data->dev); + } +} +#endif + +#ifdef CONFIG_PAJ7620_TRIGGER_GLOBAL_THREAD +static void paj7620_work_handler(struct k_work *work) +{ + struct paj7620_data *data = + CONTAINER_OF(work, struct paj7620_data, work); + + paj7620_handle_int(data->dev); +} +#endif + +int paj7620_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + struct paj7620_data *data = dev->data; + const struct paj7620_config *cfg = dev->config; + + if (cfg->int_gpio.port == NULL) { + return -ENOTSUP; + } + + if (trig->type != SENSOR_TRIG_MOTION) { + LOG_ERR("Unsupported sensor trigger"); + return -ENOTSUP; + } + + data->motion_handler = handler; + data->motion_trig = trig; + + if (handler == NULL) { + return gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_DISABLE); + } + + return gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_EDGE_FALLING); +} + +int paj7620_trigger_init(const struct device *dev) +{ + int ret; + const struct paj7620_config *config = dev->config; + struct paj7620_data *data = dev->data; + + data->dev = dev; + +#ifdef CONFIG_PAJ7620_TRIGGER_OWN_THREAD + k_sem_init(&data->trig_sem, 0, K_SEM_MAX_LIMIT); + k_thread_create(&data->thread, + data->thread_stack, + K_KERNEL_STACK_SIZEOF(data->thread_stack), + paj7620_thread_main, + data, + NULL, + NULL, + K_PRIO_COOP(CONFIG_PAJ7620_THREAD_PRIORITY), + 0, + K_NO_WAIT); +#elif CONFIG_PAJ7620_TRIGGER_GLOBAL_THREAD + data->work.handler = paj7620_work_handler; +#endif + + /* Configure GPIO */ + if (!gpio_is_ready_dt(&config->int_gpio)) { + LOG_ERR("GPIO device not ready"); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT); + if (ret < 0) { + return ret; + } + + gpio_init_callback(&data->gpio_cb, paj7620_gpio_callback, BIT(config->int_gpio.pin)); + + ret = gpio_add_callback(config->int_gpio.port, &data->gpio_cb); + if (ret < 0) { + return ret; + } + + return 0; +} diff --git a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.c b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.c index 2c3d143bb1d7..54affd497df0 100644 --- a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.c +++ b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.c @@ -1387,8 +1387,8 @@ static int lsm6dsv16x_pm_action(const struct device *dev, enum pm_device_action static struct lsm6dsv16x_data prefix##_data_##inst = { \ IF_ENABLED(UTIL_AND(CONFIG_LSM6DSV16X_STREAM, \ CONFIG_I2C_RTIO), \ - (.rtio_ctx = &lsm6dsv16x_rtio_ctx_##inst, \ - .iodev = &lsm6dsv16x_iodev_##inst, \ + (.rtio_ctx = &prefix##_rtio_ctx_##inst, \ + .iodev = &prefix##_iodev_##inst, \ .bus_type = BUS_I2C,)) \ }; \ static const struct lsm6dsv16x_config prefix##_config_##inst = \ diff --git a/drivers/stepper/adi_tmc/CMakeLists.txt b/drivers/stepper/adi_tmc/CMakeLists.txt index 51281754394a..75ad56aa4cf8 100644 --- a/drivers/stepper/adi_tmc/CMakeLists.txt +++ b/drivers/stepper/adi_tmc/CMakeLists.txt @@ -7,3 +7,4 @@ zephyr_library_property(ALLOW_EMPTY TRUE) zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC_SPI adi_tmc_spi.c) zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC2209 adi_tmc22xx_stepper_controller.c) zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC50XX adi_tmc50xx_stepper_controller.c) +zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC51XX adi_tmc51xx_stepper_controller.c) diff --git a/drivers/stepper/adi_tmc/Kconfig b/drivers/stepper/adi_tmc/Kconfig index b214be92963b..e8a86e6a4393 100644 --- a/drivers/stepper/adi_tmc/Kconfig +++ b/drivers/stepper/adi_tmc/Kconfig @@ -21,5 +21,6 @@ comment "Trinamic Stepper Drivers" rsource "Kconfig.tmc22xx" rsource "Kconfig.tmc50xx" +rsource "Kconfig.tmc51xx" endif # STEPPER_ADI_TMC diff --git a/drivers/stepper/adi_tmc/Kconfig.tmc51xx b/drivers/stepper/adi_tmc/Kconfig.tmc51xx new file mode 100644 index 000000000000..99e88ac11434 --- /dev/null +++ b/drivers/stepper/adi_tmc/Kconfig.tmc51xx @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Prevas A/S +# SPDX-License-Identifier: Apache-2.0 + +config STEPPER_ADI_TMC51XX + bool "Activate trinamic tmc51xx stepper driver" + depends on DT_HAS_ADI_TMC51XX_ENABLED && STEPPER_ADI_TMC + select STEPPER_ADI_TMC_SPI + default y + +module = TMC51XX +module-str = tmc51xx +rsource "Kconfig.tmc_rampgen_template" diff --git a/drivers/stepper/adi_tmc/adi_tmc50xx_stepper_controller.c b/drivers/stepper/adi_tmc/adi_tmc50xx_stepper_controller.c index e5be15f3c1d0..38224aa33a82 100644 --- a/drivers/stepper/adi_tmc/adi_tmc50xx_stepper_controller.c +++ b/drivers/stepper/adi_tmc/adi_tmc50xx_stepper_controller.c @@ -15,7 +15,6 @@ #include "adi_tmc5xxx_common.h" #include - LOG_MODULE_REGISTER(tmc50xx, CONFIG_STEPPER_LOG_LEVEL); struct tmc50xx_data { @@ -730,7 +729,7 @@ static DEVICE_API(stepper, tmc50xx_stepper_api) = { stallguard_velocity_check_interval_ms), \ .is_sg_enabled = DT_PROP(child, activate_stallguard2), \ IF_ENABLED(CONFIG_STEPPER_ADI_TMC50XX_RAMP_GEN, \ - (.default_ramp_config = TMC_RAMP_DT_SPEC_GET(child))) }; + (.default_ramp_config = TMC_RAMP_DT_SPEC_GET_TMC50XX(child))) }; #define TMC50XX_STEPPER_DATA_DEFINE(child) \ static struct tmc50xx_stepper_data tmc50xx_stepper_data_##child = { \ diff --git a/drivers/stepper/adi_tmc/adi_tmc51xx_stepper_controller.c b/drivers/stepper/adi_tmc/adi_tmc51xx_stepper_controller.c new file mode 100644 index 000000000000..3953d3ac67b3 --- /dev/null +++ b/drivers/stepper/adi_tmc/adi_tmc51xx_stepper_controller.c @@ -0,0 +1,690 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2025 Prevas A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_tmc51xx + +#include + +#include +#include + +#include "adi_tmc_spi.h" +#include "adi_tmc5xxx_common.h" + +#include +LOG_MODULE_REGISTER(tmc51xx, CONFIG_STEPPER_LOG_LEVEL); + +struct tmc51xx_data { + struct k_sem sem; + struct k_work_delayable stallguard_dwork; + /* Work item to run the callback in a thread context. */ +#ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL + struct k_work_delayable rampstat_callback_dwork; +#endif + /* device pointer required to access config in k_work */ + const struct device *stepper; + stepper_event_callback_t callback; + void *event_cb_user_data; +}; + +struct tmc51xx_config { + const uint32_t gconf; + struct spi_dt_spec spi; + const uint32_t clock_frequency; + const uint16_t default_micro_step_res; + const int8_t sg_threshold; + const bool is_sg_enabled; + const uint32_t sg_velocity_check_interval_ms; + const uint32_t sg_threshold_velocity; +#ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN + const struct tmc_ramp_generator_data default_ramp_config; +#endif +}; + +static int tmc51xx_write(const struct device *dev, const uint8_t reg_addr, const uint32_t reg_val) +{ + const struct tmc51xx_config *config = dev->config; + struct tmc51xx_data *data = dev->data; + const struct spi_dt_spec bus = config->spi; + int err; + + k_sem_take(&data->sem, K_FOREVER); + + err = tmc_spi_write_register(&bus, TMC5XXX_WRITE_BIT, reg_addr, reg_val); + + k_sem_give(&data->sem); + + if (err) { + LOG_ERR("Failed to write register 0x%x with value 0x%x", reg_addr, reg_val); + return err; + } + return 0; +} + +static int tmc51xx_read(const struct device *dev, const uint8_t reg_addr, uint32_t *reg_val) +{ + const struct tmc51xx_config *config = dev->config; + struct tmc51xx_data *data = dev->data; + const struct spi_dt_spec bus = config->spi; + int err; + + k_sem_take(&data->sem, K_FOREVER); + + err = tmc_spi_read_register(&bus, TMC5XXX_ADDRESS_MASK, reg_addr, reg_val); + + k_sem_give(&data->sem); + + if (err) { + LOG_ERR("Failed to read register 0x%x", reg_addr); + return err; + } + return 0; +} + +static int tmc51xx_stepper_set_event_callback(const struct device *dev, + stepper_event_callback_t callback, void *user_data) +{ + struct tmc51xx_data *data = dev->data; + + data->callback = callback; + data->event_cb_user_data = user_data; + return 0; +} + +static int stallguard_enable(const struct device *dev, const bool enable) +{ + const struct tmc51xx_config *config = dev->config; + uint32_t reg_value; + int err; + + err = tmc51xx_read(dev, TMC51XX_SWMODE, ®_value); + if (err) { + LOG_ERR("Failed to read SWMODE register"); + return -EIO; + } + + if (enable) { + reg_value |= TMC5XXX_SW_MODE_SG_STOP_ENABLE; + + int32_t actual_velocity; + + err = tmc51xx_read(dev, TMC51XX_VACTUAL, + &actual_velocity); + if (err) { + LOG_ERR("Failed to read VACTUAL register"); + return -EIO; + } + + actual_velocity = (actual_velocity << (31 - TMC_RAMP_VACTUAL_SHIFT)) >> + (31 - TMC_RAMP_VACTUAL_SHIFT); + LOG_DBG("actual velocity: %d", actual_velocity); + + if (abs(actual_velocity) < config->sg_threshold_velocity) { + return -EAGAIN; + } + } else { + reg_value &= ~TMC5XXX_SW_MODE_SG_STOP_ENABLE; + } + err = tmc51xx_write(dev, TMC51XX_SWMODE, reg_value); + if (err) { + LOG_ERR("Failed to write SWMODE register"); + return -EIO; + } + return 0; +} + +static void stallguard_work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct tmc51xx_data *stepper_data = + CONTAINER_OF(dwork, struct tmc51xx_data, stallguard_dwork); + const struct device *dev = stepper_data->stepper; + const struct tmc51xx_config *config = dev->config; + int err; + + err = stallguard_enable(dev, true); + if (err == -EAGAIN) { + LOG_ERR("retrying stallguard activation"); + k_work_reschedule(dwork, K_MSEC(config->sg_velocity_check_interval_ms)); + } + if (err == -EIO) { + LOG_ERR("Failed to enable stallguard because of I/O error"); + return; + } +} + +#ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL + +static void execute_callback(const struct device *dev, const enum stepper_event event) +{ + struct tmc51xx_data *data = dev->data; + + if (!data->callback) { + LOG_WRN_ONCE("No callback registered"); + return; + } + data->callback(dev, event, data->event_cb_user_data); +} + +static void rampstat_work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + + struct tmc51xx_data *stepper_data = + CONTAINER_OF(dwork, struct tmc51xx_data, rampstat_callback_dwork); + const struct device *dev = stepper_data->stepper; + + __ASSERT_NO_MSG(dev != NULL); + + uint32_t drv_status; + int err; + + err = tmc51xx_read(dev, TMC51XX_DRVSTATUS, + &drv_status); + if (err != 0) { + LOG_ERR("%s: Failed to read DRVSTATUS register", dev->name); + return; + } + + if (FIELD_GET(TMC5XXX_DRV_STATUS_SG_STATUS_MASK, drv_status) == 1U) { + LOG_INF("%s: Stall detected", dev->name); + err = tmc51xx_write(dev, + TMC51XX_RAMPMODE, + TMC5XXX_RAMPMODE_HOLD_MODE); + if (err != 0) { + LOG_ERR("%s: Failed to stop motor", dev->name); + return; + } + } + + uint32_t rampstat_value; + + err = tmc51xx_read(dev, TMC51XX_RAMPSTAT, + &rampstat_value); + if (err != 0) { + LOG_ERR("%s: Failed to read RAMPSTAT register", dev->name); + return; + } + + const uint8_t ramp_stat_values = FIELD_GET(TMC5XXX_RAMPSTAT_INT_MASK, rampstat_value); + + if (ramp_stat_values > 0) { + switch (ramp_stat_values) { + + case TMC5XXX_STOP_LEFT_EVENT: + LOG_DBG("RAMPSTAT %s:Left end-stop detected", dev->name); + execute_callback(dev, + STEPPER_EVENT_LEFT_END_STOP_DETECTED); + break; + + case TMC5XXX_STOP_RIGHT_EVENT: + LOG_DBG("RAMPSTAT %s:Right end-stop detected", dev->name); + execute_callback(dev, + STEPPER_EVENT_RIGHT_END_STOP_DETECTED); + break; + + case TMC5XXX_POS_REACHED_EVENT: + LOG_DBG("RAMPSTAT %s:Position reached", dev->name); + execute_callback(dev, STEPPER_EVENT_STEPS_COMPLETED); + break; + + case TMC5XXX_STOP_SG_EVENT: + LOG_DBG("RAMPSTAT %s:Stall detected", dev->name); + stallguard_enable(dev, false); + execute_callback(dev, STEPPER_EVENT_STALL_DETECTED); + break; + default: + LOG_ERR("Illegal ramp stat bit field"); + break; + } + } else { + k_work_reschedule( + &stepper_data->rampstat_callback_dwork, + K_MSEC(CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); + } +} + +#endif + +static int tmc51xx_stepper_enable(const struct device *dev) +{ + LOG_DBG("Enabling Stepper motor controller %s", dev->name); + uint32_t reg_value; + int err; + + err = tmc51xx_read(dev, TMC51XX_CHOPCONF, ®_value); + if (err != 0) { + return -EIO; + } + + reg_value |= TMC5XXX_CHOPCONF_DRV_ENABLE_MASK; + + return tmc51xx_write(dev, TMC51XX_CHOPCONF, reg_value); +} + +static int tmc51xx_stepper_disable(const struct device *dev) +{ + LOG_DBG("Disabling Stepper motor controller %s", dev->name); + uint32_t reg_value; + int err; + + err = tmc51xx_read(dev, TMC51XX_CHOPCONF, ®_value); + if (err != 0) { + return -EIO; + } + + reg_value &= ~TMC5XXX_CHOPCONF_DRV_ENABLE_MASK; + + return tmc51xx_write(dev, TMC51XX_CHOPCONF, reg_value); +} + +static int tmc51xx_stepper_is_moving(const struct device *dev, bool *is_moving) +{ + uint32_t reg_value; + int err; + + err = tmc51xx_read(dev, TMC51XX_DRVSTATUS, ®_value); + + if (err != 0) { + LOG_ERR("%s: Failed to read DRVSTATUS register", dev->name); + return -EIO; + } + + *is_moving = (FIELD_GET(TMC5XXX_DRV_STATUS_STST_BIT, reg_value) == 1U); + LOG_DBG("Stepper motor controller %s is moving: %d", dev->name, *is_moving); + return 0; +} + +int tmc51xx_stepper_set_max_velocity(const struct device *dev, uint32_t velocity) +{ + const struct tmc51xx_config *config = dev->config; + const uint32_t clock_frequency = config->clock_frequency; + uint32_t velocity_fclk; + int err; + + velocity_fclk = tmc5xxx_calculate_velocity_from_hz_to_fclk(velocity, clock_frequency); + + err = tmc51xx_write(dev, TMC51XX_VMAX, velocity_fclk); + if (err != 0) { + LOG_ERR("%s: Failed to set max velocity", dev->name); + return -EIO; + } + return 0; +} + +static int tmc51xx_stepper_set_micro_step_res(const struct device *dev, + enum stepper_micro_step_resolution res) +{ + if (!VALID_MICRO_STEP_RES(res)) { + LOG_ERR("Invalid micro step resolution %d", res); + return -ENOTSUP; + } + + uint32_t reg_value; + int err; + + err = tmc51xx_read(dev, TMC51XX_CHOPCONF, ®_value); + if (err != 0) { + return -EIO; + } + + reg_value &= ~TMC5XXX_CHOPCONF_MRES_MASK; + reg_value |= ((MICRO_STEP_RES_INDEX(STEPPER_MICRO_STEP_256) - LOG2(res)) + << TMC5XXX_CHOPCONF_MRES_SHIFT); + + err = tmc51xx_write(dev, TMC51XX_CHOPCONF, reg_value); + if (err != 0) { + return -EIO; + } + + LOG_DBG("Stepper motor controller %s set micro step resolution to 0x%x", dev->name, + reg_value); + return 0; +} + +static int tmc51xx_stepper_get_micro_step_res(const struct device *dev, + enum stepper_micro_step_resolution *res) +{ + uint32_t reg_value; + int err; + + err = tmc51xx_read(dev, TMC51XX_CHOPCONF, ®_value); + if (err != 0) { + return -EIO; + } + reg_value &= TMC5XXX_CHOPCONF_MRES_MASK; + reg_value >>= TMC5XXX_CHOPCONF_MRES_SHIFT; + *res = (1 << (MICRO_STEP_RES_INDEX(STEPPER_MICRO_STEP_256) - reg_value)); + LOG_DBG("Stepper motor controller %s get micro step resolution: %d", dev->name, *res); + return 0; +} + +static int tmc51xx_stepper_set_reference_position(const struct device *dev, const int32_t position) +{ + int err; + + err = tmc51xx_write(dev, TMC51XX_RAMPMODE, + TMC5XXX_RAMPMODE_HOLD_MODE); + if (err != 0) { + return -EIO; + } + + err = tmc51xx_write(dev, TMC51XX_XACTUAL, position); + if (err != 0) { + return -EIO; + } + LOG_DBG("Stepper motor controller %s set actual position to %d", dev->name, position); + return 0; +} + +static int tmc51xx_stepper_get_actual_position(const struct device *dev, int32_t *position) +{ + int err; + + err = tmc51xx_read(dev, TMC51XX_XACTUAL, position); + if (err != 0) { + return -EIO; + } + LOG_DBG("%s actual position: %d", dev->name, *position); + return 0; +} + +static int tmc51xx_stepper_move_to(const struct device *dev, const int32_t micro_steps) +{ + LOG_DBG("%s set target position to %d", dev->name, micro_steps); + const struct tmc51xx_config *config = dev->config; + struct tmc51xx_data *data = dev->data; + int err; + + if (config->is_sg_enabled) { + stallguard_enable(dev, false); + } + + err = tmc51xx_write(dev, TMC51XX_RAMPMODE, + TMC5XXX_RAMPMODE_POSITIONING_MODE); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_XTARGET, micro_steps); + if (err != 0) { + return -EIO; + } + + if (config->is_sg_enabled) { + k_work_reschedule(&data->stallguard_dwork, + K_MSEC(config->sg_velocity_check_interval_ms)); + } +#ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL + if (data->callback) { + k_work_reschedule( + &data->rampstat_callback_dwork, + K_MSEC(CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); + } +#endif + return 0; +} + +static int tmc51xx_stepper_move_by(const struct device *dev, const int32_t micro_steps) +{ + int err; + int32_t position; + + err = stepper_get_actual_position(dev, &position); + if (err != 0) { + return -EIO; + } + int32_t target_position = position + micro_steps; + + LOG_DBG("%s moved to %d by steps: %d", dev->name, target_position, micro_steps); + + return tmc51xx_stepper_move_to(dev, target_position); +} + +static int tmc51xx_stepper_run(const struct device *dev, const enum stepper_direction direction) +{ + LOG_DBG("Stepper motor controller %s run", dev->name); + const struct tmc51xx_config *config = dev->config; + struct tmc51xx_data *data = dev->data; + int err; + + if (config->is_sg_enabled) { + err = stallguard_enable(dev, false); + if (err != 0) { + return -EIO; + } + } + + switch (direction) { + case STEPPER_DIRECTION_POSITIVE: + err = tmc51xx_write(dev, TMC51XX_RAMPMODE, + TMC5XXX_RAMPMODE_POSITIVE_VELOCITY_MODE); + if (err != 0) { + return -EIO; + } + break; + + case STEPPER_DIRECTION_NEGATIVE: + err = tmc51xx_write(dev, TMC51XX_RAMPMODE, + TMC5XXX_RAMPMODE_NEGATIVE_VELOCITY_MODE); + if (err != 0) { + return -EIO; + } + break; + } + + if (config->is_sg_enabled) { + k_work_reschedule(&data->stallguard_dwork, + K_MSEC(config->sg_velocity_check_interval_ms)); + } +#ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL + if (data->callback) { + k_work_reschedule( + &data->rampstat_callback_dwork, + K_MSEC(CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); + } +#endif + return 0; +} + +#ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN + +int tmc51xx_stepper_set_ramp(const struct device *dev, + const struct tmc_ramp_generator_data *ramp_data) +{ + LOG_DBG("Stepper motor controller %s set ramp", dev->name); + int err; + + err = tmc51xx_write(dev, TMC51XX_VSTART, ramp_data->vstart); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_A1, ramp_data->a1); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_AMAX, ramp_data->amax); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_D1, ramp_data->d1); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_DMAX, ramp_data->dmax); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_V1, ramp_data->v1); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_VMAX, ramp_data->vmax); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_VSTOP, ramp_data->vstop); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_TZEROWAIT, + ramp_data->tzerowait); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_THIGH, ramp_data->thigh); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_TCOOLTHRS, ramp_data->tcoolthrs); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_TPWMTHRS, ramp_data->tpwmthrs); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_TPOWER_DOWN, ramp_data->tpowerdown); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_IHOLD_IRUN, ramp_data->iholdrun); + if (err != 0) { + return -EIO; + } + return 0; +} + +#endif + +static int tmc51xx_init(const struct device *dev) +{ + LOG_DBG("TMC51XX stepper motor controller %s initialized", dev->name); + struct tmc51xx_data *data = dev->data; + const struct tmc51xx_config *config = dev->config; + int err; + + k_sem_init(&data->sem, 1, 1); + + if (!spi_is_ready_dt(&config->spi)) { + LOG_ERR("SPI bus is not ready"); + return -ENODEV; + } + + LOG_DBG("GCONF: %d", config->gconf); + err = tmc51xx_write(dev, TMC5XXX_GCONF, config->gconf); + if (err != 0) { + return -EIO; + } + + /* Read and write GSTAT register to clear any SPI Datagram errors. */ + uint32_t gstat_value; + + err = tmc51xx_read(dev, TMC5XXX_GSTAT, &gstat_value); + if (err != 0) { + return -EIO; + } + + err = tmc51xx_write(dev, TMC5XXX_GSTAT, gstat_value); + if (err != 0) { + return -EIO; + } + + if (config->is_sg_enabled) { + k_work_init_delayable(&data->stallguard_dwork, stallguard_work_handler); + + err = tmc51xx_write(dev, + TMC51XX_SWMODE, BIT(10)); + if (err != 0) { + return -EIO; + } + + LOG_DBG("Setting stall guard to %d with delay %d ms", config->sg_threshold, + config->sg_velocity_check_interval_ms); + if (!IN_RANGE(config->sg_threshold, TMC5XXX_SG_MIN_VALUE, + TMC5XXX_SG_MAX_VALUE)) { + LOG_ERR("Stallguard threshold out of range"); + return -EINVAL; + } + + int32_t stall_guard_threshold = (int32_t)config->sg_threshold; + + err = tmc51xx_write( + dev, TMC51XX_COOLCONF, + stall_guard_threshold << TMC5XXX_COOLCONF_SG2_THRESHOLD_VALUE_SHIFT); + if (err != 0) { + return -EIO; + } + err = stallguard_enable(dev, true); + if (err == -EAGAIN) { + LOG_ERR("retrying stallguard activation"); + k_work_reschedule(&data->stallguard_dwork, + K_MSEC(config->sg_velocity_check_interval_ms)); + } + } + +#ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN + err = tmc51xx_stepper_set_ramp(dev, &config->default_ramp_config); + if (err != 0) { + return -EIO; + } +#endif + +#if CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL + k_work_init_delayable(&data->rampstat_callback_dwork, rampstat_work_handler); + k_work_reschedule(&data->rampstat_callback_dwork, + K_MSEC(CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); +#endif + err = tmc51xx_stepper_set_micro_step_res(dev, config->default_micro_step_res); + if (err != 0) { + return -EIO; + } + return 0; +} + +static DEVICE_API(stepper, tmc51xx_api) = { + .enable = tmc51xx_stepper_enable, + .disable = tmc51xx_stepper_disable, + .is_moving = tmc51xx_stepper_is_moving, + .move_by = tmc51xx_stepper_move_by, + .set_micro_step_res = tmc51xx_stepper_set_micro_step_res, + .get_micro_step_res = tmc51xx_stepper_get_micro_step_res, + .set_reference_position = tmc51xx_stepper_set_reference_position, + .get_actual_position = tmc51xx_stepper_get_actual_position, + .move_to = tmc51xx_stepper_move_to, + .run = tmc51xx_stepper_run, + .set_event_callback = tmc51xx_stepper_set_event_callback, +}; + +#define TMC51XX_DEFINE(inst) \ + BUILD_ASSERT((DT_INST_PROP(inst, clock_frequency) > 0), \ + "clock frequency must be non-zero positive value"); \ + static struct tmc51xx_data tmc51xx_data_##inst = { \ + .stepper = DEVICE_DT_GET(DT_DRV_INST(inst))}; \ + COND_CODE_1(DT_PROP_EXISTS(inst, stallguard_threshold_velocity), \ + BUILD_ASSERT(DT_PROP(inst, stallguard_threshold_velocity), \ + "stallguard threshold velocity must be a positive value"), ()); \ + IF_ENABLED(CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN, (CHECK_RAMP_DT_DATA(inst))); \ + static const struct tmc51xx_config tmc51xx_config_##inst = { \ + .gconf = ( \ + (DT_INST_PROP(inst, en_pwm_mode) << TMC51XX_GCONF_EN_PWM_MODE_SHIFT) | \ + (DT_INST_PROP(inst, test_mode) << TMC51XX_GCONF_TEST_MODE_SHIFT) | \ + (DT_INST_PROP(inst, invert_direction) << TMC51XX_GCONF_SHAFT_SHIFT)), \ + .spi = SPI_DT_SPEC_INST_GET(inst, (SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | \ + SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8)), 0), \ + .clock_frequency = DT_INST_PROP(inst, clock_frequency), \ + .default_micro_step_res = DT_INST_PROP(inst, micro_step_res), \ + .sg_threshold = DT_INST_PROP(inst, stallguard2_threshold), \ + .sg_threshold_velocity = DT_INST_PROP(inst, stallguard_threshold_velocity), \ + .sg_velocity_check_interval_ms = DT_INST_PROP(inst, \ + stallguard_velocity_check_interval_ms), \ + .is_sg_enabled = DT_INST_PROP(inst, activate_stallguard2), \ + IF_ENABLED(CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN, \ + (.default_ramp_config = TMC_RAMP_DT_SPEC_GET_TMC51XX(inst)))}; \ + DEVICE_DT_INST_DEFINE(inst, tmc51xx_init, NULL, &tmc51xx_data_##inst, \ + &tmc51xx_config_##inst, POST_KERNEL, CONFIG_STEPPER_INIT_PRIORITY,\ + &tmc51xx_api); + +DT_INST_FOREACH_STATUS_OKAY(TMC51XX_DEFINE) diff --git a/drivers/stepper/adi_tmc/adi_tmc_reg.h b/drivers/stepper/adi_tmc/adi_tmc_reg.h index 7dc3fc665335..616b405442c7 100644 --- a/drivers/stepper/adi_tmc/adi_tmc_reg.h +++ b/drivers/stepper/adi_tmc/adi_tmc_reg.h @@ -7,6 +7,7 @@ /* * SPDX-FileCopyrightText: Copyright (c) 2024 Carl Zeiss Meditec AG + * SPDX-FileCopyrightText: Copyright (c) 2025 Prevas A/S * SPDX-License-Identifier: Apache-2.0 */ @@ -18,12 +19,12 @@ extern "C" { #endif /** Common Registers for TMC50XX and TMC51XX */ -#if defined(CONFIG_STEPPER_ADI_TMC50XX) +#if defined(CONFIG_STEPPER_ADI_TMC50XX) || defined(CONFIG_STEPPER_ADI_TMC51XX) #define TMC5XXX_WRITE_BIT 0x80U #define TMC5XXX_ADDRESS_MASK 0x7FU - #define TMC5XXX_CLOCK_FREQ_SHIFT 24 +#define TMC5XXX_CLOCK_FREQ_SHIFT 24 #define TMC5XXX_GCONF 0x00 #define TMC5XXX_GSTAT 0x01 @@ -79,12 +80,32 @@ extern "C" { #define TMC5XXX_DRV_STATUS_SG_STATUS_MASK BIT(24) #define TMC5XXX_DRV_STATUS_SG_STATUS_SHIFT 24 +#define TMC50XX_MOTOR_ADDR(m) (0x20 << (m)) +#define TMC50XX_MOTOR_ADDR_DRV(m) ((m) << 4) + +#define TMC50XX_RAMPMODE(motor) (0x00 | TMC50XX_MOTOR_ADDR(motor)) +#define TMC50XX_XACTUAL(motor) (0x01 | TMC50XX_MOTOR_ADDR(motor)) +#define TMC50XX_VACTUAL(motor) (0x02 | TMC50XX_MOTOR_ADDR(motor)) +#define TMC50XX_VSTART(motor) (0x03 | TMC50XX_MOTOR_ADDR(motor)) +#define TMC50XX_A1(motor) (0x04 | TMC50XX_MOTOR_ADDR(motor)) +#define TMC50XX_V1(motor) (0x05 | TMC50XX_MOTOR_ADDR(motor)) +#define TMC50XX_AMAX(motor) (0x06 | TMC50XX_MOTOR_ADDR(motor)) +#define TMC50XX_VMAX(motor) (0x07 | TMC50XX_MOTOR_ADDR(motor)) +#define TMC50XX_DMAX(motor) (0x08 | TMC50XX_MOTOR_ADDR(motor)) +#define TMC50XX_D1(motor) (0x0A | TMC50XX_MOTOR_ADDR(motor)) +#define TMC50XX_VSTOP(motor) (0x0B | TMC50XX_MOTOR_ADDR(motor)) +#define TMC50XX_TZEROWAIT(motor) (0x0C | TMC50XX_MOTOR_ADDR(motor)) +#define TMC50XX_XTARGET(motor) (0x0D | TMC50XX_MOTOR_ADDR(motor)) +#define TMC50XX_SWMODE(motor) (0x14 | TMC50XX_MOTOR_ADDR(motor)) +#define TMC50XX_RAMPSTAT(motor) (0x15 | TMC50XX_MOTOR_ADDR(motor)) +#define TMC50XX_CHOPCONF(motor) (0x6C | TMC50XX_MOTOR_ADDR_DRV(motor)) +#define TMC50XX_COOLCONF(motor) (0x6D | TMC50XX_MOTOR_ADDR_DRV(motor)) +#define TMC50XX_DRVSTATUS(motor) (0x6F | TMC50XX_MOTOR_ADDR_DRV(motor)) + #endif #ifdef CONFIG_STEPPER_ADI_TMC50XX -#define TMC50XX_MOTOR_ADDR(m) (0x20 << (m)) -#define TMC50XX_MOTOR_ADDR_DRV(m) ((m) << 4) #define TMC50XX_MOTOR_ADDR_PWM(m) ((m) << 3) /** @@ -102,24 +123,9 @@ extern "C" { #define TMC50XX_PWMCONF(motor) (0x10 | TMC50XX_MOTOR_ADDR_PWM(motor)) #define TMC50XX_PWM_STATUS(motor) (0x11 | TMC50XX_MOTOR_ADDR_PWM(motor)) -#define TMC50XX_RAMPMODE(motor) (0x00 | TMC50XX_MOTOR_ADDR(motor)) -#define TMC50XX_XACTUAL(motor) (0x01 | TMC50XX_MOTOR_ADDR(motor)) -#define TMC50XX_VACTUAL(motor) (0x02 | TMC50XX_MOTOR_ADDR(motor)) -#define TMC50XX_VSTART(motor) (0x03 | TMC50XX_MOTOR_ADDR(motor)) -#define TMC50XX_A1(motor) (0x04 | TMC50XX_MOTOR_ADDR(motor)) -#define TMC50XX_V1(motor) (0x05 | TMC50XX_MOTOR_ADDR(motor)) -#define TMC50XX_AMAX(motor) (0x06 | TMC50XX_MOTOR_ADDR(motor)) -#define TMC50XX_VMAX(motor) (0x07 | TMC50XX_MOTOR_ADDR(motor)) -#define TMC50XX_DMAX(motor) (0x08 | TMC50XX_MOTOR_ADDR(motor)) -#define TMC50XX_D1(motor) (0x0A | TMC50XX_MOTOR_ADDR(motor)) -#define TMC50XX_VSTOP(motor) (0x0B | TMC50XX_MOTOR_ADDR(motor)) -#define TMC50XX_TZEROWAIT(motor) (0x0C | TMC50XX_MOTOR_ADDR(motor)) -#define TMC50XX_XTARGET(motor) (0x0D | TMC50XX_MOTOR_ADDR(motor)) #define TMC50XX_IHOLD_IRUN(motor) (0x10 | TMC50XX_MOTOR_ADDR(motor)) #define TMC50XX_VCOOLTHRS(motor) (0x11 | TMC50XX_MOTOR_ADDR(motor)) #define TMC50XX_VHIGH(motor) (0x12 | TMC50XX_MOTOR_ADDR(motor)) -#define TMC50XX_SWMODE(motor) (0x14 | TMC50XX_MOTOR_ADDR(motor)) -#define TMC50XX_RAMPSTAT(motor) (0x15 | TMC50XX_MOTOR_ADDR(motor)) #define TMC50XX_XLATCH(motor) (0x16 | TMC50XX_MOTOR_ADDR(motor)) #define TMC50XX_MSLUT0(motor) (0x60 | TMC50XX_MOTOR_ADDR_DRV(motor)) @@ -134,12 +140,43 @@ extern "C" { #define TMC50XX_MSLUTSTART(motor) (0x69 | TMC50XX_MOTOR_ADDR_DRV(motor)) #define TMC50XX_MSCNT(motor) (0x6A | TMC50XX_MOTOR_ADDR_DRV(motor)) #define TMC50XX_MSCURACT(motor) (0x6B | TMC50XX_MOTOR_ADDR_DRV(motor)) -#define TMC50XX_CHOPCONF(motor) (0x6C | TMC50XX_MOTOR_ADDR_DRV(motor)) -#define TMC50XX_COOLCONF(motor) (0x6D | TMC50XX_MOTOR_ADDR_DRV(motor)) -#define TMC50XX_DRVSTATUS(motor) (0x6F | TMC50XX_MOTOR_ADDR_DRV(motor)) #endif /* CONFIG_STEPPER_ADI_TMC50XX */ +#ifdef CONFIG_STEPPER_ADI_TMC51XX + +#define TMC51XX_GCONF_EN_PWM_MODE_SHIFT 2 +#define TMC51XX_GCONF_SHAFT_SHIFT 4 +#define TMC51XX_GCONF_TEST_MODE_SHIFT 17 + +#define TMC51XX_IHOLD_IRUN 0x10 +#define TMC51XX_TPOWER_DOWN 0x11 +#define TMC51XX_TSTEP 0x12 +#define TMC51XX_TPWMTHRS 0x13 +#define TMC51XX_TCOOLTHRS 0x14 +#define TMC51XX_THIGH 0x15 + +#define TMC51XX_RAMPMODE TMC50XX_RAMPMODE(0) +#define TMC51XX_XACTUAL TMC50XX_XACTUAL(0) +#define TMC51XX_VACTUAL TMC50XX_VACTUAL(0) +#define TMC51XX_VSTART TMC50XX_VSTART(0) +#define TMC51XX_A1 TMC50XX_A1(0) +#define TMC51XX_V1 TMC50XX_V1(0) +#define TMC51XX_AMAX TMC50XX_AMAX(0) +#define TMC51XX_VMAX TMC50XX_VMAX(0) +#define TMC51XX_DMAX TMC50XX_DMAX(0) +#define TMC51XX_D1 TMC50XX_D1(0) +#define TMC51XX_VSTOP TMC50XX_VSTOP(0) +#define TMC51XX_TZEROWAIT TMC50XX_TZEROWAIT(0) +#define TMC51XX_XTARGET TMC50XX_XTARGET(0) +#define TMC51XX_SWMODE TMC50XX_SWMODE(0) +#define TMC51XX_RAMPSTAT TMC50XX_RAMPSTAT(0) +#define TMC51XX_CHOPCONF TMC50XX_CHOPCONF(0) +#define TMC51XX_COOLCONF TMC50XX_COOLCONF(0) +#define TMC51XX_DRVSTATUS TMC50XX_DRVSTATUS(0) + +#endif /* CONFIG_STEPPER_ADI_TMC51XX */ + /** * @} */ diff --git a/drivers/timer/stm32_lptim_timer.c b/drivers/timer/stm32_lptim_timer.c index 2a1d49b87bf4..a1a1d6fc0df2 100644 --- a/drivers/timer/stm32_lptim_timer.c +++ b/drivers/timer/stm32_lptim_timer.c @@ -518,7 +518,8 @@ static int sys_clock_driver_init(void) #if defined(CONFIG_SOC_SERIES_STM32U5X) || \ defined(CONFIG_SOC_SERIES_STM32H5X) || \ - defined(CONFIG_SOC_SERIES_STM32WBAX) + defined(CONFIG_SOC_SERIES_STM32WBAX) || \ + defined(CONFIG_SOC_SERIES_STM32U0X) LL_LPTIM_OC_SetPolarity(LPTIM, LL_LPTIM_CHANNEL_CH1, LL_LPTIM_OUTPUT_POLARITY_REGULAR); #else @@ -532,7 +533,8 @@ static int sys_clock_driver_init(void) #if defined(CONFIG_SOC_SERIES_STM32U5X) || \ defined(CONFIG_SOC_SERIES_STM32H5X) || \ - defined(CONFIG_SOC_SERIES_STM32WBAX) + defined(CONFIG_SOC_SERIES_STM32WBAX) || \ + defined(CONFIG_SOC_SERIES_STM32U0X) /* Enable the LPTIM before proceeding with configuration */ LL_LPTIM_Enable(LPTIM); diff --git a/drivers/timer/ti_dmtimer.c b/drivers/timer/ti_dmtimer.c index 37b8ebe14d5a..03940c0ce171 100644 --- a/drivers/timer/ti_dmtimer.c +++ b/drivers/timer/ti_dmtimer.c @@ -21,6 +21,10 @@ #define TIMER_IRQ_PRIO DT_INST_IRQ(0, priority) #define TIMER_IRQ_FLAGS DT_INST_IRQ(0, flags) +#if defined(CONFIG_TEST) +const int32_t z_sys_timer_irq_for_test = TIMER_IRQ_NUM; +#endif + #define CYC_PER_TICK ((uint32_t)(sys_clock_hw_cycles_per_sec() / CONFIG_SYS_CLOCK_TICKS_PER_SEC)) #define MAX_TICKS ((k_ticks_t)(UINT32_MAX / CYC_PER_TICK) - 1) diff --git a/drivers/video/video_emul_rx.c b/drivers/video/video_emul_rx.c index ba44a2c59ed6..7b7d1f580a72 100644 --- a/drivers/video/video_emul_rx.c +++ b/drivers/video/video_emul_rx.c @@ -269,10 +269,11 @@ int emul_rx_init(const struct device *dev) return 0; } +#define SOURCE_DEV(n) DEVICE_DT_GET(DT_NODE_REMOTE_DEVICE(DT_INST_ENDPOINT_BY_ID(n, 0, 0))) + #define EMUL_RX_DEFINE(n) \ static const struct emul_rx_config emul_rx_cfg_##n = { \ - .source_dev = \ - DEVICE_DT_GET(DT_NODE_REMOTE_DEVICE(DT_INST_ENDPOINT_BY_ID(n, 0, 0))), \ + .source_dev = SOURCE_DEV(n), \ }; \ \ static struct emul_rx_data emul_rx_data_##n = { \ @@ -282,6 +283,6 @@ int emul_rx_init(const struct device *dev) DEVICE_DT_INST_DEFINE(n, &emul_rx_init, NULL, &emul_rx_data_##n, &emul_rx_cfg_##n, \ POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, &emul_rx_driver_api); \ \ - VIDEO_DEVICE_DEFINE(emul_rx_##n, DEVICE_DT_INST_GET(n), emul_rx_cfg_##n.source_dev); + VIDEO_DEVICE_DEFINE(emul_rx_##n, DEVICE_DT_INST_GET(n), SOURCE_DEV(n)); DT_INST_FOREACH_STATUS_OKAY(EMUL_RX_DEFINE) diff --git a/drivers/video/video_esp32_dvp.c b/drivers/video/video_esp32_dvp.c index 5d1ec69f2421..07d60d85c965 100644 --- a/drivers/video/video_esp32_dvp.c +++ b/drivers/video/video_esp32_dvp.c @@ -428,9 +428,11 @@ static DEVICE_API(video, esp32_driver_api) = { PINCTRL_DT_INST_DEFINE(0); +#define SOURCE_DEV(n) DEVICE_DT_GET(DT_INST_PHANDLE(n, source)) + static const struct video_esp32_config esp32_config = { .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), - .source_dev = DEVICE_DT_GET(DT_INST_PHANDLE(0, source)), + .source_dev = SOURCE_DEV(0), .dma_dev = ESP32_DT_INST_DMA_CTLR(0, rx), .rx_dma_channel = DT_INST_DMAS_CELL_BY_NAME(0, rx, channel), .data_width = DT_INST_PROP_OR(0, data_width, 8), @@ -450,7 +452,7 @@ static struct video_esp32_data esp32_data = {0}; DEVICE_DT_INST_DEFINE(0, video_esp32_init, NULL, &esp32_data, &esp32_config, POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, &esp32_driver_api); -VIDEO_DEVICE_DEFINE(esp32, DEVICE_DT_INST_GET(0), esp32_config.source_dev); +VIDEO_DEVICE_DEFINE(esp32, DEVICE_DT_INST_GET(0), SOURCE_DEV(0)); static int video_esp32_cam_init_master_clock(void) { diff --git a/drivers/video/video_mcux_csi.c b/drivers/video/video_mcux_csi.c index 4b4a46dc2cbd..4c9675ee2beb 100644 --- a/drivers/video/video_mcux_csi.c +++ b/drivers/video/video_mcux_csi.c @@ -456,9 +456,11 @@ static DEVICE_API(video, video_mcux_csi_driver_api) = { #if 1 /* Unique Instance */ PINCTRL_DT_INST_DEFINE(0); +#define SOURCE_DEV(n) DEVICE_DT_GET(DT_NODE_REMOTE_DEVICE(DT_INST_ENDPOINT_BY_ID(n, 0, 0))) + static const struct video_mcux_csi_config video_mcux_csi_config_0 = { .base = (CSI_Type *)DT_INST_REG_ADDR(0), - .source_dev = DEVICE_DT_GET(DT_NODE_REMOTE_DEVICE(DT_INST_ENDPOINT_BY_ID(0, 0, 0))), + .source_dev = SOURCE_DEV(0), .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), }; @@ -481,6 +483,6 @@ DEVICE_DT_INST_DEFINE(0, &video_mcux_csi_init_0, NULL, &video_mcux_csi_data_0, &video_mcux_csi_config_0, POST_KERNEL, CONFIG_VIDEO_MCUX_CSI_INIT_PRIORITY, &video_mcux_csi_driver_api); -VIDEO_DEVICE_DEFINE(csi, DEVICE_DT_INST_GET(0), video_mcux_csi_config_0.source_dev); +VIDEO_DEVICE_DEFINE(csi, DEVICE_DT_INST_GET(0), SOURCE_DEV(0)); #endif diff --git a/drivers/video/video_mcux_mipi_csi2rx.c b/drivers/video/video_mcux_mipi_csi2rx.c index be6ff4595f3a..fb3cf5efa1e9 100644 --- a/drivers/video/video_mcux_mipi_csi2rx.c +++ b/drivers/video/video_mcux_mipi_csi2rx.c @@ -320,6 +320,8 @@ static int mipi_csi2rx_init(const struct device *dev) return mipi_csi2rx_update_settings(dev, VIDEO_EP_ALL); } +#define SOURCE_DEV(n) DEVICE_DT_GET(DT_NODE_REMOTE_DEVICE(DT_INST_ENDPOINT_BY_ID(n, 1, 0))) + #define MIPI_CSI2RX_INIT(n) \ static struct mipi_csi2rx_data mipi_csi2rx_data_##n = { \ .csi2rxConfig.laneNum = DT_PROP_LEN(DT_INST_ENDPOINT_BY_ID(n, 1, 0), data_lanes), \ @@ -331,15 +333,13 @@ static int mipi_csi2rx_init(const struct device *dev) \ static const struct mipi_csi2rx_config mipi_csi2rx_config_##n = { \ .base = (MIPI_CSI2RX_Type *)DT_INST_REG_ADDR(n), \ - .sensor_dev = \ - DEVICE_DT_GET(DT_NODE_REMOTE_DEVICE(DT_INST_ENDPOINT_BY_ID(n, 1, 0))), \ + .sensor_dev = SOURCE_DEV(n), \ }; \ \ DEVICE_DT_INST_DEFINE(n, &mipi_csi2rx_init, NULL, &mipi_csi2rx_data_##n, \ &mipi_csi2rx_config_##n, POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \ &mipi_csi2rx_driver_api); \ \ - VIDEO_DEVICE_DEFINE(mipi_csi2rx_##n, DEVICE_DT_INST_GET(n), \ - mipi_csi2rx_config_##n.sensor_dev); + VIDEO_DEVICE_DEFINE(mipi_csi2rx_##n, DEVICE_DT_INST_GET(n), SOURCE_DEV(n)); DT_INST_FOREACH_STATUS_OKAY(MIPI_CSI2RX_INIT) diff --git a/drivers/video/video_mcux_smartdma.c b/drivers/video/video_mcux_smartdma.c index 9081bcb59674..d9388b0951d6 100644 --- a/drivers/video/video_mcux_smartdma.c +++ b/drivers/video/video_mcux_smartdma.c @@ -365,11 +365,13 @@ static DEVICE_API(video, nxp_video_sdma_api) = { .flush = nxp_video_sdma_flush }; +#define SOURCE_DEV(inst) DEVICE_DT_GET(DT_INST_PHANDLE(inst, sensor)) + #define NXP_VIDEO_SDMA_INIT(inst) \ PINCTRL_DT_INST_DEFINE(inst); \ const struct nxp_video_sdma_config sdma_config_##inst = { \ .dma_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ - .sensor_dev = DEVICE_DT_GET(DT_INST_PHANDLE(inst, sensor)), \ + .sensor_dev = SOURCE_DEV(n), \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ .vsync_pin = DT_INST_PROP(inst, vsync_pin), \ .hsync_pin = DT_INST_PROP(inst, hsync_pin), \ @@ -383,6 +385,6 @@ static DEVICE_API(video, nxp_video_sdma_api) = { &sdma_config_##inst, POST_KERNEL, \ CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &nxp_video_sdma_api); \ \ - VIDEO_DEVICE_DEFINE(sdma_##inst, DEVICE_DT_INST_GET(inst), sdma_config_##inst.sensor_dev); + VIDEO_DEVICE_DEFINE(sdma_##inst, DEVICE_DT_INST_GET(inst), SOURCE_DEV(inst)); DT_INST_FOREACH_STATUS_OKAY(NXP_VIDEO_SDMA_INIT) diff --git a/drivers/video/video_stm32_dcmi.c b/drivers/video/video_stm32_dcmi.c index 35c55449a558..53afb33c0b51 100644 --- a/drivers/video/video_stm32_dcmi.c +++ b/drivers/video/video_stm32_dcmi.c @@ -436,6 +436,8 @@ static struct video_stm32_dcmi_data video_stm32_dcmi_data_0 = { }, }; +#define SOURCE_DEV(n) DEVICE_DT_GET(DT_INST_PHANDLE(n, sensor)) + static const struct video_stm32_dcmi_config video_stm32_dcmi_config_0 = { .pclken = { .enr = DT_INST_CLOCKS_CELL(0, bits), @@ -443,7 +445,7 @@ static const struct video_stm32_dcmi_config video_stm32_dcmi_config_0 = { }, .irq_config = video_stm32_dcmi_irq_config_func, .pctrl = PINCTRL_DT_INST_DEV_CONFIG_GET(0), - .sensor_dev = DEVICE_DT_GET(DT_INST_PHANDLE(0, sensor)), + .sensor_dev = SOURCE_DEV(0), DCMI_DMA_CHANNEL(0, PERIPHERAL, MEMORY) }; @@ -500,4 +502,4 @@ DEVICE_DT_INST_DEFINE(0, &video_stm32_dcmi_init, POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, &video_stm32_dcmi_driver_api); -VIDEO_DEVICE_DEFINE(dcmi, DEVICE_DT_INST_GET(0), video_stm32_dcmi_config_0.sensor_dev); +VIDEO_DEVICE_DEFINE(dcmi, DEVICE_DT_INST_GET(0), SOURCE_DEV(0)); diff --git a/drivers/wifi/nrf_wifi/src/net_if.c b/drivers/wifi/nrf_wifi/src/net_if.c index 8cdb9a472bda..633ee48f9013 100644 --- a/drivers/wifi/nrf_wifi/src/net_if.c +++ b/drivers/wifi/nrf_wifi/src/net_if.c @@ -358,6 +358,7 @@ int nrf_wifi_if_send(const struct device *dev, struct nrf_wifi_sys_fmac_dev_ctx *sys_dev_ctx = NULL; struct rpu_host_stats *host_stats = NULL; void *nbuf = NULL; + bool locked = false; if (!dev || !pkt) { LOG_ERR("%s: vif_ctx_zep is NULL", __func__); @@ -371,24 +372,27 @@ int nrf_wifi_if_send(const struct device *dev, goto out; } + /* Allocate packet before locking mutex (blocks until allocation success) */ + nbuf = net_pkt_to_nbuf(pkt); + ret = k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER); if (ret != 0) { LOG_ERR("%s: Failed to lock vif_lock", __func__); - goto out; + goto drop; } + locked = true; rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; if (!rpu_ctx_zep || !rpu_ctx_zep->rpu_ctx) { - goto unlock; + goto drop; } sys_dev_ctx = wifi_dev_priv(rpu_ctx_zep->rpu_ctx); host_stats = &sys_dev_ctx->host_stats; - nbuf = net_pkt_to_nbuf(pkt); - if (!nbuf) { - LOG_DBG("Failed to allocate net_pkt"); - host_stats->total_tx_drop_pkts++; - goto out; + + if (nbuf == NULL) { + LOG_ERR("%s: allocation failed", __func__); + goto drop; } #ifdef CONFIG_NRF70_RAW_DATA_TX @@ -415,10 +419,16 @@ int nrf_wifi_if_send(const struct device *dev, #endif /* CONFIG_NRF70_RAW_DATA_TX */ goto unlock; drop: - host_stats->total_tx_drop_pkts++; - nrf_wifi_osal_nbuf_free(nbuf); + if (host_stats != NULL) { + host_stats->total_tx_drop_pkts++; + } + if (nbuf != NULL) { + nrf_wifi_osal_nbuf_free(nbuf); + } unlock: - k_mutex_unlock(&vif_ctx_zep->vif_lock); + if (locked) { + k_mutex_unlock(&vif_ctx_zep->vif_lock); + } #else ARG_UNUSED(dev); ARG_UNUSED(pkt); diff --git a/dts/arm/nxp/nxp_mcxa153.dtsi b/dts/arm/nxp/nxp_mcxa153.dtsi index 6cfeb3d75cf3..d1d2c42f0fa5 100644 --- a/dts/arm/nxp/nxp_mcxa153.dtsi +++ b/dts/arm/nxp/nxp_mcxa153.dtsi @@ -42,6 +42,45 @@ status = "disabled"; }; + flexpwm0: flexpwm@400a9000 { + compatible = "nxp,flexpwm"; + reg = <0x400a9000 0x1000>; + interrupt-names = "RELOAD-ERROR", "FAULT"; + interrupts = <44 0>, <45 0>; + flexpwm0_pwm0: pwm0 { + compatible = "nxp,imx-pwm"; + index = <0>; + interrupts = <46 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + + flexpwm0_pwm1: pwm1 { + compatible = "nxp,imx-pwm"; + index = <1>; + interrupts = <47 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + + flexpwm0_pwm2: pwm2 { + compatible = "nxp,imx-pwm"; + index = <2>; + interrupts = <48 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + }; + fmu: flash-controller@40095000 { compatible = "nxp,msf1"; reg = <0x40095000 0x1000>; diff --git a/dts/arm/realtek/ec/rts5912.dtsi b/dts/arm/realtek/ec/rts5912.dtsi index 236abbdb7d13..771bddf38035 100644 --- a/dts/arm/realtek/ec/rts5912.dtsi +++ b/dts/arm/realtek/ec/rts5912.dtsi @@ -6,6 +6,7 @@ */ #include +#include #include #include @@ -87,6 +88,84 @@ status = "disabled"; }; + timer0: timer@4000c300 { + compatible = "realtek,rts5912-timer"; + reg = < 0x4000c300 0x14 >; + interrupt-parent = <&nvic>; + interrupts = <196 0>; + clocks = <&sccon RTS5912_SCCON_PERIPH_GRP1 PERIPH_GRP1_TMR0_CLKPWR>; + clock-names = "tmr32"; + max-value = <0xFFFFFFFF>; + clock-frequency = <25000000>; + prescaler = <0>; + status = "disabled"; + }; + + timer1: timer@4000c314 { + compatible = "realtek,rts5912-timer"; + reg = < 0x4000c314 0x14 >; + interrupt-parent = <&nvic>; + interrupts = <197 0>; + clocks = <&sccon RTS5912_SCCON_PERIPH_GRP1 PERIPH_GRP1_TMR1_CLKPWR>; + clock-names = "tmr32"; + max-value = <0xFFFFFFFF>; + clock-frequency = <25000000>; + prescaler = <0>; + status = "disabled"; + }; + + timer2: timer@4000c328 { + compatible = "realtek,rts5912-timer"; + reg = < 0x4000c328 0x14 >; + interrupt-parent = <&nvic>; + interrupts = <198 0>; + clocks = <&sccon RTS5912_SCCON_PERIPH_GRP1 PERIPH_GRP1_TMR2_CLKPWR>; + clock-names = "tmr32"; + max-value = <0xFFFFFFFF>; + clock-frequency = <25000000>; + prescaler = <0>; + status = "disabled"; + }; + + timer3: timer@4000c33c { + compatible = "realtek,rts5912-timer"; + reg = < 0x4000c33c 0x14 >; + interrupt-parent = <&nvic>; + interrupts = <199 0>; + clocks = <&sccon RTS5912_SCCON_PERIPH_GRP1 PERIPH_GRP1_TMR3_CLKPWR>; + clock-names = "tmr32"; + max-value = <0xFFFFFFFF>; + clock-frequency = <25000000>; + prescaler = <0>; + status = "disabled"; + }; + + timer4: timer@4000c350 { + compatible = "realtek,rts5912-timer"; + reg = < 0x4000c350 0x14 >; + interrupt-parent = <&nvic>; + interrupts = <200 0>; + clocks = <&sccon RTS5912_SCCON_PERIPH_GRP1 PERIPH_GRP1_TMR4_CLKPWR>; + clock-names = "tmr32"; + max-value = <0xFFFFFFFF>; + clock-frequency = <25000000>; + prescaler = <0>; + status = "disabled"; + }; + + timer5: timer@4000c364 { + compatible = "realtek,rts5912-timer"; + reg = < 0x4000c364 0x14 >; + interrupt-parent = <&nvic>; + interrupts = <201 0>; + clocks = <&sccon RTS5912_SCCON_PERIPH_GRP1 PERIPH_GRP1_TMR5_CLKPWR>; + clock-names = "tmr32"; + max-value = <0xFFFFFFFF>; + clock-frequency = <25000000>; + prescaler = <0>; + status = "disabled"; + }; + slwtmr0: slwtmr0@4000c200 { compatible = "realtek,rts5912-slwtimer"; reg = <0x4000c200 0x10>; @@ -106,6 +185,15 @@ status = "okay"; }; + adc0: adc@4000fe00 { + compatible = "realtek,rts5912-adc"; + reg = <0x4000fe00 0x38>; + clocks = <&sccon RTS5912_SCCON_ADC ADC0_CLKPWR>; + interrupts = <221 0>; + #io-channel-cells = <1>; + status = "disabled"; + }; + uart0: uart@40010100 { compatible = "ns16550"; reg = <0x40010100 0x100>; diff --git a/dts/arm/st/f3/stm32f303Xe.dtsi b/dts/arm/st/f3/stm32f303Xe.dtsi index bb04ee099aee..b997e0fb4ff8 100644 --- a/dts/arm/st/f3/stm32f303Xe.dtsi +++ b/dts/arm/st/f3/stm32f303Xe.dtsi @@ -41,5 +41,21 @@ status = "disabled"; }; }; + + i2c3: i2c@4007800 { + compatible = "st,stm32-i2c-v2"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40007800 0x400>; + clocks = <&rcc STM32_CLOCK(APB1, 30)>, + /* I2C clock source should always be defined, + * even for the default value + */ + <&rcc STM32_SRC_SYSCLK I2C3_SEL(1)>; + interrupts = <72 0>, <73 0>; + interrupt-names = "event", "error"; + status = "disabled"; + }; }; }; diff --git a/dts/arm/st/n6/stm32n6.dtsi b/dts/arm/st/n6/stm32n6.dtsi index 71603b8a1268..698acda6c2d8 100644 --- a/dts/arm/st/n6/stm32n6.dtsi +++ b/dts/arm/st/n6/stm32n6.dtsi @@ -691,7 +691,7 @@ interrupts = <170 0>; clock-names = "xspix", "xspi-ker", "xspi-mgr"; clocks = <&rcc STM32_CLOCK(AHB5, 5)>, - <&rcc STM32_SRC_CKPER XSPI1_SEL(1)>, + <&rcc STM32_SRC_HCLK5 XSPI1_SEL(0)>, <&rcc STM32_CLOCK(AHB5, 13)>; #address-cells = <1>; #size-cells = <1>; @@ -704,7 +704,7 @@ interrupts = <171 0>; clock-names = "xspix", "xspi-ker", "xspi-mgr"; clocks = <&rcc STM32_CLOCK(AHB5, 12)>, - <&rcc STM32_SRC_CKPER XSPI2_SEL(1)>, + <&rcc STM32_SRC_HCLK5 XSPI2_SEL(0)>, <&rcc STM32_CLOCK(AHB5, 13)>; #address-cells = <1>; #size-cells = <1>; @@ -731,6 +731,17 @@ clocks = <&rcc STM32_CLOCK(AHB5, 27)>; #phy-cells = <0>; }; + + ltdc: ltdc@58001000 { + compatible = "st,stm32-ltdc"; + reg = <0x58001000 0x1000>; + interrupts = <193 0>, <194 0>; + interrupt-names = "ltdc", "ltdc_er"; + clocks = <&rcc STM32_CLOCK(APB5, 1)>, + <&rcc STM32_SRC_PCLK5 LTDC_SEL(0)>; + resets = <&rctl STM32_RESET(APB5, 1)>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/st/n6/stm32n657X0.dtsi b/dts/arm/st/n6/stm32n657X0.dtsi index 613c3ee443eb..b503ffed905d 100644 --- a/dts/arm/st/n6/stm32n657X0.dtsi +++ b/dts/arm/st/n6/stm32n657X0.dtsi @@ -8,7 +8,8 @@ / { axisram1: memory@34000000 { - reg = <0x34000000 DT_SIZE_K(624)>; + /* 400 kB of FLEXRAM followed by 624 kB of AXISRAM1 */ + reg = <0x34000000 (DT_SIZE_K(400) + DT_SIZE_K(624))>; }; axisram2: memory@34180400 { diff --git a/dts/arm/st/u0/stm32u0.dtsi b/dts/arm/st/u0/stm32u0.dtsi index 612747dfc4ca..20d2124bf40b 100644 --- a/dts/arm/st/u0/stm32u0.dtsi +++ b/dts/arm/st/u0/stm32u0.dtsi @@ -34,6 +34,27 @@ #address-cells = <1>; #size-cells = <1>; }; + + power-states { + stop0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <100>; + }; + stop1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <2>; + min-residency-us = <500>; + }; + stop2: state2 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <3>; + min-residency-us = <900>; + }; + }; }; sram0: memory@20000000 { diff --git a/dts/bindings/adc/realtek,rts5912-adc.yaml b/dts/bindings/adc/realtek,rts5912-adc.yaml new file mode 100644 index 000000000000..473a5c8acecc --- /dev/null +++ b/dts/bindings/adc/realtek,rts5912-adc.yaml @@ -0,0 +1,23 @@ +description: Realtek rts5912 ADC + +compatible: "realtek,rts5912-adc" + +include: [adc-controller.yaml, pinctrl-device.yaml] + +properties: + interrupts: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + vref-mv: + type: int + default: 3300 + description: The reference voltage of the ADC in mV. + +io-channel-cells: + - input diff --git a/dts/bindings/clock/st,stm32n6-rcc.yaml b/dts/bindings/clock/st,stm32n6-rcc.yaml index d04c26767c68..5bac045ec578 100644 --- a/dts/bindings/clock/st,stm32n6-rcc.yaml +++ b/dts/bindings/clock/st,stm32n6-rcc.yaml @@ -62,63 +62,35 @@ properties: apb1-prescaler: type: int - required: true + default: 1 + const: 1 description: | CPU domain APB1 prescaler - enum: - - 1 - - 2 - - 4 - - 8 - - 16 - - 32 - - 64 - - 128 + Fixed to 1 as APB prescalers cannot be modified (See Errata sheet ES0620 §2.2.1) apb2-prescaler: type: int - required: true + default: 1 + const: 1 description: | CPU domain APB2 prescaler - enum: - - 1 - - 2 - - 4 - - 8 - - 16 - - 32 - - 64 - - 128 + Fixed to 1 as APB prescalers cannot be modified (See Errata sheet ES0620 §2.2.1) apb4-prescaler: type: int - required: true + default: 1 + const: 1 description: | CPU domain APB4 prescaler - enum: - - 1 - - 2 - - 4 - - 8 - - 16 - - 32 - - 64 - - 128 + Fixed to 1 as APB prescalers cannot be modified (See Errata sheet ES0620 §2.2.1) apb5-prescaler: type: int - required: true + default: 1 + const: 1 description: | CPU domain APB5 prescaler - enum: - - 1 - - 2 - - 4 - - 8 - - 16 - - 32 - - 64 - - 128 + Fixed to 1 as APB prescalers cannot be modified (See Errata sheet ES0620 §2.2.1) timg-prescaler: type: int diff --git a/dts/bindings/counter/realtek,rts5912-timer.yaml b/dts/bindings/counter/realtek,rts5912-timer.yaml new file mode 100644 index 000000000000..c18ef8667615 --- /dev/null +++ b/dts/bindings/counter/realtek,rts5912-timer.yaml @@ -0,0 +1,30 @@ +# Copyright (c) 2025, Realtek Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Realtek RTS5912 32bit timer + +compatible: "realtek,rts5912-timer" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + max-value: + type: int + required: true + description: Maximum counter value the instance can handle + + clock-frequency: + type: int + required: true + description: Clock frequency information for timer operation + + prescaler: + type: int + required: true + description: Timer frequency equals clock-frequency divided by the prescaler value diff --git a/dts/bindings/pinctrl/ambiq,apollo4-pinctrl.yaml b/dts/bindings/pinctrl/ambiq,apollo4-pinctrl.yaml index 2ab4ddb8eb6f..cfb7cbd7a4e1 100644 --- a/dts/bindings/pinctrl/ambiq,apollo4-pinctrl.yaml +++ b/dts/bindings/pinctrl/ambiq,apollo4-pinctrl.yaml @@ -161,3 +161,11 @@ child-binding: Polarity select for NCE LOW = 0x0 - Polarity is active low HIGH = 0x1 - Polarity is active high + ambiq,sdif-cdwp: + type: int + default: 0 + description: | + Configure SD Card Detection and Write Protection pin + 0x0 - Not SDIF pin + 0x1 - SDIFCD + 0x2 - SDIFWP diff --git a/dts/bindings/sensor/pixart,paj7620.yaml b/dts/bindings/sensor/pixart,paj7620.yaml new file mode 100644 index 000000000000..2fec7adb76da --- /dev/null +++ b/dts/bindings/sensor/pixart,paj7620.yaml @@ -0,0 +1,17 @@ +# Copyright (c) 2025 Paul Timke +# SPDX-License-Identifier: Apache-2.0 + +description: Pixart PAJ7620 gesture sensor + +compatible: "pixart,paj7620" + +include: [sensor-device.yaml, i2c-device.yaml] + +properties: + int-gpios: + type: phandle-array + description: | + INT pin + This pin defaults to active low when produced by the sensor. + The property value should ensure the flags properly describe + the signal that is presented to the driver. diff --git a/dts/bindings/stepper/adi/adi,tmc50xx.yaml b/dts/bindings/stepper/adi/adi,tmc50xx.yaml index a20e680e3aee..eba9cd3f664c 100644 --- a/dts/bindings/stepper/adi/adi,tmc50xx.yaml +++ b/dts/bindings/stepper/adi/adi,tmc50xx.yaml @@ -13,7 +13,7 @@ description: | tmc50xx: tmc50xx@0 { compatible = "adi,tmc50xx"; reg = <0>; - spi-max-frequency = ; /* Maximum SPI bus frequency */ + spi-max-frequency = ; /* Maximum SPI bus frequency */ #address-cells = <1>; #size-cells = <0>; @@ -61,8 +61,6 @@ include: - name: adi,trinamic-gconf.yaml property-allowlist: - poscmp-enable - - shaft1 - - shaft2 - test-mode - lock-gconf diff --git a/dts/bindings/stepper/adi/adi,tmc51xx.yaml b/dts/bindings/stepper/adi/adi,tmc51xx.yaml new file mode 100644 index 000000000000..caad1785123b --- /dev/null +++ b/dts/bindings/stepper/adi/adi,tmc51xx.yaml @@ -0,0 +1,108 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Prevas A/S +# SPDX-License-Identifier: Apache-2.0 + +description: | + Analog Devices TMC51XX Stepper Motor Controller + + Example: + + &spi0 { + /* SPI bus options here, not shown */ + + /* Controller/driver for one 2-phase bipolar stepper motor */ + tmc51xx: tmc51xx@0 { + compatible = "adi,tmc51xx"; + reg = <0>; + spi-max-frequency = ; /* Maximum SPI bus frequency */ + + #address-cells = <1>; + #size-cells = <0>; + + en-pwm-mode; test-mode; /* ADI TMC Global configuration flags */ + clock-frequency = ; /* Internal/External Clock frequency */ + + /* common stepper controller settings */ + invert-direction; + micro-step-res = <256>; + + /* ADI TMC stallguard settings specific to TMC51XX */ + activate-stallguard2; + stallguard-velocity-check-interval-ms=<100>; + stallguard2-threshold=<9>; + stallguard-threshold-velocity=<500000>; + + /* ADI TMC ramp generator as well as current settings */ + vstart = <10>; + a1 = <20>; + v1 = <30>; + d1 = <40>; + vmax = <50>; + amax = <60>; + dmax = <70>; + tzerowait = <80>; + thigh = <90>; + tcoolthrs = <100>; + tpwmthrs = <110>; + tpowerdown = <120>; + ihold = <1>; + irun = <2>; + iholddelay = <3>; + }; + }; + + +compatible: "adi,tmc51xx" + +include: + - name: spi-device.yaml + - name: adi,trinamic-gconf.yaml + property-allowlist: + - en-pwm-mode + - test-mode + - name: stepper-controller.yaml + - name: base.yaml + property-allowlist: + - reg + - name: adi,trinamic-ramp-generator.yaml + property-allowlist: + - vstart + - a1 + - v1 + - amax + - vmax + - dmax + - d1 + - vstop + - tzerowait + - thigh + - tcoolthrs + - tpwmthrs + - tpowerdown + - ihold + - irun + - iholddelay + - name: adi,trinamic-stallguard.yaml + property-allowlist: + - activate-stallguard2 + - stallguard2-threshold + - stallguard-threshold-velocity + - stallguard-velocity-check-interval-ms + +properties: + "#address-cells": + default: 1 + const: 1 + + "#size-cells": + default: 0 + const: 0 + + clock-frequency: + type: int + required: true + description: | + The frequency of the clock signal provided to the TMC51XX. + This is used for real world conversion. + + Hint: µstep velocity v[Hz] µsteps / s v[Hz] = v[51xx] * ( fCLK[Hz]/2 / 2^23 ) + where v[51xx] is the value written to the TMC51XX. diff --git a/dts/bindings/stepper/adi/adi,trinamic-gconf.yaml b/dts/bindings/stepper/adi/adi,trinamic-gconf.yaml index 906e863f84d0..be25692bb0d0 100644 --- a/dts/bindings/stepper/adi/adi,trinamic-gconf.yaml +++ b/dts/bindings/stepper/adi/adi,trinamic-gconf.yaml @@ -1,4 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2024 Carl Zeiss Meditec AG +# SPDX-FileCopyrightText: Copyright (c) 2025 Prevas A/S # SPDX-License-Identifier: Apache-2.0 description: Global configuration flags for Trinamic stepper controller. @@ -72,3 +73,11 @@ properties: type: boolean description: | 1: GCONF is locked against further write access. + + en-pwm-mode: + type: boolean + description: | + 1: StealthChop voltage PWM mode enabled + (depending on velocity thresholds). Switch from + off to on state while in stand-still and at IHOLD= + nominal IRUN current, only. diff --git a/dts/bindings/stepper/adi/adi,trinamic-ramp-generator.yaml b/dts/bindings/stepper/adi/adi,trinamic-ramp-generator.yaml index 42d9b9e41fbf..381ddf9a654a 100644 --- a/dts/bindings/stepper/adi/adi,trinamic-ramp-generator.yaml +++ b/dts/bindings/stepper/adi/adi,trinamic-ramp-generator.yaml @@ -1,4 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2024 Carl Zeiss Meditec AG +# SPDX-FileCopyrightText: Copyright (c) 2025 Prevas A/S # SPDX-License-Identifier: Apache-2.0 description: Ramp Generator Motion Control Register-Set for Trinamic stepper controller. @@ -131,3 +132,63 @@ properties: (constant off time with slow decay, only). - If vhighfs is set, the motor operates in fullstep mode. - Voltage PWM mode StealthChop is switched off, if configured + + tcoolthrs: + type: int + default: 0 + description: | + This is the lower threshold velocity for switching on smart + energy CoolStep and StallGuard feature. (unsigned) + Set this parameter to disable CoolStep at low speeds, where it + cannot work reliably. The stop on stall function (enable with + sg_stop when using internal motion controller) and the stall + output signal become enabled when exceeding this velocity. In + non-DcStep mode, it becomes disabled again once the velocity + falls below this threshold. + TCOOLTHRS ≥ TSTEP ≥ THIGH: + - CoolStep is enabled, if configured + - StealthChop voltage PWM mode is disabled + TCOOLTHRS ≥ TSTEP + - Stop on stall is enabled, if configured + - Stall output signal (DIAG0/1) is enabled, if configured + + thigh: + type: int + default: 0 + description: | + This velocity setting allows velocity dependent switching into + a different chopper mode and fullstepping to maximize torque. + (unsigned) + The stall detection feature becomes switched off for 2-3 + electrical periods whenever passing THIGH threshold to + compensate for the effect of switching modes. + TSTEP ≤ THIGH: + - CoolStep is disabled (motor runs with normal current + scale) + - StealthChop voltage PWM mode is disabled + - If vhighchm is set, the chopper switches to chm=1 + with TFD=0 (constant off time with slow decay, only). + - If vhighfs is set, the motor operates in fullstep mode, + and the stall detection becomes switched over to + DcStep stall detection. + + tpwmthrs: + type: int + default: 0 + description: | + This is the upper velocity for StealthChop voltage PWM mode. + TSTEP ≥ TPWMTHRS + - StealthChop PWM mode is enabled, if configured + - DcStep is disabled + + tpowerdown: + type: int + default: 10 + description: | + TPOWERDOWN sets the delay time after stand still (stst) of the + motor to motor current power down. Time range is about 0 to + 4 seconds. + Attention: A minimum setting of 2 is required to allow + automatic tuning of StealthChop PWM_OFS_AUTO. + Reset Default = 10 + 0…((2^8)-1) * 2^18 tCLK diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index 62b765b81b42..af8651886d0f 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -1468,6 +1468,28 @@ struct sensor_info { #define SENSOR_DEVICE_DT_INST_DEFINE(inst, ...) \ SENSOR_DEVICE_DT_DEFINE(DT_DRV_INST(inst), __VA_ARGS__) +/** + * @brief Helper function for converting struct sensor_value to integer deci units. + * + * @param val A pointer to a sensor_value struct. + * @return The converted value. + */ +static inline int64_t sensor_value_to_deci(const struct sensor_value *val) +{ + return ((int64_t)val->val1 * 10) + val->val2 / 100000; +} + +/** + * @brief Helper function for converting struct sensor_value to integer centi units. + * + * @param val A pointer to a sensor_value struct. + * @return The converted value. + */ +static inline int64_t sensor_value_to_centi(const struct sensor_value *val) +{ + return ((int64_t)val->val1 * 100) + val->val2 / 10000; +} + /** * @brief Helper function for converting struct sensor_value to integer milli units. * diff --git a/include/zephyr/drivers/sensor/paj7620.h b/include/zephyr/drivers/sensor/paj7620.h new file mode 100644 index 000000000000..125d77d58dd2 --- /dev/null +++ b/include/zephyr/drivers/sensor/paj7620.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025 Paul Timke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Extended Public API for PAJ7620 sensor + * + * Some capabilities of the sensor cannot be expressed + * within the sensor driver abstraction + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_PAJ7620_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_PAJ7620_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#include + +#define PAJ7620_FLAG_GES_UP BIT(0) +#define PAJ7620_FLAG_GES_DOWN BIT(1) +#define PAJ7620_FLAG_GES_LEFT BIT(2) +#define PAJ7620_FLAG_GES_RIGHT BIT(3) +#define PAJ7620_FLAG_GES_FORWARD BIT(4) +#define PAJ7620_FLAG_GES_BACKWARD BIT(5) +#define PAJ7620_FLAG_GES_CLOCKWISE BIT(6) +#define PAJ7620_FLAG_GES_COUNTERCLOCKWISE BIT(7) +#define PAJ7620_FLAG_GES_WAVE BIT(8) + +enum sensor_channel_paj7620 { + /** + * This channel will contain gesture data as a bitmask where each + * set bit represents a detected gesture. The possible gestures + * that can be detected along with their corresponding bit are given + * by the PAJ7620_FLAG_GES_X macros + */ + SENSOR_CHAN_PAJ7620_GESTURES = SENSOR_CHAN_PRIV_START +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_PAJ7620_H_ */ diff --git a/include/zephyr/drivers/stepper/stepper_trinamic.h b/include/zephyr/drivers/stepper/stepper_trinamic.h index f42032fe984d..691eac73be64 100644 --- a/include/zephyr/drivers/stepper/stepper_trinamic.h +++ b/include/zephyr/drivers/stepper/stepper_trinamic.h @@ -7,6 +7,7 @@ /* * SPDX-FileCopyrightText: Copyright (c) 2024 Carl Zeiss Meditec AG + * SPDX-FileCopyrightText: Copyright (c) 2025 Prevas A/S * * SPDX-License-Identifier: Apache-2.0 */ @@ -49,16 +50,28 @@ extern "C" { #define TMC_RAMP_VSTOP_MIN 1 #define TMC_RAMP_TZEROWAIT_MAX (GENMASK(15, 0) - 512) #define TMC_RAMP_TZEROWAIT_MIN 0 -#define TMC_RAMP_VCOOLTHRS_MAX GENMASK(22, 0) -#define TMC_RAMP_VCOOLTHRS_MIN 0 -#define TMC_RAMP_VHIGH_MAX GENMASK(22, 0) -#define TMC_RAMP_VHIGH_MIN 0 #define TMC_RAMP_IHOLD_IRUN_MAX GENMASK(4, 0) #define TMC_RAMP_IHOLD_IRUN_MIN 0 #define TMC_RAMP_IHOLDDELAY_MAX GENMASK(3, 0) #define TMC_RAMP_IHOLDDELAY_MIN 0 #define TMC_RAMP_VACTUAL_SHIFT 22 +/* TMC50XX specific */ +#define TMC_RAMP_VCOOLTHRS_MAX GENMASK(22, 0) +#define TMC_RAMP_VCOOLTHRS_MIN 0 +#define TMC_RAMP_VHIGH_MAX GENMASK(22, 0) +#define TMC_RAMP_VHIGH_MIN 0 + +/* TMC51XX specific */ +#define TMC_RAMP_TPOWERDOWN_MAX GENMASK(7, 0) +#define TMC_RAMP_TPOWERDOWN_MIN 0 +#define TMC_RAMP_TPWMTHRS_MAX GENMASK(19, 0) +#define TMC_RAMP_TPWMTHRS_MIN 0 +#define TMC_RAMP_TCOOLTHRS_MAX GENMASK(19, 0) +#define TMC_RAMP_TCOOLTHRS_MIN 0 +#define TMC_RAMP_THIGH_MAX GENMASK(19, 0) +#define TMC_RAMP_THIGH_MIN 0 + /** * @brief Trinamic Stepper Ramp Generator data */ @@ -72,9 +85,21 @@ struct tmc_ramp_generator_data { uint16_t dmax; uint32_t vstop; uint16_t tzerowait; - uint32_t vcoolthrs; - uint32_t vhigh; uint32_t iholdrun; + union { + /* TMC50XX specific */ + struct { + uint32_t vcoolthrs; + uint32_t vhigh; + }; + /* TMC51XX specific */ + struct { + uint32_t tpowerdown; + uint32_t tpwmthrs; + uint32_t tcoolthrs; + uint32_t thigh; + }; + }; }; /** @@ -108,12 +133,6 @@ struct tmc_ramp_generator_data { COND_CODE_1(DT_PROP_EXISTS(node, tzerowait), \ BUILD_ASSERT(IN_RANGE(DT_PROP(node, tzerowait), TMC_RAMP_TZEROWAIT_MIN, \ TMC_RAMP_TZEROWAIT_MAX), "tzerowait out of range"), ()); \ - COND_CODE_1(DT_PROP_EXISTS(node, vcoolthrs), \ - BUILD_ASSERT(IN_RANGE(DT_PROP(node, vcoolthrs), TMC_RAMP_VCOOLTHRS_MIN, \ - TMC_RAMP_VCOOLTHRS_MAX), "vcoolthrs out of range"), ()); \ - COND_CODE_1(DT_PROP_EXISTS(node, vhigh), \ - BUILD_ASSERT(IN_RANGE(DT_PROP(node, vhigh), TMC_RAMP_VHIGH_MIN, \ - TMC_RAMP_VHIGH_MAX), "vhigh out of range"), ()); \ COND_CODE_1(DT_PROP_EXISTS(node, ihold), \ BUILD_ASSERT(IN_RANGE(DT_PROP(node, ihold), TMC_RAMP_IHOLD_IRUN_MIN, \ TMC_RAMP_IHOLD_IRUN_MAX), "ihold out of range"), ()); \ @@ -122,7 +141,27 @@ struct tmc_ramp_generator_data { TMC_RAMP_IHOLD_IRUN_MAX), "irun out of range"), ()); \ COND_CODE_1(DT_PROP_EXISTS(node, iholddelay), \ BUILD_ASSERT(IN_RANGE(DT_PROP(node, iholddelay), TMC_RAMP_IHOLDDELAY_MIN, \ - TMC_RAMP_IHOLDDELAY_MAX), "iholddelay out of range"), ()); + TMC_RAMP_IHOLDDELAY_MAX), "iholddelay out of range"), ());\ + /* TMC50XX specific */ \ + COND_CODE_1(DT_PROP_EXISTS(node, vcoolthrs), \ + BUILD_ASSERT(IN_RANGE(DT_PROP(node, vcoolthrs), TMC_RAMP_VCOOLTHRS_MIN, \ + TMC_RAMP_VCOOLTHRS_MAX), "vcoolthrs out of range"), ()); \ + COND_CODE_1(DT_PROP_EXISTS(node, vhigh), \ + BUILD_ASSERT(IN_RANGE(DT_PROP(node, vhigh), TMC_RAMP_VHIGH_MIN, \ + TMC_RAMP_VHIGH_MAX), "vhigh out of range"), ()); \ + /* TMC51XX specific */ \ + COND_CODE_1(DT_PROP_EXISTS(node, tpowerdown), \ + BUILD_ASSERT(IN_RANGE(DT_PROP(node, tpowerdown), TMC_RAMP_TPOWERDOWN_MIN, \ + TMC_RAMP_TPOWERDOWN_MAX), "tpowerdown out of range"), ());\ + COND_CODE_1(DT_PROP_EXISTS(node, tpwmthrs), \ + BUILD_ASSERT(IN_RANGE(DT_PROP(node, tpwmthrs), TMC_RAMP_TPWMTHRS_MIN, \ + TMC_RAMP_TPWMTHRS_MAX), "tpwmthrs out of range"), ()); \ + COND_CODE_1(DT_PROP_EXISTS(node, tcoolthrs), \ + BUILD_ASSERT(IN_RANGE(DT_PROP(node, tcoolthrs), TMC_RAMP_TCOOLTHRS_MIN, \ + TMC_RAMP_TCOOLTHRS_MAX), "tcoolthrs out of range"), ()); \ + COND_CODE_1(DT_PROP_EXISTS(node, thigh), \ + BUILD_ASSERT(IN_RANGE(DT_PROP(node, thigh), TMC_RAMP_THIGH_MIN, \ + TMC_RAMP_THIGH_MAX), "thigh out of range"), ()); /** * @brief Get Trinamic Stepper Ramp Generator data from DT @@ -131,8 +170,7 @@ struct tmc_ramp_generator_data { * * @return struct tmc_ramp_generator_data */ -#define TMC_RAMP_DT_SPEC_GET(node) \ - { \ +#define TMC_RAMP_DT_SPEC_GET_COMMON(node) \ .vstart = DT_PROP(node, vstart), \ .v1 = DT_PROP(node, v1), \ .vmax = DT_PROP(node, vmax), \ @@ -142,11 +180,24 @@ struct tmc_ramp_generator_data { .dmax = DT_PROP(node, dmax), \ .vstop = DT_PROP(node, vstop), \ .tzerowait = DT_PROP(node, tzerowait), \ - .vcoolthrs = DT_PROP(node, vcoolthrs), \ - .vhigh = DT_PROP(node, vhigh), \ .iholdrun = (TMC5XXX_IRUN(DT_PROP(node, irun)) | \ TMC5XXX_IHOLD(DT_PROP(node, ihold)) | \ - TMC5XXX_IHOLDDELAY(DT_PROP(node, iholddelay))), \ + TMC5XXX_IHOLDDELAY(DT_PROP(node, iholddelay))), + +#define TMC_RAMP_DT_SPEC_GET_TMC50XX(node) \ + { \ + TMC_RAMP_DT_SPEC_GET_COMMON(node) \ + .vhigh = DT_PROP(node, vhigh), \ + .vcoolthrs = DT_PROP(node, vcoolthrs), \ + } + +#define TMC_RAMP_DT_SPEC_GET_TMC51XX(node) \ + { \ + TMC_RAMP_DT_SPEC_GET_COMMON(DT_DRV_INST(node)) \ + .tpowerdown = DT_INST_PROP(node, tpowerdown), \ + .tpwmthrs = DT_INST_PROP(node, tpwmthrs), \ + .tcoolthrs = DT_INST_PROP(node, tcoolthrs), \ + .thigh = DT_INST_PROP(node, thigh), \ } /** diff --git a/include/zephyr/linker/section_tags.h b/include/zephyr/linker/section_tags.h index 560d7611b7ae..ab73c0445016 100644 --- a/include/zephyr/linker/section_tags.h +++ b/include/zephyr/linker/section_tags.h @@ -47,6 +47,7 @@ #define __imx_boot_container_section Z_GENERIC_SECTION(_IMX_BOOT_CONTAINER_SECTION_NAME) #define __stm32_sdram1_section Z_GENERIC_SECTION(_STM32_SDRAM1_SECTION_NAME) #define __stm32_sdram2_section Z_GENERIC_SECTION(_STM32_SDRAM2_SECTION_NAME) +#define __stm32_psram_section Z_GENERIC_SECTION(_STM32_PSRAM_SECTION_NAME) #define __stm32_backup_sram_section Z_GENERIC_SECTION(_STM32_BACKUP_SRAM_SECTION_NAME) #endif /* CONFIG_ARM */ diff --git a/include/zephyr/linker/sections.h b/include/zephyr/linker/sections.h index 36159427fa67..dc6fce72e6be 100644 --- a/include/zephyr/linker/sections.h +++ b/include/zephyr/linker/sections.h @@ -71,6 +71,7 @@ #define _STM32_SDRAM1_SECTION_NAME .stm32_sdram1 #define _STM32_SDRAM2_SECTION_NAME .stm32_sdram2 +#define _STM32_PSRAM_SECTION_NAME .stm32_psram #define _STM32_BACKUP_SRAM_SECTION_NAME .stm32_backup_sram diff --git a/lib/posix/options/Kconfig.semaphore b/lib/posix/options/Kconfig.semaphore index b6b839c9b1fe..b2640d970411 100644 --- a/lib/posix/options/Kconfig.semaphore +++ b/lib/posix/options/Kconfig.semaphore @@ -33,4 +33,7 @@ config POSIX_SEM_NAMELEN_MAX Maximum length of name for a named semaphore. The max value of 255 corresponds to {NAME_MAX}. +config HEAP_MEM_POOL_ADD_SIZE_POSIX_SEMAPHORES + def_int 256 + endif # POSIX_SEMAPHORES diff --git a/samples/drivers/display/boards/stm32n6570_dk.conf b/samples/drivers/display/boards/stm32n6570_dk.conf new file mode 100644 index 000000000000..89de7acad83c --- /dev/null +++ b/samples/drivers/display/boards/stm32n6570_dk.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 ST Microelectronics +# SPDX-License-Identifier: Apache-2.0 + +# On STM32N6 DK board, display being larger, it requires +# more memory to draw squares on the display (40K) +CONFIG_HEAP_MEM_POOL_SIZE=65536 diff --git a/samples/drivers/display/boards/stm32n6570_dk_stm32n657xx_sb.conf b/samples/drivers/display/boards/stm32n6570_dk_stm32n657xx_sb.conf new file mode 100644 index 000000000000..89de7acad83c --- /dev/null +++ b/samples/drivers/display/boards/stm32n6570_dk_stm32n657xx_sb.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 ST Microelectronics +# SPDX-License-Identifier: Apache-2.0 + +# On STM32N6 DK board, display being larger, it requires +# more memory to draw squares on the display (40K) +CONFIG_HEAP_MEM_POOL_SIZE=65536 diff --git a/samples/net/zperf/Kconfig b/samples/net/zperf/Kconfig index 795613f1a490..a476a9fec3f0 100644 --- a/samples/net/zperf/Kconfig +++ b/samples/net/zperf/Kconfig @@ -1,8 +1,6 @@ # Copyright 2023 NXP # SPDX-License-Identifier: Apache-2.0 -source "Kconfig.zephyr" - config NET_SAMPLE_CODE_RELOCATE bool "Relocate networking code into RAM" select CODE_DATA_RELOCATION @@ -27,3 +25,9 @@ if USB_DEVICE_STACK_NEXT # tree, you cannot use them in your own application. source "samples/subsys/usb/common/Kconfig.sample_usbd" endif + +configdefault NRF_WIFI_DATA_HEAP_SIZE + default 30000 if NRF_WIFI_ZERO_COPY_TX + default 50000 + +source "Kconfig.zephyr" diff --git a/samples/net/zperf/README.rst b/samples/net/zperf/README.rst index 79ea582e1a46..165cdc0b4379 100644 --- a/samples/net/zperf/README.rst +++ b/samples/net/zperf/README.rst @@ -13,13 +13,8 @@ allows to evaluate network bandwidth. Features ********* -- Compatible with iPerf_2.0.5. Note that in newer iPerf versions, - an error message like this is printed and the server reported statistics - are missing. - -.. code-block:: console - - LAST PACKET NOT RECEIVED!!! +- Compatible with iPerf v2.0.10 and newer. For older versions, enable + :kconfig:option:`CONFIG_NET_ZPERF_LEGACY_HEADER_COMPAT`. - Client or server mode allowed without need to modify the source code. @@ -50,7 +45,7 @@ sample does not fit into target platform RAM, reduce the following configs: Requirements ************ -- iPerf 2.0.5 installed on the host machine +- iPerf 2.0.10 or newer installed on the host machine - Supported board Depending on the network technology chosen, extra steps may be required diff --git a/samples/net/zperf/boards/nrf7002dk_nrf5340_cpuapp.conf b/samples/net/zperf/boards/nrf7002dk_nrf5340_cpuapp.conf index 2b7f5e48de16..8907ee8fbbde 100644 --- a/samples/net/zperf/boards/nrf7002dk_nrf5340_cpuapp.conf +++ b/samples/net/zperf/boards/nrf7002dk_nrf5340_cpuapp.conf @@ -4,7 +4,6 @@ CONFIG_NET_PKT_TX_COUNT=28 CONFIG_NET_BUF_RX_COUNT=28 CONFIG_NET_BUF_TX_COUNT=28 CONFIG_NRF70_RX_NUM_BUFS=16 -CONFIG_NRF_WIFI_DATA_HEAP_SIZE=30000 CONFIG_NET_PKT_BUF_TX_DATA_POOL_SIZE=20000 CONFIG_NRF70_MAX_TX_AGGREGATION=4 CONFIG_NRF70_QSPI_LOW_POWER=n diff --git a/samples/sensor/mcux_acmp/README.rst b/samples/sensor/mcux_acmp/README.rst index 9f7d58e91bcd..5a5951c2bf70 100644 --- a/samples/sensor/mcux_acmp/README.rst +++ b/samples/sensor/mcux_acmp/README.rst @@ -42,7 +42,7 @@ ACMP input voltage by changing the voltage input to J25-13. .. zephyr-app-commands:: :zephyr-app: samples/sensor/mcux_acmp - :board: mimxrt1170_evk@A/mimxrt1176/cm7 + :board: mimxrt1170_evk/mimxrt1176/cm7 :goals: flash :compact: diff --git a/samples/sensor/mcux_acmp/boards/mimxrt1170_evk_mimxrt1176_cm7_A.overlay b/samples/sensor/mcux_acmp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay similarity index 100% rename from samples/sensor/mcux_acmp/boards/mimxrt1170_evk_mimxrt1176_cm7_A.overlay rename to samples/sensor/mcux_acmp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay diff --git a/samples/sensor/mcux_acmp/sample.yaml b/samples/sensor/mcux_acmp/sample.yaml index c077538abeb2..47a0056843a2 100644 --- a/samples/sensor/mcux_acmp/sample.yaml +++ b/samples/sensor/mcux_acmp/sample.yaml @@ -4,10 +4,10 @@ sample: common: platform_allow: - twr_ke18f - - mimxrt1170_evk@A/mimxrt1176/cm7 - - mimxrt1170_evk@A/mimxrt1176/cm4 - frdm_ke17z - frdm_ke17z512 + - mimxrt1170_evk/mimxrt1176/cm7 + - mimxrt1170_evk/mimxrt1176/cm4 - mimxrt1180_evk/mimxrt1189/cm33 - mimxrt1180_evk/mimxrt1189/cm7 integration_platforms: diff --git a/samples/sensor/paj7620_gesture/CMakeLists.txt b/samples/sensor/paj7620_gesture/CMakeLists.txt new file mode 100644 index 000000000000..c1f0bfcb5808 --- /dev/null +++ b/samples/sensor/paj7620_gesture/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2025 Paul Timke +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(paj7620_gesture) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/sensor/paj7620_gesture/Kconfig b/samples/sensor/paj7620_gesture/Kconfig new file mode 100644 index 000000000000..b977690ddf3b --- /dev/null +++ b/samples/sensor/paj7620_gesture/Kconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Paul Timke +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "PAJ7620 sample application" + +config APP_USE_POLLING + bool "Select y to use polling, otherwise the sample will use triggers" + default y + +source "Kconfig.zephyr" diff --git a/samples/sensor/paj7620_gesture/README.rst b/samples/sensor/paj7620_gesture/README.rst new file mode 100644 index 000000000000..788e7561888f --- /dev/null +++ b/samples/sensor/paj7620_gesture/README.rst @@ -0,0 +1,41 @@ +.. zephyr:code-sample:: paj7620_gesture + :name: PAJ7620 Gesture Sensor + :relevant-api: sensor_interface + + Get hand gesture data from PAJ7620 sensor. + +Overview +******** + +This sample application gets the output of a gesture sensor (paj7620) using either polling or +triggers (depending on CONFIG_APP_USE_POLLING) and outputs the corresponding gesture to the +console, each time one is detected. + +Requirements +************ + +To use this sample, the following hardware is required: + +* A board with I2C support and GPIO to detect external interrutps +* PAJ7620 sensor + +Building and Running +******************** + +This sample outputs data to the console. It requires a PAJ7620 sensor. + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/paj7620_gesture + :board: nucleo_f334r8 + :goals: build + :compact: + +Sample Output +============= + +.. code-block:: console + + Gesture LEFT + Gesture RIGHT + Gesture UP + Gesture DOWN diff --git a/samples/sensor/paj7620_gesture/boards/nucleo_f334r8.overlay b/samples/sensor/paj7620_gesture/boards/nucleo_f334r8.overlay new file mode 100644 index 000000000000..0e67fa6a052b --- /dev/null +++ b/samples/sensor/paj7620_gesture/boards/nucleo_f334r8.overlay @@ -0,0 +1,13 @@ +&gpioa { + status = "okay"; +}; + +&i2c1 { + status = "okay"; + + paj7620: paj7620@73 { + compatible = "pixart,paj7620"; + reg = <0x73>; + int-gpios = <&gpioa 9 (GPIO_PULL_UP)>; + }; +}; diff --git a/samples/sensor/paj7620_gesture/prj.conf b/samples/sensor/paj7620_gesture/prj.conf new file mode 100644 index 000000000000..845bcc219b10 --- /dev/null +++ b/samples/sensor/paj7620_gesture/prj.conf @@ -0,0 +1,5 @@ +CONFIG_GPIO=y +CONFIG_STDOUT_CONSOLE=y +CONFIG_I2C=y +CONFIG_SENSOR=y +CONFIG_PAJ7620_TRIGGER_OWN_THREAD=y diff --git a/samples/sensor/paj7620_gesture/sample.yaml b/samples/sensor/paj7620_gesture/sample.yaml new file mode 100644 index 000000000000..33ee97431787 --- /dev/null +++ b/samples/sensor/paj7620_gesture/sample.yaml @@ -0,0 +1,17 @@ +sample: + name: PAJ7620 gesture trigger sample +tests: + sample.sensor.paj7620_gesture_trig: + build_only: true + tags: sensors + platform_allow: nucleo_f334r8 + depends_on: + - i2c + - gpio + filter: dt_compat_enabled("pixart,paj7620") + sample.sensor.paj7620_gesture_polling: + build_only: true + tags: sensors + platform_allow: nucleo_f334r8 + depends_on: i2c + filter: dt_compat_enabled("pixart,paj7620") diff --git a/samples/sensor/paj7620_gesture/src/main.c b/samples/sensor/paj7620_gesture/src/main.c new file mode 100644 index 000000000000..c0dbdc735c22 --- /dev/null +++ b/samples/sensor/paj7620_gesture/src/main.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025 Paul Timke + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define GESTURE_POLL_TIME_MS 100 + +K_SEM_DEFINE(sem, 0, 1); /* starts off "not available" */ + +static void trigger_handler(const struct device *dev, const struct sensor_trigger *trigger) +{ + ARG_UNUSED(trigger); + + if (sensor_sample_fetch(dev) < 0) { + printf("sensor_sample_fetch failed\n"); + return; + } + + k_sem_give(&sem); +} + +static void print_hand_gesture(uint16_t gest_flags) +{ + if ((gest_flags & PAJ7620_FLAG_GES_UP) != 0) { + printf("Gesture UP\n"); + } + if ((gest_flags & PAJ7620_FLAG_GES_DOWN) != 0) { + printf("Gesture DOWN\n"); + } + if ((gest_flags & PAJ7620_FLAG_GES_LEFT) != 0) { + printf("Gesture LEFT\n"); + } + if ((gest_flags & PAJ7620_FLAG_GES_RIGHT) != 0) { + printf("Gesture RIGHT\n"); + } + if ((gest_flags & PAJ7620_FLAG_GES_FORWARD) != 0) { + printf("Gesture FORWARD\n"); + } + if ((gest_flags & PAJ7620_FLAG_GES_BACKWARD) != 0) { + printf("Gesture BACKWARD\n"); + } + if ((gest_flags & PAJ7620_FLAG_GES_CLOCKWISE) != 0) { + printf("Gesture CLOCKWISE\n"); + } + if ((gest_flags & PAJ7620_FLAG_GES_COUNTERCLOCKWISE) != 0) { + printf("Gesture COUNTER CLOCKWISE\n"); + } +} + +static void trigger_main_loop(const struct device *dev) +{ + struct sensor_value data; + + while (1) { + k_sem_take(&sem, K_FOREVER); + + (void)sensor_channel_get(dev, (enum sensor_channel)SENSOR_CHAN_PAJ7620_GESTURES, + &data); + + print_hand_gesture(data.val1); + } +} + +static void polling_main_loop(const struct device *dev) +{ + struct sensor_value data; + + while (1) { + (void)sensor_sample_fetch(dev); + (void)sensor_channel_get(dev, (enum sensor_channel)SENSOR_CHAN_PAJ7620_GESTURES, + &data); + + print_hand_gesture(data.val1); + k_msleep(GESTURE_POLL_TIME_MS); + } +} + +int main(void) +{ + int ret; + const struct device *dev = DEVICE_DT_GET_ONE(pixart_paj7620); + + struct sensor_trigger trig = { + .type = SENSOR_TRIG_MOTION, + .chan = (enum sensor_channel)SENSOR_CHAN_PAJ7620_GESTURES, + }; + + if (!device_is_ready(dev)) { + printf("Device %s is not ready\n", dev->name); + return -ENODEV; + } + + if (IS_ENABLED(CONFIG_APP_USE_POLLING)) { + polling_main_loop(dev); + } else { + /* App was configured to NOT use polling, so use triggers */ + ret = sensor_trigger_set(dev, &trig, trigger_handler); + if (ret < 0) { + printf("Could not set trigger\n"); + return ret; + } + + trigger_main_loop(dev); + } +} diff --git a/samples/subsys/uuid/README.rst b/samples/subsys/uuid/README.rst index 3e399af2d55f..c020063389ec 100644 --- a/samples/subsys/uuid/README.rst +++ b/samples/subsys/uuid/README.rst @@ -6,10 +6,11 @@ Overview ******** -This sample app demonstrates the use of the UUID utilities to generate and manipulate UUIDs -accordingly to IETF RFC 9562. +This sample app demonstrates the use of the :c:group:`uuid` utilities to generate and manipulate +UUIDs accordingly to IETF RFC 9562. The following functionality is demonstrated: + - UUIDv4 generation - UUIDv5 generation from namespace and data - UUID conversion from/to string and to base64 and base64 URL safe formats @@ -18,6 +19,7 @@ Requirements ************ This sample relies on the following modules: + - MbedTLS for the UUIDv5 hash functions - Base64 for the base64 encoding of UUIDs - Entropy source for the pseudo-random generation of UUIDv4 @@ -26,11 +28,11 @@ Building and Running ******************** Use the standard ``west`` commands to build and flash this application. -For example for ``native_sim`` build with: -``` -west build -p -b native_sim samples/subsys/uuid -``` -Then run with: -``` -west build -t run -``` +For example, for ``native_sim``: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/uuid + :host-os: unix + :board: native_sim + :goals: run + :compact: diff --git a/scripts/utils/tls_creds_installer.py b/scripts/utils/tls_creds_installer.py index 245520ceac43..82788523031a 100755 --- a/scripts/utils/tls_creds_installer.py +++ b/scripts/utils/tls_creds_installer.py @@ -65,13 +65,28 @@ def write_credential(self, sectag, cred_type, cred_text): for c in range(chunks): chunk = encoded[c * TLS_CRED_CHUNK_SIZE : (c + 1) * TLS_CRED_CHUNK_SIZE] self.write_raw(f"cred buf {chunk}") - self.serial_wait_for_response("Stored") + result, output = self.serial_wait_for_response("Stored", "RX ring buffer full") + if not result: + logging.error("Failed to store chunk in the device: unknown error") + if output and b"RX ring buffer full" in output: + logging.error(f"Failed to store chunk in the device: {output}") + return False + if not 0 <= cred_type < len(TLS_CRED_TYPES): + logger.error( + f"Invalid credential type: {cred_type}. Range [0, {len(TLS_CRED_TYPES) - 1}]." + ) + return False self.write_raw(f"cred add {sectag} {TLS_CRED_TYPES[cred_type]} DEFAULT bint") - result, _ = self.serial_wait_for_response("Added TLS credential") + result, _ = self.serial_wait_for_response("Added TLS credential", "already exists") time.sleep(1) return result def delete_credential(self, sectag, cred_type): + if not 0 <= cred_type < len(TLS_CRED_TYPES): + logger.error( + f"Invalid credential type: {cred_type}. Range [0, {len(TLS_CRED_TYPES) - 1}]." + ) + return False self.write_raw(f'cred del {sectag} {TLS_CRED_TYPES[cred_type]}') result, _ = self.serial_wait_for_response( "Deleted TLS credential", "There is no TLS credential" @@ -94,7 +109,11 @@ def check_credential_exists(self, sectag, cred_type, get_hash=True): return True, None data = output.decode().split(",") - hash = data[2].strip() + logger.debug(f"Cred list output: {data}") + if len(data) < 4: + logger.error("Invalid output format from device, skipping hash check.") + return False, None + cred_hash = data[2].strip() status_code = data[3].strip() if status_code != "0": @@ -102,17 +121,23 @@ def check_credential_exists(self, sectag, cred_type, get_hash=True): logger.warning("Device might not support credential digests.") return True, None - return True, hash + return True, cred_hash def calculate_expected_hash(self, cred_text): - hash = hashlib.sha256(cred_text.encode('utf-8') + b'\x00') - return base64.b64encode(hash.digest()).decode() + cred_hash = hashlib.sha256(cred_text.encode('utf-8') + b'\x00') + return base64.b64encode(cred_hash.digest()).decode() def check_cred_command(self): logger.info("Checking for 'cred' command existence...") self.serial_write_line("cred") - result, output = self.serial_wait_for_response(timeout=5) - if not result or (output and b"command not found" in output): + result, output = self.serial_wait_for_response( + "TLS Credentials Commands", "command not found", store="cred" + ) + logger.debug(f"Result: {result}, Output: {output}") + if not result: + logger.error("Device did not respond to 'cred' command.") + return False + if output and b"command not found" in output: logger.error("Device does not support 'cred' command.") logger.error("Hint: Add 'CONFIG_TLS_CREDENTIALS_SHELL=y' to your prj.conf file.") return False @@ -294,20 +319,25 @@ def main(in_args): logger.info(f'Deleting sectag {args.sectag}...') cred_if.delete_credential(args.sectag, args.cert_type) - cred_if.write_credential(args.sectag, args.cert_type, dev_bytes) + result = cred_if.write_credential(args.sectag, args.cert_type, dev_bytes) + if not result: + logger.error(f'Failed to write credential for sectag {args.sectag}, it may already exist') + sys.exit(5) logger.info(f'Writing sectag {args.sectag}...') - result, hash = cred_if.check_credential_exists(args.sectag, args.cert_type, args.check_hash) + result, cred_hash = cred_if.check_credential_exists( + args.sectag, args.cert_type, args.check_hash + ) if args.check_hash: logger.debug(f'Checking hash for sectag {args.sectag}...') if not result: logger.error(f'Failed to check credential existence for sectag {args.sectag}') sys.exit(4) - if hash: - logger.debug(f'Credential hash: {hash}') + if cred_hash: + logger.debug(f'Credential hash: {cred_hash}') expected_hash = cred_if.calculate_expected_hash(dev_bytes) - if hash != expected_hash: + if cred_hash != expected_hash: logger.error( - f'Hash mismatch for sectag {args.sectag}. Expected: {expected_hash}, got: {hash}' + f'Hash mismatch for sectag {args.sectag}. Exp: {expected_hash}, got: {cred_hash}' ) sys.exit(6) logger.info(f'Credential for sectag {args.sectag} written successfully') diff --git a/soc/ambiq/apollo4x/pinctrl_soc.h b/soc/ambiq/apollo4x/pinctrl_soc.h index fdf060c91297..34cc43ca863f 100644 --- a/soc/ambiq/apollo4x/pinctrl_soc.h +++ b/soc/ambiq/apollo4x/pinctrl_soc.h @@ -39,6 +39,8 @@ struct apollo4_pinctrl_soc_pin { uint32_t nce : 6; /** nCE module polarity */ uint32_t nce_pol: 1; + /** SDIF CD WP pad select */ + uint32_t sdif_cdwp: 2; }; typedef struct apollo4_pinctrl_soc_pin pinctrl_soc_pin_t; @@ -65,6 +67,7 @@ typedef struct apollo4_pinctrl_soc_pin pinctrl_soc_pin_t; DT_ENUM_IDX(node_id, ambiq_pull_up_ohms), \ DT_PROP(node_id, ambiq_nce_src), \ DT_PROP(node_id, ambiq_nce_pol), \ + DT_PROP(node_id, ambiq_sdif_cdwp), \ }, /** diff --git a/soc/andestech/ae350/linker.ld b/soc/andestech/ae350/linker.ld index 4c94c7052123..ae10cab3ccd8 100644 --- a/soc/andestech/ae350/linker.ld +++ b/soc/andestech/ae350/linker.ld @@ -405,6 +405,15 @@ GROUP_END(DTCM) KEEP(*(.gnu.attributes)) } +/* Output section descriptions are needed for these sections to suppress + * warnings when "--orphan-handling=warn" is set for lld. + */ +#if defined(CONFIG_LLVM_USE_LLD) + SECTION_PROLOGUE(.symtab, 0,) { *(.symtab) } + SECTION_PROLOGUE(.strtab, 0,) { *(.strtab) } + SECTION_PROLOGUE(.shstrtab, 0,) { *(.shstrtab) } +#endif + /* Sections generated from 'zephyr,memory-region' nodes */ LINKER_DT_SECTIONS() diff --git a/soc/ene/kb1200/reg/fsmbm.h b/soc/ene/kb1200/reg/fsmbm.h index 33f96ae0c0e5..129fbae71b49 100644 --- a/soc/ene/kb1200/reg/fsmbm.h +++ b/soc/ene/kb1200/reg/fsmbm.h @@ -58,28 +58,27 @@ struct fsmbm_regs { #define FSMBM_SMBUS_BUSY 0x1A #define FSMBM_STOP_FAIL 0x1E #define FSMBM_PEC_ERROR 0x1F +#define FSMBM_SDA_TIMEOUT 0x80 +#define FSMBM_MAX_TIMEOUT 200 /* Unit: ms */ + /* Packet Form */ -#define ___NONE 0x00 -#define ___STOP 0x01 -#define __PEC_ 0x02 -#define __PEC_STOP 0x03 -#define _CNT__ 0x04 -#define _CNT__STOP 0x05 -#define _CNT_PEC_ 0x06 -#define _CNT_PEC_STOP 0x07 -#define CMD___ 0x08 -#define CMD___STOP 0x09 -#define CMD__PEC_ 0x0A -#define CMD__PEC_STOP 0x0B -#define CMD_CNT__ 0x0C -#define CMD_CNT__STOP 0x0D -#define CMD_CNT_PEC_ 0x0E -#define CMD_CNT_PEC_STOP 0x0F +#define FRT_NONE 0x00 +#define FRT_STOP 0x01 +#define FRT_PEC 0x02 +#define FRT_CNT 0x04 +#define FRT_CMD 0x08 +#define FRT_PEC_STOP (FRT_PEC | FRT_STOP) +#define FRT_CNT_STOP (FRT_CNT | FRT_STOP) +#define FRT_CNT_PEC (FRT_CNT | FRT_PEC) +#define FRT_CNT_PEC_STOP (FRT_CNT | FRT_PEC | FRT_STOP) +#define FRT_CMD_STOP (FRT_CMD | FRT_STOP) +#define FRT_CMD_PEC (FRT_CMD | FRT_PEC) +#define FRT_CMD_PEC_STOP (FRT_CMD | FRT_PEC | FRT_STOP) +#define FRT_CMD_CNT (FRT_CMD | FRT_CNT) +#define FRT_CMD_CNT_STOP (FRT_CMD | FRT_CNT | FRT_STOP) +#define FRT_CMD_CNT_PEC (FRT_CMD | FRT_CNT | FRT_PEC) +#define FRT_CMD_CNT_PEC_STOP (FRT_CMD | FRT_CNT | FRT_PEC | FRT_STOP) -#define FLEXIBLE_CMD 0x08 -#define FLEXIBLE_CNT 0x04 -#define FLEXIBLE_PEC 0x02 -#define FLEXIBLE_STOP 0x01 /* HW */ #define FSMBM_BUFFER_SIZE 0x20 #define FSMBM_MAXCNT 0xFF @@ -109,6 +108,7 @@ struct fsmbm_regs { #define FSMBM_CLK_10K 0x6363 /* Other(non 50% Duty Cycle) */ #define FSMBM_CLK_400K 0x0102 +#define FSMBM_CLK_666K 0x0001 #define FSMBM_COMPLETE_EVENT 0x01 #define FSMBM_HOST_NOTIFY_EVENT 0x02 diff --git a/soc/realtek/ec/rts5912/reg/reg_adc.h b/soc/realtek/ec/rts5912/reg/reg_adc.h new file mode 100644 index 000000000000..0b54d13c8af8 --- /dev/null +++ b/soc/realtek/ec/rts5912/reg/reg_adc.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025 Realtek, SIBG-SD7 + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_REALTEK_RTS5912_REG_ADC_H +#define ZEPHYR_SOC_REALTEK_RTS5912_REG_ADC_H + +struct adc_regs { + uint32_t ctrl; + uint32_t chctrl; + uint32_t sts; + uint32_t chdata[12]; + uint32_t coeffa; + uint32_t coeffb; +}; + +/* CTRL */ +#define ADC_CTRL_EN BIT(0) +#define ADC_CTRL_START BIT(1) +#define ADC_CTRL_RST BIT(2) +#define ADC_CTRL_MDSEL BIT(3) +#define ADC_CTRL_SGLDNINTEN BIT(4) +#define ADC_CTRL_RPTDNINTEN BIT(5) + +/* CHCTRL */ +#define ADC_CHCTRL_CH0EN BIT(0) +#define ADC_CHCTRL_CH1EN BIT(1) +#define ADC_CHCTRL_CH2EN BIT(2) +#define ADC_CHCTRL_CH3EN BIT(3) +#define ADC_CHCTRL_CH4EN BIT(4) +#define ADC_CHCTRL_CH5EN BIT(5) +#define ADC_CHCTRL_CH6EN BIT(6) +#define ADC_CHCTRL_CH7EN BIT(7) +#define ADC_CHCTRL_CH8EN BIT(8) +#define ADC_CHCTRL_CH9EN BIT(9) +#define ADC_CHCTRL_CH10EN BIT(10) +#define ADC_CHCTRL_CH11EN BIT(11) +#define ADC_CHCTRL_LPFBP BIT(12) +#define ADC_CHCTRL_CALBP BIT(24) + +/* STS */ +#define ADC_STS_CH0DN BIT(0) +#define ADC_STS_CH1DN BIT(1) +#define ADC_STS_CH2DN BIT(2) +#define ADC_STS_CH3DN BIT(3) +#define ADC_STS_CH4DN BIT(4) +#define ADC_STS_CH5DN BIT(5) +#define ADC_STS_CH6DN BIT(6) +#define ADC_STS_CH7DN BIT(7) +#define ADC_STS_CH8DN BIT(8) +#define ADC_STS_CH9DN BIT(9) +#define ADC_STS_CH10DN BIT(10) +#define ADC_STS_CH11DN BIT(11) +#define ADC_STS_SGLDN BIT(12) +#define ADC_STS_RPTDN BIT(13) +#define ADC_STS_RDY BIT(16) +#define ADC_STS_LPFSTB BIT(17) + +/* CHDATA */ +#define ADC_CHDATA_RESULT_Pos (0U) +#define ADC_CHDATA_RESULT_Msk GENMASK(11, 0) + +#endif /* ZEPHYR_SOC_REALTEK_RTS5912_REG_ADC_H */ diff --git a/soc/realtek/ec/rts5912/reg/reg_timer.h b/soc/realtek/ec/rts5912/reg/reg_timer.h new file mode 100644 index 000000000000..b3cd8f5583b2 --- /dev/null +++ b/soc/realtek/ec/rts5912/reg/reg_timer.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Realtek, SIBG-SD7 + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_REALTEK_RTS5912_REG_TMRER_H +#define ZEPHYR_SOC_REALTEK_RTS5912_REG_TMRER_H + +/** + * @brief 32-bit Timer Controller (TMR) + */ + +struct timer32_type { + uint32_t ldcnt; + uint32_t cnt; + uint32_t ctrl; + uint32_t intclr; + uint32_t intsts; +}; + +/* CTRL */ +#define TIMER32_CTRL_EN BIT(0) + +#define TIMER32_CTRL_MDSELS_ONESHOT 0 +#define TIMER32_CTRL_MDSELS_PERIOD BIT(1) + +#define TIMER32_CTRL_INTEN_DIS BIT(2) +/* INTCLR */ +#define TIMER32_INTCLR_INTCLR BIT(0) +/* INTSTS */ +#define TIMER32_INTSTS_STS (0UL) + +#endif /* ZEPHYR_SOC_REALTEK_RTS5912_REG_TMRER_H */ diff --git a/soc/st/stm32/stm32n6x/soc.c b/soc/st/stm32/stm32n6x/soc.c index fa06138ce67c..d3bae6eeff81 100644 --- a/soc/st/stm32/stm32n6x/soc.c +++ b/soc/st/stm32/stm32n6x/soc.c @@ -54,6 +54,9 @@ void soc_early_init_hook(void) /* Enable PWR */ LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_PWR); + /* Set the main internal Regulator output voltage for best performance */ + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE0); + /* Enable IOs */ LL_PWR_EnableVddIO2(); LL_PWR_EnableVddIO3(); diff --git a/soc/st/stm32/stm32u0x/CMakeLists.txt b/soc/st/stm32/stm32u0x/CMakeLists.txt index eebd281cd96b..31324b8144c0 100644 --- a/soc/st/stm32/stm32u0x/CMakeLists.txt +++ b/soc/st/stm32/stm32u0x/CMakeLists.txt @@ -2,6 +2,7 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources( + power.c soc.c ) diff --git a/soc/st/stm32/stm32u0x/Kconfig b/soc/st/stm32/stm32u0x/Kconfig index e6035c0a2d0e..4cc4af8f0446 100644 --- a/soc/st/stm32/stm32u0x/Kconfig +++ b/soc/st/stm32/stm32u0x/Kconfig @@ -11,3 +11,4 @@ config SOC_SERIES_STM32U0X select HAS_STM32CUBE select CPU_CORTEX_M_HAS_SYSTICK select SOC_EARLY_INIT_HOOK + select HAS_PM diff --git a/soc/st/stm32/stm32u0x/power.c b/soc/st/stm32/stm32u0x/power.c new file mode 100644 index 000000000000..bdb59fa98291 --- /dev/null +++ b/soc/st/stm32/stm32u0x/power.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2021 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +/* select MSI as wake-up system clock if configured, HSI otherwise */ +#if STM32_SYSCLK_SRC_MSI +#define RCC_STOP_WAKEUPCLOCK_SELECTED LL_RCC_STOP_WAKEUPCLOCK_MSI +#else +#define RCC_STOP_WAKEUPCLOCK_SELECTED LL_RCC_STOP_WAKEUPCLOCK_HSI +#endif + + +void set_mode_stop(uint8_t substate_id) +{ + /* ensure the proper wake-up system clock */ + LL_RCC_SetClkAfterWakeFromStop(RCC_STOP_WAKEUPCLOCK_SELECTED); + + switch (substate_id) { + case 1: /* enter STOP0 mode */ + LL_PWR_SetPowerMode(LL_PWR_MODE_STOP0); + break; + case 2: /* enter STOP1 mode */ + LL_PWR_SetPowerMode(LL_PWR_MODE_STOP1); + break; + case 3: /* enter STOP2 mode */ + LL_PWR_SetPowerMode(LL_PWR_MODE_STOP2); + break; + default: + LOG_DBG("Unsupported power state substate-id %u", substate_id); + break; + } +} + +void set_mode_standby(uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + /* Select standby mode */ + LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY); +} + +/* Invoke Low Power/System Off specific Tasks */ +void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + switch (state) { + case PM_STATE_SUSPEND_TO_IDLE: + set_mode_stop(substate_id); + break; + case PM_STATE_STANDBY: + /* To be tested */ + set_mode_standby(substate_id); + break; + default: + LOG_DBG("Unsupported power state %u", state); + return; + } + + /* Set SLEEPDEEP bit of Cortex System Control Register */ + LL_LPM_EnableDeepSleep(); + + __WFI(); +} + +/* Handle SOC specific activity after Low Power Mode Exit */ +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + switch (state) { + case PM_STATE_SUSPEND_TO_IDLE: + if (substate_id <= 3) { + LL_LPM_DisableSleepOnExit(); + LL_LPM_EnableSleep(); + } else { + LOG_DBG("Unsupported power substate-id %u", + substate_id); + } + case PM_STATE_STANDBY: + /* To be tested */ + LL_LPM_EnableSleep(); + case PM_STATE_SUSPEND_TO_RAM: + __fallthrough; + case PM_STATE_SUSPEND_TO_DISK: + __fallthrough; + default: + LOG_DBG("Unsupported power state %u", state); + break; + } + /* need to restore the clock */ + stm32_clock_control_init(NULL); + + /* + * System is now in active mode. + * Reenable interrupts which were disabled + * when OS started idling code. + */ + irq_unlock(0); +} + +/* Initialize STM32 Power */ +void stm32_power_init(void) +{ + + /* enable Power clock */ + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR); + +} diff --git a/soc/st/stm32/stm32u0x/soc.c b/soc/st/stm32/stm32u0x/soc.c index 2c9685932dfa..2b629cfa3998 100644 --- a/soc/st/stm32/stm32u0x/soc.c +++ b/soc/st/stm32/stm32u0x/soc.c @@ -20,6 +20,7 @@ #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL LOG_MODULE_REGISTER(soc); +extern void stm32_power_init(void); /** * @brief Perform basic hardware initialization at boot. * @@ -35,4 +36,8 @@ void soc_early_init_hook(void) SystemCoreClock = 16000000; LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR); + +#if CONFIG_PM + stm32_power_init(); +#endif } diff --git a/submanifests/optional.yaml b/submanifests/optional.yaml index 62d7d6b83f23..82a9de6a12ad 100644 --- a/submanifests/optional.yaml +++ b/submanifests/optional.yaml @@ -41,7 +41,7 @@ manifest: groups: - optional - name: tf-m-tests - revision: 502ea90105ee18f20c78f710e2ba2ded0fc0756e + revision: c712761dd5391bf3f38033643d28a736cae89a19 path: modules/tee/tf-m/tf-m-tests remote: upstream groups: diff --git a/subsys/bluetooth/host/classic/l2cap_br.c b/subsys/bluetooth/host/classic/l2cap_br.c index ad5a896b1848..36f49bba3a80 100644 --- a/subsys/bluetooth/host/classic/l2cap_br.c +++ b/subsys/bluetooth/host/classic/l2cap_br.c @@ -4685,6 +4685,7 @@ static void l2cap_br_conn_rsp(struct bt_l2cap_br *l2cap, uint8_t ident, struct n atomic_clear_bit(BR_CHAN(chan)->flags, L2CAP_FLAG_CONN_PENDING); break; case BT_L2CAP_BR_PENDING: + br_chan->ident = ident; k_work_reschedule(&br_chan->rtx_work, L2CAP_BR_CONN_TIMEOUT); break; default: diff --git a/subsys/net/lib/zperf/Kconfig b/subsys/net/lib/zperf/Kconfig index 44ef4815c3cc..ea146b4ecdd4 100644 --- a/subsys/net/lib/zperf/Kconfig +++ b/subsys/net/lib/zperf/Kconfig @@ -13,6 +13,14 @@ menuconfig NET_ZPERF if NET_ZPERF +config NET_ZPERF_LEGACY_HEADER_COMPAT + bool "Legacy iperf UDP header format" + help + iperf 2.0.10 (2017) updated the UDP header format in a + backwards incompatible manner that cannot be automatically + detected. This option reverts the header format for use with + iperf version 2.0.9 and earlier. + config ZPERF_WORK_Q_THREAD_PRIORITY int "zperf work queue thread priority" default NUM_PREEMPT_PRIORITIES diff --git a/subsys/net/lib/zperf/zperf_internal.h b/subsys/net/lib/zperf/zperf_internal.h index a798edd85377..ed2e8fb58c5e 100644 --- a/subsys/net/lib/zperf/zperf_internal.h +++ b/subsys/net/lib/zperf/zperf_internal.h @@ -54,13 +54,21 @@ #define ZPERF_VERSION "1.1" struct zperf_udp_datagram { - int32_t id; + uint32_t id; uint32_t tv_sec; uint32_t tv_usec; +#ifndef CONFIG_NET_ZPERF_LEGACY_HEADER_COMPAT + uint32_t id2; +#endif } __packed; BUILD_ASSERT(sizeof(struct zperf_udp_datagram) <= PACKET_SIZE_MAX, "Invalid PACKET_SIZE_MAX"); +#define ZPERF_FLAGS_VERSION1 0x80000000 +#define ZPERF_FLAGS_EXTEND 0x40000000 +#define ZPERF_FLAGS_UDPTESTS 0x20000000 +#define ZPERF_FLAGS_SEQNO64B 0x08000000 + struct zperf_client_hdr_v1 { int32_t flags; int32_t num_of_threads; diff --git a/subsys/net/lib/zperf/zperf_udp_uploader.c b/subsys/net/lib/zperf/zperf_udp_uploader.c index daf2cf21d01f..bcb858eedd14 100644 --- a/subsys/net/lib/zperf/zperf_udp_uploader.c +++ b/subsys/net/lib/zperf/zperf_udp_uploader.c @@ -25,6 +25,7 @@ static inline void zperf_upload_decode_stat(const uint8_t *data, struct zperf_results *results) { struct zperf_server_hdr *stat; + uint32_t flags; if (datalen < sizeof(struct zperf_udp_datagram) + sizeof(struct zperf_server_hdr)) { @@ -33,6 +34,10 @@ static inline void zperf_upload_decode_stat(const uint8_t *data, stat = (struct zperf_server_hdr *) (data + sizeof(struct zperf_udp_datagram)); + flags = ntohl(UNALIGNED_GET(&stat->flags)); + if (!(flags & ZPERF_FLAGS_VERSION1)) { + NET_WARN("Unexpected response flags"); + } results->nb_packets_rcvd = ntohl(UNALIGNED_GET(&stat->datagrams)); results->nb_packets_lost = ntohl(UNALIGNED_GET(&stat->error_cnt)); diff --git a/tests/arch/arm/arm_custom_interrupt/src/arm_custom_interrupt.c b/tests/arch/arm/arm_custom_interrupt/src/arm_custom_interrupt.c index 97d3c55365d5..998fe9a29571 100644 --- a/tests/arch/arm/arm_custom_interrupt/src/arm_custom_interrupt.c +++ b/tests/arch/arm/arm_custom_interrupt/src/arm_custom_interrupt.c @@ -120,7 +120,7 @@ void arm_isr_handler(const void *args) * @{ */ -ZTEST(arm_custom_interrupt, test_arm_interrupt) +ZTEST(arm_custom_interrupt, test_arm_custom_interrupt) { zassert_true(custom_init_called, "Custom IRQ init not called\n"); diff --git a/tests/arch/arm/arm_interrupt/src/arm_interrupt.c b/tests/arch/arm/arm_interrupt/src/arm_interrupt.c index dce39ede938a..05535283be33 100644 --- a/tests/arch/arm/arm_interrupt/src/arm_interrupt.c +++ b/tests/arch/arm/arm_interrupt/src/arm_interrupt.c @@ -142,6 +142,10 @@ void set_regs_with_known_pattern(void *p1, void *p2, void *p3) "udf #90\n"); } +/** + * @brief Test to verify code fault handling in ISR execution context + * @ingroup kernel_fatal_tests + */ ZTEST(arm_interrupt, test_arm_esf_collection) { int test_validation_rv; @@ -222,6 +226,10 @@ void arm_isr_handler(const void *args) } } +/** + * @brief Test ARM Interrupt handling + * @ingroup kernel_arch_interrupt_tests + */ ZTEST(arm_interrupt, test_arm_interrupt) { /* Determine an NVIC IRQ line that is not currently in use. */ @@ -390,6 +398,10 @@ static inline void z_vrfy_test_arm_user_interrupt_syscall(void) } #include +/** + * @brief Test ARM Interrupt handling in user mode + * @ingroup kernel_arch_interrupt_tests + */ ZTEST_USER(arm_interrupt, test_arm_user_interrupt) { /* Test thread executing in user mode */ @@ -434,6 +446,11 @@ ZTEST_USER(arm_interrupt, test_arm_user_interrupt) #pragma GCC push_options #pragma GCC optimize("O0") /* Avoid compiler optimizing null pointer de-referencing. */ + +/** + * @brief Test ARM Null Pointer Exception handling + * @ingroup kernel_arch_interrupt_tests + */ ZTEST(arm_interrupt, test_arm_null_pointer_exception) { Z_TEST_SKIP_IFNDEF(CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION); @@ -454,7 +471,3 @@ ZTEST(arm_interrupt, test_arm_null_pointer_exception) zassert_equal(reason, -1, "expected_reason has not been reset (%d)\n", reason); } #pragma GCC pop_options - -/** - * @} - */ diff --git a/tests/arch/arm/arm_irq_advanced_features/src/arm_dynamic_direct_interrupts.c b/tests/arch/arm/arm_irq_advanced_features/src/arm_dynamic_direct_interrupts.c index ce5043d882f4..22634a19021e 100644 --- a/tests/arch/arm/arm_irq_advanced_features/src/arm_dynamic_direct_interrupts.c +++ b/tests/arch/arm/arm_irq_advanced_features/src/arm_dynamic_direct_interrupts.c @@ -28,6 +28,10 @@ void arm_direct_isr_handler_1(const void *args) test_flag = 2; } +/** + * @brief Test the ARM Dynamic Direct Interrupts functionality. + * @ingroup kernel_arch_interrupt_tests + */ ZTEST(arm_irq_advanced_features, test_arm_dynamic_direct_interrupts) { int post_flag = 0; @@ -81,6 +85,3 @@ ZTEST(arm_irq_advanced_features, test_arm_dynamic_direct_interrupts) post_flag = test_flag; zassert_true(post_flag == 2, "Test flag not set by ISR1\n"); } -/** - * @} - */ diff --git a/tests/arch/arm/arm_irq_advanced_features/src/arm_irq_target_state.c b/tests/arch/arm/arm_irq_advanced_features/src/arm_irq_target_state.c index f1d005b47c59..47f5cc03bdca 100644 --- a/tests/arch/arm/arm_irq_advanced_features/src/arm_irq_target_state.c +++ b/tests/arch/arm/arm_irq_advanced_features/src/arm_irq_target_state.c @@ -13,6 +13,10 @@ extern irq_target_state_t irq_target_state_set(unsigned int irq, irq_target_state_t target_state); extern int irq_target_state_is_secure(unsigned int irq); +/** + * @brief Test the ARM IRQ target state functionality. + * @ingroup kernel_arch_interrupt_tests + */ ZTEST(arm_irq_advanced_features, test_arm_irq_target_state) { /* Determine an NVIC IRQ line that is implemented @@ -82,6 +86,3 @@ ZTEST(arm_irq_advanced_features, test_arm_irq_target_state) TC_PRINT("Skipped (TrustZone-M-enabled Cortex-M Mainline only)\n"); } #endif /* CONFIG_ZERO_LATENCY_IRQS */ -/** - * @} - */ diff --git a/tests/arch/arm/arm_irq_advanced_features/src/arm_zero_latency_irqs.c b/tests/arch/arm/arm_irq_advanced_features/src/arm_zero_latency_irqs.c index c3e8b5f574e4..ca23716f17e7 100644 --- a/tests/arch/arm/arm_irq_advanced_features/src/arm_zero_latency_irqs.c +++ b/tests/arch/arm/arm_irq_advanced_features/src/arm_zero_latency_irqs.c @@ -18,6 +18,10 @@ void arm_zero_latency_isr_handler(const void *args) test_flag = 1; } +/** + * @brief Test ARM Zero latency Interrupt functionality. + * @ingroup kernel_arch_interrupt_tests + */ ZTEST(arm_irq_advanced_features, test_arm_zero_latency_irqs) { @@ -101,7 +105,3 @@ ZTEST(arm_irq_advanced_features, test_arm_zero_latency_irqs) irq_unlock(key); } - -/** - * @} - */ diff --git a/tests/arch/arm/arm_sw_vector_relay/src/arm_sw_vector_relay.c b/tests/arch/arm/arm_sw_vector_relay/src/arm_sw_vector_relay.c index 8f5728abee07..506febcdb44e 100644 --- a/tests/arch/arm/arm_sw_vector_relay/src/arm_sw_vector_relay.c +++ b/tests/arch/arm/arm_sw_vector_relay/src/arm_sw_vector_relay.c @@ -15,6 +15,13 @@ extern uint32_t _vector_table; extern uint32_t __vector_relay_handler; extern uint32_t _vector_table_pointer; + +/** + * @brief Test the ARM Software Vector Relay functionality. + * + * This test verifies the correctness of the ARM software vector relay mechanism. + * @ingroup kernel_arch_interrupt_tests + */ ZTEST(arm_sw_vector_relay, test_arm_sw_vector_relay) { uint32_t vector_relay_table_addr = (uint32_t)&__vector_relay_table; @@ -61,6 +68,3 @@ ZTEST(arm_sw_vector_relay, test_arm_sw_vector_relay) _vector_table_pointer, _vector_start); #endif } -/** - * @} - */ diff --git a/tests/arch/arm/arm_thread_swap/src/arm_syscalls.c b/tests/arch/arm/arm_thread_swap/src/arm_syscalls.c index 42a25f7dc286..4d55241bed77 100644 --- a/tests/arch/arm/arm_thread_swap/src/arm_syscalls.c +++ b/tests/arch/arm/arm_thread_swap/src/arm_syscalls.c @@ -143,7 +143,10 @@ static void user_thread_entry(void *p1, void *p2, void *p3) barrier_isync_fence_full(); #endif } - +/** + * @brief Test ARM thread swap mechanism + * @ingroup kernel_arch_sched_tests + */ ZTEST(arm_thread_swap, test_arm_syscalls) { int i = 0; @@ -288,6 +291,3 @@ ZTEST(arm_thread_swap, test_arm_syscalls) } #endif /* CONFIG_USERSPACE */ -/** - * @} - */ diff --git a/tests/arch/arm/arm_thread_swap/src/arm_thread_arch.c b/tests/arch/arm/arm_thread_swap/src/arm_thread_arch.c index 7572982a775e..a29b76fc5a2b 100644 --- a/tests/arch/arm/arm_thread_swap/src/arm_thread_arch.c +++ b/tests/arch/arm/arm_thread_swap/src/arm_thread_arch.c @@ -370,6 +370,10 @@ static int __noinline arch_swap_wrapper(void) } #endif +/** + * @brief Test the ARM thread swap mechanism + * @ingroup kernel_arch_sched_tests + */ ZTEST(arm_thread_swap, test_arm_thread_swap) { int test_flag; @@ -662,6 +666,3 @@ ZTEST(arm_thread_swap, test_arm_thread_swap) #endif #endif /* CONFIG_FPU && CONFIG_FPU_SHARING */ } -/** - * @} - */ diff --git a/tests/arch/common/ramfunc/src/ramfunc.c b/tests/arch/common/ramfunc/src/ramfunc.c index cd55c6536186..f76c511687dc 100644 --- a/tests/arch/common/ramfunc/src/ramfunc.c +++ b/tests/arch/common/ramfunc/src/ramfunc.c @@ -53,6 +53,3 @@ ZTEST(ramfunc, test_ramfunc) zassert_true(post_flag == 1, "ram_function() execution failed."); } -/** - * @} - */ diff --git a/tests/bluetooth/classic/sdp_c/testcase.yaml b/tests/bluetooth/classic/sdp_c/testcase.yaml index 0eae8a22ea6f..ad618436e239 100644 --- a/tests/bluetooth/classic/sdp_c/testcase.yaml +++ b/tests/bluetooth/classic/sdp_c/testcase.yaml @@ -2,7 +2,6 @@ tests: bluetooth.classic.sdp.client: platform_allow: - native_sim - - mimxrt1170_evk@B/mimxrt1176/cm7 integration_platforms: - native_sim tags: @@ -13,3 +12,13 @@ tests: pytest_dut_scope: session fixture: usb_hci timeout: 180 + bluetooth.classic.sdp.client.no_blobs: + platform_allow: + - mimxrt1170_evk@B/mimxrt1176/cm7 + tags: + - bluetooth + - sdp + extra_args: + - CONFIG_BUILD_ONLY_NO_BLOBS=y + timeout: 180 + build_only: true diff --git a/tests/bluetooth/classic/sdp_s/testcase.yaml b/tests/bluetooth/classic/sdp_s/testcase.yaml index 92feaccd6865..3b54405040bf 100644 --- a/tests/bluetooth/classic/sdp_s/testcase.yaml +++ b/tests/bluetooth/classic/sdp_s/testcase.yaml @@ -2,7 +2,6 @@ tests: bluetooth.classic.sdp.server: platform_allow: - native_sim - - mimxrt1170_evk@B/mimxrt1176/cm7 integration_platforms: - native_sim tags: @@ -13,3 +12,13 @@ tests: pytest_dut_scope: session fixture: usb_hci timeout: 60 + bluetooth.classic.sdp.server.no_blobs: + platform_allow: + - mimxrt1170_evk@B/mimxrt1176/cm7 + tags: + - bluetooth + - sdp + extra_args: + - CONFIG_BUILD_ONLY_NO_BLOBS=y + timeout: 60 + build_only: true diff --git a/tests/drivers/adc/adc_api/boards/rts5912_evb.overlay b/tests/drivers/adc/adc_api/boards/rts5912_evb.overlay new file mode 100644 index 000000000000..6ac2c0ebd781 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/rts5912_evb.overlay @@ -0,0 +1,34 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 Realtek Semiconductor Corporation, SIBG-SD7 + * + */ + +/ { + zephyr,user { + io-channels = <&adc0 0>, <&adc0 1>; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = <0>; + zephyr,resolution = <10>; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = <0>; + zephyr,resolution = <10>; + }; +}; diff --git a/tests/drivers/build_all/adc/testcase.yaml b/tests/drivers/build_all/adc/testcase.yaml index a0c7dda13262..f73b054761b6 100644 --- a/tests/drivers/build_all/adc/testcase.yaml +++ b/tests/drivers/build_all/adc/testcase.yaml @@ -39,6 +39,8 @@ tests: platform_allow: disco_l475_iot1 drivers.adc.xec.build: platform_allow: mec15xxevb_assy6853 + drivers.adc.realtek.rts5912.build: + platform_allow: rts5912_evb drivers.adc.test.build: platform_allow: qemu_cortex_m3 drivers.adc.linker_generator.build: diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 9203c24dda69..aeceeea27e33 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -1284,3 +1284,9 @@ test_i2c_icp201xx: icp201xx@af { op-mode = "mode0"; drive-strength = "current_12mA_1_8V"; }; + +test_i2c_paj7620: paj7620@b0 { + compatible = "pixart,paj7620"; + reg = <0xb0>; + int-gpios = <&test_gpio 0 0>; +}; diff --git a/tests/drivers/build_all/stepper/spi.dtsi b/tests/drivers/build_all/stepper/spi.dtsi index 98f80ceb9445..1999e3ee017d 100644 --- a/tests/drivers/build_all/stepper/spi.dtsi +++ b/tests/drivers/build_all/stepper/spi.dtsi @@ -8,19 +8,115 @@ adi_tmc50xx: adi_tmc50xx@0 { compatible = "adi,tmc50xx"; + status = "okay"; reg = <0x0>; - spi-max-frequency = <0>; + spi-max-frequency = <8000000>; + label = "tmc5041_0"; + #address-cells = <1>; #size-cells = <0>; - clock-frequency = <1>; + + poscmp-enable; test-mode; lock-gconf; /* ADI TMC Global configuration flags */ + clock-frequency = <16000000>; /* Internal/External Clock frequency */ tmc50xx_0: tmc50xx_0@0 { status = "okay"; reg = <0>; + + /* common stepper controller settings */ + invert-direction; + micro-step-res = <256>; + + /* ADI TMC stallguard settings specific to TMC50XX */ + activate-stallguard2; + stallguard-velocity-check-interval-ms=<100>; + stallguard2-threshold=<9>; + stallguard-threshold-velocity=<500000>; + + /* ADI TMC ramp generator as well as current settings */ + vstart = <10>; + a1 = <20>; + v1 = <30>; + d1 = <40>; + vmax = <50>; + amax = <60>; + dmax = <70>; + tzerowait = <80>; + vhigh = <90>; + vcoolthrs = <100>; + ihold = <1>; + irun = <2>; + iholddelay = <3>; }; tmc50xx_1: tmc50xx_1@1 { status = "okay"; reg = <1>; + + /* common stepper controller settings */ + invert-direction; + micro-step-res = <256>; + + /* ADI TMC stallguard settings specific to TMC50XX */ + activate-stallguard2; + stallguard-velocity-check-interval-ms=<100>; + stallguard2-threshold=<9>; + stallguard-threshold-velocity=<500000>; + + /* ADI TMC ramp generator as well as current settings */ + vstart = <10>; + a1 = <20>; + v1 = <30>; + d1 = <40>; + vmax = <50>; + amax = <60>; + dmax = <70>; + tzerowait = <80>; + vhigh = <90>; + vcoolthrs = <100>; + ihold = <1>; + irun = <2>; + iholddelay = <3>; }; }; + +adi_tmc51xx: adi_tmc51xx@1 { + compatible = "adi,tmc51xx"; + status = "okay"; + reg = <0x01>; + spi-max-frequency = <8000000>; + label = "tmc5160_1"; + + #address-cells = <1>; + #size-cells = <0>; + + en-pwm-mode; test-mode; /* ADI TMC Global configuration flags */ + clock-frequency = <16000000>; /* Internal/External Clock frequency */ + + /* common stepper controller settings */ + invert-direction; + micro-step-res = <256>; + + /* ADI TMC stallguard settings specific to TMC5160 */ + activate-stallguard2; + stallguard-velocity-check-interval-ms=<100>; + stallguard2-threshold=<9>; + stallguard-threshold-velocity=<50000>; + + /* ADI TMC ramp generator as well as current settings */ + vstart = <10>; + a1 = <20>; + v1 = <30>; + d1 = <40>; + vmax = <50>; + amax = <60>; + dmax = <70>; + tzerowait = <80>; + thigh = <90>; + tcoolthrs = <100>; + tpwmthrs = <110>; + tpowerdown = <120>; + ihold = <1>; + irun = <2>; + iholddelay = <3>; +}; diff --git a/tests/drivers/i2c/i2c_ram/src/test_i2c_ram.c b/tests/drivers/i2c/i2c_ram/src/test_i2c_ram.c index 415a9dd67535..5d99f9c7af84 100644 --- a/tests/drivers/i2c/i2c_ram/src/test_i2c_ram.c +++ b/tests/drivers/i2c/i2c_ram/src/test_i2c_ram.c @@ -35,6 +35,10 @@ uint8_t rx_data[7]; const struct device *i2c_dev = DEVICE_DT_GET(I2C_DEV_NODE); +#ifdef CONFIG_I2C_RTIO +static void i2c_ram_rtio_before(void); +#endif + /* Address from datasheet is 0b1010xxxr where x bits are additional * memory address bits and r is the r/w i2c bit. * @@ -75,6 +79,10 @@ static void i2c_ram_before(void *f) addr += ARRAY_SIZE(tx_data) - TX_DATA_OFFSET; memset(rx_data, 0, ARRAY_SIZE(rx_data)); +#ifdef CONFIG_I2C_RTIO + i2c_ram_rtio_before(); +#endif + #ifdef CONFIG_PM_DEVICE_RUNTIME pm_device_runtime_get(i2c_dev); #endif @@ -178,6 +186,26 @@ ZTEST(i2c_ram, test_ram_transfer_cb) I2C_IODEV_DEFINE(i2c_iodev, I2C_DEV_NODE, RAM_ADDR); RTIO_DEFINE(i2c_rtio, 2, 2); +static void i2c_ram_rtio_before(void) +{ + struct rtio_cqe *cqe; + + while ((cqe = rtio_cqe_consume(&i2c_rtio))) { + rtio_cqe_release(&i2c_rtio, cqe); + } +} + +static void check_completion(struct rtio_cqe *cqe, const char *msg) +{ + int32_t result; + + result = cqe->result; + rtio_cqe_release(&i2c_rtio, cqe); + if (result) { + zassert_ok(result, msg); + } +} + ZTEST(i2c_ram, test_ram_rtio) { struct rtio_sqe *wr_sqe, *rd_sqe; @@ -190,8 +218,7 @@ ZTEST(i2c_ram, test_ram_rtio) zassert_ok(rtio_submit(&i2c_rtio, 1), "submit should succeed"); wr_cqe = rtio_cqe_consume(&i2c_rtio); - zassert_ok(wr_cqe->result, "i2c write should succeed"); - rtio_cqe_release(&i2c_rtio, wr_cqe); + check_completion(wr_cqe, "i2c write should succeed"); /* Write the address and read the data back */ msgs[0].len = ARRAY_SIZE(rx_cmd); @@ -209,11 +236,9 @@ ZTEST(i2c_ram, test_ram_rtio) zassert_ok(rtio_submit(&i2c_rtio, 2), "submit should succeed"); wr_cqe = rtio_cqe_consume(&i2c_rtio); + check_completion(wr_cqe, "i2c write should succeed"); rd_cqe = rtio_cqe_consume(&i2c_rtio); - zassert_ok(wr_cqe->result, "i2c write should succeed"); - zassert_ok(rd_cqe->result, "i2c read should succeed"); - rtio_cqe_release(&i2c_rtio, wr_cqe); - rtio_cqe_release(&i2c_rtio, rd_cqe); + check_completion(rd_cqe, "i2c read should succeed"); zassert_equal(memcmp(&tx_data[TX_DATA_OFFSET], &rx_data[0], ARRAY_SIZE(rx_data)), 0, "Written and Read data should match"); @@ -242,11 +267,9 @@ ZTEST(i2c_ram, test_ram_rtio_write_with_transaction) zassert_ok(rtio_submit(&i2c_rtio, 2), "submit should succeed"); wr_cqe = rtio_cqe_consume(&i2c_rtio); - zassert_ok(wr_cqe->result, "i2c write should succeed"); - rtio_cqe_release(&i2c_rtio, wr_cqe); + check_completion(wr_cqe, "i2c write should succeed"); wr_cqe = rtio_cqe_consume(&i2c_rtio); - zassert_ok(wr_cqe->result, "i2c write should succeed"); - rtio_cqe_release(&i2c_rtio, wr_cqe); + check_completion(wr_cqe, "i2c write should succeed"); /** Now read the register address to confirm the write was performed */ wr_sqe = rtio_sqe_acquire(&i2c_rtio); @@ -258,11 +281,9 @@ ZTEST(i2c_ram, test_ram_rtio_write_with_transaction) zassert_ok(rtio_submit(&i2c_rtio, 2), "submit should succeed"); wr_cqe = rtio_cqe_consume(&i2c_rtio); + check_completion(wr_cqe, "i2c write should succeed"); rd_cqe = rtio_cqe_consume(&i2c_rtio); - zassert_ok(wr_cqe->result, "i2c write should succeed"); - zassert_ok(rd_cqe->result, "i2c read should succeed"); - rtio_cqe_release(&i2c_rtio, wr_cqe); - rtio_cqe_release(&i2c_rtio, rd_cqe); + check_completion(rd_cqe, "i2c read should succeed"); zassert_equal(memcmp(®_data[0], &rx_data[0], ARRAY_SIZE(reg_data)), 0, "Written and Read data should match"); @@ -296,8 +317,7 @@ void ram_rtio_isr(struct k_timer *tid) wr_cqe = rtio_cqe_consume(&i2c_rtio); if (wr_cqe) { TC_PRINT("timer checking write result, submitting read\n"); - zassert_ok(wr_cqe->result, "i2c write should succeed"); - rtio_cqe_release(&i2c_rtio, wr_cqe); + check_completion(wr_cqe, "i2c write should succeed"); /* Write the address and read the data back */ msgs[0].len = ARRAY_SIZE(rx_cmd); @@ -322,8 +342,7 @@ void ram_rtio_isr(struct k_timer *tid) wr_cqe = rtio_cqe_consume(&i2c_rtio); if (wr_cqe) { TC_PRINT("read command complete\n"); - zassert_ok(wr_cqe->result, "i2c read command should succeed"); - rtio_cqe_release(&i2c_rtio, wr_cqe); + check_completion(wr_cqe, "i2c read command should succeed"); isr_state += 1; } break; @@ -331,8 +350,7 @@ void ram_rtio_isr(struct k_timer *tid) rd_cqe = rtio_cqe_consume(&i2c_rtio); if (rd_cqe) { TC_PRINT("read data complete\n"); - zassert_ok(rd_cqe->result, "i2c read data should succeed"); - rtio_cqe_release(&i2c_rtio, rd_cqe); + check_completion(rd_cqe, "i2c read data should succeed"); isr_state += 1; k_sem_give(&ram_rtio_isr_sem); k_timer_stop(tid); diff --git a/tests/drivers/sensor/generic/src/main.c b/tests/drivers/sensor/generic/src/main.c index 5bec8b45a745..e20749bd7cd6 100644 --- a/tests/drivers/sensor/generic/src/main.c +++ b/tests/drivers/sensor/generic/src/main.c @@ -329,6 +329,10 @@ ZTEST(sensor_api, test_sensor_unit_conversion) /* reset test data to positive value */ data.val1 = 3; data.val2 = 300000; + zassert_equal(sensor_value_to_deci(&data), 33LL, + "the result does not match"); + zassert_equal(sensor_value_to_centi(&data), 330LL, + "the result does not match"); zassert_equal(sensor_value_to_milli(&data), 3300LL, "the result does not match"); zassert_equal(sensor_value_to_micro(&data), 3300000LL, @@ -336,11 +340,21 @@ ZTEST(sensor_api, test_sensor_unit_conversion) /* reset test data to negative value */ data.val1 = -data.val1; data.val2 = -data.val2; + zassert_equal(sensor_value_to_deci(&data), -33LL, + "the result does not match"); + zassert_equal(sensor_value_to_centi(&data), -330LL, + "the result does not match"); zassert_equal(sensor_value_to_milli(&data), -3300LL, "the result does not match"); zassert_equal(sensor_value_to_micro(&data), -3300000LL, "the result does not match"); /* Test when result is greater than 32-bit wide */ + data.val1 = 2123456789; + data.val2 = 876543; + zassert_equal(sensor_value_to_deci(&data), 21234567898LL, + "the result does not match"); + zassert_equal(sensor_value_to_centi(&data), 212345678987LL, + "the result does not match"); data.val1 = 5432109; data.val2 = 876543; zassert_equal(sensor_value_to_milli(&data), 5432109876LL, diff --git a/tests/kernel/common/src/atomic.c b/tests/kernel/common/src/atomic.c index 1bdbfe3bf5c1..fb88900a1eb4 100644 --- a/tests/kernel/common/src/atomic.c +++ b/tests/kernel/common/src/atomic.c @@ -28,7 +28,12 @@ static struct k_thread thread[THREADS_NUM]; atomic_t total_atomic; /** - * @addtogroup kernel_common_tests + * @defgroup kernel_atomic_ops_tests Atomic Operations + * @ingroup all_tests + * @{ + * @} + * + * @addtogroup kernel_atomic_ops_tests * @{ */ @@ -92,7 +97,6 @@ atomic_t total_atomic; * atomic_test_and_set_bit(), atomic_clear_bit(), atomic_set_bit(), * ATOMIC_DEFINE * - * @ingroup kernel_common_tests */ ZTEST_USER(atomic, test_atomic) { @@ -312,7 +316,6 @@ void atomic_handler(void *p1, void *p2, void *p3) * In this time, the two sub threads will be scheduled separately * according to the time slice. * - * @ingroup kernel_common_tests */ ZTEST(atomic, test_threads_access_atomic) { @@ -349,7 +352,6 @@ ZTEST(atomic, test_threads_access_atomic) * in a non-atomic manner (as long as it is logically safe) * and expect its value to match the result of the similar atomic increment. * - * @ingroup kernel_common_tests */ ZTEST(atomic, test_atomic_overflow) { @@ -383,8 +385,8 @@ ZTEST(atomic, test_atomic_overflow) atomic_value); } -extern void *common_setup(void); -ZTEST_SUITE(atomic, NULL, common_setup, NULL, NULL, NULL); /** * @} */ +extern void *common_setup(void); +ZTEST_SUITE(atomic, NULL, common_setup, NULL, NULL, NULL); diff --git a/tests/kernel/common/src/bitarray.c b/tests/kernel/common/src/bitarray.c index a7a7be02a017..acac6efdf51a 100644 --- a/tests/kernel/common/src/bitarray.c +++ b/tests/kernel/common/src/bitarray.c @@ -22,7 +22,12 @@ #define BITFIELD_SIZE 512 /** - * @addtogroup kernel_common_tests + * @defgroup kernel_bitarray_tests Bit Arrays + * @ingroup all_tests + * @{ + * @} + * + * @addtogroup kernel_bitarray_tests * @{ */ @@ -1058,9 +1063,8 @@ ZTEST(bitarray, test_ffs) zassert_equal(find_lsb_set(value), bit + 1, "LSB is not matched"); } } -extern void *common_setup(void); -ZTEST_SUITE(bitarray, NULL, common_setup, NULL, NULL, NULL); - /** * @} */ +extern void *common_setup(void); +ZTEST_SUITE(bitarray, NULL, common_setup, NULL, NULL, NULL); diff --git a/tests/kernel/common/src/bitfield.c b/tests/kernel/common/src/bitfield.c index 84e0258a8721..c62627a7ebd7 100644 --- a/tests/kernel/common/src/bitfield.c +++ b/tests/kernel/common/src/bitfield.c @@ -19,7 +19,12 @@ #define BITFIELD_SIZE 512 /** - * @addtogroup kernel_common_tests + * @defgroup kernel_bitfield_tests Bit Fields + * @ingroup all_tests + * @{ + * @} + * + * @addtogroup kernel_bitfield_tests * @{ */ @@ -131,10 +136,10 @@ ZTEST(bitfield, test_bitfield) } -extern void *common_setup(void); - -ZTEST_SUITE(bitfield, NULL, common_setup, NULL, NULL, NULL); - /** * @} */ + +extern void *common_setup(void); + +ZTEST_SUITE(bitfield, NULL, common_setup, NULL, NULL, NULL); diff --git a/tests/kernel/common/src/boot_delay.c b/tests/kernel/common/src/boot_delay.c index 7d4e44630fac..62e9c20fb589 100644 --- a/tests/kernel/common/src/boot_delay.c +++ b/tests/kernel/common/src/boot_delay.c @@ -6,11 +6,15 @@ #include + /** - * @brief Test delay during boot - * @defgroup kernel_init_tests Init + * @defgroup kernel_init_tests Kernel Initialization * @ingroup all_tests * @{ + * @} + * + * @addtogroup kernel_init_tests + * @{ */ /** @@ -39,9 +43,9 @@ ZTEST(boot_delay, test_bootdelay) (NSEC_PER_MSEC * CONFIG_BOOT_DELAY)); } -extern void *common_setup(void); -ZTEST_SUITE(boot_delay, NULL, common_setup, NULL, NULL, NULL); - /** * @} */ + +extern void *common_setup(void); +ZTEST_SUITE(boot_delay, NULL, common_setup, NULL, NULL, NULL); diff --git a/tests/kernel/common/src/byteorder.c b/tests/kernel/common/src/byteorder.c index a888ad1f1e08..6998360a6608 100644 --- a/tests/kernel/common/src/byteorder.c +++ b/tests/kernel/common/src/byteorder.c @@ -10,9 +10,15 @@ #include /** - * @addtogroup kernel_common_tests + * @defgroup kernel_byteorder_tests Byteorder Operations + * @ingroup all_tests + * @{ + * @} + * + * @addtogroup kernel_byteorder_tests * @{ */ + /** * @brief Test swapping for memory contents * @@ -704,9 +710,10 @@ ZTEST(byteorder, test_sys_get_be) zassert_mem_equal(host, exp, sizeof(exp), "sys_get_be() failed"); } -extern void *common_setup(void); -ZTEST_SUITE(byteorder, NULL, common_setup, NULL, NULL, NULL); - /** * @} */ + + +extern void *common_setup(void); +ZTEST_SUITE(byteorder, NULL, common_setup, NULL, NULL, NULL); diff --git a/tests/kernel/common/src/clock.c b/tests/kernel/common/src/clock.c index 813a5c7c36e8..090b2763fa8d 100644 --- a/tests/kernel/common/src/clock.c +++ b/tests/kernel/common/src/clock.c @@ -29,7 +29,12 @@ static ZTEST_BMEM struct timer_data tdata; #define LESS_DURATION 70 /** - * @addtogroup kernel_common_tests + * @defgroup kernel_clock_tests Clock Operations + * @ingroup all_tests + * @{ + * @} + * + * @addtogroup kernel_clock_tests * @{ */ @@ -231,9 +236,9 @@ ZTEST(clock, test_ms_time_duration) k_timer_stop(&ktimer); } -extern void *common_setup(void); -ZTEST_SUITE(clock, NULL, common_setup, NULL, NULL, NULL); - /** * @} */ + + extern void *common_setup(void); + ZTEST_SUITE(clock, NULL, common_setup, NULL, NULL, NULL); diff --git a/tests/kernel/common/src/constructor.c b/tests/kernel/common/src/constructor.c index 6aca7f7cbe34..7a1bb054852d 100644 --- a/tests/kernel/common/src/constructor.c +++ b/tests/kernel/common/src/constructor.c @@ -8,14 +8,15 @@ #include #include #include -/** - * @addtogroup kernel_common_tests - * @{ - */ /** - * @brief Test if constructors work + * @defgroup kernel_constructor_tests Constructors + * @ingroup all_tests + * @{ + * @} * + * @addtogroup kernel_constructor_tests + * @{ */ static int constructor_number; @@ -35,7 +36,10 @@ void __attribute__((__constructor__(1000))) __constructor_init_priority_1000(voi { constructor_values[constructor_number++] = 1000; } - +/** + * @brief Test if constructors work + * + */ ZTEST(constructor, test_constructor) { zassert_equal(constructor_number, 3, @@ -51,9 +55,9 @@ ZTEST(constructor, test_constructor) "constructor without priority not called last"); } -extern void *common_setup(void); -ZTEST_SUITE(constructor, NULL, common_setup, NULL, NULL, NULL); - /** * @} */ + + extern void *common_setup(void); + ZTEST_SUITE(constructor, NULL, common_setup, NULL, NULL, NULL); diff --git a/tests/kernel/common/src/errno.c b/tests/kernel/common/src/errno.c index 9155a5bd4185..b185835b7d2b 100644 --- a/tests/kernel/common/src/errno.c +++ b/tests/kernel/common/src/errno.c @@ -9,16 +9,7 @@ #include #include -/** - * @brief Test the thread context - * - * @defgroup kernel_threadcontext_tests Thread Context Tests - * - * @ingroup all_tests - * - * @{ - * @} - */ + #define N_THREADS 2 #define STACK_SIZE (384 + CONFIG_TEST_EXTRA_STACK_SIZE) @@ -59,11 +50,17 @@ static void errno_thread(void *_n, void *_my_errno, void *_unused) k_fifo_put(&fifo, &result[n]); } - /** - * @brief Verify thread context + * @defgroup kernel_errno_tests Error Number + * @ingroup all_tests + * @{ + * @} * - * @ingroup kernel_threadcontext_tests + * @addtogroup kernel_errno_tests + * @{ + */ +/** + * @brief Verify thread context * * @details Check whether variable value per-thread are saved during * context switch @@ -140,8 +137,6 @@ void thread_entry_user(void *p1, void *p2, void *p3) * * @details Check whether a C standard errno can be stored successfully, * no matter it is using tls or not. - * - * @ingroup kernel_threadcontext_tests */ ZTEST_USER(common_errno, test_errno) { @@ -160,6 +155,8 @@ ZTEST_USER(common_errno, test_errno) k_thread_join(tid, K_FOREVER); } +/** + * @} + */ extern void *common_setup(void); - ZTEST_SUITE(common_errno, NULL, common_setup, NULL, NULL, NULL); diff --git a/tests/kernel/common/src/irq_offload.c b/tests/kernel/common/src/irq_offload.c index bffeb0dc94e6..3526aa81b841 100644 --- a/tests/kernel/common/src/irq_offload.c +++ b/tests/kernel/common/src/irq_offload.c @@ -17,6 +17,16 @@ #include #include +/** + * @defgroup kernel_irq_offload_tests IRQ Offload + * @ingroup all_tests + * @{ + * @} + * + * @addtogroup kernel_irq_offload_tests + * @{ + */ + volatile uint32_t sentinel; #define SENTINEL_VALUE 0xDEADBEEF @@ -36,8 +46,6 @@ static void offload_function(const void *param) /** * @brief Verify thread context * - * @ingroup kernel_interrupt_tests - * * @details Check whether offloaded running function is in interrupt * context, on the IRQ stack or not. */ @@ -97,7 +105,8 @@ static void offload_thread_fn(void *p0, void *p1, void *p2) } } -/* Invoke irq_offload() from an interrupt and verify that the +/** + * @brief Invoke irq_offload from an interrupt and verify that the * resulting nested interrupt doesn't explode */ ZTEST(common_1cpu, test_nested_irq_offload) @@ -130,6 +139,8 @@ ZTEST(common_1cpu, test_nested_irq_offload) k_thread_abort(&offload_thread); } - +/** + * @} + */ extern void *common_setup(void); ZTEST_SUITE(irq_offload, NULL, common_setup, NULL, NULL, NULL); diff --git a/tests/kernel/common/src/printk.c b/tests/kernel/common/src/printk.c index 7c3a714817b6..af0fd330d517 100644 --- a/tests/kernel/common/src/printk.c +++ b/tests/kernel/common/src/printk.c @@ -181,8 +181,14 @@ static int ram_console_out(int character) pos = (pos + 1) % BUF_SZ; return _old_char_out(character); } + /** - * @addtogroup kernel_common_tests + * @defgroup kernel_printk_tests Printk + * @ingroup all_tests + * @{ + * @} + * + * @addtogroup kernel_printk_tests * @{ */ @@ -253,9 +259,9 @@ ZTEST(printk, test_printk) zassert_str_equal(pk_console, expected, "snprintk failed"); } -extern void *common_setup(void); -ZTEST_SUITE(printk, NULL, common_setup, NULL, NULL, NULL); /** * @} */ +extern void *common_setup(void); +ZTEST_SUITE(printk, NULL, common_setup, NULL, NULL, NULL); diff --git a/tests/kernel/common/src/timeout_order.c b/tests/kernel/common/src/timeout_order.c index 582f659ae892..9dcd097a73fb 100644 --- a/tests/kernel/common/src/timeout_order.c +++ b/tests/kernel/common/src/timeout_order.c @@ -36,7 +36,12 @@ static K_THREAD_STACK_ARRAY_DEFINE(stacks, NUM_TIMEOUTS, STACKSIZE); static struct k_thread threads[NUM_TIMEOUTS]; /** - * @addtogroup kernel_common_tests + * @defgroup kernel_timeout_tests Timeout Order + * @ingroup all_tests + * @{ + * @} + * + * @addtogroup kernel_timeout_tests * @{ */ @@ -88,10 +93,9 @@ ZTEST(common_1cpu, test_timeout_order) } } -extern void *common_setup(void); -ZTEST_SUITE(common_1cpu, NULL, common_setup, - ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL); - /** * @} */ +extern void *common_setup(void); +ZTEST_SUITE(common_1cpu, NULL, common_setup, + ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL); diff --git a/tests/kernel/condvar/condvar_api/src/main.c b/tests/kernel/condvar/condvar_api/src/main.c index 3b422f7d1a6b..7ad2eadf2e8b 100644 --- a/tests/kernel/condvar/condvar_api/src/main.c +++ b/tests/kernel/condvar/condvar_api/src/main.c @@ -133,7 +133,15 @@ void condvar_wait_wake_task(void *p1, void *p2, void *p3) k_mutex_unlock(&test_mutex); } - +/** + * @defgroup kernel_condvar_tests Condition Variables + * @ingroup all_tests + * @{ + * @} + * + * @addtogroup kernel_condvar_tests + * @{ + */ /** * @brief Test k_condvar_wait() and k_condvar_wake() */ @@ -163,7 +171,9 @@ ZTEST_USER(condvar_tests, test_condvar_wait_forever_wake) k_thread_abort(&condvar_tid); } - +/** + * @brief Test k_condvar_wait() and k_condvar_wake() with timeout + */ ZTEST_USER(condvar_tests, test_condvar_wait_timeout_wake) { woken = 1; @@ -191,6 +201,9 @@ ZTEST_USER(condvar_tests, test_condvar_wait_timeout_wake) k_thread_abort(&condvar_tid); } +/** + * @brief Test k_condvar_wait() and k_condvar_wake() with timeout + */ ZTEST_USER(condvar_tests, test_condvar_wait_timeout) { timeout = k_ms_to_ticks_ceil32(50); @@ -224,7 +237,9 @@ ZTEST_USER(condvar_tests, test_condvar_wait_forever) k_thread_abort(&condvar_tid); } - +/** + * @brief Test k_condvar_wait() with no wait + */ ZTEST_USER(condvar_tests, test_condvar_wait_nowait) { timeout = 0; @@ -240,6 +255,12 @@ ZTEST_USER(condvar_tests, test_condvar_wait_nowait) } +/** + * @brief Test case for conditional variable wait and wake functionality. + * + * This test validates the behavior of conditional variables when a thread + * waits on a condition and another thread wakes it up. + */ ZTEST_USER(condvar_tests, test_condvar_wait_nowait_wake) { woken = 0; @@ -266,6 +287,13 @@ ZTEST_USER(condvar_tests, test_condvar_wait_nowait_wake) } +/** + * @brief Test case for condition variable wait and wake functionality. + * + * This test verifies the behavior of a thread waiting on a condition variable + * with an infinite timeout and being woken up from an interrupt service routine (ISR). + * + */ ZTEST(condvar_tests, test_condvar_wait_forever_wake_from_isr) { timeout = K_TICKS_FOREVER; @@ -285,6 +313,15 @@ ZTEST(condvar_tests, test_condvar_wait_forever_wake_from_isr) k_thread_abort(&condvar_tid); } +/** + * @brief Test case for multiple threads waiting and waking on a condition variable. + * + * This test initializes a condition variable and creates multiple threads that + * wait on the condition variable. Another thread is created to wake up the + * waiting threads. The test ensures proper synchronization and behavior of + * threads waiting and waking on the condition variable. + + */ ZTEST_USER(condvar_tests, test_condvar_multiple_threads_wait_wake) { timeout = K_TICKS_FOREVER; @@ -353,6 +390,15 @@ void condvar_multiple_wake_task(void *p1, void *p2, void *p3) ret_value, woken_num); } + +/** + * @brief Test multiple threads waiting and waking on a condition variable. + * + * This test creates multiple threads that wait on a condition variable and + * another set of threads that wake them up. It ensures that the condition + * variable mechanism works correctly when multiple threads are involved. + + */ ZTEST_USER(condvar_tests, test_multiple_condvar_wait_wake) { woken = 1; @@ -404,6 +450,14 @@ static void cond_init_null(void *p1, void *p2, void *p3) ztest_test_fail(); } + +/** + * @brief Test case for conditional variable initialization with a null parameter. + * + * This test verifies the behavior of the conditional variable initialization + * when a null parameter is passed. It creates a thread to execute the + * `cond_init_null` function and ensures the thread completes execution. + */ ZTEST_USER(condvar_tests, test_condvar_init_null) { k_tid_t tid = k_thread_create(&condvar_tid, stack_1, STACK_SIZE, @@ -460,7 +514,13 @@ static void cond_wait_null(void *p1, void *p2, void *p3) /* should not go here*/ ztest_test_fail(); } - +/** + * @brief Test case for signaling a condition variable with a NULL parameter. + * + * This test creates a thread that attempts to signal a condition variable + * with a NULL parameter. It ensures that the system handles this scenario + * gracefully without causing unexpected behavior or crashes. + */ ZTEST_USER(condvar_tests, test_condvar_signal_null) { k_tid_t tid = k_thread_create(&condvar_tid, stack_1, STACK_SIZE, @@ -470,6 +530,14 @@ ZTEST_USER(condvar_tests, test_condvar_signal_null) K_USER | K_INHERIT_PERMS, K_NO_WAIT); k_thread_join(tid, K_FOREVER); } + +/** + * @brief Test case for broadcasting a condition variable with a NULL parameter. + * + * This test creates a thread that attempts to broadcast a condition variable + * with a NULL parameter. It verifies that the system can handle this edge case + * correctly and does not result in undefined behavior. + */ ZTEST_USER(condvar_tests, test_condvar_broadcast_null) { k_tid_t tid = k_thread_create(&condvar_tid, stack_1, STACK_SIZE, @@ -480,6 +548,14 @@ ZTEST_USER(condvar_tests, test_condvar_broadcast_null) k_thread_join(tid, K_FOREVER); } + +/** + * @brief Test case for waiting on a condition variable with a NULL parameter. + * + * This test creates a thread that attempts to wait on a condition variable + * with a NULL parameter. It ensures that the system properly handles this + * invalid operation and maintains stability. + */ ZTEST_USER(condvar_tests, test_condvar_wait_null) { k_tid_t tid = k_thread_create(&condvar_tid, stack_1, STACK_SIZE, @@ -575,11 +651,20 @@ void _condvar_usecase(long multi) } + +/** + * @brief Test case for conditional variable use case with signal + * + * This test verifies the behavior of a conditional variable in a specific + * use case where a signal is used. It ensures that the conditional variable + * operates correctly when signaled, validating synchronization mechanisms. + */ ZTEST_USER(condvar_tests, test_condvar_usecase_signal) { _condvar_usecase(0); } + ZTEST_USER(condvar_tests, test_condvar_usecase_broadcast) { _condvar_usecase(1); @@ -604,4 +689,8 @@ static void *condvar_tests_setup(void) return NULL; } +/** + * @} + */ + ZTEST_SUITE(condvar_tests, NULL, condvar_tests_setup, NULL, NULL, NULL); diff --git a/tests/kernel/early_sleep/src/main.c b/tests/kernel/early_sleep/src/main.c index 6c4614e4ba85..7b1f319158d3 100644 --- a/tests/kernel/early_sleep/src/main.c +++ b/tests/kernel/early_sleep/src/main.c @@ -4,25 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -/* - * @file - * @brief Test early sleep functionality - * - * @defgroup kernel_earlysleep_tests Early Sleep Tests - * - * @ingroup all_tests - * - * This test verifies that k_sleep() can be used to put the calling thread to - * sleep for a specified number of ticks during system initialization. In this - * test we are calling k_sleep() at POST_KERNEL and APPLICATION level - * initialization sequence. - * - * Note: We can not call k_sleep() during PRE_KERNEL1 or PRE_KERNEL2 level - * because the core kernel objects and devices initialization happens at these - * levels. - * @{ - * @} - */ + #include #include @@ -82,12 +64,19 @@ static int test_early_sleep_app(void) SYS_INIT(test_early_sleep_app, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); -/** - * @brief Test early sleep +/* + * @brief Test early sleep functionality + * + * @ingroup kernel_sleep_tests * - * @ingroup kernel_earlysleep_tests + * This test verifies that k_sleep() can be used to put the calling thread to + * sleep for a specified number of ticks during system initialization. In this + * test we are calling k_sleep() at POST_KERNEL and APPLICATION level + * initialization sequence. * - * @see k_sleep() + * Note: We can not call k_sleep() during PRE_KERNEL1 or PRE_KERNEL2 level + * because the core kernel objects and devices initialization happens at these + * levels. */ ZTEST(earlysleep, test_early_sleep) { diff --git a/tests/kernel/events/event_api/src/main.c b/tests/kernel/events/event_api/src/main.c index 650b0e4159d8..f8a2f4909602 100644 --- a/tests/kernel/events/event_api/src/main.c +++ b/tests/kernel/events/event_api/src/main.c @@ -17,7 +17,7 @@ * -# k_event_wait_all * -# k_event_test * - * @defgroup kernel_event_tests events + * @defgroup kernel_event_tests Events * @ingroup all_tests * @{ * @} diff --git a/tests/kernel/events/event_api/src/test_event_apis.c b/tests/kernel/events/event_api/src/test_event_apis.c index a6c81272bcdd..75628e5b8f2e 100644 --- a/tests/kernel/events/event_api/src/test_event_apis.c +++ b/tests/kernel/events/event_api/src/test_event_apis.c @@ -46,6 +46,10 @@ static void entry_extra2(void *p1, void *p2, void *p3) k_event_post(&test_event, events); } +/** +* @ingroup kernel_event_tests +* @{ +*/ /** * Test the k_event_init() API. @@ -53,7 +57,6 @@ static void entry_extra2(void *p1, void *p2, void *p3) * This is a white-box test to verify that the k_event_init() API initializes * the fields of a k_event structure as expected. */ - ZTEST(events_api, test_k_event_init) { static struct k_event event; @@ -431,3 +434,6 @@ ZTEST(events_api, test_event_receive) test_wake_multiple_threads(); } +/** + * @} + */ diff --git a/tests/kernel/events/sys_event/src/main.c b/tests/kernel/events/sys_event/src/main.c index 0dc34fb6fc1e..fb15bed645ad 100644 --- a/tests/kernel/events/sys_event/src/main.c +++ b/tests/kernel/events/sys_event/src/main.c @@ -34,10 +34,8 @@ static K_SEM_DEFINE(sync_sem, 0, 1); volatile static uint32_t test_events; /** - * @defgroup kernel_sys_events_tests Semaphore - * @ingroup all_tests + * @ingroup kernel_event_tests * @{ - * @} */ static void entry_extra1(void *p1, void *p2, void *p3) @@ -404,5 +402,8 @@ void *sys_events_setup(void) return NULL; } +/** + * @} + */ ZTEST_SUITE(sys_events, NULL, sys_events_setup, ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL); diff --git a/tests/kernel/fatal/exception/src/main.c b/tests/kernel/fatal/exception/src/main.c index 1033473a21ca..260ef39e396c 100644 --- a/tests/kernel/fatal/exception/src/main.c +++ b/tests/kernel/fatal/exception/src/main.c @@ -300,7 +300,7 @@ void check_stack_overflow(k_thread_entry_t handler, uint32_t flags) * should match. Check for stack sentinel feature by overflowing the * thread's stack and check for the exception. * - * @ingroup kernel_common_tests + * @ingroup kernel_fatal_tests */ ZTEST(fatal_exception, test_fatal) { diff --git a/tests/kernel/fatal/no-multithreading/src/main.c b/tests/kernel/fatal/no-multithreading/src/main.c index c48ef3d9fd53..fe94c64b308c 100644 --- a/tests/kernel/fatal/no-multithreading/src/main.c +++ b/tests/kernel/fatal/no-multithreading/src/main.c @@ -117,14 +117,14 @@ static const exc_trigger_func_t exc_trigger_func[] = { }; /** - * @brief Test the kernel fatal error handling works correctly + * @brief Verify the kernel fatal error handling works correctly * @details Manually trigger the crash with various ways and check * that the kernel is handling that properly or not. Also the crash reason * should match. * - * @ingroup kernel_common_tests + * @ingroup kernel_fatal_tests */ -ZTEST(fatal_no_mt, test_fatal) +ZTEST(fatal_no_mt, test_fatal_no_mt) { #ifdef VIA_TWISTER #define EXC_TRIGGER_FUNC_IDX VIA_TWISTER diff --git a/tests/kernel/mbox/mbox_api/src/test_mbox_api.c b/tests/kernel/mbox/mbox_api/src/test_mbox_api.c index e0268ea96e66..cbc38e1d1763 100644 --- a/tests/kernel/mbox/mbox_api/src/test_mbox_api.c +++ b/tests/kernel/mbox/mbox_api/src/test_mbox_api.c @@ -417,13 +417,32 @@ static void tmbox(struct k_mbox *pmbox) k_thread_abort(receiver_tid); } -/*test cases*/ +/** + * @addtogroup kernel_mbox_api + * @{ + */ + + +/** + * @brief Test mailbox initialization + */ ZTEST(mbox_api, test_mbox_kinit) { /**TESTPOINT: init via k_mbox_init*/ k_mbox_init(&mbox); } +/** + * @brief Test mailbox definition + * + * @details + * - Define a mailbox and verify the mailbox whether as expected + * - Verify the mailbox can be used + * + * @ingroup kernel_mbox_api + * + * @see k_mbox_init() k_mbox_put() k_mbox_get() + */ ZTEST(mbox_api, test_mbox_kdefine) { info_type = PUT_GET_NULL; @@ -434,7 +453,7 @@ static ZTEST_BMEM char __aligned(4) buffer[8]; /** * - * @brief Test mailbox enhance capabilities + * @brief Test mailbox enhanced capabilities * * @details * - Define and initialized a message queue and a mailbox @@ -445,7 +464,7 @@ static ZTEST_BMEM char __aligned(4) buffer[8]; * * @see k_msgq_init() k_msgq_put() k_mbox_async_put() k_mbox_get() */ -ZTEST(mbox_api, test_enhance_capability) +ZTEST(mbox_api, test_mbox_enhanced_capabilities) { info_type = ASYNC_PUT_GET_BUFFER; struct k_msgq msgq; @@ -460,15 +479,13 @@ ZTEST(mbox_api, test_enhance_capability) tmbox(&mbox); } -/* - * - * @brife Test any number of mailbox can be defined +/** + * @brief Test that multiple mailboxs can be defined * * @details - * - Define multi mailbox and verify the mailbox whether as + * - Define multiple mailbox and verify the mailbox whether as * expected * - Verify the mailbox can be used - * */ ZTEST(mbox_api, test_define_multi_mbox) { @@ -486,84 +503,129 @@ ZTEST(mbox_api, test_define_multi_mbox) tmbox(&mbox3); } +/** + * @brief Test case for mailbox put and get operations with null data. + */ ZTEST(mbox_api, test_mbox_put_get_null) { info_type = PUT_GET_NULL; tmbox(&mbox); } +/** + * @brief Test case for mailbox put and get operations with buffer. + * + */ ZTEST(mbox_api, test_mbox_put_get_buffer) { info_type = PUT_GET_BUFFER; tmbox(&mbox); } +/** + * @brief Test case for mailbox asynchronous put and get operations with buffer. + * + */ ZTEST(mbox_api, test_mbox_async_put_get_buffer) { info_type = ASYNC_PUT_GET_BUFFER; tmbox(&mbox); } +/** + * @brief Test case for mailbox asynchronous put and get operations with block. + * + */ ZTEST(mbox_api, test_mbox_async_put_get_block) { info_type = ASYNC_PUT_GET_BLOCK; tmbox(&mbox); } +/** + * @brief Test case for mailbox target/source thread buffer operations. + */ ZTEST(mbox_api, test_mbox_target_source_thread_buffer) { info_type = TARGET_SOURCE_THREAD_BUFFER; tmbox(&mbox); } +/** + * @brief Test case for mailbox incorrect receiver thread ID. + */ ZTEST(mbox_api, test_mbox_incorrect_receiver_tid) { info_type = INCORRECT_RECEIVER_TID; tmbox(&mbox); } +/** + * @brief Test case for mailbox incorrect transmit thread ID. + */ ZTEST(mbox_api, test_mbox_incorrect_transmit_tid) { info_type = INCORRECT_TRANSMIT_TID; tmbox(&mbox); } +/** + * @brief Test case for mailbox timed out get operation. + */ ZTEST(mbox_api, test_mbox_timed_out_mbox_get) { info_type = TIMED_OUT_MBOX_GET; tmbox(&mbox); } +/** + * @brief Test case for mailbox message thread ID mismatch. + */ ZTEST(mbox_api, test_mbox_msg_tid_mismatch) { info_type = MSG_TID_MISMATCH; tmbox(&mbox); } +/** + * @brief Test case for mailbox dispose size 0 message. + */ ZTEST(mbox_api, test_mbox_dispose_size_0_msg) { info_type = DISPOSE_SIZE_0_MSG; tmbox(&mbox); } +/** + * @brief Test case for mailbox asynchronous put to waiting get operation. + */ ZTEST(mbox_api, test_mbox_async_put_to_waiting_get) { info_type = ASYNC_PUT_TO_WAITING_GET; tmbox(&mbox); } +/** + * @brief Test case for mailbox get waiting put with incorrect thread ID. + */ ZTEST(mbox_api, test_mbox_get_waiting_put_incorrect_tid) { info_type = GET_WAITING_PUT_INCORRECT_TID; tmbox(&mbox); } +/** + * @brief Test case for mailbox asynchronous multiple put operation. + */ ZTEST(mbox_api, test_mbox_async_multiple_put) { info_type = ASYNC_MULTIPLE_PUT; tmbox(&mbox); } +/** + * @brief Test case for mailbox multiple waiting get operation. + */ ZTEST(mbox_api, test_mbox_multiple_waiting_get) { info_type = MULTIPLE_WAITING_GET; @@ -584,4 +646,8 @@ void *setup_mbox_api(void) return NULL; } +/** + * @} + */ + ZTEST_SUITE(mbox_api, NULL, setup_mbox_api, NULL, NULL, NULL); diff --git a/tests/kernel/mem_heap/k_heap_api/src/main.c b/tests/kernel/mem_heap/k_heap_api/src/main.c index 80c296c32ebb..167d3cfd4b31 100644 --- a/tests/kernel/mem_heap/k_heap_api/src/main.c +++ b/tests/kernel/mem_heap/k_heap_api/src/main.c @@ -7,9 +7,9 @@ #include /** - * @brief k heap api tests + * @brief Kernel Heap API Tests * - * @defgroup k_heap api Tests + * @defgroup k_heap_api_tests Kernel Heap Tests * * @ingroup all_tests * @{ diff --git a/tests/kernel/mem_heap/k_heap_api/src/test_kheap_api.c b/tests/kernel/mem_heap/k_heap_api/src/test_kheap_api.c index bce18d20b89a..4f6d637c0ff1 100644 --- a/tests/kernel/mem_heap/k_heap_api/src/test_kheap_api.c +++ b/tests/kernel/mem_heap/k_heap_api/src/test_kheap_api.c @@ -72,7 +72,7 @@ K_HEAP_DEFINE(tiny_heap, 1); volatile uint32_t heap_guard1; /** @brief Test a minimum-size static k_heap - * @ingroup kernel_kheap_api_tests + * @ingroup k_heap_api_tests * * @details Create a minimum size (1-byte) static heap, verify that it * works to allocate that byte at runtime and that it doesn't overflow @@ -105,7 +105,7 @@ ZTEST(k_heap_api, test_k_heap_min_size) /** * @brief Test to demonstrate k_heap_alloc() and k_heap_free() API usage * - * @ingroup kernel_kheap_api_tests + * @ingroup k_heap_api_tests * * @details The test allocates 1024 bytes from 2048 byte heap, * and checks if allocation is successful or not @@ -129,7 +129,7 @@ ZTEST(k_heap_api, test_k_heap_alloc) /** * @brief Test to demonstrate k_heap_alloc() and k_heap_free() API usage * - * @ingroup kernel_kheap_api_tests + * @ingroup k_heap_api_tests * * @details The test allocates 2049 bytes, which is greater than the heap * size(2048 bytes), and checks for NULL return from k_heap_alloc @@ -151,7 +151,7 @@ ZTEST(k_heap_api, test_k_heap_alloc_fail) /** * @brief Test to demonstrate k_heap_free() API functionality. * - * @ingroup kernel_kheap_api_tests + * @ingroup k_heap_api_tests * * @details The test validates k_heap_free() * API, by using below steps @@ -184,7 +184,7 @@ ZTEST(k_heap_api, test_k_heap_free) * @details The test validates k_heap_alloc() in isr context, the timeout * param should be K_NO_WAIT, because this situation isn't allow to wait. * - * @ingroup kernel_heap_tests + * @ingroup k_heap_api_tests */ ZTEST(k_heap_api, test_kheap_alloc_in_isr_nowait) { @@ -198,7 +198,7 @@ ZTEST(k_heap_api, test_kheap_alloc_in_isr_nowait) * child thread. If there isn't enough space in the heap, the child thread * will wait timeout long until main thread free the buffer to heap. * - * @ingroup kernel_heap_tests + * @ingroup k_heap_api_tests */ ZTEST(k_heap_api, test_k_heap_alloc_pending) { @@ -235,7 +235,7 @@ ZTEST(k_heap_api, test_k_heap_alloc_pending) * will wait timeout long until main thread free one of the buffer to heap, space in * the heap is still not enough and then return null after timeout. * - * @ingroup kernel_heap_tests + * @ingroup k_heap_api_tests */ ZTEST(k_heap_api, test_k_heap_alloc_pending_null) { @@ -271,7 +271,7 @@ ZTEST(k_heap_api, test_k_heap_alloc_pending_null) /** * @brief Test to demonstrate k_heap_calloc() and k_heap_free() API usage * - * @ingroup kernel_kheap_api_tests + * @ingroup k_heap_api_tests * * @details The test allocates 256 unsigned integers of 4 bytes for a * total of 1024 bytes from the 2048 byte heap. It checks if allocation diff --git a/tests/kernel/mem_protect/mem_protect/src/mem_domain.c b/tests/kernel/mem_protect/mem_protect/src/mem_domain.c index 4ea5ad7ed1b1..1d74cea29d26 100644 --- a/tests/kernel/mem_protect/mem_protect/src/mem_domain.c +++ b/tests/kernel/mem_protect/mem_protect/src/mem_domain.c @@ -176,7 +176,7 @@ ZTEST(mem_protect_domain, test_mem_domain_invalid_access) /** * @brief Show that a read-only partition can't be written to * - * @ingroup kernel_memgroup_tests + * @ingroup kernel_memprotect_tests */ ZTEST(mem_protect_domain, test_mem_domain_no_writes_to_ro) { diff --git a/tests/kernel/semaphore/sys_sem/src/main.c b/tests/kernel/semaphore/sys_sem/src/main.c index fc65668a7adb..8a9a5dfc522c 100644 --- a/tests/kernel/semaphore/sys_sem/src/main.c +++ b/tests/kernel/semaphore/sys_sem/src/main.c @@ -27,7 +27,6 @@ static ZTEST_DMEM int flag; static ZTEST_DMEM atomic_t atomic_count; /** - * @defgroup kernel_sys_sem_tests Semaphore * @ingroup all_tests * @{ * @} @@ -73,7 +72,7 @@ static void thread_high_prio_sem_take(void *p1, void *p2, void *p3) * - Use semaphore normally * - Use semaphore with different priority threads * - * @ingroup kernel_sys_sem_tests + * @ingroup kernel_semaphore_tests */ ZTEST_USER(kernel_sys_sem, test_multiple_thread_sem_usage) { @@ -168,7 +167,7 @@ static void multi_thread_sem_take(void *p1, void *p2, void *p3) * - Verify more than max count about semaphore can reach. * - Take sem by multiple threads and verify if sem count is correct. * - * @ingroup kernel_sys_sem_tests + * @ingroup kernel_semaphore_tests */ ZTEST_USER(kernel_sys_sem, test_multi_thread_sem_limit) { diff --git a/tests/kernel/threads/thread_apis/src/main.c b/tests/kernel/threads/thread_apis/src/main.c index a39565758e7c..e073e0a87254 100644 --- a/tests/kernel/threads/thread_apis/src/main.c +++ b/tests/kernel/threads/thread_apis/src/main.c @@ -78,7 +78,7 @@ static void customdata_entry(void *p1, void *p2, void *p3) /** * @ingroup kernel_thread_tests - * @brief test thread custom data get/set from coop thread + * @brief Test thread custom data get/set from coop thread * * @see k_thread_custom_data_get(), k_thread_custom_data_set() */ @@ -101,7 +101,7 @@ static void thread_name_entry(void *p1, void *p2, void *p3) /** * @ingroup kernel_thread_tests - * @brief test thread name get/set from supervisor thread + * @brief Test thread name get/set from supervisor thread * @see k_thread_name_get(), k_thread_name_copy(), k_thread_name_set() */ ZTEST(threads_lifecycle, test_thread_name_get_set) @@ -142,7 +142,7 @@ struct k_sem sem; /** * @ingroup kernel_thread_tests - * @brief test thread name get/set from user thread + * @brief Test thread name get/set from user thread * @see k_thread_name_copy(), k_thread_name_set() */ ZTEST_USER(threads_lifecycle, test_thread_name_user_get_set) @@ -211,7 +211,7 @@ ZTEST_USER(threads_lifecycle, test_thread_name_user_get_set) /** * @ingroup kernel_thread_tests - * @brief test thread custom data get/set from preempt thread + * @brief Test thread custom data get/set from preempt thread * @see k_thread_custom_data_get(), k_thread_custom_data_set() */ ZTEST_USER(threads_lifecycle_1cpu, test_customdata_get_set_preempt) @@ -243,7 +243,7 @@ static void umode_entry(void *thread_id, void *p2, void *p3) /** * @ingroup kernel_thread_tests - * @brief Test k_thread_user_mode_enter() to cover when userspace + * @brief Test k_thread_user_mode_enter to cover when userspace * is not supported/enabled * @see k_thread_user_mode_enter() */ @@ -392,6 +392,11 @@ static inline int join_scenario(enum control_method m) return join_scenario_interval(m, NULL); } +/** + * @ingroup kernel_thread_tests + * @brief Test thread join + * + */ ZTEST_USER(threads_lifecycle, test_thread_join) { int64_t interval; @@ -415,6 +420,13 @@ ZTEST_USER(threads_lifecycle, test_thread_join) } +/** + * @ingroup kernel_thread_tests + * @brief Test thread join from ISR + * + * @see k_thread_join() + * @see k_thread_abort() + */ ZTEST(threads_lifecycle, test_thread_join_isr) { zassert_equal(join_scenario(ISR_RUNNING), -EBUSY, "failed isr running"); @@ -447,6 +459,21 @@ static void deadlock2_entry(void *p1, void *p2, void *p3) zassert_equal(ret, 0, "couldn't join deadlock2_thread"); } + + +/** + * @brief Test case for thread join deadlock scenarios. + * + * This test verifies the behavior of the `k_thread_join` API in scenarios + * that could lead to deadlocks. It includes the following checks: + * + * - Ensures that a thread cannot join itself, which would result in a + * self-deadlock. The API should return `-EDEADLK` in this case. + * - Creates two threads (`deadlock1_thread` and `deadlock2_thread`) and + * verifies that they can be joined successfully without causing a deadlock. + * + * @ingroup kernel_thread_tests + */ ZTEST_USER(threads_lifecycle, test_thread_join_deadlock) { /* Deadlock scenarios */ @@ -476,6 +503,11 @@ static void user_start_thread(void *p1, void *p2, void *p3) { /* do nothing */ } +/** + * @brief Test case for verifying thread timeout expiration and remaining time. + * + * @ingroup kernel_thread_tests + */ ZTEST_USER(threads_lifecycle, test_thread_timeout_remaining_expires) { @@ -528,10 +560,16 @@ static void foreach_callback(const struct k_thread *thread, void *user_data) stats.execution_cycles; } -/* This case accumulates every thread's execution_cycles first, then +/** + * @brief Test case for thread runtime statistics retrieval in Zephyr kernel + * + * This case accumulates every thread's execution_cycles first, then * get the total execution_cycles from a global * k_thread_runtime_stats_t to see that all time is reflected in the * total. + * + * @ingroup kernel_thread_tests + * @see k_thread_runtime_stats_get() */ ZTEST(threads_lifecycle, test_thread_runtime_stats_get) { @@ -551,6 +589,13 @@ ZTEST(threads_lifecycle, test_thread_runtime_stats_get) zassert_true(stats.execution_cycles <= stats_all.execution_cycles); } + +/** + * @brief Test the behavior of k_busy_wait with thread runtime statistics. + * + * This test verifies the accuracy of the `k_busy_wait` function by checking + * the thread's execution cycle statistics before and after calling the function. + */ ZTEST(threads_lifecycle, test_k_busy_wait) { uint64_t cycles, dt; @@ -589,6 +634,12 @@ static void tp_entry(void *p1, void *p2, void *p3) tp = 100; } +/** + * @brief Test the behavior of k_busy_wait with thread runtime statistics + * in user mode. + * + * @ingroup kernel_thread_tests + */ ZTEST_USER(threads_lifecycle_1cpu, test_k_busy_wait_user) { @@ -624,9 +675,14 @@ static int small_stack(size_t *space) return k_thread_stack_space_get(k_current_get(), space); } -/* test k_thread_stack_sapce_get(), unused stack space in large_stack_space() +/** + * @brief Test k_thread_stack_sapce_get + * + * Test k_thread_stack_sapce_get unused stack space in large_stack_space() * is smaller than that in small_stack() because the former function has a * large local variable + * + * @ingroup kernel_thread_tests */ ZTEST_USER(threads_lifecycle, test_k_thread_stack_space_get_user) { diff --git a/tests/kernel/threads/thread_apis/src/test_essential_thread.c b/tests/kernel/threads/thread_apis/src/test_essential_thread.c index 1803c56758f7..5fb316d51e54 100644 --- a/tests/kernel/threads/thread_apis/src/test_essential_thread.c +++ b/tests/kernel/threads/thread_apis/src/test_essential_thread.c @@ -114,6 +114,16 @@ ZTEST(threads_lifecycle, test_essential_thread_abort) zassert_true(fatal_error_signaled, "fatal error was not signaled"); } +/** + * @brief Abort an essential thread from itself + * + * @details The kernel shall raise a fatal system error if an essential thread + * aborts, implement k_sys_fatal_error_handler to handle this error. + * + * @ingroup kernel_thread_tests + * + * @see #K_ESSENTIAL(x) + */ ZTEST(threads_lifecycle, test_essential_thread_abort_self) { /* This test case needs to be able to handle a k_panic() call diff --git a/tests/kernel/threads/thread_apis/src/test_threads_cancel_abort.c b/tests/kernel/threads/thread_apis/src/test_threads_cancel_abort.c index b99347a404ff..b79f237d7a79 100644 --- a/tests/kernel/threads/thread_apis/src/test_threads_cancel_abort.c +++ b/tests/kernel/threads/thread_apis/src/test_threads_cancel_abort.c @@ -32,7 +32,7 @@ static void thread_entry_abort(void *p1, void *p2, void *p3) } /** * @ingroup kernel_thread_tests - * @brief Validate k_thread_abort() when called by current thread + * @brief Validate aborting a thread when called by current thread * * @details Create a user thread and let the thread execute. * Then call k_thread_abort() and check if the thread is terminated. @@ -52,7 +52,7 @@ ZTEST_USER(threads_lifecycle, test_threads_abort_self) /** * @ingroup kernel_thread_tests - * @brief Validate k_thread_abort() when called by other thread + * @brief Validate aborting a thread when called by other thread * * @details Create a user thread and abort the thread before its * execution. Create a another user thread and abort the thread @@ -85,7 +85,7 @@ ZTEST_USER(threads_lifecycle, test_threads_abort_others) /** * @ingroup kernel_thread_tests - * @brief Test abort on a terminated thread + * @brief Test abort on an already terminated thread * * @see k_thread_abort() */ diff --git a/tests/kernel/threads/thread_apis/src/test_threads_cpu_mask.c b/tests/kernel/threads/thread_apis/src/test_threads_cpu_mask.c index dd521cbbf57f..574bcd5aeee2 100644 --- a/tests/kernel/threads/thread_apis/src/test_threads_cpu_mask.c +++ b/tests/kernel/threads/thread_apis/src/test_threads_cpu_mask.c @@ -22,6 +22,19 @@ void child_fn(void *a, void *b, void *c) child_has_run = true; } + +/** + * @brief Test the CPU mask APIs for thread lifecycle management + * + * This test verifies the behavior of the CPU mask APIs in the Zephyr kernel + * for thread lifecycle management. It ensures that the APIs behave as expected + * when operating on both running and non-running threads. + * + * @note This test is only executed if `CONFIG_SCHED_CPU_MASK` is enabled. + * Otherwise, the test is skipped. + * + * @ingroup kernel_thread_tests + */ ZTEST(threads_lifecycle_1cpu, test_threads_cpu_mask) { #ifdef CONFIG_SCHED_CPU_MASK diff --git a/tests/kernel/threads/thread_apis/src/test_threads_set_priority.c b/tests/kernel/threads/thread_apis/src/test_threads_set_priority.c index 06672af99d1d..1d022a3e28b1 100644 --- a/tests/kernel/threads/thread_apis/src/test_threads_set_priority.c +++ b/tests/kernel/threads/thread_apis/src/test_threads_set_priority.c @@ -23,7 +23,7 @@ struct isr_arg { static struct isr_arg prio_args; /** - * @brief Test ISR used to change a thread's priority + * @brief Test changing a thread's priority from an ISR */ static void test_isr(const void *arg) { @@ -33,9 +33,7 @@ static void test_isr(const void *arg) } /** - * - * @brief thread2 portion to test setting the priority - * + * @brief Test thread behavior when its priority is changed */ void thread2_set_prio_test(void *p1, void *p2, void *p3) { @@ -61,7 +59,11 @@ void thread2_set_prio_test(void *p1, void *p2, void *p3) /** * @ingroup kernel_thread_tests - * @brief Test the k_thread_priority_set() API + * @brief Test setting and verifying thread priorities + * + * @details This test creates a thread with a lower priority than the + * current thread. It then sets the priority of the thread to a + * higher value, and checks that the priority has been set correctly. * * @see k_thread_priority_set(), k_thread_priority_get() */ @@ -74,61 +76,64 @@ ZTEST(threads_lifecycle, test_threads_priority_set) k_thread_priority_set(k_current_get(), prio + 2); rv = k_thread_priority_get(k_current_get()); zassert_equal(rv, prio + 2, - "Expected priority to be changed to %d, not %d\n", - prio + 2, rv); + "Expected priority to be changed to %d, not %d\n", + prio + 2, rv); /* Raise the priority of the current thread (thread1) */ k_thread_priority_set(k_current_get(), prio - 2); rv = k_thread_priority_get(k_current_get()); zassert_equal(rv, prio - 2, - "Expected priority to be changed to %d, not %d\n", - prio - 2, rv); + "Expected priority to be changed to %d, not %d\n", + prio - 2, rv); /* Restore the priority of the current thread (thread1) */ k_thread_priority_set(k_current_get(), prio); rv = k_thread_priority_get(k_current_get()); zassert_equal(rv, prio, - "Expected priority to be changed to %d, not %d\n", - prio, rv); + "Expected priority to be changed to %d, not %d\n", + prio, rv); /* create thread with lower priority */ int thread2_prio = prio + 1; k_tid_t thread2_id = k_thread_create(&tdata, tstack, STACK_SIZE, - thread2_set_prio_test, - NULL, NULL, NULL, thread2_prio, 0, - K_NO_WAIT); + thread2_set_prio_test, + NULL, NULL, NULL, thread2_prio, 0, + K_NO_WAIT); /* Lower the priority of thread2 */ k_thread_priority_set(thread2_id, thread2_prio + 2); k_sem_give(&sem_thread2); k_sem_take(&sem_thread1, K_FOREVER); zassert_equal(thread2_data, thread2_prio + 2, - "Expected priority to be changed to %d, not %d\n", - thread2_prio + 2, thread2_data); + "Expected priority to be changed to %d, not %d\n", + thread2_prio + 2, thread2_data); /* Raise the priority of thread2 */ k_thread_priority_set(thread2_id, thread2_prio - 2); k_sem_give(&sem_thread2); k_sem_take(&sem_thread1, K_FOREVER); zassert_equal(thread2_data, thread2_prio - 2, - "Expected priority to be changed to %d, not %d\n", - thread2_prio - 2, thread2_data); + "Expected priority to be changed to %d, not %d\n", + thread2_prio - 2, thread2_data); /* Restore the priority of thread2 */ k_thread_priority_set(thread2_id, thread2_prio); k_sem_give(&sem_thread2); k_sem_take(&sem_thread1, K_FOREVER); zassert_equal(thread2_data, thread2_prio, - "Expected priority to be changed to %d, not %d\n", - thread2_prio, thread2_data); + "Expected priority to be changed to %d, not %d\n", + thread2_prio, thread2_data); k_thread_join(thread2_id, K_FOREVER); } /** * @ingroup kernel_thread_tests - * @brief Test the k_thread_priority_set() API from an ISR + * @brief Test changing thread priorities from an ISR + * + * @details This test verifies that thread priorities can be changed + * correctly when invoked from an interrupt service routine (ISR). * * @see k_thread_priority_set(), k_thread_priority_get() */ @@ -143,32 +148,32 @@ ZTEST(threads_lifecycle, test_isr_threads_priority_set_) irq_offload(test_isr, &prio_args); rv = k_thread_priority_get(k_current_get()); zassert_equal(rv, prio + 2, - "Expected priority to be changed to %d, not %d\n", - prio + 2, rv); + "Expected priority to be changed to %d, not %d\n", + prio + 2, rv); /* Raise the priority of the current thread (thread1) */ prio_args.prio = prio - 2; irq_offload(test_isr, &prio_args); rv = k_thread_priority_get(k_current_get()); zassert_equal(rv, prio - 2, - "Expected priority to be changed to %d, not %d\n", - prio - 2, rv); + "Expected priority to be changed to %d, not %d\n", + prio - 2, rv); /* Restore the priority of the current thread (thread1) */ prio_args.prio = prio; irq_offload(test_isr, &prio_args); rv = k_thread_priority_get(k_current_get()); zassert_equal(rv, prio, - "Expected priority to be changed to %d, not %d\n", - prio, rv); + "Expected priority to be changed to %d, not %d\n", + prio, rv); /* create thread with lower priority */ int thread2_prio = prio + 1; k_tid_t thread2_id = k_thread_create(&tdata, tstack, STACK_SIZE, - thread2_set_prio_test, - NULL, NULL, NULL, thread2_prio, 0, - K_NO_WAIT); + thread2_set_prio_test, + NULL, NULL, NULL, thread2_prio, 0, + K_NO_WAIT); /* Lower the priority of thread2 */ prio_args.thread = thread2_id; @@ -177,8 +182,8 @@ ZTEST(threads_lifecycle, test_isr_threads_priority_set_) k_sem_give(&sem_thread2); k_sem_take(&sem_thread1, K_FOREVER); zassert_equal(thread2_data, thread2_prio + 2, - "Expected priority to be changed to %d, not %d\n", - thread2_prio + 2, thread2_data); + "Expected priority to be changed to %d, not %d\n", + thread2_prio + 2, thread2_data); /* Raise the priority of thread2 */ prio_args.prio = thread2_prio - 2; @@ -186,8 +191,8 @@ ZTEST(threads_lifecycle, test_isr_threads_priority_set_) k_sem_give(&sem_thread2); k_sem_take(&sem_thread1, K_FOREVER); zassert_equal(thread2_data, thread2_prio - 2, - "Expected priority to be changed to %d, not %d\n", - thread2_prio - 2, thread2_data); + "Expected priority to be changed to %d, not %d\n", + thread2_prio - 2, thread2_data); /* Restore the priority of thread2 */ prio_args.prio = thread2_prio; @@ -195,7 +200,7 @@ ZTEST(threads_lifecycle, test_isr_threads_priority_set_) k_sem_give(&sem_thread2); k_sem_take(&sem_thread1, K_FOREVER); zassert_equal(thread2_data, thread2_prio, - "Expected priority to be changed to %d, not %d\n", - thread2_prio, thread2_data); + "Expected priority to be changed to %d, not %d\n", + thread2_prio, thread2_data); k_thread_join(thread2_id, K_FOREVER); } diff --git a/tests/kernel/threads/thread_apis/src/test_threads_spawn.c b/tests/kernel/threads/thread_apis/src/test_threads_spawn.c index 7d4847c44d72..893ccaa1f6d3 100644 --- a/tests/kernel/threads/thread_apis/src/test_threads_spawn.c +++ b/tests/kernel/threads/thread_apis/src/test_threads_spawn.c @@ -129,7 +129,7 @@ ZTEST(threads_lifecycle, test_threads_spawn_forever) /** * @ingroup kernel_thread_tests - * @brief Validate behavior of multiple calls to k_thread_start() + * @brief Validate behavior of multiple calls to k_thread_start * * @details Call k_thread_start() on an already terminated thread * diff --git a/tests/kernel/threads/thread_apis/src/test_threads_suspend_resume.c b/tests/kernel/threads/thread_apis/src/test_threads_suspend_resume.c index bc23b5f67741..a5810bad4fdf 100644 --- a/tests/kernel/threads/thread_apis/src/test_threads_suspend_resume.c +++ b/tests/kernel/threads/thread_apis/src/test_threads_suspend_resume.c @@ -86,7 +86,7 @@ void suspend_myself(void *arg0, void *arg1, void *arg2) /** * @ingroup kernel_thread_tests * - * @brief Check that k_thread_suspend() is a schedule point when + * @brief Check that suspending a thread is a schedule point when * called on the current thread. */ ZTEST(threads_lifecycle, test_threads_suspend) @@ -121,7 +121,7 @@ void sleep_suspended(void *arg0, void *arg1, void *arg2) /** * @ingroup kernel_thread_tests - * @brief Check that k_thread_suspend() cancels a preexisting thread timeout + * @brief Check that suspending a thread cancels a preexisting thread timeout * * @details Suspended threads should not wake up unexpectedly if they * happened to have been sleeping when suspended. @@ -149,7 +149,7 @@ ZTEST(threads_lifecycle, test_threads_suspend_timeout) /** * @ingroup kernel_thread_tests - * @brief Check resume an unsuspend thread + * @brief Check resuming a thread that is not suspended * * @details Use k_thread_state_str() to get thread state. * Resume an unsuspend thread will not change the thread state. diff --git a/tests/lib/c_lib/common/src/main.c b/tests/lib/c_lib/common/src/main.c index 693e0cfd73ec..f5379d545846 100644 --- a/tests/lib/c_lib/common/src/main.c +++ b/tests/lib/c_lib/common/src/main.c @@ -65,17 +65,17 @@ volatile long long_max = LONG_MAX; volatile long long_one = 1L; /** - * * @brief Test implementation-defined constants library - * @defgroup libc_api + * @defgroup libc_api C Library APIs * @ingroup all_tests * @{ * */ - +/** + * @brief Test c library limits + */ ZTEST(libc_common, test_limits) { - zassert_true((long_max + long_one == LONG_MIN)); } @@ -84,13 +84,15 @@ static ssize_t foobar(void) return -1; } +/** + * @brief Test C library ssize_t + */ ZTEST(libc_common, test_ssize_t) { zassert_true(foobar() < 0); } /** - * * @brief Test boolean types and values library * */ @@ -110,7 +112,6 @@ volatile long long_variable; volatile size_t size_of_long_variable = sizeof(long_variable); /** - * * @brief Test standard type definitions library * */ @@ -132,7 +133,6 @@ volatile uint8_t unsigned_byte = 0xff; volatile uint32_t unsigned_int = 0xffffff00; /** - * * @brief Test integer types library * */ @@ -157,7 +157,6 @@ ZTEST(libc_common, test_stdint) } /** - * * @brief Test time_t to make sure it is at least 64 bits * */ @@ -179,7 +178,6 @@ ZTEST(libc_common, test_time_t) char buffer[BUFSIZE]; /** - * * @brief Test string memset * */ @@ -199,7 +197,6 @@ ZTEST(libc_common, test_memset) } /** - * * @brief Test string length function * * @see strlen(), strnlen(). @@ -216,7 +213,6 @@ ZTEST(libc_common, test_strlen) } /** - * * @brief Test string compare function * * @see strcmp(), strncasecmp(). @@ -669,7 +665,7 @@ ZTEST(libc_common, test_str_operate) * * @brief test strtol function * - * @detail in 32bit system: + * @details in 32bit system: * when base is 10, [-2147483648..2147483647] * in 64bit system: * when base is 10, @@ -1330,3 +1326,6 @@ ZTEST(libc_common, test_exit) zassert_equal(a, 0, "exit failed"); #endif } +/** + * @} + */ diff --git a/tests/lib/mem_alloc/src/main.c b/tests/lib/mem_alloc/src/main.c index 9cabe4367334..d9ccd151a934 100644 --- a/tests/lib/mem_alloc/src/main.c +++ b/tests/lib/mem_alloc/src/main.c @@ -35,8 +35,7 @@ TOOLCHAIN_DISABLE_GCC_WARNING(TOOLCHAIN_WARNING_ALLOC_SIZE_LARGER_THAN) /** * * @brief Test implementation-defined constants library - * @defgroup libc_api - * @ingroup all_tests + * @ingroup libc_api * @{ * */ @@ -349,10 +348,6 @@ ZTEST(c_lib_dynamic_memalloc, test_memalloc_all) reloc_ptr = NULL; } -/** - * @} - */ - /** * * @brief Test dynamic memory allocation upto maximum size @@ -375,4 +370,8 @@ ZTEST(c_lib_dynamic_memalloc, test_memalloc_max) } #endif +/** + * @} + */ + ZTEST_SUITE(c_lib_dynamic_memalloc, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/lib/multi_heap/src/test_mheap_api.c b/tests/lib/multi_heap/src/test_mheap_api.c index 1fba3b1b7e75..dff17cea2db9 100644 --- a/tests/lib/multi_heap/src/test_mheap_api.c +++ b/tests/lib/multi_heap/src/test_mheap_api.c @@ -180,7 +180,7 @@ static void realloc_handler(void *p1, void *p2, void *p3) /** * @brief Test to demonstrate k_malloc() and k_free() API usage * - * @ingroup kernel_heap_tests + * @ingroup k_heap_api_tests * * @details The test allocates 4 blocks from heap memory pool * using k_malloc() API. It also tries to allocate a block of size @@ -225,7 +225,7 @@ ZTEST(mheap_api, test_mheap_realloc) /** * @brief Test to demonstrate k_calloc() API functionality. * - * @ingroup kernel_heap_tests + * @ingroup k_heap_api_tests * * @details The test validates k_calloc() API. When requesting a * huge size of space or a space larger than heap memory, @@ -299,7 +299,7 @@ ZTEST(mheap_api, test_k_aligned_alloc) * a block of memory smaller than the pool and will fail when alloc * a block of memory larger than the pool. * - * @ingroup kernel_heap_tests + * @ingroup k_heap_api_tests * * @see k_thread_system_pool_assign(), z_thread_malloc(), k_free() */ @@ -328,7 +328,7 @@ ZTEST(mheap_api, test_sys_heap_mem_pool_assign) * memory because in this situation, the kernel will assign the heap memory * as resource pool. * - * @ingroup kernel_heap_tests + * @ingroup k_heap_api_tests * * @see z_thread_malloc(), k_free() */ @@ -347,7 +347,7 @@ ZTEST(mheap_api, test_malloc_in_isr) * * @details When a thread's resource pool is not assigned, alloc memory will fail. * - * @ingroup kernel_heap_tests + * @ingroup k_heap_api_tests * * @see z_thread_malloc() */ diff --git a/tests/lib/multi_heap/src/test_mheap_concept.c b/tests/lib/multi_heap/src/test_mheap_concept.c index 8821f4d3587a..efd331ad41e4 100644 --- a/tests/lib/multi_heap/src/test_mheap_concept.c +++ b/tests/lib/multi_heap/src/test_mheap_concept.c @@ -49,7 +49,7 @@ static void tmheap_malloc_align4_handler(void *p1, void *p2, void *p3) /** * @brief The test validates k_calloc() API. * - * @ingroup kernel_heap_tests + * @ingroup k_heap_api_tests * * @details The 8 blocks of memory of size 16 bytes are allocated * by k_calloc() API. When allocated using k_calloc() the memory buffers diff --git a/tests/lib/sprintf/src/main.c b/tests/lib/sprintf/src/main.c index d91c2d891f39..d582516a0b75 100644 --- a/tests/lib/sprintf/src/main.c +++ b/tests/lib/sprintf/src/main.c @@ -19,8 +19,7 @@ /** * * @brief Test implementation-defined constants library - * @defgroup libc_api - * @ingroup all_tests + * @ingroup libc_api * @{ * */ diff --git a/tests/posix/semaphores/prj.conf b/tests/posix/semaphores/prj.conf index 5376678d6a90..49b867610a0c 100644 --- a/tests/posix/semaphores/prj.conf +++ b/tests/posix/semaphores/prj.conf @@ -3,3 +3,7 @@ CONFIG_ZTEST=y CONFIG_POSIX_AEP_CHOICE_BASE=y CONFIG_POSIX_SEMAPHORES=y + +CONFIG_DYNAMIC_THREAD=y +CONFIG_DYNAMIC_THREAD_POOL_SIZE=2 +CONFIG_THREAD_STACK_INFO=y diff --git a/tests/posix/semaphores/src/main.c b/tests/posix/semaphores/src/main.c index 228165fb131f..c99e0fca1e95 100644 --- a/tests/posix/semaphores/src/main.c +++ b/tests/posix/semaphores/src/main.c @@ -13,6 +13,12 @@ #include #include +#define WAIT_TIME_MS 100 +BUILD_ASSERT(WAIT_TIME_MS > 0, "WAIT_TIME_MS must be posistive"); + +/* based on the current structure of this unit test */ +BUILD_ASSERT(CONFIG_DYNAMIC_THREAD_POOL_SIZE >= 2, "CONFIG_DYNAMIC_THREAD_POOL_SIZE must be >= 2"); + static void *child_func(void *p1) { sem_t *sem = (sem_t *)p1; @@ -51,11 +57,10 @@ static void semaphore_test(sem_t *sem) zassert_equal(clock_gettime(CLOCK_REALTIME, &abstime), 0, "clock_gettime failed"); - abstime.tv_sec += 5; + abstime.tv_sec += WAIT_TIME_MS / MSEC_PER_SEC; + abstime.tv_nsec += (WAIT_TIME_MS % MSEC_PER_SEC) * NSEC_PER_MSEC; - /* TESPOINT: Wait for 5 seconds and acquire sema given - * by thread1 - */ + /* TESPOINT: Wait to acquire sem given by thread1 */ zassert_equal(sem_timedwait(sem, &abstime), 0); /* TESTPOINT: Semaphore is already acquired, check if @@ -71,9 +76,7 @@ static void semaphore_test(sem_t *sem) zassert_equal(sem_getvalue(sem, &val), 0); zassert_equal(val, 1); - zassert_equal(sem_destroy(sem), -1, - "acquired semaphore" - " is destroyed"); + zassert_equal(sem_destroy(sem), -1, "acquired semaphore is destroyed"); zassert_equal(errno, EBUSY); /* TESTPOINT: take semaphore which is initialized with 1 */ @@ -312,14 +315,4 @@ ZTEST(posix_semaphores, test_named_semaphore) zassert_equal(nsem_get_list_len(), 0); } -static void before(void *arg) -{ - ARG_UNUSED(arg); - - if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { - /* skip redundant testing if there is no thread pool / heap allocation */ - ztest_test_skip(); - } -} - -ZTEST_SUITE(posix_semaphores, NULL, NULL, before, NULL, NULL); +ZTEST_SUITE(posix_semaphores, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/tests.dox b/tests/tests.dox new file mode 100644 index 000000000000..3f525c9d9386 --- /dev/null +++ b/tests/tests.dox @@ -0,0 +1,28 @@ +/** + +@brief Tests +@defgroup all_tests Tests +@{ +@} + +@defgroup kernel_fatal_tests Fatal Handling +@ingroup all_tests +@{ +@} + +@defgroup kernel_arch_sched_tests Architecture Context Switching / Swap +@ingroup all_tests +@{ +@} + +@defgroup kernel_arch_interrupt_tests Architecture Interrupt Handling +@ingroup all_tests +@{ +@} + +@defgroup kernel_memprotect_tests Memory Protection +@ingroup all_tests +@{ +@} + +*/ diff --git a/west.yml b/west.yml index 159c15ce9216..4ae20b9895bc 100644 --- a/west.yml +++ b/west.yml @@ -353,7 +353,7 @@ manifest: groups: - tee - name: trusted-firmware-m - revision: 857f3697ece6f44a663f007de71205a7b34974ef + revision: e2288c13ee0abc16163186523897e7910b03dd31 path: modules/tee/tf-m/trusted-firmware-m groups: - tee