From d1338dedf90514ab2029949bbd097d8386e8a049 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Fri, 13 Sep 2024 17:06:11 +0700 Subject: [PATCH 1/3] drivers: introduce support Peripheral Sensor Interface (PSI5) driver This driver allows to communication (send, receive) with PSI5 device Signed-off-by: Cong Nguyen Huu --- MAINTAINERS.yml | 12 + doc/hardware/peripherals/index.rst | 1 + doc/hardware/peripherals/psi5.rst | 22 ++ drivers/CMakeLists.txt | 1 + drivers/Kconfig | 1 + drivers/psi5/CMakeLists.txt | 8 + drivers/psi5/Kconfig | 23 ++ drivers/psi5/Kconfig.nxp_s32 | 9 + drivers/psi5/psi5_nxp_s32.c | 480 +++++++++++++++++++++++++ dts/bindings/psi5/nxp,s32-psi5.yaml | 26 ++ dts/bindings/psi5/psi5-controller.yaml | 152 ++++++++ include/zephyr/drivers/psi5/psi5.h | 240 +++++++++++++ west.yml | 2 +- 13 files changed, 976 insertions(+), 1 deletion(-) create mode 100644 doc/hardware/peripherals/psi5.rst create mode 100644 drivers/psi5/CMakeLists.txt create mode 100644 drivers/psi5/Kconfig create mode 100644 drivers/psi5/Kconfig.nxp_s32 create mode 100644 drivers/psi5/psi5_nxp_s32.c create mode 100644 dts/bindings/psi5/nxp,s32-psi5.yaml create mode 100644 dts/bindings/psi5/psi5-controller.yaml create mode 100644 include/zephyr/drivers/psi5/psi5.h diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 758e976df35297..e9d94a92a4422e 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1942,6 +1942,18 @@ Release Notes: tests: - sample.drivers.espi.ps2 +"Drivers: PSI5": + status: maintained + maintainers: + - congnguyenhuu + files: + - drivers/psi5/ + - include/zephyr/drivers/psi5/ + - dts/bindings/psi5/ + - doc/hardware/peripherals/psi5.rst + labels: + - "area: PSI5" + "Drivers: PTP Clock": status: maintained maintainers: diff --git a/doc/hardware/peripherals/index.rst b/doc/hardware/peripherals/index.rst index 2a7405aced2baf..d24f485819cbb5 100644 --- a/doc/hardware/peripherals/index.rst +++ b/doc/hardware/peripherals/index.rst @@ -48,6 +48,7 @@ Peripherals pcie.rst peci.rst ps2.rst + psi5.rst pwm.rst rtc.rst regulators.rst diff --git a/doc/hardware/peripherals/psi5.rst b/doc/hardware/peripherals/psi5.rst new file mode 100644 index 00000000000000..adcafdf27ba8d5 --- /dev/null +++ b/doc/hardware/peripherals/psi5.rst @@ -0,0 +1,22 @@ +.. _psi5_api: + +Peripheral Sensor Interface (PSI5) +################################## + +Overview +******** + +The PSI5 API provides functionality to communicate with Peripheral Sensor Interface (PSI5) +devices. + +Configuration Options +********************* + +Related configuration options: + +* :kconfig:option:`CONFIG_PSI5` + +API Reference +************* + +.. doxygengroup:: psi5_interface diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 2536e2011710c0..e2a1ac10cbbd54 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -73,6 +73,7 @@ add_subdirectory_ifdef(CONFIG_PINCTRL pinctrl) add_subdirectory_ifdef(CONFIG_PM_CPU_OPS pm_cpu_ops) add_subdirectory_ifdef(CONFIG_POWER_DOMAIN power_domain) add_subdirectory_ifdef(CONFIG_PS2 ps2) +add_subdirectory_ifdef(CONFIG_PSI5 psi5) add_subdirectory_ifdef(CONFIG_PTP_CLOCK ptp_clock) add_subdirectory_ifdef(CONFIG_PWM pwm) add_subdirectory_ifdef(CONFIG_REGULATOR regulator) diff --git a/drivers/Kconfig b/drivers/Kconfig index 65f097f2acc97f..ae3f14521cdbd9 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -70,6 +70,7 @@ source "drivers/pinctrl/Kconfig" source "drivers/pm_cpu_ops/Kconfig" source "drivers/power_domain/Kconfig" source "drivers/ps2/Kconfig" +source "drivers/psi5/Kconfig" source "drivers/ptp_clock/Kconfig" source "drivers/pwm/Kconfig" source "drivers/regulator/Kconfig" diff --git a/drivers/psi5/CMakeLists.txt b/drivers/psi5/CMakeLists.txt new file mode 100644 index 00000000000000..2ffb128051201b --- /dev/null +++ b/drivers/psi5/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/psi5/psi5.h) + +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_PSI5_NXP_S32 psi5_nxp_s32.c) diff --git a/drivers/psi5/Kconfig b/drivers/psi5/Kconfig new file mode 100644 index 00000000000000..03b2a3d4d6a9cc --- /dev/null +++ b/drivers/psi5/Kconfig @@ -0,0 +1,23 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +menuconfig PSI5 + bool "Peripheral Sensor Interface (PSI5) driver" + help + Enable PSI5 Driver Configuration + +if PSI5 + +module = PSI5 +module-str = psi5 +source "subsys/logging/Kconfig.template.log_config" + +config PSI5_INIT_PRIORITY + int "PSI5 driver init priority" + default KERNEL_INIT_PRIORITY_DEVICE + help + PSI5 driver device initialization priority. + +source "drivers/psi5/Kconfig.nxp_s32" + +endif # PSI5 diff --git a/drivers/psi5/Kconfig.nxp_s32 b/drivers/psi5/Kconfig.nxp_s32 new file mode 100644 index 00000000000000..3d2d70f14a910a --- /dev/null +++ b/drivers/psi5/Kconfig.nxp_s32 @@ -0,0 +1,9 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config PSI5_NXP_S32 + bool "NXP S32 PSI5 driver" + default y + depends on DT_HAS_NXP_S32_PSI5_ENABLED + help + Enable support for NXP S32 PSI5 driver. diff --git a/drivers/psi5/psi5_nxp_s32.c b/drivers/psi5/psi5_nxp_s32.c new file mode 100644 index 00000000000000..45a7c224686e29 --- /dev/null +++ b/drivers/psi5/psi5_nxp_s32.c @@ -0,0 +1,480 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_s32_psi5 + +#include + +LOG_MODULE_REGISTER(nxp_s32_psi5, CONFIG_PSI5_LOG_LEVEL); + +#include +#include +#include + +#include + +#include "Psi5_Ip.h" + +struct psi5_nxp_s32_config { + uint8_t ctrl_inst; + PSI5_Type *base; + uint8_t channel_mask; + const struct pinctrl_dev_config *pin_cfg; + void (*irq_config_func)(void); +}; + +struct psi5_nxp_s32_tx_callback { + psi5_tx_callback_t callback; + void *user_data; +}; +struct psi5_nxp_s32_rx_callback { + psi5_rx_callback_t callback; + struct psi5_frame frame; + void *user_data; +}; + +struct psi5_nxp_s32_channel_data { + boolean started; + bool async_mode; + struct psi5_nxp_s32_tx_callback tx_callback; + struct psi5_nxp_s32_rx_callback rx_callback; + struct k_sem tx_sem; + struct k_mutex lock; +}; + +struct psi5_nxp_s32_data { + struct psi5_nxp_s32_channel_data channel_data[PSI5_CHANNEL_COUNT]; +}; + +static int psi5_nxp_s32_start_sync(const struct device *dev, uint8_t channel) +{ + const struct psi5_nxp_s32_config *config = dev->config; + struct psi5_nxp_s32_data *data = dev->data; + struct psi5_nxp_s32_channel_data *channel_data = &data->channel_data[channel]; + int err; + + if (!(config->channel_mask & BIT(channel))) { + return -EINVAL; + } + + if (channel_data->started) { + return -EALREADY; + } + + k_mutex_lock(&channel_data->lock, K_FOREVER); + + err = Psi5_Ip_SetChannelSync(config->ctrl_inst, channel, true); + + if (err) { + LOG_ERR("Failed to start sync PSI5 %d channel %d", config->ctrl_inst, channel); + k_mutex_unlock(&channel_data->lock); + return -EIO; + } + + k_mutex_unlock(&channel_data->lock); + + channel_data->started = true; + + return 0; +} + +static int psi5_nxp_s32_stop_sync(const struct device *dev, uint8_t channel) +{ + const struct psi5_nxp_s32_config *config = dev->config; + struct psi5_nxp_s32_data *data = dev->data; + struct psi5_nxp_s32_channel_data *channel_data = &data->channel_data[channel]; + int err; + + if (!(config->channel_mask & BIT(channel))) { + return -EINVAL; + } + + if (!channel_data->started) { + return -EALREADY; + } + + k_mutex_lock(&channel_data->lock, K_FOREVER); + + err = Psi5_Ip_SetChannelSync(config->ctrl_inst, channel, false); + + if (err) { + LOG_ERR("Failed to stop sync PSI5 %d channel %d", config->ctrl_inst, channel); + k_mutex_unlock(&channel_data->lock); + return -EIO; + } + + channel_data->started = false; + + k_mutex_unlock(&channel_data->lock); + + return 0; +} + +static int psi5_nxp_s32_send(const struct device *dev, uint8_t channel, uint64_t psi5_data, + k_timeout_t timeout, psi5_tx_callback_t callback, void *user_data) +{ + const struct psi5_nxp_s32_config *config = dev->config; + struct psi5_nxp_s32_data *data = dev->data; + struct psi5_nxp_s32_channel_data *channel_data = &data->channel_data[channel]; + int err; + uint64_t start_time; + + if (!(config->channel_mask & BIT(channel))) { + return -EINVAL; + } + + if (!channel_data->started) { + return -ENETDOWN; + } + + if (channel_data->async_mode) { + return -ENOTSUP; + } + + if (k_sem_take(&channel_data->tx_sem, timeout) != 0) { + return -EAGAIN; + } + + if (callback != NULL) { + channel_data->tx_callback.callback = callback; + channel_data->tx_callback.user_data = user_data; + } + + k_mutex_lock(&channel_data->lock, K_FOREVER); + + err = Psi5_Ip_Transmit(config->ctrl_inst, channel, psi5_data); + + if (err) { + LOG_ERR("Failed to transmit PSI5 %d channel %d (err %d)", config->ctrl_inst, + channel, err); + k_sem_give(&channel_data->tx_sem); + goto unlock; + return -EIO; + } + + if (callback != NULL) { + goto unlock; + return 0; + } + + start_time = k_uptime_ticks(); + + while (!Psi5_Ip_GetTransmissionStatus(config->ctrl_inst, channel)) { + if (k_uptime_ticks() - start_time >= timeout.ticks) { + LOG_ERR("Timeout for waiting transmision PSI5 %d channel %d", + config->ctrl_inst, channel); + k_sem_give(&channel_data->tx_sem); + goto unlock; + return -EAGAIN; + } + } + + k_sem_give(&channel_data->tx_sem); + +unlock: + k_mutex_unlock(&channel_data->lock); + + return 0; +} + +static int psi5_nxp_s32_add_rx_callback(const struct device *dev, uint8_t channel, + psi5_rx_callback_t callback, void *user_data) +{ + const struct psi5_nxp_s32_config *config = dev->config; + struct psi5_nxp_s32_data *data = dev->data; + struct psi5_nxp_s32_channel_data *channel_data = &data->channel_data[channel]; + + if (!(config->channel_mask & BIT(channel))) { + return -EINVAL; + } + + k_mutex_lock(&channel_data->lock, K_FOREVER); + + channel_data->rx_callback.callback = callback; + channel_data->rx_callback.user_data = user_data; + + k_mutex_unlock(&channel_data->lock); + + return 0; +} + +static DEVICE_API(psi5, psi5_nxp_s32_driver_api) = { + .start_sync = psi5_nxp_s32_start_sync, + .stop_sync = psi5_nxp_s32_stop_sync, + .send = psi5_nxp_s32_send, + .add_rx_callback = psi5_nxp_s32_add_rx_callback, +}; + +#define PSI5_NXP_S32_HW_INSTANCE_CHECK(i, n) ((DT_INST_REG_ADDR(n) == IP_PSI5_##i##_BASE) ? i : 0) + +#define PSI5_NXP_S32_HW_INSTANCE(n) \ + LISTIFY(PSI5_INSTANCE_COUNT, PSI5_NXP_S32_HW_INSTANCE_CHECK, (|), n) + +#define PSI5_NXP_S32_CHANNEL_CALLBACK(node_id) \ + void _CONCAT(psi5_nxp_s32_channel_callBack, node_id)(Psi5_EventType event) \ + { \ + const struct device *dev = DEVICE_DT_GET(DT_PARENT(node_id)); \ + const struct psi5_nxp_s32_config *config = dev->config; \ + Psi5_Ip_Psi5FrameType ip_frame; \ + Psi5_Ip_SmcFrameType ip_smc_frame; \ + uint8_t channel = DT_REG_ADDR(node_id); \ + struct psi5_nxp_s32_data *data = dev->data; \ + struct psi5_nxp_s32_channel_data *channel_data = &data->channel_data[channel]; \ + struct psi5_nxp_s32_tx_callback *tx_callback = &channel_data->tx_callback; \ + struct psi5_nxp_s32_rx_callback *rx_callback = &channel_data->rx_callback; \ + \ + if (event.Psi5_DriverReadyToTransmit) { \ + if (tx_callback->callback) { \ + tx_callback->callback(dev, channel, PSI5_TX_READY, \ + tx_callback->user_data); \ + } \ + k_sem_give(&channel_data->tx_sem); \ + } else if (event.Psi5_TxDataOverwrite) { \ + if (tx_callback->callback) { \ + tx_callback->callback(dev, channel, PSI5_TX_ERR, \ + tx_callback->user_data); \ + } \ + k_sem_give(&channel_data->tx_sem); \ + } else if (event.Psi5_Psi5MessageReceived) { \ + Psi5_Ip_GetPsi5Frame(config->ctrl_inst, channel, &ip_frame); \ + \ + rx_callback->frame.data_frame.data = ip_frame.DATA_REGION; \ + rx_callback->frame.data_frame.timestamp = ip_frame.TIME_STAMP; \ + rx_callback->frame.data_frame.crc = ip_frame.CRC; \ + rx_callback->frame.data_frame.slot_number = ip_frame.SLOT_COUNTER; \ + \ + if (rx_callback->callback) { \ + rx_callback->callback(dev, channel, &rx_callback->frame, \ + !!(ip_frame.C | ip_frame.F | ip_frame.EM | \ + ip_frame.E | ip_frame.T) \ + ? PSI5_RX_ERR \ + : PSI5_DATA_FRAME_RECEIVED, \ + rx_callback->user_data); \ + } \ + } else if (event.Psi5_SmcMessageReceived) { \ + Psi5_Ip_GetSmcFrame(config->ctrl_inst, channel, &ip_smc_frame); \ + \ + if (ip_smc_frame.C) { \ + rx_callback->frame.smc_data_frame.id = ip_smc_frame.ID; \ + rx_callback->frame.smc_data_frame.data = \ + FIELD_PREP(GENMASK(15, 12), (ip_smc_frame.IDDATA)) | \ + FIELD_PREP(GENMASK(11, 0), (ip_smc_frame.DATA)); \ + } else { \ + rx_callback->frame.smc_data_frame.id = \ + FIELD_PREP(GENMASK(7, 4), (ip_smc_frame.ID)) | \ + FIELD_PREP(GENMASK(3, 0), (ip_smc_frame.IDDATA)); \ + rx_callback->frame.smc_data_frame.data = ip_smc_frame.DATA; \ + } \ + rx_callback->frame.smc_data_frame.crc = ip_smc_frame.CRC; \ + rx_callback->frame.smc_data_frame.slot_number = ip_smc_frame.SLOT_NO; \ + \ + if (rx_callback->callback) { \ + rx_callback->callback(dev, channel, &rx_callback->frame, \ + !!(ip_smc_frame.CER | ip_smc_frame.OW) \ + ? PSI5_RX_ERR \ + : PSI5_SMC_DATA_FRAME_RECEIVED, \ + rx_callback->user_data); \ + } \ + } else { \ + if (rx_callback->callback) { \ + rx_callback->callback(dev, channel, NULL, PSI5_RX_ERR, \ + rx_callback->user_data); \ + } \ + } \ + } + +#define _PSI5_NXP_S32_CHANNEL_RX_SLOT_CONFIG(i, node_id) \ + { \ + .slotId = UTIL_INC(i), \ + .slotLen = DT_PROP_BY_IDX(node_id, array_slot_duration_us, i), \ + .startOffs = DT_PROP_BY_IDX(node_id, array_slot_start_offset_us, i), \ + .dataSize = DT_PROP_BY_IDX(node_id, array_slot_data_length, i), \ + .msbFirst = DT_PROP_BY_IDX(node_id, array_slot_data_msb_first, i), \ + .hasSMC = DT_PROP_BY_IDX(node_id, array_slot_has_smc, i), \ + .hasParity = DT_PROP_BY_IDX(node_id, array_slot_has_parity, i), \ + }, + +#define PSI5_NXP_S32_CHANNEL_RX_SLOT_CONFIG(node_id) \ + BUILD_ASSERT(DT_PROP_LEN(node_id, array_slot_duration_us) == \ + DT_PROP_LEN(node_id, array_slot_start_offset_us) && \ + DT_PROP_LEN(node_id, array_slot_duration_us) == \ + DT_PROP_LEN(node_id, array_slot_data_length) && \ + DT_PROP_LEN(node_id, array_slot_duration_us) == \ + DT_PROP_LEN(node_id, array_slot_data_msb_first) && \ + DT_PROP_LEN(node_id, array_slot_duration_us) == \ + DT_PROP_LEN(node_id, array_slot_has_smc) && \ + DT_PROP_LEN(node_id, array_slot_duration_us) == \ + DT_PROP_LEN(node_id, array_slot_has_parity), \ + "Invalid channel RX slot configuration"); \ + static const Psi5_Ip_SlotConfigType _CONCAT( \ + psi5_nxp_s32_channel_rx_slot_config, \ + node_id)[DT_PROP_LEN(node_id, array_slot_duration_us)] = { \ + LISTIFY(DT_PROP_LEN(node_id, array_slot_duration_us), \ + _PSI5_NXP_S32_CHANNEL_RX_SLOT_CONFIG, (), node_id)}; + +#define PSI5_NXP_S32_CHANNEL_RX_CONFIG(node_id) \ + const Psi5_Ip_ChannelRxConfigType _CONCAT(psi5_nxp_s32_channel_rx_config, node_id) = { \ + .rxBufSize = DT_PROP(node_id, num_rx_buf), \ + .bitRate = DT_ENUM_IDX(node_id, rx_bitrate_kbps), \ + .slotConfig = &_CONCAT(psi5_nxp_s32_channel_rx_slot_config, node_id)[0], \ + .numOfSlotConfigs = DT_PROP_LEN(node_id, array_slot_duration_us), \ + .watermarkInterruptLevel = GENMASK(UTIL_DEC(DT_PROP(node_id, num_rx_buf)), 0), \ + }; + +#define PSI5_NXP_S32_CHANNEL_TX_CONFIG(node_id) \ + const Psi5_Ip_ChannelTxConfigType _CONCAT(psi5_nxp_s32_channel_tx_config, node_id) = { \ + .targetPulse = DT_PROP(node_id, period_sync_pulse_us), \ + .decoderOffset = DT_PROP(node_id, decoder_start_offset_us), \ + .pulse0Width = DT_PROP(node_id, sync_pulse_width_0_us), \ + .pulse1Width = DT_PROP(node_id, sync_pulse_width_1_us), \ + .txMode = DT_ENUM_IDX(node_id, tx_mode), \ + .syncState = PSI5_SYNC_STATE_2, \ + .txSize = 64, /* This setting is applicable only in NON STANDARD FRAME */ \ + }; + +#define PSI5_NXP_S32_CHANNEL_ERR_SEL_CONFIG(node_id) \ + const Psi5_Ip_ErrorSelectConfigType _CONCAT(psi5_nxp_s32_channel_err_sel_config, \ + node_id) = { \ + .errorSelect0 = true, \ + .errorSelect1 = true, \ + .errorSelect2 = true, \ + .errorSelect3 = true, \ + .errorSelect4 = true, \ + }; + +/* + * The macro get index of array configuration that corresponds to each the ID of HW channel. + * Assign 0xff to unused channels. + */ + +#define PSI5_NXP_S32_CHANNEL_NODE(n, i) DT_INST_CHILD(n, DT_CAT(ch_, i)) + +#define PSI5_NXP_S32_ID_CFG_CNT(i, node_id, n) \ + (DT_NODE_HAS_STATUS(PSI5_NXP_S32_CHANNEL_NODE(n, i), okay) && \ + (DT_REG_ADDR(PSI5_NXP_S32_CHANNEL_NODE(n, i)) < (DT_REG_ADDR(node_id))) \ + ? 1 \ + : 0) + +#define PSI5_NXP_S32_ID_CFG(node_id, n) \ + COND_CODE_1(DT_NODE_HAS_STATUS(node_id, okay), \ + (LISTIFY(PSI5_CHANNEL_COUNT, PSI5_NXP_S32_ID_CFG_CNT, (+), node_id, n),), (0xff,)) + +#define PSI5_NXP_S32_CHANNEL_CONFIG(node_id) \ + { \ + .channelId = DT_REG_ADDR(node_id), \ + .channelMode = !DT_PROP(node_id, async_mode), \ + .callback = _CONCAT(psi5_nxp_s32_channel_callBack, node_id), \ + .rxConfig = &_CONCAT(psi5_nxp_s32_channel_rx_config, node_id), \ + .txConfig = &_CONCAT(psi5_nxp_s32_channel_tx_config, node_id), \ + .errorSelectConfig = &_CONCAT(psi5_nxp_s32_channel_err_sel_config, node_id), \ + }, + +/* Define array channel configuration */ +#define PSI5_NXP_S32_ARRAY_CHANNEL_CONFIG(n) \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(n, PSI5_NXP_S32_CHANNEL_CALLBACK) \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(n, PSI5_NXP_S32_CHANNEL_RX_SLOT_CONFIG) \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(n, PSI5_NXP_S32_CHANNEL_RX_CONFIG) \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(n, PSI5_NXP_S32_CHANNEL_TX_CONFIG) \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(n, PSI5_NXP_S32_CHANNEL_ERR_SEL_CONFIG) \ + const Psi5_Ip_ChannelConfigType \ + psi5_nxp_s32_channel_array_config_##n[DT_INST_CHILD_NUM_STATUS_OKAY(n)] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(n, PSI5_NXP_S32_CHANNEL_CONFIG)}; \ + const uint8_t psi5_nxp_s32_map_idex_array_config_##n[PSI5_CHANNEL_COUNT] = { \ + DT_INST_FOREACH_CHILD_VARGS(n, PSI5_NXP_S32_ID_CFG, n)}; + +DT_INST_FOREACH_STATUS_OKAY(PSI5_NXP_S32_ARRAY_CHANNEL_CONFIG) + +/* Define array instance configuration */ +#define PSI5_NXP_S32_INST_CONFIG(n) \ + { \ + .instanceId = PSI5_NXP_S32_HW_INSTANCE(n), \ + .channelConfig = &psi5_nxp_s32_channel_array_config_##n[0], \ + .numOfChannels = DT_INST_CHILD_NUM_STATUS_OKAY(n), \ + .chHwIdToIndexArrayConfig = &psi5_nxp_s32_map_idex_array_config_##n[0], \ + }, + +static const Psi5_Ip_InstanceType psi5_nxp_s32_array_inst_config[DT_NUM_INST_STATUS_OKAY( + DT_DRV_COMPAT)] = {DT_INST_FOREACH_STATUS_OKAY(PSI5_NXP_S32_INST_CONFIG)}; + +/* The structure configuration for all controller instances that used for Psi5_Ip_Init() */ +static const Psi5_Ip_ConfigType psi5_nxp_s32_controller_config = { + .instancesConfig = &psi5_nxp_s32_array_inst_config[0], + .numOfInstances = DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT), +}; + +#define PSI5_NXP_S32_CHANNEL_ISR(node_id) \ + static void _CONCAT(psi5_nxp_s32_channel_isr, node_id)(const struct device *dev) \ + { \ + const struct psi5_nxp_s32_config *config = dev->config; \ + \ + Psi5_Ip_IRQ_Handler(config->ctrl_inst, DT_REG_ADDR(node_id)); \ + } + +#define PSI5_NXP_S32_CHANNEL_IRQ_CONFIG(node_id, n) \ + do { \ + IRQ_CONNECT(DT_IRQ_BY_IDX(node_id, 0, irq), DT_IRQ_BY_IDX(node_id, 0, priority), \ + _CONCAT(psi5_nxp_s32_channel_isr, node_id), DEVICE_DT_INST_GET(n), \ + DT_IRQ_BY_IDX(node_id, 0, flags)); \ + irq_enable(DT_IRQN(node_id)); \ + } while (false); + +#define PSI5_NXP_S32_IRQ_CONFIG(n) \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(n, PSI5_NXP_S32_CHANNEL_ISR) \ + static void psi5_irq_config_##n(void) \ + { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY_VARGS(n, PSI5_NXP_S32_CHANNEL_IRQ_CONFIG, n) \ + } + +#define PSI5_NXP_S32_CHANNEL_BIT_MASK(node_id) BIT(DT_REG_ADDR(node_id)) + +#define PSI5_NXP_S32_CHANNEL_ASYNC_MODE(node_id) \ + data->channel_data[DT_REG_ADDR(node_id)].async_mode = DT_PROP(node_id, async_mode); + +#define DEV_PSI5_NXP_S32_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + PSI5_NXP_S32_IRQ_CONFIG(n) \ + static struct psi5_nxp_s32_config psi5_nxp_s32_config_##n = { \ + .ctrl_inst = PSI5_NXP_S32_HW_INSTANCE(n), \ + .base = (PSI5_Type *)DT_INST_REG_ADDR(n), \ + .channel_mask = DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP( \ + n, PSI5_NXP_S32_CHANNEL_BIT_MASK, (|)), \ + .pin_cfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .irq_config_func = psi5_irq_config_##n, \ + }; \ + static struct psi5_nxp_s32_data psi5_nxp_s32_data_##n; \ + static int psi5_nxp_s32_init_##n(const struct device *dev) \ + { \ + const struct psi5_nxp_s32_config *config = dev->config; \ + struct psi5_nxp_s32_data *data = dev->data; \ + int err = 0; \ + \ + err = pinctrl_apply_state(config->pin_cfg, PINCTRL_STATE_DEFAULT); \ + if (err < 0) { \ + LOG_ERR("PSI5 pinctrl setup failed (%d)", err); \ + return err; \ + } \ + \ + for (int i = 0; i < PSI5_CHANNEL_COUNT; i++) { \ + k_sem_init(&data->channel_data[i].tx_sem, 1, 1); \ + k_mutex_init(&data->channel_data[i].lock); \ + } \ + \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(n, PSI5_NXP_S32_CHANNEL_ASYNC_MODE) \ + \ + /* Common configuration setup for all controller instances */ \ + if (n == UTIL_DEC(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT))) { \ + Psi5_Ip_Init(&psi5_nxp_s32_controller_config); \ + } \ + \ + config->irq_config_func(); \ + \ + return 0; \ + } \ + DEVICE_DT_INST_DEFINE(n, psi5_nxp_s32_init_##n, NULL, &psi5_nxp_s32_data_##n, \ + &psi5_nxp_s32_config_##n, POST_KERNEL, CONFIG_PSI5_INIT_PRIORITY, \ + &psi5_nxp_s32_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(DEV_PSI5_NXP_S32_INIT) diff --git a/dts/bindings/psi5/nxp,s32-psi5.yaml b/dts/bindings/psi5/nxp,s32-psi5.yaml new file mode 100644 index 00000000000000..02ced284c92c2e --- /dev/null +++ b/dts/bindings/psi5/nxp,s32-psi5.yaml @@ -0,0 +1,26 @@ +# Copyright 2025 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +description: Properties for Peripheral Sensor Interface (PSI5) + +compatible: "nxp,s32-psi5" + +include: [psi5-controller.yaml, pinctrl-device.yaml] + +properties: + pinctrl-0: + required: true + + pinctrl-names: + required: true + +child-binding: + + include: base.yaml + + compatible: "nxp,s32-psi5-channel" + + properties: + interrupts: + required: true diff --git a/dts/bindings/psi5/psi5-controller.yaml b/dts/bindings/psi5/psi5-controller.yaml new file mode 100644 index 00000000000000..12928ba73b6f1a --- /dev/null +++ b/dts/bindings/psi5/psi5-controller.yaml @@ -0,0 +1,152 @@ +# Copyright 2025 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +description: Properties for Peripheral Sensor Interface (PSI5) + +include: base.yaml + +properties: + reg: + required: true + +child-binding: + description: Properties for Peripheral Sensor Interface (PSI5) channel + + properties: + reg: + type: array + required: true + description: Channel identifier. + + async-mode: + type: boolean + description: | + Determines the channel operation mode. When set to true, the channel operates in + asynchronous mode with only the receive function active. When set to false, + the channel operates in synchronous mode with both transmit and receive functions active. + + period-sync-pulse-us: + type: int + required: true + description: | + Specifies the period of the internally generated synchronization pulses, measured in + microseconds (us). This value determines the length of each synchronization pulse used + in the system. + + sync-pulse-width-0-us: + required: true + type: int + description: | + Specifies the duration of the synchronization pulse width for a logic '0', measured in + microseconds (us). + + sync-pulse-width-1-us: + required: true + type: int + description: | + Specifies the duration of the synchronization pulse width for a logic '1', measured in + microseconds (us). + + decoder-start-offset-us: + type: int + required: true + description: | + Specifies the duration for which the Manchester decoder remains inactive after the + falling edge of a synchronization pulse, measured in microseconds (us). This value + determines the delay before the decoder starts processing incoming signals again. + + tx-mode: + type: string + required: true + enum: + - short-frame-31 + - short-frame-5 + - long-frame-31 + - long-frame-5 + - x-long-frame-31 + - x-long-frame-5 + - xx-long-frame + - non-standard-frame + description: | + Specifies the transmitter mode. Each mode defines the frame length and + the start condition for data transmission: + - short-frame-31: Short Frame (V1.3) with 31 "1s" as the start condition + - short-frame-5: Short Frame (V1.3) with 5 "0s" as the start condition + - long-frame-31: Long Frame (V1.3) with 31 "1s" as the start condition + - long-frame-5: Long Frame (V1.3) with 5 "0s" as the start condition + - x-long-fram-31: X-Long Frame (V1.3) with 31 "1s" as the start condition + - x-long-frame-5: X-Long Frame (V1.3) with 5 "0s" as the start condition + - xx-long-frame: XX-Long (V2.0) + - non-standard-frame: Non Standard Length + + num-rx-buf: + type: int + required: true + description: | + Specifies the maximum number of receive buffers used for storing PSI5 messages. + The value can range from 1 to 32, determining how many messages can be stored in + the buffer at any given time. + + rx-bitrate-kbps: + type: int + required: true + enum: + - 125 + - 189 + description: | + Selects the receive message bitrate in kbps. This setting determines the speed at + which data is received. + + array-slot-duration-us: + type: array + required: true + description: | + Contains the slot durations in microseconds (us). Each value in the array represents + the duration of a slot, starting from the rising edge of the timing synchronization pulse + and ending at the final slot. + + array-slot-start-offset-us: + type: array + required: true + description: | + Contains the start offsets for each slot in microseconds (us). Each value in the array + represents the time offset at which the slot should start, measured from the rising edge + of the timing synchronization pulse. + + array-slot-data-length: + type: array + required: true + description: | + Contains the data length in bits for each slot. Each value in the array specifies the number + of bits in a slot, with valid lengths ranging from 8 to 28 bits. + + array-slot-data-msb-first: + type: array + required: true + enum: + - 0 + - 1 + description: | + Specifies the endianness type for each slot. Set to 1 when data is interpreted with the + Most Significant Bit (MSB) first. + + array-slot-has-smc: + type: array + required: true + enum: + - 0 + - 1 + description: | + Specifies whether each slot has Serial Messaging Channel (SMC) field. Set to 1 when + the bit (M0, M1) SMC is present in the Rx Message. + + array-slot-has-parity: + type: array + required: true + enum: + - 0 + - 1 + description: | + Specifies whether each slot has parity field. Set to 1 when the Parity field is + present in the Rx Message; otherwise, the CRC field is present. diff --git a/include/zephyr/drivers/psi5/psi5.h b/include/zephyr/drivers/psi5/psi5.h new file mode 100644 index 00000000000000..a6a6e6b876e962 --- /dev/null +++ b/include/zephyr/drivers/psi5/psi5.h @@ -0,0 +1,240 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Peripheral Sensor Interface (PSI5) driver API. + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_PSI5_H_ +#define ZEPHYR_INCLUDE_DRIVERS_PSI5_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief PSI5 Interface + * @defgroup psi5_interface PSI5 Interface + * @ingroup io_interfaces + * @{ + */ + +/** + * @brief PSI5 frame structure + */ +struct psi5_frame { + union { + /* PSI5 recevice data frame */ + struct { + uint32_t data; + uint32_t timestamp; + uint8_t crc; + uint8_t slot_number; + } data_frame; + + /* PSI5 serial message channel (SMC) data frame */ + struct { + uint16_t data; + uint8_t id; + uint8_t crc; + uint8_t slot_number; + } smc_data_frame; + }; +}; + +/** + * @brief PSI5 status + */ +enum psi5_status { + PSI5_TX_READY, + PSI5_DATA_FRAME_RECEIVED, + PSI5_SMC_DATA_FRAME_RECEIVED, + PSI5_TX_ERR, + PSI5_RX_ERR, +}; + +/** + * @brief Defines the application callback handler function signature for sending. + * + * @param dev Pointer to the device structure for the driver instance. + * @param channel The hardware channel of the driver instance. + * @param status PSI5 status. + * @param user_data User data provided when the frame was sent. + */ +typedef void (*psi5_tx_callback_t)(const struct device *dev, uint8_t channel, + enum psi5_status status, void *user_data); + +/** + * @brief Defines the application callback handler function signature for receiving. + * + * @param dev Pointer to the device structure for the driver instance. + * @param channel The hardware channel of the driver instance. + * @param frame Received frame. + * @param status PSI5 status. + * @param user_data User data provided when the filter was added. + */ +typedef void (*psi5_rx_callback_t)(const struct device *dev, uint8_t channel, + struct psi5_frame *frame, enum psi5_status status, + void *user_data); + +/** @cond INTERNAL_HIDDEN */ + +/** + * @brief Callback API upon starting sync PSI5 + * See @a psi5_start_sync() for argument description + */ +typedef int (*psi5_start_sync_t)(const struct device *dev, uint8_t channel); + +/** + * @brief Callback API upon stopping sync PSI5 + * See @a psi5_stop_sync() for argument description + */ +typedef int (*psi5_stop_sync_t)(const struct device *dev, uint8_t channel); + +/** + * @brief Callback API upon sending PSI5 frame + * See @a psi5_send() for argument description + */ +typedef int (*psi5_send_t)(const struct device *dev, uint8_t channel, const uint64_t data, + k_timeout_t timeout, psi5_tx_callback_t callback, void *user_data); + +/** + * @brief Callback API upon adding RX callback + * See @a psi5_add_rx_callback() for argument description + */ +typedef int (*psi5_add_rx_callback_t)(const struct device *dev, uint8_t channel, + psi5_rx_callback_t callback, void *user_data); + +__subsystem struct psi5_driver_api { + psi5_start_sync_t start_sync; + psi5_stop_sync_t stop_sync; + psi5_send_t send; + psi5_add_rx_callback_t add_rx_callback; +}; + +/** @endcond */ + +/** + * @brief Start the sync pulse generator on a specific channel + * + * @param dev Pointer to the device structure for the driver instance. + * @param channel The hardware channel of the driver instance. + * @retval 0 if successful. + * @retval -EINVAL if an invalid channel is given. + * @retval -EALREADY if the device is already started. + * @retval -EIO General input/output error, failed to start device. + */ +__syscall int psi5_start_sync(const struct device *dev, uint8_t channel); + +static inline int z_impl_psi5_start_sync(const struct device *dev, uint8_t channel) +{ + const struct psi5_driver_api *api = (const struct psi5_driver_api *)dev->api; + + if (api->start_sync) { + return api->start_sync(dev, channel); + } + + return -ENOSYS; +} + +/** + * @brief Stop the sync pulse generator on a specific channel + * + * @param dev Pointer to the device structure for the driver instance. + * @param channel The hardware channel of the driver instance. + * @retval 0 if successful. + * @retval -EINVAL if an invalid channel is given. + * @retval -EALREADY if the device is already stopped. + * @retval -EIO General input/output error, failed to stop device. + */ +__syscall int psi5_stop_sync(const struct device *dev, uint8_t channel); + +static inline int z_impl_psi5_stop_sync(const struct device *dev, uint8_t channel) +{ + const struct psi5_driver_api *api = (const struct psi5_driver_api *)dev->api; + + if (api->stop_sync) { + return api->stop_sync(dev, channel); + } + + return -ENOSYS; +} + +/** + * @brief Transmitting PSI5 data on a specific channel + * + * @param dev Pointer to the device structure for the driver instance. + * @param channel The hardware channel of the driver instance. + * @param data PSI5 data to transmit. + * @param timeout Timeout waiting for ready to transmit new data. + * @param callback Optional callback for when the frame was sent or a + * transmission error occurred. If ``NULL``, this function is + * blocking until frame is sent. + * @param user_data User data to pass to callback function. + * + * @retval 0 if successful. + * @retval -EINVAL if an invalid channel is given. + * @retval -ENOTSUP if an unsupported parameter was passed to the function. + * @retval -ENETDOWN if PSI5 is in stopped state. + * @retval -EIO if a general transmit error occurred. + * @retval -EAGAIN on timeout. + */ +__syscall int psi5_send(const struct device *dev, uint8_t channel, const uint64_t data, + k_timeout_t timeout, psi5_tx_callback_t callback, void *user_data); + +static inline int z_impl_psi5_send(const struct device *dev, uint8_t channel, const uint64_t data, + k_timeout_t timeout, psi5_tx_callback_t callback, + void *user_data) +{ + const struct psi5_driver_api *api = (const struct psi5_driver_api *)dev->api; + + if (api->send) { + return api->send(dev, channel, data, timeout, callback, user_data); + } + + return -ENOSYS; +} + +/** + * @brief Add a callback function to handle messages received for a specific channel + * + * @param dev Pointer to the device structure for the driver instance. + * @param channel The hardware channel of the driver instance. + * @param callback This function is called by PSI5 driver whenever a frame is received. + * @param user_data User data to pass to callback function. + * @retval 0 if successful. + * @retval -EINVAL if an invalid channel is given. + */ +__syscall int psi5_add_rx_callback(const struct device *dev, uint8_t channel, + psi5_rx_callback_t callback, void *user_data); + +static inline int z_impl_psi5_add_rx_callback(const struct device *dev, uint8_t channel, + psi5_rx_callback_t callback, void *user_data) +{ + const struct psi5_driver_api *api = (const struct psi5_driver_api *)dev->api; + + if (api->add_rx_callback) { + return api->add_rx_callback(dev, channel, callback, user_data); + } + + return -ENOSYS; +} + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#include + +#endif /* ZEPHYR_INCLUDE_DRIVERS_PSI5_H_ */ diff --git a/west.yml b/west.yml index 510d671cc3fc39..645412ac927012 100644 --- a/west.yml +++ b/west.yml @@ -203,7 +203,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 0ac830233092247c26f5dd01a07b0a484532ea4c + revision: pull/451/head path: modules/hal/nxp groups: - hal From f046b4c934a9a1fd577980131b0df963634f51eb Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Mon, 14 Oct 2024 13:52:33 +0700 Subject: [PATCH 2/3] boards: s32z270: enable support psi5 enable support psi5 Signed-off-by: Cong Nguyen Huu --- boards/nxp/s32z2xxdc2/doc/index.rst | 2 + dts/arm/nxp/nxp_s32z27x_r52.dtsi | 73 ++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/boards/nxp/s32z2xxdc2/doc/index.rst b/boards/nxp/s32z2xxdc2/doc/index.rst index 9cb0972bf8fc7e..16118d0028f6d4 100644 --- a/boards/nxp/s32z2xxdc2/doc/index.rst +++ b/boards/nxp/s32z2xxdc2/doc/index.rst @@ -60,6 +60,8 @@ The boards support the following hardware features: +-----------+------------+-------------------------------------+ | DSPI | on-chip | spi | +-----------+------------+-------------------------------------+ +| PSI5 | on-chip | psi5 | ++-----------+------------+-------------------------------------+ Other hardware features are not currently supported by the port. diff --git a/dts/arm/nxp/nxp_s32z27x_r52.dtsi b/dts/arm/nxp/nxp_s32z27x_r52.dtsi index 013c80c87eadaa..99ff6bdee2ac0d 100644 --- a/dts/arm/nxp/nxp_s32z27x_r52.dtsi +++ b/dts/arm/nxp/nxp_s32z27x_r52.dtsi @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 NXP + * Copyright 2022-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -1259,5 +1259,76 @@ status = "disabled"; }; + psi5_0: psi5@401e0000 { + compatible = "nxp,s32-psi5"; + reg = <0x401e0000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + psi5_0_ch0: ch@0 { + compatible = "nxp,s32-psi5-channel"; + reg = <0>; + interrupts = ; + status = "disabled"; + }; + + psi5_0_ch1: ch@1 { + compatible = "nxp,s32-psi5-channel"; + reg = <1>; + interrupts = ; + status = "disabled"; + }; + + psi5_0_ch2: ch@2 { + compatible = "nxp,s32-psi5-channel"; + reg = <2>; + interrupts = ; + status = "disabled"; + }; + + psi5_0_ch3: ch@3 { + compatible = "nxp,s32-psi5-channel"; + reg = <3>; + interrupts = ; + status = "disabled"; + }; + }; + + psi5_1: psi5@421e0000 { + compatible = "nxp,s32-psi5"; + reg = <0x421e0000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + psi5_1_ch0: ch@0 { + compatible = "nxp,s32-psi5-channel"; + reg = <0>; + interrupts = ; + status = "disabled"; + }; + + psi5_1_ch1: ch@1 { + compatible = "nxp,s32-psi5-channel"; + reg = <1>; + interrupts = ; + status = "disabled"; + }; + + psi5_1_ch2: ch@2 { + compatible = "nxp,s32-psi5-channel"; + reg = <2>; + interrupts = ; + status = "disabled"; + }; + + psi5_1_ch3: ch@3 { + compatible = "nxp,s32-psi5-channel"; + reg = <3>; + interrupts = ; + status = "disabled"; + }; + }; }; }; From 05f26444c76aebb3265a0e1ab1af9e514c5fee45 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Wed, 25 Sep 2024 14:00:55 +0700 Subject: [PATCH 3/3] samples: boards: nxp: add sample for using psi5 driver Add sample for using psi5 driver on s32z Signed-off-by: Cong Nguyen Huu --- samples/boards/nxp/s32/psi5/CMakeLists.txt | 8 +++ samples/boards/nxp/s32/psi5/README.rst | 33 +++++++++++ .../boards/s32z2xxdc2_s32z270_rtu0.overlay | 58 +++++++++++++++++++ .../boards/s32z2xxdc2_s32z270_rtu1.overlay | 7 +++ samples/boards/nxp/s32/psi5/prj.conf | 3 + samples/boards/nxp/s32/psi5/sample.yaml | 14 +++++ samples/boards/nxp/s32/psi5/src/main.c | 48 +++++++++++++++ 7 files changed, 171 insertions(+) create mode 100644 samples/boards/nxp/s32/psi5/CMakeLists.txt create mode 100644 samples/boards/nxp/s32/psi5/README.rst create mode 100644 samples/boards/nxp/s32/psi5/boards/s32z2xxdc2_s32z270_rtu0.overlay create mode 100644 samples/boards/nxp/s32/psi5/boards/s32z2xxdc2_s32z270_rtu1.overlay create mode 100644 samples/boards/nxp/s32/psi5/prj.conf create mode 100644 samples/boards/nxp/s32/psi5/sample.yaml create mode 100644 samples/boards/nxp/s32/psi5/src/main.c diff --git a/samples/boards/nxp/s32/psi5/CMakeLists.txt b/samples/boards/nxp/s32/psi5/CMakeLists.txt new file mode 100644 index 00000000000000..cc19ea188af9b7 --- /dev/null +++ b/samples/boards/nxp/s32/psi5/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(psi5) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/nxp/s32/psi5/README.rst b/samples/boards/nxp/s32/psi5/README.rst new file mode 100644 index 00000000000000..2ae206a70cd255 --- /dev/null +++ b/samples/boards/nxp/s32/psi5/README.rst @@ -0,0 +1,33 @@ +.. zephyr:code-sample:: nxp_s32_psi5 + :name: NXP S32 Peripheral Sensor Interface (PSI5) + + Use NXP S32 Peripheral Sensor Interface (PSI5). + +Overview +******** + +The sample application shows how to use NXP S32 Peripheral Sensor Interface (PSI5): + +* Receive data +* Transmit data + +Requirements +************ + +This sample requires connecting a wire between pin PA6 (data reception pin) and sensor. + +Building, Flashing and Running +****************************** + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/nxp/s32/psi5 + :board: s32z2xxdc2/s32z270/rtu0 + :goals: build flash + +Sample Output: + +.. code-block:: console + + Rx channel 1 completed + + Tx channel 2 completed diff --git a/samples/boards/nxp/s32/psi5/boards/s32z2xxdc2_s32z270_rtu0.overlay b/samples/boards/nxp/s32/psi5/boards/s32z2xxdc2_s32z270_rtu0.overlay new file mode 100644 index 00000000000000..82bedf73f37a1d --- /dev/null +++ b/samples/boards/nxp/s32/psi5/boards/s32z2xxdc2_s32z270_rtu0.overlay @@ -0,0 +1,58 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + psi5_0_default: psi5_0_default { + group1 { + pinmux = , ; + output-enable; + }; + group2 { + pinmux = , ; + input-enable; + }; + }; +}; + +&psi5_0 { + pinctrl-0 = <&psi5_0_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&psi5_0_ch1 { + period-sync-pulse-us = <500>; + decoder-start-offset-us = <0>; + sync-pulse-width-0-us = <100>; + sync-pulse-width-1-us = <127>; + tx-mode = "long-frame-31"; + num-rx-buf = <32>; + rx-bitrate-kbps = <189>; + array-slot-duration-us = <150>; + array-slot-start-offset-us = <110>; + array-slot-data-length = <16>; + array-slot-data-msb-first = <0>; + array-slot-has-smc = <0>; + array-slot-has-parity = <0>; + status = "okay"; +}; + +&psi5_0_ch2 { + period-sync-pulse-us = <8>; + decoder-start-offset-us = <0>; + sync-pulse-width-0-us = <2>; + sync-pulse-width-1-us = <6>; + tx-mode = "long-frame-31"; + num-rx-buf = <32>; + rx-bitrate-kbps = <189>; + array-slot-duration-us = <500>; + array-slot-start-offset-us = <0>; + array-slot-data-length = <16>; + array-slot-data-msb-first = <0>; + array-slot-has-smc = <0>; + array-slot-has-parity = <0>; + status = "okay"; +}; diff --git a/samples/boards/nxp/s32/psi5/boards/s32z2xxdc2_s32z270_rtu1.overlay b/samples/boards/nxp/s32/psi5/boards/s32z2xxdc2_s32z270_rtu1.overlay new file mode 100644 index 00000000000000..0a3db999430256 --- /dev/null +++ b/samples/boards/nxp/s32/psi5/boards/s32z2xxdc2_s32z270_rtu1.overlay @@ -0,0 +1,7 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "s32z2xxdc2_s32z270_rtu0.overlay" diff --git a/samples/boards/nxp/s32/psi5/prj.conf b/samples/boards/nxp/s32/psi5/prj.conf new file mode 100644 index 00000000000000..bac255b3c7052b --- /dev/null +++ b/samples/boards/nxp/s32/psi5/prj.conf @@ -0,0 +1,3 @@ +CONFIG_PSI5=y +CONFIG_PSI5_LOG_LEVEL_DBG=y +CONFIG_LOG=y diff --git a/samples/boards/nxp/s32/psi5/sample.yaml b/samples/boards/nxp/s32/psi5/sample.yaml new file mode 100644 index 00000000000000..1fa21692904dce --- /dev/null +++ b/samples/boards/nxp/s32/psi5/sample.yaml @@ -0,0 +1,14 @@ +sample: + description: Sample for using PSI5 driver + name: NXP S32 PSI5 sample + +tests: + sample.boards.nxp_s32.psi5: + platform_allow: + - s32z2xxdc2/s32z270/rtu0 + - s32z2xxdc2/s32z270/rtu1 + - s32z2xxdc2@D/s32z270/rtu0 + - s32z2xxdc2@D/s32z270/rtu1 + depends_on: psi5 + tags: psi5 + harness: sensor diff --git a/samples/boards/nxp/s32/psi5/src/main.c b/samples/boards/nxp/s32/psi5/src/main.c new file mode 100644 index 00000000000000..213bc2b26de283 --- /dev/null +++ b/samples/boards/nxp/s32/psi5/src/main.c @@ -0,0 +1,48 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(nxp_s32_psi5_sample, LOG_LEVEL_DBG); + +#include + +#include + +#define PSI5_NODE DT_INST(0, nxp_s32_psi5) + +void tx_cb(const struct device *dev, uint8_t channel_id, enum psi5_status status, void *user_data) +{ + LOG_INF("Tx channel %d completed\n", channel_id); +} + +void rx_cb(const struct device *dev, uint8_t channel_id, struct psi5_frame *frame, + enum psi5_status status, void *user_data) +{ + + LOG_INF("Rx channel %d completed\n", channel_id); +} + +int main(void) +{ + const struct device *const dev = DEVICE_DT_GET(PSI5_NODE); + uint64_t send_data = 0x1234; + + /* Test receive data */ + psi5_add_rx_callback(dev, 1, rx_cb, NULL); + + psi5_start_sync(dev, 1); + + k_sleep(K_MSEC(100)); + + psi5_stop_sync(dev, 1); + + /* Test send data */ + psi5_start_sync(dev, 2); + + psi5_send(dev, 2, send_data, K_MSEC(100), tx_cb, NULL); + + return 0; +}