diff --git a/components/esp_driver_i3c/i3c_master.c b/components/esp_driver_i3c/i3c_master.c index 06e18f035b..d53d2c6ad3 100644 --- a/components/esp_driver_i3c/i3c_master.c +++ b/components/esp_driver_i3c/i3c_master.c @@ -332,14 +332,14 @@ static esp_err_t i3c_pins_config(const i3c_master_bus_config_t *bus_config) { esp_err_t ret = ESP_OK; // SDA pin configurations - ESP_RETURN_ON_ERROR(gpio_set_level(bus_config->sda_io_num, 1), TAG, "i2c sda pin set level failed"); + ESP_RETURN_ON_ERROR(gpio_set_level(bus_config->sda_io_num, 1), TAG, "i3c sda pin set level failed"); gpio_input_enable(bus_config->sda_io_num); gpio_func_sel(bus_config->sda_io_num, PIN_FUNC_GPIO); gpio_matrix_output(bus_config->sda_io_num, i3c_master_periph_signal->sda_out_sig, 0, 0); gpio_matrix_input(bus_config->sda_io_num, i3c_master_periph_signal->sda_in_sig, 0); // SCL pin configurations - ESP_RETURN_ON_ERROR(gpio_set_level(bus_config->scl_io_num, 1), TAG, "i2c scl pin set level failed"); + ESP_RETURN_ON_ERROR(gpio_set_level(bus_config->scl_io_num, 1), TAG, "i3c scl pin set level failed"); gpio_input_enable(bus_config->scl_io_num); gpio_func_sel(bus_config->scl_io_num, PIN_FUNC_GPIO); gpio_matrix_output(bus_config->scl_io_num, i3c_master_periph_signal->scl_out_sig, 0, 0); @@ -445,7 +445,6 @@ static esp_err_t do_dma_transaction_handler(i3c_master_bus_handle_t bus_handle, { esp_err_t err = ESP_OK; bus_handle->cur_trans = trans; - printf("here, do dma\n"); portENTER_CRITICAL_SAFE(&bus_handle->spinlock); if (trans->scl_freq_hz > 400 * 1000) { @@ -509,7 +508,6 @@ static esp_err_t do_dma_transaction_handler(i3c_master_bus_handle_t bus_handle, portENTER_CRITICAL_SAFE(&bus_handle->spinlock); i3c_master_ll_start_transaction(bus_handle->hal.dev); portEXIT_CRITICAL_SAFE(&bus_handle->spinlock); - printf("here, start transaction\n"); return ESP_OK; } diff --git a/components/esp_driver_i3c/test_apps/i3c_test_apps/CMakeLists.txt b/components/esp_driver_i3c/test_apps/i3c_test_apps/CMakeLists.txt index 02b47e6f69..8341f9aa6d 100644 --- a/components/esp_driver_i3c/test_apps/i3c_test_apps/CMakeLists.txt +++ b/components/esp_driver_i3c/test_apps/i3c_test_apps/CMakeLists.txt @@ -27,5 +27,5 @@ endif() message(STATUS "Checking i3c registers are not read-write by half-word") include($ENV{IDF_PATH}/tools/ci/check_register_rw_half_word.cmake) -check_register_rw_half_word(SOC_MODULES "i3c_mst" "i3c_mst_mem" "hp_sys_clkrst" "lpperi" "lp_clkrst" - HAL_MODULES "i3c_master") +check_register_rw_half_word(SOC_MODULES "i3c_mst" "i3c_mst_mem" "hp_sys_clkrst" "i3c_slv" + HAL_MODULES "i3c_master" "i3c_slave") diff --git a/components/esp_driver_i3c/test_apps/i3c_test_apps/main/CMakeLists.txt b/components/esp_driver_i3c/test_apps/i3c_test_apps/main/CMakeLists.txt index a0e58cf55e..b5a62ea5d0 100644 --- a/components/esp_driver_i3c/test_apps/i3c_test_apps/main/CMakeLists.txt +++ b/components/esp_driver_i3c/test_apps/i3c_test_apps/main/CMakeLists.txt @@ -1,7 +1,8 @@ set(srcs "test_app_main.c" - "test_i3c_master_common.c" + "test_i3c_master_common.cpp" + "test_i3c_multi.cpp" ) idf_component_register(SRCS ${srcs} - PRIV_REQUIRES unity test_utils esp_driver_i3c + PRIV_REQUIRES unity test_utils esp_driver_i3c esp_driver_uart esp_driver_gpio WHOLE_ARCHIVE) diff --git a/components/esp_driver_i3c/test_apps/i3c_test_apps/main/test_app_main.c b/components/esp_driver_i3c/test_apps/i3c_test_apps/main/test_app_main.c index b9f22e5153..68c944844d 100644 --- a/components/esp_driver_i3c/test_apps/i3c_test_apps/main/test_app_main.c +++ b/components/esp_driver_i3c/test_apps/i3c_test_apps/main/test_app_main.c @@ -10,7 +10,7 @@ #include "esp_heap_caps.h" #include "sdkconfig.h" -#define LEAKS (100) +#define LEAKS (150) void setUp(void) { diff --git a/components/esp_driver_i3c/test_apps/i3c_test_apps/main/test_i3c_board.h b/components/esp_driver_i3c/test_apps/i3c_test_apps/main/test_i3c_board.h new file mode 100644 index 0000000000..eeacb6d37a --- /dev/null +++ b/components/esp_driver_i3c/test_apps/i3c_test_apps/main/test_i3c_board.h @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "sdkconfig.h" +#include "soc/gpio_num.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define I3C_SLAVE_SCL_IO GPIO_NUM_32 /*! +#include +#include "sdkconfig.h" +#include "unity.h" +#include "esp_err.h" +#include "soc/clk_tree_defs.h" +#include "esp_private/periph_ctrl.h" +#include "driver/i3c_master.h" +#include "driver/i3c_master_i2c.h" +#include "hal/i3c_slave_ll.h" +#include "esp_log.h" +#include "test_utils.h" +#include "test_i3c_board.h" +#include "esp_private/gpio.h" +#include "driver/gpio.h" +#include "esp_heap_caps.h" +#include "soc/gpio_sig_map.h" +#include "soc/io_mux_reg.h" +#include "soc/i3c_slv_struct.h" +#include "soc/i3c_slv_reg.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char TAG[] = "test-i3c"; + +static esp_err_t i3c_slave_pins_config(void) +{ + esp_err_t ret = ESP_OK; + // SDA pin configurations + gpio_input_enable(I3C_SLAVE_SDA_IO); + gpio_func_sel(I3C_SLAVE_SDA_IO, PIN_FUNC_GPIO); + gpio_matrix_output(I3C_SLAVE_SDA_IO, I3C_SLV_SDA_PAD_OUT_IDX, 0, 0); + gpio_matrix_input(I3C_SLAVE_SDA_IO, I3C_SLV_SDA_PAD_IN_IDX, 0); + + // SCL pin configurations + gpio_input_enable(I3C_SLAVE_SCL_IO); + gpio_func_sel(I3C_SLAVE_SCL_IO, PIN_FUNC_GPIO); + gpio_matrix_output(I3C_SLAVE_SCL_IO, I3C_SLV_SCL_PAD_OUT_IDX, 0, 0); + gpio_matrix_input(I3C_SLAVE_SCL_IO, I3C_SLV_SCL_PAD_IN_IDX, 0); + return ret; +} + +static void i3c_slave_init(void) +{ + PERIPH_RCC_ATOMIC() { + i3c_slave_ll_enable_bus_clock(&I3C_SLV, true); + i3c_slave_ll_reset_register(&I3C_SLV); + } + + i3c_slave_pins_config(); + i3c_slave_ll_config_static_address(&I3C_SLV, TEST_STATIC_ADDRESS); + i3c_slave_ll_enable_intr_mask(&I3C_SLV, I3C_SLAVE_LL_EVENT_INTR); + + i3c_slave_ll_unlock_register(&I3C_SLV, true); + i3c_slave_ll_set_transmit_fifo_threshold(&I3C_SLV, 1); + i3c_slave_ll_set_receive_fifo_threshold(&I3C_SLV, 1); +} + +static void i3c_i2c_slave_read_test(void) +{ + unity_wait_for_signal("i2c master init first"); + + uint8_t *temp_data = (uint8_t*)heap_caps_malloc(DATA_LENGTH, MALLOC_CAP_DEFAULT); + assert(temp_data); + + i3c_slave_init(); + + unity_send_signal("i2c slave init finish"); + + unity_wait_for_signal("master write"); + + i3c_slave_ll_read_data(&I3C_SLV, temp_data, DATA_LENGTH); + + ESP_LOG_BUFFER_HEX(TAG, temp_data, DATA_LENGTH); + + for (int i = 0; i < DATA_LENGTH; i++) { + TEST_ASSERT(temp_data[i] == i); + } + + unity_send_signal("ready to delete"); + free(temp_data); +} + +static void i3c_i2c_master_write_test(void) +{ + uint8_t data_wr[DATA_LENGTH] = { 0 }; + int i; + + i3c_master_bus_config_t i3c_mst_config = { + .sda_io_num = I3C_MASTER_SDA_IO, + .scl_io_num = I3C_MASTER_SCL_IO, + .clock_source = I3C_MASTER_CLK_SRC_DEFAULT, + .trans_queue_depth = 1, + .intr_priority = 0, + .flags = {0} + }; + i3c_master_bus_handle_t bus_handle; + gpio_pullup_en(I3C_MASTER_SCL_IO); + gpio_pullup_en(I3C_MASTER_SDA_IO); + + TEST_ESP_OK(i3c_new_master_bus(&i3c_mst_config, &bus_handle)); + + i3c_device_i2c_config_t dev_cfg = { + .device_address = TEST_STATIC_ADDRESS, + .scl_freq_hz = 100 * 1000 + }; + i3c_master_i2c_device_handle_t dev; + TEST_ESP_OK(i3c_master_bus_add_i2c_device(bus_handle, &dev_cfg, &dev)); + + unity_send_signal("i2c master init first"); + + unity_wait_for_signal("i2c slave init finish"); + + unity_send_signal("master write"); + for (i = 0; i < DATA_LENGTH; i++) { + data_wr[i] = i; + } + + ESP_LOG_BUFFER_HEX(TAG, data_wr, i); + + i3c_master_i2c_device_transmit(dev, data_wr, DATA_LENGTH, -1); + + unity_wait_for_signal("ready to delete"); + + TEST_ESP_OK(i3c_master_bus_rm_i2c_device(dev)); + TEST_ESP_OK(i3c_del_master_bus(bus_handle)); +} + +TEST_CASE_MULTIPLE_DEVICES("I3C-I2C master write slave test in fifo mode", "[i3c][test_env=generic_multi_device][timeout=150]", i3c_i2c_master_write_test, i3c_i2c_slave_read_test); + +static void i3c_i2c_master_read_slave_test(void) +{ + uint8_t data_rd[DATA_LENGTH] = {0}; + i3c_master_bus_config_t i3c_mst_config = { + .sda_io_num = I3C_MASTER_SDA_IO, + .scl_io_num = I3C_MASTER_SCL_IO, + .clock_source = I3C_MASTER_CLK_SRC_DEFAULT, + .trans_queue_depth = 1, + .intr_priority = 0, + .flags = {0} + }; + i3c_master_bus_handle_t bus_handle; + gpio_pullup_en(I3C_MASTER_SCL_IO); + gpio_pullup_en(I3C_MASTER_SDA_IO); + + TEST_ESP_OK(i3c_new_master_bus(&i3c_mst_config, &bus_handle)); + + i3c_device_i2c_config_t dev_cfg = { + .device_address = TEST_STATIC_ADDRESS, + .scl_freq_hz = 100 * 1000 + }; + i3c_master_i2c_device_handle_t dev; + TEST_ESP_OK(i3c_master_bus_add_i2c_device(bus_handle, &dev_cfg, &dev)); + + unity_wait_for_signal("i2c slave init finish"); + + i3c_master_i2c_device_receive(dev, data_rd, DATA_LENGTH, -1); + vTaskDelay(100 / portTICK_PERIOD_MS); + for (int i = 0; i < DATA_LENGTH; i++) { + printf("%x\n", data_rd[i]); + TEST_ASSERT(data_rd[i] == i); + } + unity_send_signal("ready to delete master read test"); + + TEST_ESP_OK(i3c_master_bus_rm_i2c_device(dev)); + TEST_ESP_OK(i3c_del_master_bus(bus_handle)); +} + +static void i3c_i2c_slave_write_buffer_test(void) +{ + + uint8_t data_wr[DATA_LENGTH]; + + i3c_slave_init(); + + for (int i = 0; i < DATA_LENGTH; i++) { + data_wr[i] = i; + } + + i3c_slave_ll_write_data(&I3C_SLV, data_wr, DATA_LENGTH); + + unity_send_signal("i2c slave init finish"); + + unity_wait_for_signal("ready to delete master read test"); +} + +TEST_CASE_MULTIPLE_DEVICES("I3C-I2C master read slave test in fifo mode", "[i3c][test_env=generic_multi_device][timeout=150]", i3c_i2c_master_read_slave_test, i3c_i2c_slave_write_buffer_test); + +static void i3c_i2c_master_write_via_dma_test(void) +{ + __attribute__((aligned(4))) uint8_t data_wr[DATA_LENGTH] = { 0 }; + int i; + + i3c_master_bus_config_t i3c_mst_config = { + .sda_io_num = I3C_MASTER_SDA_IO, + .scl_io_num = I3C_MASTER_SCL_IO, + .clock_source = I3C_MASTER_CLK_SRC_DEFAULT, + .trans_queue_depth = 1, + .intr_priority = 0, + .flags = {0} + }; + i3c_master_bus_handle_t bus_handle; + gpio_pullup_en(I3C_MASTER_SCL_IO); + gpio_pullup_en(I3C_MASTER_SDA_IO); + + TEST_ESP_OK(i3c_new_master_bus(&i3c_mst_config, &bus_handle)); + + i3c_device_i2c_config_t dev_cfg = { + .device_address = TEST_STATIC_ADDRESS, + .scl_freq_hz = 100 * 1000 + }; + i3c_master_i2c_device_handle_t dev; + TEST_ESP_OK(i3c_master_bus_add_i2c_device(bus_handle, &dev_cfg, &dev)); + + i3c_master_dma_config_t dma_config = { + .max_transfer_size = 50, + .dma_burst_size = 16, + }; + + i3c_master_bus_decorate_dma(bus_handle, &dma_config); + + unity_send_signal("i2c master init first"); + + unity_wait_for_signal("i2c slave init finish"); + + unity_send_signal("master write"); + for (i = 0; i < DATA_LENGTH; i++) { + data_wr[i] = i; + } + + ESP_LOG_BUFFER_HEX(TAG, data_wr, i); + i3c_master_i2c_device_transmit(dev, data_wr, DATA_LENGTH, -1); + + unity_wait_for_signal("ready to delete"); + + TEST_ESP_OK(i3c_master_bus_rm_i2c_device(dev)); + TEST_ESP_OK(i3c_master_bus_decorate_dma(bus_handle, NULL)); + TEST_ESP_OK(i3c_del_master_bus(bus_handle)); +} + +TEST_CASE_MULTIPLE_DEVICES("I3C-I2C master write slave test in dma mode", "[i3c][test_env=generic_multi_device][timeout=150]", i3c_i2c_master_write_via_dma_test, i3c_i2c_slave_read_test); diff --git a/components/esp_driver_i3c/test_apps/i3c_test_apps/pytest_i3c.py b/components/esp_driver_i3c/test_apps/i3c_test_apps/pytest_i3c.py index a7369b37ab..670f670b1f 100644 --- a/components/esp_driver_i3c/test_apps/i3c_test_apps/pytest_i3c.py +++ b/components/esp_driver_i3c/test_apps/i3c_test_apps/pytest_i3c.py @@ -18,3 +18,17 @@ from pytest_embedded_idf.utils import soc_filtered_targets @idf_parametrize('target', soc_filtered_targets('SOC_I3C_MASTER_SUPPORTED == 1'), indirect=['target']) def test_i3c(dut: Dut) -> None: dut.run_all_single_board_cases() + + +@pytest.mark.generic_multi_device +@pytest.mark.parametrize( + 'count, config', + [ + (2, 'release'), + (2, 'cache_safe'), + ], + indirect=True, +) +@idf_parametrize('target', soc_filtered_targets('SOC_I3C_MASTER_SUPPORTED == 1'), indirect=['target']) +def test_i3c_multi_device(case_tester) -> None: # type: ignore + case_tester.run_all_multi_dev_cases(reset=True) diff --git a/components/esp_hw_support/include/esp_private/periph_ctrl.h b/components/esp_hw_support/include/esp_private/periph_ctrl.h index a126750ba1..ea9910c315 100644 --- a/components/esp_hw_support/include/esp_private/periph_ctrl.h +++ b/components/esp_hw_support/include/esp_private/periph_ctrl.h @@ -84,7 +84,7 @@ void periph_rcc_exit(void); #ifdef __PERIPH_CTRL_ALLOW_LEGACY_API #define __PERIPH_CTRL_DEPRECATE_ATTR #else -#define __PERIPH_CTRL_DEPRECATE_ATTR __attribute__((deprecated("This function is not functional on "CONFIG_IDF_TARGET))) +#define __PERIPH_CTRL_DEPRECATE_ATTR __attribute__((deprecated("This function is not functional on " CONFIG_IDF_TARGET))) #endif /** diff --git a/components/hal/esp32p4/include/hal/i3c_master_ll.h b/components/hal/esp32p4/include/hal/i3c_master_ll.h index 4e2383be3c..ea0832c4ed 100644 --- a/components/hal/esp32p4/include/hal/i3c_master_ll.h +++ b/components/hal/esp32p4/include/hal/i3c_master_ll.h @@ -14,7 +14,6 @@ #include "soc/soc_caps.h" #include "soc/clk_tree_defs.h" #include "soc/hp_sys_clkrst_struct.h" -#include "soc/lpperi_struct.h" #include "hal/misc.h" #include "soc/i3c_mst_mem_struct.h" #include "soc/i3c_mst_struct.h" diff --git a/components/hal/esp32p4/include/hal/i3c_slave_ll.h b/components/hal/esp32p4/include/hal/i3c_slave_ll.h new file mode 100644 index 0000000000..0b72986f29 --- /dev/null +++ b/components/hal/esp32p4/include/hal/i3c_slave_ll.h @@ -0,0 +1,211 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// The LL layer for I3C slave register operations + +#include +#include +#include "hal/misc.h" +#include "hal/assert.h" +#include "soc/soc_caps.h" +#include "soc/clk_tree_defs.h" +#include "soc/hp_sys_clkrst_struct.h" +#include "hal/misc.h" +#include "soc/i3c_slv_struct.h" +#include "soc/i3c_slv_reg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define I3C_SLAVE_LL_EVENT_INTR (I3C_SLV_RXPEND_ENA_M | I3C_SLV_TXSEND_ENA_M) + + +/** + * @brief Enable or disable I3C slave bus clock + * + * @param hw I3C slave hardware pointer (currently unused) + * @param enable true: enable clock, false: disable clock + */ +static inline void i3c_slave_ll_enable_bus_clock(i3c_slv_dev_t *hw, bool enable) +{ + (void)hw; // Suppress unused parameter warning + HP_SYS_CLKRST.soc_clk_ctrl2.reg_i3c_slv_apb_clk_en = enable; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i3c_slave_ll_enable_bus_clock(...) do {(void)__DECLARE_RCC_ATOMIC_ENV; i3c_slave_ll_enable_bus_clock(__VA_ARGS__);} while(0) + +/** + * @brief Reset I3C slave registers + * + * Perform register reset by setting reset signal to 1 then 0 + * + * @param hw I3C slave hardware pointer (currently unused) + */ +static inline void i3c_slave_ll_reset_register(i3c_slv_dev_t *hw) +{ + (void)hw; // Suppress unused parameter warning + HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_i3cslv = 1; + HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_i3cslv = 0; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i3c_slave_ll_reset_register(...) do {(void)__DECLARE_RCC_ATOMIC_ENV; i3c_slave_ll_reset_register(__VA_ARGS__);} while(0) + +/** + * @brief Configure I3C slave static address + * + * @param hw I3C slave hardware pointer + * @param address 7-bit static address to set + */ +static inline void i3c_slave_ll_config_static_address(i3c_slv_dev_t *hw, uint8_t address) +{ + hw->config.saddr = address; +} + + +/** + * @brief Get pointer to I3C slave interrupt status register + * + * @param dev I3C slave hardware pointer + * @return volatile void* Pointer to interrupt masked status register + */ +static inline volatile void *i3c_slave_ll_get_interrupt_status_reg(i3c_slv_dev_t *dev) +{ + return &dev->intmasked; +} + + +/** + * @brief Clear I3C slave interrupt flags + * + * @param dev I3C slave hardware pointer + * @param mask Interrupt bit mask to clear + */ +static inline void i3c_slave_ll_clear_intr_mask(i3c_slv_dev_t *dev, uint32_t mask) +{ + dev->intclr.val = mask; +} + +/** + * @brief Enable I3C slave interrupt mask + * + * @param dev I3C slave hardware pointer + * @param mask Interrupt bit mask to enable + */ +static inline void i3c_slave_ll_enable_intr_mask(i3c_slv_dev_t *dev, uint32_t mask) +{ + dev->intset.val |= mask; +} + +/** + * @brief Disable I3C slave interrupt mask + * + * @param dev I3C slave hardware pointer + * @param mask Interrupt bit mask to disable + */ +static inline void i3c_slave_ll_disable_intr_mask(i3c_slv_dev_t *dev, uint32_t mask) +{ + dev->intset.val &= (~mask); +} + +/** + * @brief Get current I3C slave interrupt mask status + * + * @param dev I3C slave hardware pointer + * @param intr_status Pointer to store interrupt status + */ +static inline void i3c_slave_ll_get_intr_mask(i3c_slv_dev_t *dev, uint32_t *intr_status) +{ + *intr_status = dev->intmasked.val; +} + +/** + * @brief Write data to I3C slave device + * + * Write data to transmit FIFO byte by byte + * + * @param dev I3C slave hardware pointer + * @param data Pointer to data to write + * @param length Length of data to write (bytes) + */ +static inline void i3c_slave_ll_write_data(i3c_slv_dev_t *dev, const uint8_t *data, size_t length) +{ + for (size_t i = 0; i < length; i++) { + dev->wdatab.val = data[i]; + } +} + +/** + * @brief Get data length in I3C slave receive FIFO + * + * @param dev I3C slave hardware pointer + * @return size_t Number of bytes available to read in receive FIFO + */ +static inline size_t i3c_slave_ll_get_read_data_length(i3c_slv_dev_t *dev) +{ + return dev->datactrl.rxcount; +} + +/** + * @brief Read data from I3C slave device + * + * Read data from receive FIFO byte by byte + * + * @param dev I3C slave hardware pointer + * @param data Buffer to store read data + * @param length Length of data to read (bytes) + */ +static inline void i3c_slave_ll_read_data(i3c_slv_dev_t *dev, uint8_t *data, size_t length) +{ + for (size_t i = 0; i < length; i++) { + data[i] = dev->rdarab.data0; + } +} + +/** + * @brief Unlock or lock I3C slave registers + * + * @param dev I3C slave hardware pointer + * @param unlock true: unlock registers to allow modification, false: lock registers to prevent modification + */ +static inline void i3c_slave_ll_unlock_register(i3c_slv_dev_t *dev, bool unlock) +{ + dev->datactrl.unlock = unlock; +} + +/** + * @brief Set I3C slave transmit FIFO trigger level + * + * When transmit FIFO contains fewer bytes than this level, interrupt or DMA request will be triggered + * + * @param dev I3C slave hardware pointer + * @param threshold Transmit FIFO trigger level (0-3) + */ +static inline void i3c_slave_ll_set_transmit_fifo_threshold(i3c_slv_dev_t *dev, uint8_t threshold) +{ + dev->datactrl.txtrig = threshold; +} + +/** + * @brief Set I3C slave receive FIFO trigger level + * + * When receive FIFO reaches this level, interrupt or DMA request will be triggered + * + * @param dev I3C slave hardware pointer + * @param threshold Receive FIFO trigger level (0-3) + */ +static inline void i3c_slave_ll_set_receive_fifo_threshold(i3c_slv_dev_t *dev, uint8_t threshold) +{ + dev->datactrl.rxtrig = threshold; +} + +#ifdef __cplusplus +} +#endif