From f5bf295597329d0d83dc15e9d4551ac8df1679ba Mon Sep 17 00:00:00 2001 From: Qiang Zhao Date: Wed, 2 Jul 2025 14:06:04 +0530 Subject: [PATCH 1/6] drivers: adc: add support sar adc driver Add driver for the SAR ADC Signed-off-by: Qiang Zhao --- drivers/adc/CMakeLists.txt | 1 + drivers/adc/Kconfig.mcux | 23 ++ drivers/adc/adc_mcux_sar_adc.c | 231 ++++++++++++++++++ dts/bindings/adc/nxp,sar-adc.yaml | 21 ++ .../mcux/mcux-sdk-ng/drivers/drivers.cmake | 1 + 5 files changed, 277 insertions(+) create mode 100644 drivers/adc/adc_mcux_sar_adc.c create mode 100644 dts/bindings/adc/nxp,sar-adc.yaml diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index 571318ac56d39..4c33f245ced5b 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -13,6 +13,7 @@ zephyr_library_sources_ifdef(CONFIG_ADC_MCUX_ADC12 adc_mcux_adc12.c) zephyr_library_sources_ifdef(CONFIG_ADC_MCUX_ADC16 adc_mcux_adc16.c) zephyr_library_sources_ifdef(CONFIG_ADC_MCUX_12B1MSPS_SAR adc_mcux_12b1msps_sar.c) zephyr_library_sources_ifdef(CONFIG_ADC_MCUX_LPADC adc_mcux_lpadc.c) +zephyr_library_sources_ifdef(CONFIG_ADC_MCUX_SAR_ADC adc_mcux_sar_adc.c) zephyr_library_sources_ifdef(CONFIG_ADC_VF610 adc_vf610.c) zephyr_library_sources_ifdef(CONFIG_ADC_SAM_AFEC adc_sam_afec.c) zephyr_library_sources_ifdef(CONFIG_ADC_NRFX_ADC adc_nrfx_adc.c) diff --git a/drivers/adc/Kconfig.mcux b/drivers/adc/Kconfig.mcux index 1ed2bf75a6bf4..7bdf8e27bc680 100644 --- a/drivers/adc/Kconfig.mcux +++ b/drivers/adc/Kconfig.mcux @@ -37,6 +37,14 @@ config ADC_MCUX_LPADC help Enable the MCUX LPADC driver. +config ADC_MCUX_SAR_ADC + bool "MCUX SAR ADC driver" + default y + select ADC_CONFIGURABLE_INPUTS + depends on DT_HAS_NXP_SAR_ADC_ENABLED + help + Enable the MCUX SAR ADC driver. + if ADC_MCUX_12B1MSPS_SAR || ADC_MCUX_LPADC config ADC_MCUX_ETC bool "MCUX ADC ETC driver" @@ -123,3 +131,18 @@ config LPADC_CHANNEL_COUNT endif # ADC_MCUX_LPADC + +if ADC_MCUX_SAR_ADC + +config SAR_ADC_CHANNEL_COUNT + int "SAR_ADC channel count" + default 8 + range 1 8 + help + Amount of hardware command channels to use, reduce to save RAM. + The user can reduce this value if their application uses fewer than + 8 ADC channels. This value corresponds to how many of the CMD + registers can be configured within the ADC. + + +endif # ADC_MCUX_SAR_ADC diff --git a/drivers/adc/adc_mcux_sar_adc.c b/drivers/adc/adc_mcux_sar_adc.c new file mode 100644 index 0000000000000..a4e2ffcadfc2f --- /dev/null +++ b/drivers/adc/adc_mcux_sar_adc.c @@ -0,0 +1,231 @@ +/* + * Copyright 2025 NXP + * + * Based on adc_mcux_sar_adc.c, which is: + * Copyright 2023-2024 NXP + * Copyright (c) 2020 Toby Firth + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_sar_adc + +#include +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_ADC_LOG_LEVEL +#include +#include +#include +LOG_MODULE_REGISTER(adc_mcux_sar_adc); + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" + +struct mcux_sar_adc_config { + ADC_Type *base; + void (*irq_config_func)(const struct device *dev); + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; +}; + +struct mcux_sar_adc_data { + const struct device *dev; + struct adc_context ctx; + uint16_t *buffer; + uint16_t *repeat_buffer; + uint32_t channels; +}; + +static int mcux_sar_adc_channel_setup(const struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + /* User may configure maximum number of active channels */ + if (channel_cfg->channel_id >= CONFIG_SAR_ADC_CHANNEL_COUNT) { + LOG_ERR("Channel %d is not valid", channel_cfg->channel_id); + return -EINVAL; + } + + if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { + LOG_ERR("Unsupported channel acquisition time"); + return -ENOTSUP; + } + + if (channel_cfg->gain != ADC_GAIN_1) { + LOG_ERR("Unsupported channel gain %d", channel_cfg->gain); + return -ENOTSUP; + } + + if (channel_cfg->reference != ADC_REF_INTERNAL) { + LOG_ERR("Unsupported channel reference"); + return -ENOTSUP; + } + + return 0; +} + +static int mcux_sar_adc_start_read(const struct device *dev, const struct adc_sequence *sequence) +{ + const struct mcux_sar_adc_config *config = dev->config; + struct mcux_sar_adc_data *data = dev->data; + ADC_Type *base = config->base; + uint8_t channel_id; + + if (sequence->resolution != 12) { + LOG_ERR("Unsupported resolution %d", sequence->resolution); + return -ENOTSUP; + } + + channel_id = CONFIG_SAR_ADC_CHANNEL_COUNT; + while (channel_id-- > 0) { + if (sequence->channels & BIT(channel_id)) { + ADC_EnableSpecificChannelNormalConv(base, channel_id); + } else { + ADC_DisableSpecificChannelNormalConv(base, channel_id); + } + } + + data->buffer = sequence->buffer; + + adc_context_start_read(&data->ctx, sequence); + int error = adc_context_wait_for_completion(&data->ctx); + + return error; +} + +static int mcux_sar_adc_read_async(const struct device *dev, const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + struct mcux_sar_adc_data *data = dev->data; + int error; + + adc_context_lock(&data->ctx, async ? true : false, async); + error = mcux_sar_adc_start_read(dev, sequence); + adc_context_release(&data->ctx, error); + + return error; +} + +static int mcux_sar_adc_read(const struct device *dev, const struct adc_sequence *sequence) +{ + return mcux_sar_adc_read_async(dev, sequence, NULL); +} + +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct mcux_sar_adc_data *data = CONTAINER_OF(ctx, struct mcux_sar_adc_data, ctx); + const struct mcux_sar_adc_config *config = data->dev->config; + ADC_Type *base = config->base; + + data->channels = ctx->sequence.channels; + data->repeat_buffer = data->buffer; + + ADC_StartConvChain(base, kADC_NormalConvOneShotMode); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat_sampling) +{ + struct mcux_sar_adc_data *data = CONTAINER_OF(ctx, struct mcux_sar_adc_data, ctx); + + if (repeat_sampling) { + data->buffer = data->repeat_buffer; + } +} + +static void mcux_sar_adc_isr(const struct device *dev) +{ + const struct mcux_sar_adc_config *config = dev->config; + struct mcux_sar_adc_data *data = dev->data; + ADC_Type *base = config->base; + adc_conv_result_t conv_result; + uint16_t channel_id; + + if (((ADC_GetConvIntStatus(base) & kADC_NormalConvChainEndIntFlag))) { + ADC_ClearConvIntStatus(base, kADC_NormalConvChainEndIntFlag); + } + + for (channel_id = 0; channel_id < CONFIG_SAR_ADC_CHANNEL_COUNT; channel_id++) { + if (ADC_GetChannelConvResult(base, &conv_result, channel_id)) { + data->channels &= ~BIT(channel_id); + *(data->buffer++) = conv_result.convData; + if (data->channels == 0) { + adc_context_on_sampling_done(&data->ctx, dev); + } + } + } +} + +static int mcux_sar_adc_init(const struct device *dev) +{ + const struct mcux_sar_adc_config *config = dev->config; + struct mcux_sar_adc_data *data = dev->data; + ADC_Type *base = config->base; + adc_config_t adc_config; + adc_calibration_config_t calibrationConfig; + + ADC_GetDefaultConfig(&adc_config); + ADC_Init(base, &adc_config); + ADC_SetConvMode(base, kADC_NormalConvOneShotMode); + ADC_EnableConvInt(base, (uint32_t)kADC_NormalConvChainEndIntEnable); + + /* Do calibration to reduce or eliminate the various error contribution effects. */ + calibrationConfig.enableAverage = true; + calibrationConfig.sampleTime = kADC_SampleTime22; +#if (defined(FSL_FEATURE_ADC_HAS_CALBISTREG) && (FSL_FEATURE_ADC_HAS_CALBISTREG == 1U)) + calibrationConfig.averageSampleNumbers = kADC_AverageSampleNumbers32; +#else + calibrationConfig.averageSampleNumbers = kADC_AverageSampleNumbers512; +#endif /* FSL_FEATURE_ADC_HAS_CALBISTREG */ + + if (!(ADC_DoCalibration(base, &calibrationConfig))) { + LOG_WRN("Calibration failed."); + } + + config->irq_config_func(dev); + data->dev = dev; + + adc_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +static DEVICE_API(adc, mcux_sar_adc_driver_api) = { + .channel_setup = mcux_sar_adc_channel_setup, + .read = mcux_sar_adc_read, +#ifdef CONFIG_ADC_ASYNC + .read_async = mcux_sar_adc_read_async, +#endif +}; + +#define SAR_ADC_MCUX_INIT(n) \ + \ + static void mcux_sar_adc_config_func_##n(const struct device *dev); \ + \ + static const struct mcux_sar_adc_config mcux_sar_adc_config_##n = { \ + .base = (ADC_Type *)DT_INST_REG_ADDR(n), \ + .irq_config_func = mcux_sar_adc_config_func_##n, \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name), \ + }; \ + static struct mcux_sar_adc_data mcux_sar_adc_data_##n = { \ + ADC_CONTEXT_INIT_TIMER(mcux_sar_adc_data_##n, ctx), \ + ADC_CONTEXT_INIT_LOCK(mcux_sar_adc_data_##n, ctx), \ + ADC_CONTEXT_INIT_SYNC(mcux_sar_adc_data_##n, ctx), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, &mcux_sar_adc_init, NULL, &mcux_sar_adc_data_##n, \ + &mcux_sar_adc_config_##n, POST_KERNEL, CONFIG_ADC_INIT_PRIORITY, \ + &mcux_sar_adc_driver_api); \ + \ + static void mcux_sar_adc_config_func_##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), mcux_sar_adc_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + } + +DT_INST_FOREACH_STATUS_OKAY(SAR_ADC_MCUX_INIT) diff --git a/dts/bindings/adc/nxp,sar-adc.yaml b/dts/bindings/adc/nxp,sar-adc.yaml new file mode 100644 index 0000000000000..509bef80b978d --- /dev/null +++ b/dts/bindings/adc/nxp,sar-adc.yaml @@ -0,0 +1,21 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP SAR ADC controller + +compatible: "nxp,sar-adc" + +include: [adc-controller.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + "#io-channel-cells": + const: 1 + +io-channel-cells: + - input diff --git a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake index b794013ca972c..461d83d1e09e4 100644 --- a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake +++ b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake @@ -15,6 +15,7 @@ endif() set_variable_ifdef(CONFIG_HWINFO_MCUX_SRC_V2 CONFIG_MCUX_COMPONENT_driver.src_2) set_variable_ifdef(CONFIG_GPIO_MCUX_IGPIO CONFIG_MCUX_COMPONENT_driver.igpio) set_variable_ifdef(CONFIG_ADC_MCUX_LPADC CONFIG_MCUX_COMPONENT_driver.lpadc) +set_variable_ifdef(CONFIG_ADC_MCUX_SAR_ADC CONFIG_MCUX_COMPONENT_driver.sar_adc) set_variable_ifdef(CONFIG_COUNTER_MCUX_CTIMER CONFIG_MCUX_COMPONENT_driver.ctimer) set_variable_ifdef(CONFIG_COUNTER_MCUX_LPC_RTC CONFIG_MCUX_COMPONENT_driver.lpc_rtc) set_variable_ifdef(CONFIG_GLIKEY_MCUX_GLIKEY CONFIG_MCUX_COMPONENT_driver.glikey) From d985cb0ec7cbc1e38615695ebbcdf53bb9206ddb Mon Sep 17 00:00:00 2001 From: Qiang Zhao Date: Thu, 3 Jul 2025 08:00:09 +0530 Subject: [PATCH 2/6] drivers: clock_control_mcux_ccm_rev2: add SAR_ADC clock support Added SAR_ADC clock support for clock_control_mcux_ccm_rev2 Signed-off-by: Qiang Zhao --- drivers/clock_control/clock_control_mcux_ccm_rev2.c | 6 ++++++ include/zephyr/dt-bindings/clock/imx_ccm_rev2.h | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/clock_control/clock_control_mcux_ccm_rev2.c b/drivers/clock_control/clock_control_mcux_ccm_rev2.c index 9eff29cad3ddd..f28513a25bd5d 100644 --- a/drivers/clock_control/clock_control_mcux_ccm_rev2.c +++ b/drivers/clock_control/clock_control_mcux_ccm_rev2.c @@ -263,6 +263,12 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, break; #endif +#ifdef CONFIG_ADC_MCUX_SAR_ADC + case IMX_CCM_SAR_ADC1_CLK: + clock_root = kCLOCK_Root_Adc + instance; + break; +#endif + #if defined(CONFIG_ETH_NXP_IMX_NETC) case IMX_CCM_NETC_CLK: clock_root = kCLOCK_Root_Netc; diff --git a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h index e5035584cbec0..054a7c8de54a3 100644 --- a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h +++ b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h @@ -1,5 +1,5 @@ /* - * Copyright 2021,2024 NXP + * Copyright 2021,2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -121,6 +121,7 @@ /* ADC */ #define IMX_CCM_LPADC1_CLK 0x1500UL #define IMX_CCM_LPADC2_CLK 0x1501UL +#define IMX_CCM_SAR_ADC1_CLK 0x1500UL /* TPM */ #define IMX_CCM_TPM_CLK 0x1600UL From aa3e729967a9406b5b7bb2b20a06f53cba9377d5 Mon Sep 17 00:00:00 2001 From: Qiang Zhao Date: Thu, 3 Jul 2025 08:15:48 +0530 Subject: [PATCH 3/6] dts: arm: nxp_imx93_m33: add ADC node Add ADC node on imx93 core m33 Signed-off-by: Qiang Zhao --- boards/nxp/imx93_evk/imx93_evk_mimx9352_m33.dts | 6 +++++- boards/nxp/imx93_evk/imx93_evk_mimx9352_m33.yaml | 3 ++- dts/arm/nxp/nxp_imx93_m33.dtsi | 11 ++++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/boards/nxp/imx93_evk/imx93_evk_mimx9352_m33.dts b/boards/nxp/imx93_evk/imx93_evk_mimx9352_m33.dts index e8db0b549295d..face44749ad05 100644 --- a/boards/nxp/imx93_evk/imx93_evk_mimx9352_m33.dts +++ b/boards/nxp/imx93_evk/imx93_evk_mimx9352_m33.dts @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -69,6 +69,10 @@ pinctrl-names = "default"; }; +&sar_adc1 { + status = "okay"; +}; + &gpio1 { status = "okay"; }; diff --git a/boards/nxp/imx93_evk/imx93_evk_mimx9352_m33.yaml b/boards/nxp/imx93_evk/imx93_evk_mimx9352_m33.yaml index b450925b2728e..d34fbfb31ccd5 100644 --- a/boards/nxp/imx93_evk/imx93_evk_mimx9352_m33.yaml +++ b/boards/nxp/imx93_evk/imx93_evk_mimx9352_m33.yaml @@ -1,4 +1,4 @@ -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # SPDX-License-Identifier: Apache-2.0 identifier: imx93_evk/mimx9352/m33 @@ -13,4 +13,5 @@ flash: 128 supported: - gpio - uart + - adc vendor: nxp diff --git a/dts/arm/nxp/nxp_imx93_m33.dtsi b/dts/arm/nxp/nxp_imx93_m33.dtsi index e7a67f7599b88..580b87a57cd72 100644 --- a/dts/arm/nxp/nxp_imx93_m33.dtsi +++ b/dts/arm/nxp/nxp_imx93_m33.dtsi @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -95,6 +95,15 @@ clocks = <&ccm IMX_CCM_LPUART2_CLK 0x6c 24>; status = "disabled"; }; + + sar_adc1: adc@44530000 { + compatible = "nxp,sar-adc"; + reg = <0x44530000 DT_SIZE_K(64)>; + interrupts = <219 0>; + status = "disabled"; + #io-channel-cells = <1>; + clocks = <&ccm IMX_CCM_SAR_ADC1_CLK 0x0 0>; + }; }; }; From a35747f2dec7b6bea4f35d663f8329931efdb632 Mon Sep 17 00:00:00 2001 From: Qiang Zhao Date: Thu, 3 Jul 2025 08:41:27 +0530 Subject: [PATCH 4/6] tests: drivers: adc: add imx93_evk support for adc_api case Add necessary configuration for sar_adc1 on imx93 core cm33 There are some issues with USERSPACE, so add an overlay to disable CONFIG_TEST_USERSPACE, will drop it once it works. Signed-off-by: Qiang Zhao --- .../boards/imx93_evk_mimx9352_m33.conf | 7 ++++ .../boards/imx93_evk_mimx9352_m33.overlay | 34 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 tests/drivers/adc/adc_api/boards/imx93_evk_mimx9352_m33.conf create mode 100644 tests/drivers/adc/adc_api/boards/imx93_evk_mimx9352_m33.overlay diff --git a/tests/drivers/adc/adc_api/boards/imx93_evk_mimx9352_m33.conf b/tests/drivers/adc/adc_api/boards/imx93_evk_mimx9352_m33.conf new file mode 100644 index 0000000000000..e83c366dadb97 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/imx93_evk_mimx9352_m33.conf @@ -0,0 +1,7 @@ +# +# Copyright (c) 2025, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_TEST_USERSPACE=n diff --git a/tests/drivers/adc/adc_api/boards/imx93_evk_mimx9352_m33.overlay b/tests/drivers/adc/adc_api/boards/imx93_evk_mimx9352_m33.overlay new file mode 100644 index 0000000000000..4f0afa5c1b782 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/imx93_evk_mimx9352_m33.overlay @@ -0,0 +1,34 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2025 NXP + */ + +#include + +/ { + zephyr,user { + io-channels = <&sar_adc1 0>, <&sar_adc1 1>; + }; +}; + +&sar_adc1 { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; From ce739cfb3204321468472d0ddc46e375442e3f74 Mon Sep 17 00:00:00 2001 From: Qiang Zhao Date: Fri, 4 Jul 2025 11:34:10 +0530 Subject: [PATCH 5/6] soc: imx93 m33: enable CPU_CORTEX_M_HAS_DWT enable CPU_CORTEX_M_HAS_DWT for imx93 core m33 Signed-off-by: Qiang Zhao --- soc/nxp/imx/imx9/imx93/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/soc/nxp/imx/imx9/imx93/Kconfig b/soc/nxp/imx/imx9/imx93/Kconfig index f17c137891189..930a068b5e551 100644 --- a/soc/nxp/imx/imx9/imx93/Kconfig +++ b/soc/nxp/imx/imx9/imx93/Kconfig @@ -1,4 +1,4 @@ -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # SPDX-License-Identifier: Apache-2.0 config SOC_MIMX9352_A55 @@ -13,6 +13,7 @@ config SOC_MIMX9352_A55 config SOC_MIMX9352_M33 select ARM select CPU_CORTEX_M33 + select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU select CPU_HAS_ARM_MPU select CPU_HAS_ARM_SAU From bab30bfc3d39dcb037b9cd31591edba4a04d95f8 Mon Sep 17 00:00:00 2001 From: Qiang Zhao Date: Wed, 9 Jul 2025 13:09:56 +0530 Subject: [PATCH 6/6] west.yml: update hal_nxp - Update imx93 headers and sar_adc driver Signed-off-by: Qiang Zhao --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 91d959de4fba7..e5302d14f5c5a 100644 --- a/west.yml +++ b/west.yml @@ -210,7 +210,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 7a52cbb7cb56db3a276cbd617db3ea7cc3435d12 + revision: refs/pull/573/head path: modules/hal/nxp groups: - hal