diff --git a/doc/releases/migration-guide-4.1.rst b/doc/releases/migration-guide-4.1.rst index c033dd9c81c8..05a6960830df 100644 --- a/doc/releases/migration-guide-4.1.rst +++ b/doc/releases/migration-guide-4.1.rst @@ -51,6 +51,32 @@ Enhanced Serial Peripheral Interface (eSPI) GNSS ==== +GPIO +==== + +* Renamed the device tree property ``pin_mask`` to ``pin-mask``. +* Renamed the device tree property ``pinmux_mask`` to ``pinmux-mask``. +* Renamed the device tree property ``vbatts_pins`` to ``vbatts-pins``. +* Renamed the device tree property ``bit_per_gpio`` to ``bit-per-gpio``. +* Renamed the device tree property ``off_val`` to ``off-val``. +* Renamed the device tree property ``on_val`` to ``on-val``. +* Renamed the ``compatible`` from ``ti,ads114s0x-gpio`` to :dtcompatible:`ti,ads1x4s0x-gpio`. + +HWSPINLOCK +========== + +* Renamed the DeviceTree property ``num_locks`` to ``num-locks``. + +I2C +=== + +* Renamed the ``compatible`` from ``nxp,imx-lpi2c`` to :dtcompatible:`nxp,lpi2c`. + +I2S +=== + +* Renamed the device tree property from ``fifo_depth`` to ``fifo-depth``. + Input ===== diff --git a/doc/releases/release-notes-4.1.rst b/doc/releases/release-notes-4.1.rst index fb44daad14a6..ca57888372d5 100644 --- a/doc/releases/release-notes-4.1.rst +++ b/doc/releases/release-notes-4.1.rst @@ -83,7 +83,185 @@ Drivers and Sensors * CAN -* Charger + * :kconfig:option:`CONFIG_MBEDTLS_PSA_STATIC_KEY_SLOTS` + * :kconfig:option:`CONFIG_MBEDTLS_PSA_KEY_SLOT_COUNT` + +* Other + + * :kconfig:option:`CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA` + * :c:macro:`DT_ANY_INST_HAS_BOOL_STATUS_OKAY` + * :c:struct:`led_dt_spec` + * :kconfig:option:`CONFIG_STEP_DIR_STEPPER` + +New Boards +********** +.. + You may update this list as you contribute a new board during the release cycle, in order to make + is visible to people who might be looking at the working draft of the release notes. However, note + that this list will be recomputed at the time of the release, so you don't *have* to update it. + In any case, just link the board, further details go in the board description. + +* Adafruit Industries, LLC + + * :zephyr:board:`adafruit_feather_m4_express` (``adafruit_feather_m4_express``) + * :zephyr:board:`adafruit_qt_py_esp32s3` (``adafruit_qt_py_esp32s3``) + +* Advanced Micro Devices (AMD), Inc. + + * :zephyr:board:`acp_6_0_adsp` (``acp_6_0_adsp``) + +* Analog Devices, Inc. + + * :zephyr:board:`max78000evkit` (``max78000evkit``) + * :zephyr:board:`max78000fthr` (``max78000fthr``) + * :zephyr:board:`max78002evkit` (``max78002evkit``) + +* Antmicro + + * :zephyr:board:`myra_sip_baseboard` (``myra_sip_baseboard``) + +* BeagleBoard.org Foundation + + * :zephyr:board:`beagley_ai` (``beagley_ai``) + +* FANKE Technology Co., Ltd. + + * :zephyr:board:`fk750m1_vbt6` (``fk750m1_vbt6``) + +* Google, Inc. + + * :zephyr:board:`google_icetower` (``google_icetower``) + * :zephyr:board:`google_quincy` (``google_quincy``) + +* Infineon Technologies + + * :zephyr:board:`cy8ckit_062s2_ai` (``cy8ckit_062s2_ai``) + +* Lilygo Shenzhen Xinyuan Electronic Technology Co., Ltd + + * :zephyr:board:`ttgo_t7v1_5` (``ttgo_t7v1_5``) + * :zephyr:board:`ttgo_t8s3` (``ttgo_t8s3``) + +* M5Stack + + * :zephyr:board:`m5stack_cores3` (``m5stack_cores3``) + +* Makerbase Co., Ltd. + + * :zephyr:board:`mks_canable_v20` (``mks_canable_v20``) + +* MediaTek Inc. + + * MT8186 (``mt8186``) + * MT8188 (``mt8188``) + * MT8196 (``mt8196``) + +* NXP Semiconductors + + * :zephyr:board:`mimxrt700_evk` (``mimxrt700_evk``) + +* Nordic Semiconductor + + * :zephyr:board:`nrf54l09pdk` (``nrf54l09pdk``) + +* Norik Systems + + * :zephyr:board:`octopus_io_board` (``octopus_io_board``) + * :zephyr:board:`octopus_som` (``octopus_som``) + +* Qorvo, Inc. + + * :zephyr:board:`decawave_dwm3001cdk` (``decawave_dwm3001cdk``) + +* Raspberry Pi Foundation + + * :zephyr:board:`rpi_pico2` (``rpi_pico2``) + +* Realtek Semiconductor Corp. + + * :zephyr:board:`rts5912_evb` (``rts5912_evb``) + +* Renesas Electronics Corporation + + * :zephyr:board:`fpb_ra4e1` (``fpb_ra4e1``) + * :zephyr:board:`rzg3s_smarc` (``rzg3s_smarc``) + * :zephyr:board:`voice_ra4e1` (``voice_ra4e1``) + +* STMicroelectronics + + * :zephyr:board:`nucleo_c071rb` (``nucleo_c071rb``) + * :zephyr:board:`nucleo_f072rb` (``nucleo_f072rb``) + * :zephyr:board:`nucleo_h7s3l8` (``nucleo_h7s3l8``) + * :zephyr:board:`nucleo_wb07cc` (``nucleo_wb07cc``) + * :zephyr:board:`stm32f413h_disco` (``stm32f413h_disco``) + +* Seeed Technology Co., Ltd + + * :zephyr:board:`xiao_esp32c6` (``xiao_esp32c6``) + +* Shenzhen Fuyuansheng Electronic Technology Co., Ltd. + + * :zephyr:board:`ucan` (``ucan``) + +* Silicon Laboratories + + * :zephyr:board:`xg23_rb4210a` (``xg23_rb4210a``) + * :zephyr:board:`xg24_ek2703a` (``xg24_ek2703a``) + * :zephyr:board:`xg29_rb4412a` (``xg29_rb4412a``) + +* Toradex AG + + * :zephyr:board:`verdin_imx8mm` (``verdin_imx8mm``) + +* Waveshare Electronics + + * :zephyr:board:`rp2040_zero` (``rp2040_zero``) + +* WeAct Studio + + * :zephyr:board:`mini_stm32h7b0` (``mini_stm32h7b0``) + +* WinChipHead + + * :zephyr:board:`ch32v003evt` (``ch32v003evt``) + +* Würth Elektronik GmbH. + + * :zephyr:board:`we_oceanus1ev` (``we_oceanus1ev``) + * :zephyr:board:`we_orthosie1ev` (``we_orthosie1ev``) + +* others + + * :zephyr:board:`canbardo` (``canbardo``) + * :zephyr:board:`candlelight` (``candlelight``) + * :zephyr:board:`candlelightfd` (``candlelightfd``) + * :zephyr:board:`esp32c3_supermini` (``esp32c3_supermini``) + * :zephyr:board:`promicro_nrf52840` (``promicro_nrf52840``) + +New Drivers +*********** +.. + Same as above for boards, this will also be recomputed at the time of the release. + Just link the driver, further details go in the binding description + +* :abbr:`ADC (Analog to Digital Converter)` + + * :dtcompatible:`adi,ad4114-adc` + * :dtcompatible:`ti,ads131m02` + * :dtcompatible:`ti,tla2022` + * :dtcompatible:`ti,tla2024` + * :dtcompatible:`ti,ads114s06` + * :dtcompatible:`ti,ads124s06` + * :dtcompatible:`ti,ads124s08` + +* ARM architecture + + * :dtcompatible:`nxp,nbu` + +* Bluetooth + + * :dtcompatible:`renesas,bt-hci-da1453x` + * :dtcompatible:`st,hci-stm32wb0` * Clock control diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index dce35036f432..18e6e2b12e43 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -33,7 +33,8 @@ zephyr_library_sources_ifdef(CONFIG_ADC_GD32 adc_gd32.c) zephyr_library_sources_ifdef(CONFIG_ADC_ADS1112 adc_ads1112.c) zephyr_library_sources_ifdef(CONFIG_ADC_ADS1119 adc_ads1119.c) zephyr_library_sources_ifdef(CONFIG_ADC_ADS7052 adc_ads7052.c) -zephyr_library_sources_ifdef(CONFIG_ADC_ADS114S0X adc_ads114s0x.c) +zephyr_library_sources_ifdef(CONFIG_ADC_ADS1X4S0X adc_ads114s0x.c) +zephyr_library_sources_ifdef(CONFIG_ADC_ADS131M02 adc_ads131m02.c) zephyr_library_sources_ifdef(CONFIG_ADC_RPI_PICO adc_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_ADC_XMC4XXX adc_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_ADC_ESP32 adc_esp32.c) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 1e26de71e760..d78c3c06dd32 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -100,7 +100,7 @@ source "drivers/adc/Kconfig.ads1119" source "drivers/adc/Kconfig.ads7052" -source "drivers/adc/Kconfig.ads114s0x" +source "drivers/adc/Kconfig.ads1x4s0x" source "drivers/adc/Kconfig.rpi_pico" diff --git a/drivers/adc/Kconfig.ads114s0x b/drivers/adc/Kconfig.ads114s0x deleted file mode 100644 index 45191bb92eab..000000000000 --- a/drivers/adc/Kconfig.ads114s0x +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (c) 2023 SILA Embedded Solutions GmbH -# -# SPDX-License-Identifier: Apache-2.0 - -menuconfig ADC_ADS114S0X - bool "Texas instruments ADS114S0x" - default y - depends on DT_HAS_TI_ADS114S08_ENABLED - select SPI - select ADC_CONFIGURABLE_INPUTS - select ADC_CONFIGURABLE_EXCITATION_CURRENT_SOURCE_PIN - select ADC_CONFIGURABLE_VBIAS_PIN - help - Enable the driver implementation for the ADS114S0X family - -config ADC_ADS114S0X_ASYNC_THREAD_INIT_PRIO - int "ADC ADS114S0x async thread priority" - default 0 - depends on ADC_ADS114S0X - -config ADC_ADS114S0X_ACQUISITION_THREAD_STACK_SIZE - int "Stack size for the ADC data acquisition thread" - default 400 - depends on ADC_ADS114S0X - help - Size of the stack used for the internal data acquisition - thread. - -config ADC_ADS114S0X_GPIO - bool "GPIO support" - default n - depends on GPIO && ADC_ADS114S0X - help - Enable GPIO child device support in the ADS114S0x ADC driver. - - The GPIO functionality is handled by the ADS114S0x GPIO - driver. - -config ADC_ADS114S0X_WAIT_FOR_COMPLETION_TIMEOUT_MS - int "Timeout for wait for completion of a read in ms" - default 1000 - depends on ADC_ADS114S0X - help - This is the wait time in ms until a read is completed. diff --git a/drivers/adc/Kconfig.ads1x4s0x b/drivers/adc/Kconfig.ads1x4s0x new file mode 100644 index 000000000000..6ea48b13086b --- /dev/null +++ b/drivers/adc/Kconfig.ads1x4s0x @@ -0,0 +1,44 @@ +# Copyright (c) 2023 SILA Embedded Solutions GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +menuconfig ADC_ADS1X4S0X + bool "Texas instruments ADS1X4S0X" + default y + depends on DT_HAS_TI_ADS1X4S08_ENABLED + select SPI + select ADC_CONFIGURABLE_INPUTS + select ADC_CONFIGURABLE_EXCITATION_CURRENT_SOURCE_PIN + select ADC_CONFIGURABLE_VBIAS_PIN + help + Enable the driver implementation for the ADS1X4S0X family + +config ADC_ADS1X4S0X_ASYNC_THREAD_INIT_PRIO + int "ADC ADS1X4S0X async thread priority" + default 0 + depends on ADC_ADS1X4S0X + +config ADC_ADS1X4S0X_ACQUISITION_THREAD_STACK_SIZE + int "Stack size for the ADC data acquisition thread" + default 400 + depends on ADC_ADS1X4S0X + help + Size of the stack used for the internal data acquisition + thread. + +config ADC_ADS1X4S0X_GPIO + bool "GPIO support" + default n + depends on GPIO && ADC_ADS1X4S0X + help + Enable GPIO child device support in the ADS1X4S0X ADC driver. + + The GPIO functionality is handled by the ADS1X4S0X GPIO + driver. + +config ADC_ADS1X4S0X_WAIT_FOR_COMPLETION_TIMEOUT_MS + int "Timeout for wait for completion of a read in ms" + default 1000 + depends on ADC_ADS1X4S0X + help + This is the wait time in ms until a read is completed. diff --git a/drivers/adc/adc_ads114s0x.c b/drivers/adc/adc_ads114s0x.c deleted file mode 100644 index 9864fd689f46..000000000000 --- a/drivers/adc/adc_ads114s0x.c +++ /dev/null @@ -1,1508 +0,0 @@ -/* - * Copyright (c) 2023 SILA Embedded Solutions GmbH - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ADC_CONTEXT_USES_KERNEL_TIMER 1 -#define ADC_CONTEXT_WAIT_FOR_COMPLETION_TIMEOUT \ - K_MSEC(CONFIG_ADC_ADS114S0X_WAIT_FOR_COMPLETION_TIMEOUT_MS) -#include "adc_context.h" - -LOG_MODULE_REGISTER(ads114s0x, CONFIG_ADC_LOG_LEVEL); - -#define ADS114S0X_CLK_FREQ_IN_KHZ 4096 -#define ADS114S0X_RESET_LOW_TIME_IN_CLOCK_CYCLES 4 -#define ADS114S0X_START_SYNC_PULSE_DURATION_IN_CLOCK_CYCLES 4 -#define ADS114S0X_SETUP_TIME_IN_CLOCK_CYCLES 32 -#define ADS114S0X_INPUT_SELECTION_AINCOM 12 -#define ADS114S0X_RESOLUTION 16 -#define ADS114S0X_REF_INTERNAL 2500 -#define ADS114S0X_GPIO_MAX 3 -#define ADS114S0X_POWER_ON_RESET_TIME_IN_US 2200 -#define ADS114S0X_VBIAS_PIN_MAX 7 -#define ADS114S0X_VBIAS_PIN_MIN 0 - -/* Not mentioned in the datasheet, but instead determined experimentally. */ -#define ADS114S0X_RESET_DELAY_TIME_SAFETY_MARGIN_IN_US 1000 -#define ADS114S0X_RESET_DELAY_TIME_IN_US \ - (4096 * 1000 / ADS114S0X_CLK_FREQ_IN_KHZ + ADS114S0X_RESET_DELAY_TIME_SAFETY_MARGIN_IN_US) - -#define ADS114S0X_RESET_LOW_TIME_IN_US \ - (ADS114S0X_RESET_LOW_TIME_IN_CLOCK_CYCLES * 1000 / ADS114S0X_CLK_FREQ_IN_KHZ) -#define ADS114S0X_START_SYNC_PULSE_DURATION_IN_US \ - (ADS114S0X_START_SYNC_PULSE_DURATION_IN_CLOCK_CYCLES * 1000 / ADS114S0X_CLK_FREQ_IN_KHZ) -#define ADS114S0X_SETUP_TIME_IN_US \ - (ADS114S0X_SETUP_TIME_IN_CLOCK_CYCLES * 1000 / ADS114S0X_CLK_FREQ_IN_KHZ) - -enum ads114s0x_command { - ADS114S0X_COMMAND_NOP = 0x00, - ADS114S0X_COMMAND_WAKEUP = 0x02, - ADS114S0X_COMMAND_POWERDOWN = 0x04, - ADS114S0X_COMMAND_RESET = 0x06, - ADS114S0X_COMMAND_START = 0x08, - ADS114S0X_COMMAND_STOP = 0x0A, - ADS114S0X_COMMAND_SYOCAL = 0x16, - ADS114S0X_COMMAND_SYGCAL = 0x17, - ADS114S0X_COMMAND_SFOCAL = 0x19, - ADS114S0X_COMMAND_RDATA = 0x12, - ADS114S0X_COMMAND_RREG = 0x20, - ADS114S0X_COMMAND_WREG = 0x40, -}; - -enum ads114s0x_register { - ADS114S0X_REGISTER_ID = 0x00, - ADS114S0X_REGISTER_STATUS = 0x01, - ADS114S0X_REGISTER_INPMUX = 0x02, - ADS114S0X_REGISTER_PGA = 0x03, - ADS114S0X_REGISTER_DATARATE = 0x04, - ADS114S0X_REGISTER_REF = 0x05, - ADS114S0X_REGISTER_IDACMAG = 0x06, - ADS114S0X_REGISTER_IDACMUX = 0x07, - ADS114S0X_REGISTER_VBIAS = 0x08, - ADS114S0X_REGISTER_SYS = 0x09, - ADS114S0X_REGISTER_OFCAL0 = 0x0B, - ADS114S0X_REGISTER_OFCAL1 = 0x0C, - ADS114S0X_REGISTER_FSCAL0 = 0x0E, - ADS114S0X_REGISTER_FSCAL1 = 0x0F, - ADS114S0X_REGISTER_GPIODAT = 0x10, - ADS114S0X_REGISTER_GPIOCON = 0x11, -}; - -#define ADS114S0X_REGISTER_GET_VALUE(value, pos, length) \ - FIELD_GET(GENMASK(pos + length - 1, pos), value) -#define ADS114S0X_REGISTER_SET_VALUE(target, value, pos, length) \ - target &= ~GENMASK(pos + length - 1, pos); \ - target |= FIELD_PREP(GENMASK(pos + length - 1, pos), value) - -#define ADS114S0X_REGISTER_ID_DEV_ID_LENGTH 3 -#define ADS114S0X_REGISTER_ID_DEV_ID_POS 0 -#define ADS114S0X_REGISTER_ID_DEV_ID_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_ID_DEV_ID_POS, \ - ADS114S0X_REGISTER_ID_DEV_ID_LENGTH) -#define ADS114S0X_REGISTER_ID_DEV_ID_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_ID_DEV_ID_POS, \ - ADS114S0X_REGISTER_ID_DEV_ID_LENGTH) -#define ADS114S0X_REGISTER_STATUS_FL_POR_LENGTH 1 -#define ADS114S0X_REGISTER_STATUS_FL_POR_POS 7 -#define ADS114S0X_REGISTER_STATUS_FL_POR_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_STATUS_FL_POR_POS, \ - ADS114S0X_REGISTER_STATUS_FL_POR_LENGTH) -#define ADS114S0X_REGISTER_STATUS_FL_POR_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_STATUS_FL_POR_POS, \ - ADS114S0X_REGISTER_STATUS_FL_POR_LENGTH) -#define ADS114S0X_REGISTER_STATUS_NOT_RDY_LENGTH 1 -#define ADS114S0X_REGISTER_STATUS_NOT_RDY_POS 6 -#define ADS114S0X_REGISTER_STATUS_NOT_RDY_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_STATUS_NOT_RDY_POS, \ - ADS114S0X_REGISTER_STATUS_NOT_RDY_LENGTH) -#define ADS114S0X_REGISTER_STATUS_NOT_RDY_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_STATUS_NOT_RDY_POS, \ - ADS114S0X_REGISTER_STATUS_NOT_RDY_LENGTH) -#define ADS114S0X_REGISTER_STATUS_FL_P_RAILP_LENGTH 1 -#define ADS114S0X_REGISTER_STATUS_FL_P_RAILP_POS 5 -#define ADS114S0X_REGISTER_STATUS_FL_P_RAILP_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_STATUS_FL_P_RAILP_POS, \ - ADS114S0X_REGISTER_STATUS_FL_P_RAILP_LENGTH) -#define ADS114S0X_REGISTER_STATUS_FL_P_RAILP_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_STATUS_FL_P_RAILP_POS, \ - ADS114S0X_REGISTER_STATUS_FL_P_RAILP_LENGTH) -#define ADS114S0X_REGISTER_STATUS_FL_P_RAILN_LENGTH 1 -#define ADS114S0X_REGISTER_STATUS_FL_P_RAILN_POS 4 -#define ADS114S0X_REGISTER_STATUS_FL_P_RAILN_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_STATUS_FL_P_RAILN_POS, \ - ADS114S0X_REGISTER_STATUS_FL_P_RAILN_LENGTH) -#define ADS114S0X_REGISTER_STATUS_FL_P_RAILN_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_STATUS_FL_P_RAILN_POS, \ - ADS114S0X_REGISTER_STATUS_FL_P_RAILN_LENGTH) -#define ADS114S0X_REGISTER_STATUS_FL_N_RAILP_LENGTH 1 -#define ADS114S0X_REGISTER_STATUS_FL_N_RAILP_POS 3 -#define ADS114S0X_REGISTER_STATUS_FL_N_RAILP_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_STATUS_FL_N_RAILP_POS, \ - ADS114S0X_REGISTER_STATUS_FL_N_RAILP_LENGTH) -#define ADS114S0X_REGISTER_STATUS_FL_N_RAILP_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_STATUS_FL_N_RAILP_POS, \ - ADS114S0X_REGISTER_STATUS_FL_N_RAILP_LENGTH) -#define ADS114S0X_REGISTER_STATUS_FL_N_RAILN_LENGTH 1 -#define ADS114S0X_REGISTER_STATUS_FL_N_RAILN_POS 2 -#define ADS114S0X_REGISTER_STATUS_FL_N_RAILN_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_STATUS_FL_N_RAILN_POS, \ - ADS114S0X_REGISTER_STATUS_FL_N_RAILN_LENGTH) -#define ADS114S0X_REGISTER_STATUS_FL_N_RAILN_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_STATUS_FL_N_RAILN_POS, \ - ADS114S0X_REGISTER_STATUS_FL_N_RAILN_LENGTH) -#define ADS114S0X_REGISTER_STATUS_FL_REF_L1_LENGTH 1 -#define ADS114S0X_REGISTER_STATUS_FL_REF_L1_POS 1 -#define ADS114S0X_REGISTER_STATUS_FL_REF_L1_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_STATUS_FL_REF_L1_POS, \ - ADS114S0X_REGISTER_STATUS_FL_REF_L1_LENGTH) -#define ADS114S0X_REGISTER_STATUS_FL_REF_L1_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_STATUS_FL_REF_L1_POS, \ - ADS114S0X_REGISTER_STATUS_FL_REF_L1_LENGTH) -#define ADS114S0X_REGISTER_STATUS_FL_REF_L0_LENGTH 1 -#define ADS114S0X_REGISTER_STATUS_FL_REF_L0_POS 0 -#define ADS114S0X_REGISTER_STATUS_FL_REF_L0_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_STATUS_FL_REF_L0_POS, \ - ADS114S0X_REGISTER_STATUS_FL_REF_L0_LENGTH) -#define ADS114S0X_REGISTER_STATUS_FL_REF_L0_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_STATUS_FL_REF_L0_POS, \ - ADS114S0X_REGISTER_STATUS_FL_REF_L0_LENGTH) -#define ADS114S0X_REGISTER_INPMUX_MUXP_LENGTH 4 -#define ADS114S0X_REGISTER_INPMUX_MUXP_POS 4 -#define ADS114S0X_REGISTER_INPMUX_MUXP_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_INPMUX_MUXP_POS, \ - ADS114S0X_REGISTER_INPMUX_MUXP_LENGTH) -#define ADS114S0X_REGISTER_INPMUX_MUXP_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_INPMUX_MUXP_POS, \ - ADS114S0X_REGISTER_INPMUX_MUXP_LENGTH) -#define ADS114S0X_REGISTER_INPMUX_MUXN_LENGTH 4 -#define ADS114S0X_REGISTER_INPMUX_MUXN_POS 0 -#define ADS114S0X_REGISTER_INPMUX_MUXN_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_INPMUX_MUXN_POS, \ - ADS114S0X_REGISTER_INPMUX_MUXN_LENGTH) -#define ADS114S0X_REGISTER_INPMUX_MUXN_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_INPMUX_MUXN_POS, \ - ADS114S0X_REGISTER_INPMUX_MUXN_LENGTH) -#define ADS114S0X_REGISTER_PGA_DELAY_LENGTH 3 -#define ADS114S0X_REGISTER_PGA_DELAY_POS 5 -#define ADS114S0X_REGISTER_PGA_DELAY_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_PGA_DELAY_POS, \ - ADS114S0X_REGISTER_PGA_DELAY_LENGTH) -#define ADS114S0X_REGISTER_PGA_DELAY_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_PGA_DELAY_POS, \ - ADS114S0X_REGISTER_PGA_DELAY_LENGTH) -#define ADS114S0X_REGISTER_PGA_PGA_EN_LENGTH 2 -#define ADS114S0X_REGISTER_PGA_PGA_EN_POS 3 -#define ADS114S0X_REGISTER_PGA_PGA_EN_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_PGA_PGA_EN_POS, \ - ADS114S0X_REGISTER_PGA_PGA_EN_LENGTH) -#define ADS114S0X_REGISTER_PGA_PGA_EN_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_PGA_PGA_EN_POS, \ - ADS114S0X_REGISTER_PGA_PGA_EN_LENGTH) -#define ADS114S0X_REGISTER_PGA_GAIN_LENGTH 3 -#define ADS114S0X_REGISTER_PGA_GAIN_POS 0 -#define ADS114S0X_REGISTER_PGA_GAIN_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_PGA_GAIN_POS, \ - ADS114S0X_REGISTER_PGA_GAIN_LENGTH) -#define ADS114S0X_REGISTER_PGA_GAIN_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_PGA_GAIN_POS, \ - ADS114S0X_REGISTER_PGA_GAIN_LENGTH) -#define ADS114S0X_REGISTER_DATARATE_G_CHOP_LENGTH 1 -#define ADS114S0X_REGISTER_DATARATE_G_CHOP_POS 7 -#define ADS114S0X_REGISTER_DATARATE_G_CHOP_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_DATARATE_G_CHOP_POS, \ - ADS114S0X_REGISTER_DATARATE_G_CHOP_LENGTH) -#define ADS114S0X_REGISTER_DATARATE_G_CHOP_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_DATARATE_G_CHOP_POS, \ - ADS114S0X_REGISTER_DATARATE_G_CHOP_LENGTH) -#define ADS114S0X_REGISTER_DATARATE_CLK_LENGTH 1 -#define ADS114S0X_REGISTER_DATARATE_CLK_POS 6 -#define ADS114S0X_REGISTER_DATARATE_CLK_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_DATARATE_CLK_POS, \ - ADS114S0X_REGISTER_DATARATE_CLK_LENGTH) -#define ADS114S0X_REGISTER_DATARATE_CLK_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_DATARATE_CLK_POS, \ - ADS114S0X_REGISTER_DATARATE_CLK_LENGTH) -#define ADS114S0X_REGISTER_DATARATE_MODE_LENGTH 1 -#define ADS114S0X_REGISTER_DATARATE_MODE_POS 5 -#define ADS114S0X_REGISTER_DATARATE_MODE_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_DATARATE_MODE_POS, \ - ADS114S0X_REGISTER_DATARATE_MODE_LENGTH) -#define ADS114S0X_REGISTER_DATARATE_MODE_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_DATARATE_MODE_POS, \ - ADS114S0X_REGISTER_DATARATE_MODE_LENGTH) -#define ADS114S0X_REGISTER_DATARATE_FILTER_LENGTH 1 -#define ADS114S0X_REGISTER_DATARATE_FILTER_POS 4 -#define ADS114S0X_REGISTER_DATARATE_FILTER_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_DATARATE_FILTER_POS, \ - ADS114S0X_REGISTER_DATARATE_FILTER_LENGTH) -#define ADS114S0X_REGISTER_DATARATE_FILTER_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_DATARATE_FILTER_POS, \ - ADS114S0X_REGISTER_DATARATE_FILTER_LENGTH) -#define ADS114S0X_REGISTER_DATARATE_DR_LENGTH 4 -#define ADS114S0X_REGISTER_DATARATE_DR_POS 0 -#define ADS114S0X_REGISTER_DATARATE_DR_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_DATARATE_DR_POS, \ - ADS114S0X_REGISTER_DATARATE_DR_LENGTH) -#define ADS114S0X_REGISTER_DATARATE_DR_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_DATARATE_DR_POS, \ - ADS114S0X_REGISTER_DATARATE_DR_LENGTH) -#define ADS114S0X_REGISTER_REF_FL_REF_EN_LENGTH 2 -#define ADS114S0X_REGISTER_REF_FL_REF_EN_POS 6 -#define ADS114S0X_REGISTER_REF_FL_REF_EN_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_REF_FL_REF_EN_POS, \ - ADS114S0X_REGISTER_REF_FL_REF_EN_LENGTH) -#define ADS114S0X_REGISTER_REF_FL_REF_EN_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_REF_FL_REF_EN_POS, \ - ADS114S0X_REGISTER_REF_FL_REF_EN_LENGTH) -#define ADS114S0X_REGISTER_REF_NOT_REFP_BUF_LENGTH 1 -#define ADS114S0X_REGISTER_REF_NOT_REFP_BUF_POS 5 -#define ADS114S0X_REGISTER_REF_NOT_REFP_BUF_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_REF_NOT_REFP_BUF_POS, \ - ADS114S0X_REGISTER_REF_NOT_REFP_BUF_LENGTH) -#define ADS114S0X_REGISTER_REF_NOT_REFP_BUF_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_REF_NOT_REFP_BUF_POS, \ - ADS114S0X_REGISTER_REF_NOT_REFP_BUF_LENGTH) -#define ADS114S0X_REGISTER_REF_NOT_REFN_BUF_LENGTH 1 -#define ADS114S0X_REGISTER_REF_NOT_REFN_BUF_POS 4 -#define ADS114S0X_REGISTER_REF_NOT_REFN_BUF_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_REF_NOT_REFN_BUF_POS, \ - ADS114S0X_REGISTER_REF_NOT_REFN_BUF_LENGTH) -#define ADS114S0X_REGISTER_REF_NOT_REFN_BUF_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_REF_NOT_REFN_BUF_POS, \ - ADS114S0X_REGISTER_REF_NOT_REFN_BUF_LENGTH) -#define ADS114S0X_REGISTER_REF_REFSEL_LENGTH 2 -#define ADS114S0X_REGISTER_REF_REFSEL_POS 2 -#define ADS114S0X_REGISTER_REF_REFSEL_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_REF_REFSEL_POS, \ - ADS114S0X_REGISTER_REF_REFSEL_LENGTH) -#define ADS114S0X_REGISTER_REF_REFSEL_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_REF_REFSEL_POS, \ - ADS114S0X_REGISTER_REF_REFSEL_LENGTH) -#define ADS114S0X_REGISTER_REF_REFCON_LENGTH 2 -#define ADS114S0X_REGISTER_REF_REFCON_POS 0 -#define ADS114S0X_REGISTER_REF_REFCON_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_REF_REFCON_POS, \ - ADS114S0X_REGISTER_REF_REFCON_LENGTH) -#define ADS114S0X_REGISTER_REF_REFCON_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_REF_REFCON_POS, \ - ADS114S0X_REGISTER_REF_REFCON_LENGTH) -#define ADS114S0X_REGISTER_IDACMAG_FL_RAIL_EN_LENGTH 1 -#define ADS114S0X_REGISTER_IDACMAG_FL_RAIL_EN_POS 7 -#define ADS114S0X_REGISTER_IDACMAG_FL_RAIL_EN_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_IDACMAG_FL_RAIL_EN_POS, \ - ADS114S0X_REGISTER_IDACMAG_FL_RAIL_EN_LENGTH) -#define ADS114S0X_REGISTER_IDACMAG_FL_RAIL_EN_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_IDACMAG_FL_RAIL_EN_POS, \ - ADS114S0X_REGISTER_IDACMAG_FL_RAIL_EN_LENGTH) -#define ADS114S0X_REGISTER_IDACMAG_PSW_LENGTH 1 -#define ADS114S0X_REGISTER_IDACMAG_PSW_POS 6 -#define ADS114S0X_REGISTER_IDACMAG_PSW_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_IDACMAG_PSW_POS, \ - ADS114S0X_REGISTER_IDACMAG_PSW_LENGTH) -#define ADS114S0X_REGISTER_IDACMAG_PSW_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_IDACMAG_PSW_POS, \ - ADS114S0X_REGISTER_IDACMAG_PSW_LENGTH) -#define ADS114S0X_REGISTER_IDACMAG_IMAG_LENGTH 4 -#define ADS114S0X_REGISTER_IDACMAG_IMAG_POS 0 -#define ADS114S0X_REGISTER_IDACMAG_IMAG_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_IDACMAG_IMAG_POS, \ - ADS114S0X_REGISTER_IDACMAG_IMAG_LENGTH) -#define ADS114S0X_REGISTER_IDACMAG_IMAG_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_IDACMAG_IMAG_POS, \ - ADS114S0X_REGISTER_IDACMAG_IMAG_LENGTH) -#define ADS114S0X_REGISTER_IDACMUX_I2MUX_LENGTH 4 -#define ADS114S0X_REGISTER_IDACMUX_I2MUX_POS 4 -#define ADS114S0X_REGISTER_IDACMUX_I2MUX_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_IDACMUX_I2MUX_POS, \ - ADS114S0X_REGISTER_IDACMUX_I2MUX_LENGTH) -#define ADS114S0X_REGISTER_IDACMUX_I2MUX_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_IDACMUX_I2MUX_POS, \ - ADS114S0X_REGISTER_IDACMUX_I2MUX_LENGTH) -#define ADS114S0X_REGISTER_IDACMUX_I1MUX_LENGTH 4 -#define ADS114S0X_REGISTER_IDACMUX_I1MUX_POS 0 -#define ADS114S0X_REGISTER_IDACMUX_I1MUX_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_IDACMUX_I1MUX_POS, \ - ADS114S0X_REGISTER_IDACMUX_I1MUX_LENGTH) -#define ADS114S0X_REGISTER_IDACMUX_I1MUX_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_IDACMUX_I1MUX_POS, \ - ADS114S0X_REGISTER_IDACMUX_I1MUX_LENGTH) -#define ADS114S0X_REGISTER_VBIAS_VB_LEVEL_LENGTH 1 -#define ADS114S0X_REGISTER_VBIAS_VB_LEVEL_POS 7 -#define ADS114S0X_REGISTER_VBIAS_VB_LEVEL_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_VBIAS_VB_LEVEL_POS, \ - ADS114S0X_REGISTER_VBIAS_VB_LEVEL_LENGTH) -#define ADS114S0X_REGISTER_VBIAS_VB_LEVEL_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_VBIAS_VB_LEVEL_POS, \ - ADS114S0X_REGISTER_VBIAS_VB_LEVEL_LENGTH) -#define ADS114S0X_REGISTER_GPIODAT_DIR_LENGTH 4 -#define ADS114S0X_REGISTER_GPIODAT_DIR_POS 4 -#define ADS114S0X_REGISTER_GPIODAT_DIR_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_GPIODAT_DIR_POS, \ - ADS114S0X_REGISTER_GPIODAT_DIR_LENGTH) -#define ADS114S0X_REGISTER_GPIODAT_DIR_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_GPIODAT_DIR_POS, \ - ADS114S0X_REGISTER_GPIODAT_DIR_LENGTH) -#define ADS114S0X_REGISTER_GPIODAT_DAT_LENGTH 4 -#define ADS114S0X_REGISTER_GPIODAT_DAT_POS 0 -#define ADS114S0X_REGISTER_GPIODAT_DAT_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_GPIODAT_DAT_POS, \ - ADS114S0X_REGISTER_GPIODAT_DAT_LENGTH) -#define ADS114S0X_REGISTER_GPIODAT_DAT_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_GPIODAT_DAT_POS, \ - ADS114S0X_REGISTER_GPIODAT_DAT_LENGTH) -#define ADS114S0X_REGISTER_GPIOCON_CON_LENGTH 4 -#define ADS114S0X_REGISTER_GPIOCON_CON_POS 0 -#define ADS114S0X_REGISTER_GPIOCON_CON_GET(value) \ - ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_GPIOCON_CON_POS, \ - ADS114S0X_REGISTER_GPIOCON_CON_LENGTH) -#define ADS114S0X_REGISTER_GPIOCON_CON_SET(target, value) \ - ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_GPIOCON_CON_POS, \ - ADS114S0X_REGISTER_GPIOCON_CON_LENGTH) - -/* - * - AIN0 as positive input - * - AIN1 as negative input - */ -#define ADS114S0X_REGISTER_INPMUX_SET_DEFAULTS(target) \ - ADS114S0X_REGISTER_INPMUX_MUXP_SET(target, 0b0000); \ - ADS114S0X_REGISTER_INPMUX_MUXN_SET(target, 0b0001) -/* - * - disable reference monitor - * - enable positive reference buffer - * - disable negative reference buffer - * - use internal reference - * - enable internal voltage reference - */ -#define ADS114S0X_REGISTER_REF_SET_DEFAULTS(target) \ - ADS114S0X_REGISTER_REF_FL_REF_EN_SET(target, 0b00); \ - ADS114S0X_REGISTER_REF_NOT_REFP_BUF_SET(target, 0b0); \ - ADS114S0X_REGISTER_REF_NOT_REFN_BUF_SET(target, 0b1); \ - ADS114S0X_REGISTER_REF_REFSEL_SET(target, 0b10); \ - ADS114S0X_REGISTER_REF_REFCON_SET(target, 0b01) -/* - * - disable global chop - * - use internal oscillator - * - single shot conversion mode - * - low latency filter - * - 20 samples per second - */ -#define ADS114S0X_REGISTER_DATARATE_SET_DEFAULTS(target) \ - ADS114S0X_REGISTER_DATARATE_G_CHOP_SET(target, 0b0); \ - ADS114S0X_REGISTER_DATARATE_CLK_SET(target, 0b0); \ - ADS114S0X_REGISTER_DATARATE_MODE_SET(target, 0b1); \ - ADS114S0X_REGISTER_DATARATE_FILTER_SET(target, 0b1); \ - ADS114S0X_REGISTER_DATARATE_DR_SET(target, 0b0100) -/* - * - delay of 14*t_mod - * - disable gain - * - gain 1 - */ -#define ADS114S0X_REGISTER_PGA_SET_DEFAULTS(target) \ - ADS114S0X_REGISTER_PGA_DELAY_SET(target, 0b000); \ - ADS114S0X_REGISTER_PGA_PGA_EN_SET(target, 0b00); \ - ADS114S0X_REGISTER_PGA_GAIN_SET(target, 0b000) -/* - * - disable PGA output rail flag - * - low-side power switch - * - IDAC off - */ -#define ADS114S0X_REGISTER_IDACMAG_SET_DEFAULTS(target) \ - ADS114S0X_REGISTER_IDACMAG_FL_RAIL_EN_SET(target, 0b0); \ - ADS114S0X_REGISTER_IDACMAG_PSW_SET(target, 0b0); \ - ADS114S0X_REGISTER_IDACMAG_IMAG_SET(target, 0b0000) -/* - * - disconnect IDAC1 - * - disconnect IDAC2 - */ -#define ADS114S0X_REGISTER_IDACMUX_SET_DEFAULTS(target) \ - ADS114S0X_REGISTER_IDACMUX_I1MUX_SET(target, 0b1111); \ - ADS114S0X_REGISTER_IDACMUX_I2MUX_SET(target, 0b1111) - -struct ads114s0x_config { - struct spi_dt_spec bus; -#if CONFIG_ADC_ASYNC - k_thread_stack_t *stack; -#endif - const struct gpio_dt_spec gpio_reset; - const struct gpio_dt_spec gpio_data_ready; - const struct gpio_dt_spec gpio_start_sync; - int idac_current; - uint8_t vbias_level; -}; - -struct ads114s0x_data { - struct adc_context ctx; -#if CONFIG_ADC_ASYNC - struct k_thread thread; -#endif /* CONFIG_ADC_ASYNC */ - struct gpio_callback callback_data_ready; - struct k_sem data_ready_signal; - struct k_sem acquire_signal; - int16_t *buffer; - int16_t *buffer_ptr; -#if CONFIG_ADC_ADS114S0X_GPIO - struct k_mutex gpio_lock; - uint8_t gpio_enabled; /* one bit per GPIO, 1 = enabled */ - uint8_t gpio_direction; /* one bit per GPIO, 1 = input */ - uint8_t gpio_value; /* one bit per GPIO, 1 = high */ -#endif /* CONFIG_ADC_ADS114S0X_GPIO */ -}; - -static void ads114s0x_data_ready_handler(const struct device *dev, struct gpio_callback *gpio_cb, - uint32_t pins) -{ - ARG_UNUSED(dev); - ARG_UNUSED(pins); - - struct ads114s0x_data *data = - CONTAINER_OF(gpio_cb, struct ads114s0x_data, callback_data_ready); - - k_sem_give(&data->data_ready_signal); -} - -static int ads114s0x_read_register(const struct device *dev, - enum ads114s0x_register register_address, uint8_t *value) -{ - const struct ads114s0x_config *config = dev->config; - uint8_t buffer_tx[3]; - uint8_t buffer_rx[ARRAY_SIZE(buffer_tx)]; - const struct spi_buf tx_buf[] = {{ - .buf = buffer_tx, - .len = ARRAY_SIZE(buffer_tx), - }}; - const struct spi_buf rx_buf[] = {{ - .buf = buffer_rx, - .len = ARRAY_SIZE(buffer_rx), - }}; - const struct spi_buf_set tx = { - .buffers = tx_buf, - .count = ARRAY_SIZE(tx_buf), - }; - const struct spi_buf_set rx = { - .buffers = rx_buf, - .count = ARRAY_SIZE(rx_buf), - }; - - buffer_tx[0] = ((uint8_t)ADS114S0X_COMMAND_RREG) | ((uint8_t)register_address); - /* read one register */ - buffer_tx[1] = 0x00; - - int result = spi_transceive_dt(&config->bus, &tx, &rx); - - if (result != 0) { - LOG_ERR("%s: spi_transceive failed with error %i", dev->name, result); - return result; - } - - *value = buffer_rx[2]; - LOG_DBG("%s: read from register 0x%02X value 0x%02X", dev->name, register_address, *value); - - return 0; -} - -static int ads114s0x_write_register(const struct device *dev, - enum ads114s0x_register register_address, uint8_t value) -{ - const struct ads114s0x_config *config = dev->config; - uint8_t buffer_tx[3]; - const struct spi_buf tx_buf[] = {{ - .buf = buffer_tx, - .len = ARRAY_SIZE(buffer_tx), - }}; - const struct spi_buf_set tx = { - .buffers = tx_buf, - .count = ARRAY_SIZE(tx_buf), - }; - - buffer_tx[0] = ((uint8_t)ADS114S0X_COMMAND_WREG) | ((uint8_t)register_address); - /* write one register */ - buffer_tx[1] = 0x00; - buffer_tx[2] = value; - - LOG_DBG("%s: writing to register 0x%02X value 0x%02X", dev->name, register_address, value); - int result = spi_write_dt(&config->bus, &tx); - - if (result != 0) { - LOG_ERR("%s: spi_write failed with error %i", dev->name, result); - return result; - } - - return 0; -} - -static int ads114s0x_write_multiple_registers(const struct device *dev, - enum ads114s0x_register *register_addresses, - uint8_t *values, size_t count) -{ - const struct ads114s0x_config *config = dev->config; - uint8_t buffer_tx[2]; - const struct spi_buf tx_buf[] = { - { - .buf = buffer_tx, - .len = ARRAY_SIZE(buffer_tx), - }, - { - .buf = values, - .len = count, - }, - }; - const struct spi_buf_set tx = { - .buffers = tx_buf, - .count = ARRAY_SIZE(tx_buf), - }; - - if (count == 0) { - LOG_WRN("%s: ignoring the command to write 0 registers", dev->name); - return -EINVAL; - } - - buffer_tx[0] = ((uint8_t)ADS114S0X_COMMAND_WREG) | ((uint8_t)register_addresses[0]); - buffer_tx[1] = count - 1; - - LOG_HEXDUMP_DBG(register_addresses, count, "writing to registers"); - LOG_HEXDUMP_DBG(values, count, "values"); - - /* ensure that the register addresses are in the correct order */ - for (size_t i = 1; i < count; ++i) { - __ASSERT(register_addresses[i - 1] + 1 == register_addresses[i], - "register addresses are not consecutive"); - } - - int result = spi_write_dt(&config->bus, &tx); - - if (result != 0) { - LOG_ERR("%s: spi_write failed with error %i", dev->name, result); - return result; - } - - return 0; -} - -static int ads114s0x_send_command(const struct device *dev, enum ads114s0x_command command) -{ - const struct ads114s0x_config *config = dev->config; - uint8_t buffer_tx[1]; - const struct spi_buf tx_buf[] = {{ - .buf = buffer_tx, - .len = ARRAY_SIZE(buffer_tx), - }}; - const struct spi_buf_set tx = { - .buffers = tx_buf, - .count = ARRAY_SIZE(tx_buf), - }; - - buffer_tx[0] = (uint8_t)command; - - LOG_DBG("%s: sending command 0x%02X", dev->name, command); - int result = spi_write_dt(&config->bus, &tx); - - if (result != 0) { - LOG_ERR("%s: spi_write failed with error %i", dev->name, result); - return result; - } - - return 0; -} - -static int ads114s0x_channel_setup(const struct device *dev, - const struct adc_channel_cfg *channel_cfg) -{ - const struct ads114s0x_config *config = dev->config; - uint8_t input_mux = 0; - uint8_t reference_control = 0; - uint8_t data_rate = 0; - uint8_t gain = 0; - uint8_t idac_magnitude = 0; - uint8_t idac_mux = 0; - uint8_t pin_selections[4]; - uint8_t vbias = 0; - size_t pin_selections_size; - int result; - enum ads114s0x_register register_addresses[7]; - uint8_t values[ARRAY_SIZE(register_addresses)]; - uint16_t acquisition_time_value = ADC_ACQ_TIME_VALUE(channel_cfg->acquisition_time); - uint16_t acquisition_time_unit = ADC_ACQ_TIME_UNIT(channel_cfg->acquisition_time); - - ADS114S0X_REGISTER_INPMUX_SET_DEFAULTS(gain); - ADS114S0X_REGISTER_REF_SET_DEFAULTS(reference_control); - ADS114S0X_REGISTER_DATARATE_SET_DEFAULTS(data_rate); - ADS114S0X_REGISTER_PGA_SET_DEFAULTS(gain); - ADS114S0X_REGISTER_IDACMAG_SET_DEFAULTS(idac_magnitude); - ADS114S0X_REGISTER_IDACMUX_SET_DEFAULTS(idac_mux); - - if (channel_cfg->channel_id != 0) { - LOG_ERR("%s: only one channel is supported", dev->name); - return -EINVAL; - } - - /* The ADS114 uses samples per seconds units with the lowest being 2.5SPS - * and with acquisition_time only having 14b for time, this will not fit - * within here for microsecond units. Use Tick units and allow the user to - * specify the ODR directly. - */ - if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT && - acquisition_time_unit != ADC_ACQ_TIME_TICKS) { - LOG_ERR("%s: invalid acquisition time %i", dev->name, - channel_cfg->acquisition_time); - return -EINVAL; - } - - if (channel_cfg->acquisition_time == ADC_ACQ_TIME_DEFAULT) { - ADS114S0X_REGISTER_DATARATE_DR_SET(data_rate, ADS114S0X_CONFIG_DR_20); - } else { - ADS114S0X_REGISTER_DATARATE_DR_SET(data_rate, acquisition_time_value); - } - - switch (channel_cfg->reference) { - case ADC_REF_INTERNAL: - /* disable negative reference buffer */ - ADS114S0X_REGISTER_REF_NOT_REFN_BUF_SET(reference_control, 0b1); - /* disable positive reference buffer */ - ADS114S0X_REGISTER_REF_NOT_REFP_BUF_SET(reference_control, 0b1); - /* use internal reference */ - ADS114S0X_REGISTER_REF_REFSEL_SET(reference_control, 0b10); - break; - case ADC_REF_EXTERNAL0: - /* enable negative reference buffer */ - ADS114S0X_REGISTER_REF_NOT_REFN_BUF_SET(reference_control, 0b0); - /* enable positive reference buffer */ - ADS114S0X_REGISTER_REF_NOT_REFP_BUF_SET(reference_control, 0b0); - /* use external reference 0*/ - ADS114S0X_REGISTER_REF_REFSEL_SET(reference_control, 0b00); - break; - case ADC_REF_EXTERNAL1: - /* enable negative reference buffer */ - ADS114S0X_REGISTER_REF_NOT_REFN_BUF_SET(reference_control, 0b0); - /* enable positive reference buffer */ - ADS114S0X_REGISTER_REF_NOT_REFP_BUF_SET(reference_control, 0b0); - /* use external reference 0*/ - ADS114S0X_REGISTER_REF_REFSEL_SET(reference_control, 0b01); - break; - default: - LOG_ERR("%s: reference %i is not supported", dev->name, channel_cfg->reference); - return -EINVAL; - } - - if (channel_cfg->differential) { - LOG_DBG("%s: configuring channel for a differential measurement from the pins (p, " - "n) (%i, %i)", - dev->name, channel_cfg->input_positive, channel_cfg->input_negative); - if (channel_cfg->input_positive >= ADS114S0X_INPUT_SELECTION_AINCOM) { - LOG_ERR("%s: positive channel input %i is invalid", dev->name, - channel_cfg->input_positive); - return -EINVAL; - } - - if (channel_cfg->input_negative >= ADS114S0X_INPUT_SELECTION_AINCOM) { - LOG_ERR("%s: negative channel input %i is invalid", dev->name, - channel_cfg->input_negative); - return -EINVAL; - } - - if (channel_cfg->input_positive == channel_cfg->input_negative) { - LOG_ERR("%s: negative and positive channel inputs must be different", - dev->name); - return -EINVAL; - } - - ADS114S0X_REGISTER_INPMUX_MUXP_SET(input_mux, channel_cfg->input_positive); - ADS114S0X_REGISTER_INPMUX_MUXN_SET(input_mux, channel_cfg->input_negative); - pin_selections[0] = channel_cfg->input_positive; - pin_selections[1] = channel_cfg->input_negative; - } else { - LOG_DBG("%s: configuring channel for single ended measurement from input %i", - dev->name, channel_cfg->input_positive); - if (channel_cfg->input_positive >= ADS114S0X_INPUT_SELECTION_AINCOM) { - LOG_ERR("%s: channel input %i is invalid", dev->name, - channel_cfg->input_positive); - return -EINVAL; - } - - ADS114S0X_REGISTER_INPMUX_MUXP_SET(input_mux, channel_cfg->input_positive); - ADS114S0X_REGISTER_INPMUX_MUXN_SET(input_mux, ADS114S0X_INPUT_SELECTION_AINCOM); - pin_selections[0] = channel_cfg->input_positive; - pin_selections[1] = ADS114S0X_INPUT_SELECTION_AINCOM; - } - - switch (channel_cfg->gain) { - case ADC_GAIN_1: - /* set gain value */ - ADS114S0X_REGISTER_PGA_GAIN_SET(gain, 0b000); - break; - case ADC_GAIN_2: - ADS114S0X_REGISTER_PGA_GAIN_SET(gain, 0b001); - break; - case ADC_GAIN_4: - ADS114S0X_REGISTER_PGA_GAIN_SET(gain, 0b010); - break; - case ADC_GAIN_8: - ADS114S0X_REGISTER_PGA_GAIN_SET(gain, 0b011); - break; - case ADC_GAIN_16: - ADS114S0X_REGISTER_PGA_GAIN_SET(gain, 0b100); - break; - case ADC_GAIN_32: - ADS114S0X_REGISTER_PGA_GAIN_SET(gain, 0b101); - break; - case ADC_GAIN_64: - ADS114S0X_REGISTER_PGA_GAIN_SET(gain, 0b110); - break; - case ADC_GAIN_128: - ADS114S0X_REGISTER_PGA_GAIN_SET(gain, 0b111); - break; - default: - LOG_ERR("%s: gain value %i not supported", dev->name, channel_cfg->gain); - return -EINVAL; - } - - if (channel_cfg->gain != ADC_GAIN_1) { - /* enable gain */ - ADS114S0X_REGISTER_PGA_PGA_EN_SET(gain, 0b01); - } - - switch (config->idac_current) { - case 0: - ADS114S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b0000); - break; - case 10: - ADS114S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b0001); - break; - case 50: - ADS114S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b0010); - break; - case 100: - ADS114S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b0011); - break; - case 250: - ADS114S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b0100); - break; - case 500: - ADS114S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b0101); - break; - case 750: - ADS114S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b0110); - break; - case 1000: - ADS114S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b0111); - break; - case 1500: - ADS114S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b1000); - break; - case 2000: - ADS114S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b1001); - break; - default: - LOG_ERR("%s: IDAC magnitude %i not supported", dev->name, config->idac_current); - return -EINVAL; - } - - if (channel_cfg->current_source_pin_set) { - LOG_DBG("%s: current source pin set to %i and %i", dev->name, - channel_cfg->current_source_pin[0], channel_cfg->current_source_pin[1]); - if (channel_cfg->current_source_pin[0] > 0b1111) { - LOG_ERR("%s: invalid selection %i for I1MUX", dev->name, - channel_cfg->current_source_pin[0]); - return -EINVAL; - } - - if (channel_cfg->current_source_pin[1] > 0b1111) { - LOG_ERR("%s: invalid selection %i for I2MUX", dev->name, - channel_cfg->current_source_pin[1]); - return -EINVAL; - } - - ADS114S0X_REGISTER_IDACMUX_I1MUX_SET(idac_mux, channel_cfg->current_source_pin[0]); - ADS114S0X_REGISTER_IDACMUX_I2MUX_SET(idac_mux, channel_cfg->current_source_pin[1]); - pin_selections[2] = channel_cfg->current_source_pin[0]; - pin_selections[3] = channel_cfg->current_source_pin[1]; - pin_selections_size = 4; - } else { - LOG_DBG("%s: current source pins not set", dev->name); - pin_selections_size = 2; - } - - for (size_t i = 0; i < pin_selections_size; ++i) { - if (pin_selections[i] > ADS114S0X_INPUT_SELECTION_AINCOM) { - continue; - } - - for (size_t j = i + 1; j < pin_selections_size; ++j) { - if (pin_selections[j] > ADS114S0X_INPUT_SELECTION_AINCOM) { - continue; - } - - if (pin_selections[i] == pin_selections[j]) { - LOG_ERR("%s: pins for inputs and current sources must be different", - dev->name); - return -EINVAL; - } - } - } - - ADS114S0X_REGISTER_VBIAS_VB_LEVEL_SET(vbias, config->vbias_level); - - if ((channel_cfg->vbias_pins & - ~GENMASK(ADS114S0X_VBIAS_PIN_MAX, ADS114S0X_VBIAS_PIN_MIN)) != 0) { - LOG_ERR("%s: invalid VBIAS pin selection 0x%08X", dev->name, - channel_cfg->vbias_pins); - return -EINVAL; - } - - vbias |= channel_cfg->vbias_pins; - - register_addresses[0] = ADS114S0X_REGISTER_INPMUX; - register_addresses[1] = ADS114S0X_REGISTER_PGA; - register_addresses[2] = ADS114S0X_REGISTER_DATARATE; - register_addresses[3] = ADS114S0X_REGISTER_REF; - register_addresses[4] = ADS114S0X_REGISTER_IDACMAG; - register_addresses[5] = ADS114S0X_REGISTER_IDACMUX; - register_addresses[6] = ADS114S0X_REGISTER_VBIAS; - BUILD_ASSERT(ARRAY_SIZE(register_addresses) == 7); - values[0] = input_mux; - values[1] = gain; - values[2] = data_rate; - values[3] = reference_control; - values[4] = idac_magnitude; - values[5] = idac_mux; - values[6] = vbias; - BUILD_ASSERT(ARRAY_SIZE(values) == 7); - - result = ads114s0x_write_multiple_registers(dev, register_addresses, values, - ARRAY_SIZE(values)); - - if (result != 0) { - LOG_ERR("%s: unable to configure registers", dev->name); - return result; - } - - return 0; -} - -static int ads114s0x_validate_buffer_size(const struct adc_sequence *sequence) -{ - size_t needed = sizeof(int16_t); - - if (sequence->options) { - needed *= (1 + sequence->options->extra_samplings); - } - - if (sequence->buffer_size < needed) { - return -ENOMEM; - } - - return 0; -} - -static int ads114s0x_validate_sequence(const struct device *dev, - const struct adc_sequence *sequence) -{ - if (sequence->resolution != ADS114S0X_RESOLUTION) { - LOG_ERR("%s: invalid resolution", dev->name); - return -EINVAL; - } - - if (sequence->channels != BIT(0)) { - LOG_ERR("%s: invalid channel", dev->name); - return -EINVAL; - } - - if (sequence->oversampling) { - LOG_ERR("%s: oversampling is not supported", dev->name); - return -EINVAL; - } - - return ads114s0x_validate_buffer_size(sequence); -} - -static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat_sampling) -{ - struct ads114s0x_data *data = CONTAINER_OF(ctx, struct ads114s0x_data, ctx); - - if (repeat_sampling) { - data->buffer = data->buffer_ptr; - } -} - -static void adc_context_start_sampling(struct adc_context *ctx) -{ - struct ads114s0x_data *data = CONTAINER_OF(ctx, struct ads114s0x_data, ctx); - - data->buffer_ptr = data->buffer; - k_sem_give(&data->acquire_signal); -} - -static int ads114s0x_adc_start_read(const struct device *dev, const struct adc_sequence *sequence, - bool wait) -{ - int result; - struct ads114s0x_data *data = dev->data; - - result = ads114s0x_validate_sequence(dev, sequence); - - if (result != 0) { - LOG_ERR("%s: sequence validation failed", dev->name); - return result; - } - - data->buffer = sequence->buffer; - - adc_context_start_read(&data->ctx, sequence); - - if (wait) { - result = adc_context_wait_for_completion(&data->ctx); - } - - return result; -} - -static int ads114s0x_send_start_read(const struct device *dev) -{ - const struct ads114s0x_config *config = dev->config; - int result; - - if (config->gpio_start_sync.port == 0) { - result = ads114s0x_send_command(dev, ADS114S0X_COMMAND_START); - if (result != 0) { - LOG_ERR("%s: unable to send START/SYNC command", dev->name); - return result; - } - } else { - result = gpio_pin_set_dt(&config->gpio_start_sync, 1); - - if (result != 0) { - LOG_ERR("%s: unable to start ADC operation", dev->name); - return result; - } - - k_sleep(K_USEC(ADS114S0X_START_SYNC_PULSE_DURATION_IN_US + - ADS114S0X_SETUP_TIME_IN_US)); - - result = gpio_pin_set_dt(&config->gpio_start_sync, 0); - - if (result != 0) { - LOG_ERR("%s: unable to start ADC operation", dev->name); - return result; - } - } - - return 0; -} - -static int ads114s0x_wait_data_ready(const struct device *dev) -{ - struct ads114s0x_data *data = dev->data; - - return k_sem_take(&data->data_ready_signal, ADC_CONTEXT_WAIT_FOR_COMPLETION_TIMEOUT); -} - -static int ads114s0x_read_sample(const struct device *dev, uint16_t *buffer) -{ - const struct ads114s0x_config *config = dev->config; - uint8_t buffer_tx[3]; - uint8_t buffer_rx[ARRAY_SIZE(buffer_tx)]; - const struct spi_buf tx_buf[] = {{ - .buf = buffer_tx, - .len = ARRAY_SIZE(buffer_tx), - }}; - const struct spi_buf rx_buf[] = {{ - .buf = buffer_rx, - .len = ARRAY_SIZE(buffer_rx), - }}; - const struct spi_buf_set tx = { - .buffers = tx_buf, - .count = ARRAY_SIZE(tx_buf), - }; - const struct spi_buf_set rx = { - .buffers = rx_buf, - .count = ARRAY_SIZE(rx_buf), - }; - - buffer_tx[0] = (uint8_t)ADS114S0X_COMMAND_RDATA; - - int result = spi_transceive_dt(&config->bus, &tx, &rx); - - if (result != 0) { - LOG_ERR("%s: spi_transceive failed with error %i", dev->name, result); - return result; - } - - *buffer = sys_get_be16(buffer_rx + 1); - LOG_DBG("%s: read ADC sample %i", dev->name, *buffer); - - return 0; -} - -static int ads114s0x_adc_perform_read(const struct device *dev) -{ - int result; - struct ads114s0x_data *data = dev->data; - - k_sem_take(&data->acquire_signal, K_FOREVER); - k_sem_reset(&data->data_ready_signal); - - result = ads114s0x_send_start_read(dev); - if (result != 0) { - LOG_ERR("%s: unable to start ADC conversion", dev->name); - adc_context_complete(&data->ctx, result); - return result; - } - - result = ads114s0x_wait_data_ready(dev); - if (result != 0) { - LOG_ERR("%s: waiting for data to be ready failed", dev->name); - adc_context_complete(&data->ctx, result); - return result; - } - - result = ads114s0x_read_sample(dev, data->buffer); - if (result != 0) { - LOG_ERR("%s: reading sample failed", dev->name); - adc_context_complete(&data->ctx, result); - return result; - } - - data->buffer++; - - adc_context_on_sampling_done(&data->ctx, dev); - - return result; -} - -#if CONFIG_ADC_ASYNC -static int ads114s0x_adc_read_async(const struct device *dev, const struct adc_sequence *sequence, - struct k_poll_signal *async) -{ - int result; - struct ads114s0x_data *data = dev->data; - - adc_context_lock(&data->ctx, true, async); - result = ads114s0x_adc_start_read(dev, sequence, true); - adc_context_release(&data->ctx, result); - - return result; -} - -static int ads114s0x_read(const struct device *dev, const struct adc_sequence *sequence) -{ - int result; - struct ads114s0x_data *data = dev->data; - - adc_context_lock(&data->ctx, false, NULL); - result = ads114s0x_adc_start_read(dev, sequence, true); - adc_context_release(&data->ctx, result); - - return result; -} - -#else -static int ads114s0x_read(const struct device *dev, const struct adc_sequence *sequence) -{ - int result; - struct ads114s0x_data *data = dev->data; - - adc_context_lock(&data->ctx, false, NULL); - result = ads114s0x_adc_start_read(dev, sequence, false); - - while (result == 0 && k_sem_take(&data->ctx.sync, K_NO_WAIT) != 0) { - result = ads114s0x_adc_perform_read(dev); - } - - adc_context_release(&data->ctx, result); - return result; -} -#endif - -#if CONFIG_ADC_ASYNC -static void ads114s0x_acquisition_thread(void *p1, void *p2, void *p3) -{ - ARG_UNUSED(p2); - ARG_UNUSED(p3); - - const struct device *dev = p1; - while (true) { - ads114s0x_adc_perform_read(dev); - } -} -#endif - -#ifdef CONFIG_ADC_ADS114S0X_GPIO -static int ads114s0x_gpio_write_config(const struct device *dev) -{ - struct ads114s0x_data *data = dev->data; - enum ads114s0x_register register_addresses[2]; - uint8_t register_values[ARRAY_SIZE(register_addresses)]; - uint8_t gpio_dat = 0; - uint8_t gpio_con = 0; - - ADS114S0X_REGISTER_GPIOCON_CON_SET(gpio_con, data->gpio_enabled); - ADS114S0X_REGISTER_GPIODAT_DAT_SET(gpio_dat, data->gpio_value); - ADS114S0X_REGISTER_GPIODAT_DIR_SET(gpio_dat, data->gpio_direction); - - register_values[0] = gpio_dat; - register_values[1] = gpio_con; - register_addresses[0] = ADS114S0X_REGISTER_GPIODAT; - register_addresses[1] = ADS114S0X_REGISTER_GPIOCON; - return ads114s0x_write_multiple_registers(dev, register_addresses, register_values, - ARRAY_SIZE(register_values)); -} - -static int ads114s0x_gpio_write_value(const struct device *dev) -{ - struct ads114s0x_data *data = dev->data; - uint8_t gpio_dat = 0; - - ADS114S0X_REGISTER_GPIODAT_DAT_SET(gpio_dat, data->gpio_value); - ADS114S0X_REGISTER_GPIODAT_DIR_SET(gpio_dat, data->gpio_direction); - - return ads114s0x_write_register(dev, ADS114S0X_REGISTER_GPIODAT, gpio_dat); -} - -int ads114s0x_gpio_set_output(const struct device *dev, uint8_t pin, bool initial_value) -{ - struct ads114s0x_data *data = dev->data; - int result = 0; - - if (pin > ADS114S0X_GPIO_MAX) { - LOG_ERR("%s: invalid pin %i", dev->name, pin); - return -EINVAL; - } - - k_mutex_lock(&data->gpio_lock, K_FOREVER); - - data->gpio_enabled |= BIT(pin); - data->gpio_direction &= ~BIT(pin); - - if (initial_value) { - data->gpio_value |= BIT(pin); - } else { - data->gpio_value &= ~BIT(pin); - } - - result = ads114s0x_gpio_write_config(dev); - - k_mutex_unlock(&data->gpio_lock); - - return result; -} - -int ads114s0x_gpio_set_input(const struct device *dev, uint8_t pin) -{ - struct ads114s0x_data *data = dev->data; - int result = 0; - - if (pin > ADS114S0X_GPIO_MAX) { - LOG_ERR("%s: invalid pin %i", dev->name, pin); - return -EINVAL; - } - - k_mutex_lock(&data->gpio_lock, K_FOREVER); - - data->gpio_enabled |= BIT(pin); - data->gpio_direction |= BIT(pin); - data->gpio_value &= ~BIT(pin); - - result = ads114s0x_gpio_write_config(dev); - - k_mutex_unlock(&data->gpio_lock); - - return result; -} - -int ads114s0x_gpio_deconfigure(const struct device *dev, uint8_t pin) -{ - struct ads114s0x_data *data = dev->data; - int result = 0; - - if (pin > ADS114S0X_GPIO_MAX) { - LOG_ERR("%s: invalid pin %i", dev->name, pin); - return -EINVAL; - } - - k_mutex_lock(&data->gpio_lock, K_FOREVER); - - data->gpio_enabled &= ~BIT(pin); - data->gpio_direction |= BIT(pin); - data->gpio_value &= ~BIT(pin); - - result = ads114s0x_gpio_write_config(dev); - - k_mutex_unlock(&data->gpio_lock); - - return result; -} - -int ads114s0x_gpio_set_pin_value(const struct device *dev, uint8_t pin, bool value) -{ - struct ads114s0x_data *data = dev->data; - int result = 0; - - if (pin > ADS114S0X_GPIO_MAX) { - LOG_ERR("%s: invalid pin %i", dev->name, pin); - return -EINVAL; - } - - k_mutex_lock(&data->gpio_lock, K_FOREVER); - - if ((BIT(pin) & data->gpio_enabled) == 0) { - LOG_ERR("%s: gpio pin %i not configured", dev->name, pin); - result = -EINVAL; - } else if ((BIT(pin) & data->gpio_direction) != 0) { - LOG_ERR("%s: gpio pin %i not configured as output", dev->name, pin); - result = -EINVAL; - } else { - data->gpio_value |= BIT(pin); - - result = ads114s0x_gpio_write_value(dev); - } - - k_mutex_unlock(&data->gpio_lock); - - return result; -} - -int ads114s0x_gpio_get_pin_value(const struct device *dev, uint8_t pin, bool *value) -{ - struct ads114s0x_data *data = dev->data; - int result = 0; - uint8_t gpio_dat; - - if (pin > ADS114S0X_GPIO_MAX) { - LOG_ERR("%s: invalid pin %i", dev->name, pin); - return -EINVAL; - } - - k_mutex_lock(&data->gpio_lock, K_FOREVER); - - if ((BIT(pin) & data->gpio_enabled) == 0) { - LOG_ERR("%s: gpio pin %i not configured", dev->name, pin); - result = -EINVAL; - } else if ((BIT(pin) & data->gpio_direction) == 0) { - LOG_ERR("%s: gpio pin %i not configured as input", dev->name, pin); - result = -EINVAL; - } else { - result = ads114s0x_read_register(dev, ADS114S0X_REGISTER_GPIODAT, &gpio_dat); - data->gpio_value = ADS114S0X_REGISTER_GPIODAT_DAT_GET(gpio_dat); - *value = (BIT(pin) & data->gpio_value) != 0; - } - - k_mutex_unlock(&data->gpio_lock); - - return result; -} - -int ads114s0x_gpio_port_get_raw(const struct device *dev, gpio_port_value_t *value) -{ - struct ads114s0x_data *data = dev->data; - int result = 0; - uint8_t gpio_dat; - - k_mutex_lock(&data->gpio_lock, K_FOREVER); - - result = ads114s0x_read_register(dev, ADS114S0X_REGISTER_GPIODAT, &gpio_dat); - data->gpio_value = ADS114S0X_REGISTER_GPIODAT_DAT_GET(gpio_dat); - *value = data->gpio_value; - - k_mutex_unlock(&data->gpio_lock); - - return result; -} - -int ads114s0x_gpio_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, - gpio_port_value_t value) -{ - struct ads114s0x_data *data = dev->data; - int result = 0; - - k_mutex_lock(&data->gpio_lock, K_FOREVER); - - data->gpio_value = ((data->gpio_value & ~mask) | (mask & value)) & data->gpio_enabled & - ~data->gpio_direction; - result = ads114s0x_gpio_write_value(dev); - - k_mutex_unlock(&data->gpio_lock); - - return result; -} - -int ads114s0x_gpio_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) -{ - struct ads114s0x_data *data = dev->data; - int result = 0; - - k_mutex_lock(&data->gpio_lock, K_FOREVER); - - data->gpio_value = (data->gpio_value ^ pins) & data->gpio_enabled & ~data->gpio_direction; - result = ads114s0x_gpio_write_value(dev); - - k_mutex_unlock(&data->gpio_lock); - - return result; -} - -#endif /* CONFIG_ADC_ADS114S0X_GPIO */ - -static int ads114s0x_init(const struct device *dev) -{ - uint8_t status = 0; - uint8_t reference_control = 0; - uint8_t reference_control_read; - int result; - const struct ads114s0x_config *config = dev->config; - struct ads114s0x_data *data = dev->data; - - adc_context_init(&data->ctx); - - k_sem_init(&data->data_ready_signal, 0, 1); - k_sem_init(&data->acquire_signal, 0, 1); - -#ifdef CONFIG_ADC_ADS114S0X_GPIO - k_mutex_init(&data->gpio_lock); -#endif /* CONFIG_ADC_ADS114S0X_GPIO */ - - if (!spi_is_ready_dt(&config->bus)) { - LOG_ERR("%s: SPI device is not ready", dev->name); - return -ENODEV; - } - - if (config->gpio_reset.port != NULL) { - result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE); - if (result != 0) { - LOG_ERR("%s: failed to initialize GPIO for reset", dev->name); - return result; - } - } - - if (config->gpio_start_sync.port != NULL) { - result = gpio_pin_configure_dt(&config->gpio_start_sync, GPIO_OUTPUT_INACTIVE); - if (result != 0) { - LOG_ERR("%s: failed to initialize GPIO for start/sync", dev->name); - return result; - } - } - - result = gpio_pin_configure_dt(&config->gpio_data_ready, GPIO_INPUT); - if (result != 0) { - LOG_ERR("%s: failed to initialize GPIO for data ready", dev->name); - return result; - } - - result = gpio_pin_interrupt_configure_dt(&config->gpio_data_ready, GPIO_INT_EDGE_TO_ACTIVE); - if (result != 0) { - LOG_ERR("%s: failed to configure data ready interrupt", dev->name); - return -EIO; - } - - gpio_init_callback(&data->callback_data_ready, ads114s0x_data_ready_handler, - BIT(config->gpio_data_ready.pin)); - result = gpio_add_callback(config->gpio_data_ready.port, &data->callback_data_ready); - if (result != 0) { - LOG_ERR("%s: failed to add data ready callback", dev->name); - return -EIO; - } - -#if CONFIG_ADC_ASYNC - k_tid_t tid = k_thread_create(&data->thread, config->stack, - CONFIG_ADC_ADS114S0X_ACQUISITION_THREAD_STACK_SIZE, - ads114s0x_acquisition_thread, (void *)dev, NULL, NULL, - CONFIG_ADC_ADS114S0X_ASYNC_THREAD_INIT_PRIO, 0, K_NO_WAIT); - k_thread_name_set(tid, "adc_ads114s0x"); -#endif - - k_busy_wait(ADS114S0X_POWER_ON_RESET_TIME_IN_US); - - if (config->gpio_reset.port == NULL) { - result = ads114s0x_send_command(dev, ADS114S0X_COMMAND_RESET); - if (result != 0) { - LOG_ERR("%s: unable to send RESET command", dev->name); - return result; - } - } else { - k_busy_wait(ADS114S0X_RESET_LOW_TIME_IN_US); - gpio_pin_set_dt(&config->gpio_reset, 0); - } - - k_busy_wait(ADS114S0X_RESET_DELAY_TIME_IN_US); - - result = ads114s0x_read_register(dev, ADS114S0X_REGISTER_STATUS, &status); - if (result != 0) { - LOG_ERR("%s: unable to read status register", dev->name); - return result; - } - - if (ADS114S0X_REGISTER_STATUS_NOT_RDY_GET(status) == 0x01) { - LOG_ERR("%s: ADS114 is not yet ready", dev->name); - return -EBUSY; - } - - /* - * Activate internal voltage reference during initialization to - * avoid the necessary setup time for it to settle later on. - */ - ADS114S0X_REGISTER_REF_SET_DEFAULTS(reference_control); - - result = ads114s0x_write_register(dev, ADS114S0X_REGISTER_REF, reference_control); - if (result != 0) { - LOG_ERR("%s: unable to set default reference control values", dev->name); - return result; - } - - /* - * Ensure that the internal voltage reference is active. - */ - result = ads114s0x_read_register(dev, ADS114S0X_REGISTER_REF, &reference_control_read); - if (result != 0) { - LOG_ERR("%s: unable to read reference control values", dev->name); - return result; - } - - if (reference_control != reference_control_read) { - LOG_ERR("%s: reference control register is incorrect: 0x%02X", dev->name, - reference_control_read); - return -EIO; - } - -#ifdef CONFIG_ADC_ADS114S0X_GPIO - data->gpio_enabled = 0x00; - data->gpio_direction = 0x0F; - data->gpio_value = 0x00; - - result = ads114s0x_gpio_write_config(dev); - - if (result != 0) { - LOG_ERR("%s: unable to configure defaults for GPIOs", dev->name); - return result; - } -#endif - - adc_context_unlock_unconditionally(&data->ctx); - - return result; -} - -static const struct adc_driver_api api = { - .channel_setup = ads114s0x_channel_setup, - .read = ads114s0x_read, - .ref_internal = ADS114S0X_REF_INTERNAL, -#ifdef CONFIG_ADC_ASYNC - .read_async = ads114s0x_adc_read_async, -#endif -}; - -BUILD_ASSERT(CONFIG_ADC_INIT_PRIORITY > CONFIG_SPI_INIT_PRIORITY, - "CONFIG_ADC_INIT_PRIORITY must be higher than CONFIG_SPI_INIT_PRIORITY"); - -#define DT_DRV_COMPAT ti_ads114s08 - -#define ADC_ADS114S0X_INST_DEFINE(n) \ - IF_ENABLED( \ - CONFIG_ADC_ASYNC, \ - (static K_KERNEL_STACK_DEFINE( \ - thread_stack_##n, CONFIG_ADC_ADS114S0X_ACQUISITION_THREAD_STACK_SIZE);)) \ - static const struct ads114s0x_config config_##n = { \ - .bus = SPI_DT_SPEC_INST_GET( \ - n, SPI_OP_MODE_MASTER | SPI_MODE_CPHA | SPI_WORD_SET(8), 0), \ - IF_ENABLED(CONFIG_ADC_ASYNC, (.stack = thread_stack_##n,)) \ - .gpio_reset = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {0}), \ - .gpio_data_ready = GPIO_DT_SPEC_INST_GET(n, drdy_gpios), \ - .gpio_start_sync = GPIO_DT_SPEC_INST_GET_OR(n, start_sync_gpios, {0}), \ - .idac_current = DT_INST_PROP(n, idac_current), \ - .vbias_level = DT_INST_PROP(n, vbias_level), \ - }; \ - static struct ads114s0x_data data_##n; \ - DEVICE_DT_INST_DEFINE(n, ads114s0x_init, NULL, &data_##n, &config_##n, POST_KERNEL, \ - CONFIG_ADC_INIT_PRIORITY, &api); - -DT_INST_FOREACH_STATUS_OKAY(ADC_ADS114S0X_INST_DEFINE); diff --git a/drivers/adc/adc_ads1x4s0x.c b/drivers/adc/adc_ads1x4s0x.c new file mode 100644 index 000000000000..b0cec9b2b4ea --- /dev/null +++ b/drivers/adc/adc_ads1x4s0x.c @@ -0,0 +1,1613 @@ +/* + * Copyright (c) 2023 SILA Embedded Solutions GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ADS1X4S0X_HAS_16_BIT_DEV \ + (DT_HAS_COMPAT_STATUS_OKAY(ti_ads114s06) || DT_HAS_COMPAT_STATUS_OKAY(ti_ads114s08)) +#define ADS1X4S0X_HAS_24_BIT_DEV \ + (DT_HAS_COMPAT_STATUS_OKAY(ti_ads124s06) || DT_HAS_COMPAT_STATUS_OKAY(ti_ads124s08)) + +#define ADC_CONTEXT_USES_KERNEL_TIMER 1 +#define ADC_CONTEXT_WAIT_FOR_COMPLETION_TIMEOUT \ + K_MSEC(CONFIG_ADC_ADS1X4S0X_WAIT_FOR_COMPLETION_TIMEOUT_MS) +#include "adc_context.h" + +LOG_MODULE_REGISTER(ads1x4s0x, CONFIG_ADC_LOG_LEVEL); + +#define ADS1X4S0X_CLK_FREQ_IN_KHZ 4096 +#define ADS1X4S0X_RESET_LOW_TIME_IN_CLOCK_CYCLES 4 +#define ADS1X4S0X_START_SYNC_PULSE_DURATION_IN_CLOCK_CYCLES 4 +#define ADS1X4S0X_SETUP_TIME_IN_CLOCK_CYCLES 32 +#define ADS1X4S0X_INPUT_SELECTION_AINCOM 12 +#define ADS1X4S0X_RESOLUTION 16 +#define ADS1X4S0X_REF_INTERNAL 2500 +#define ADS1X4S0X_GPIO_MAX 3 +#define ADS1X4S0X_POWER_ON_RESET_TIME_IN_US 2200 +#define ADS1X4S0X_VBIAS_PIN_MAX 7 +#define ADS1X4S0X_VBIAS_PIN_MIN 0 + +/* Not mentioned in the datasheet, but instead determined experimentally. */ +#define ADS1X4S0X_RESET_DELAY_TIME_SAFETY_MARGIN_IN_US 1000 +#define ADS1X4S0X_RESET_DELAY_TIME_IN_US \ + (4096 * 1000 / ADS1X4S0X_CLK_FREQ_IN_KHZ + ADS1X4S0X_RESET_DELAY_TIME_SAFETY_MARGIN_IN_US) + +#define ADS1X4S0X_RESET_LOW_TIME_IN_US \ + (ADS1X4S0X_RESET_LOW_TIME_IN_CLOCK_CYCLES * 1000 / ADS1X4S0X_CLK_FREQ_IN_KHZ) +#define ADS1X4S0X_START_SYNC_PULSE_DURATION_IN_US \ + (ADS1X4S0X_START_SYNC_PULSE_DURATION_IN_CLOCK_CYCLES * 1000 / ADS1X4S0X_CLK_FREQ_IN_KHZ) +#define ADS1X4S0X_SETUP_TIME_IN_US \ + (ADS1X4S0X_SETUP_TIME_IN_CLOCK_CYCLES * 1000 / ADS1X4S0X_CLK_FREQ_IN_KHZ) + +enum ads1x4s0x_command { + ADS1X4S0X_COMMAND_NOP = 0x00, + ADS1X4S0X_COMMAND_WAKEUP = 0x02, + ADS1X4S0X_COMMAND_POWERDOWN = 0x04, + ADS1X4S0X_COMMAND_RESET = 0x06, + ADS1X4S0X_COMMAND_START = 0x08, + ADS1X4S0X_COMMAND_STOP = 0x0A, + ADS1X4S0X_COMMAND_SYOCAL = 0x16, + ADS1X4S0X_COMMAND_SYGCAL = 0x17, + ADS1X4S0X_COMMAND_SFOCAL = 0x19, + ADS1X4S0X_COMMAND_RDATA = 0x12, + ADS1X4S0X_COMMAND_RREG = 0x20, + ADS1X4S0X_COMMAND_WREG = 0x40, +}; + +enum ads1x4s0x_register { + ADS1X4S0X_REGISTER_ID = 0x00, + ADS1X4S0X_REGISTER_STATUS = 0x01, + ADS1X4S0X_REGISTER_INPMUX = 0x02, + ADS1X4S0X_REGISTER_PGA = 0x03, + ADS1X4S0X_REGISTER_DATARATE = 0x04, + ADS1X4S0X_REGISTER_REF = 0x05, + ADS1X4S0X_REGISTER_IDACMAG = 0x06, + ADS1X4S0X_REGISTER_IDACMUX = 0x07, + ADS1X4S0X_REGISTER_VBIAS = 0x08, + ADS1X4S0X_REGISTER_SYS = 0x09, + ADS1X4S0X_REGISTER_OFCAL0 = 0x0B, + ADS1X4S0X_REGISTER_OFCAL1 = 0x0C, + ADS1X4S0X_REGISTER_FSCAL0 = 0x0E, + ADS1X4S0X_REGISTER_FSCAL1 = 0x0F, + ADS1X4S0X_REGISTER_GPIODAT = 0x10, + ADS1X4S0X_REGISTER_GPIOCON = 0x11, +}; + +#define ADS1X4S0X_REGISTER_GET_VALUE(value, pos, length) \ + FIELD_GET(GENMASK(pos + length - 1, pos), value) +#define ADS1X4S0X_REGISTER_SET_VALUE(target, value, pos, length) \ + target &= ~GENMASK(pos + length - 1, pos); \ + target |= FIELD_PREP(GENMASK(pos + length - 1, pos), value) + +#define ADS1X4S0X_REGISTER_ID_DEV_ID_LENGTH 3 +#define ADS1X4S0X_REGISTER_ID_DEV_ID_POS 0 +#define ADS1X4S0X_REGISTER_ID_DEV_ID_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_ID_DEV_ID_POS, \ + ADS1X4S0X_REGISTER_ID_DEV_ID_LENGTH) +#define ADS1X4S0X_REGISTER_ID_DEV_ID_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_ID_DEV_ID_POS, \ + ADS1X4S0X_REGISTER_ID_DEV_ID_LENGTH) +#define ADS1X4S0X_REGISTER_STATUS_FL_POR_LENGTH 1 +#define ADS1X4S0X_REGISTER_STATUS_FL_POR_POS 7 +#define ADS1X4S0X_REGISTER_STATUS_FL_POR_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_STATUS_FL_POR_POS, \ + ADS1X4S0X_REGISTER_STATUS_FL_POR_LENGTH) +#define ADS1X4S0X_REGISTER_STATUS_FL_POR_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_STATUS_FL_POR_POS, \ + ADS1X4S0X_REGISTER_STATUS_FL_POR_LENGTH) +#define ADS1X4S0X_REGISTER_STATUS_NOT_RDY_LENGTH 1 +#define ADS1X4S0X_REGISTER_STATUS_NOT_RDY_POS 6 +#define ADS1X4S0X_REGISTER_STATUS_NOT_RDY_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_STATUS_NOT_RDY_POS, \ + ADS1X4S0X_REGISTER_STATUS_NOT_RDY_LENGTH) +#define ADS1X4S0X_REGISTER_STATUS_NOT_RDY_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_STATUS_NOT_RDY_POS, \ + ADS1X4S0X_REGISTER_STATUS_NOT_RDY_LENGTH) +#define ADS1X4S0X_REGISTER_STATUS_FL_P_RAILP_LENGTH 1 +#define ADS1X4S0X_REGISTER_STATUS_FL_P_RAILP_POS 5 +#define ADS1X4S0X_REGISTER_STATUS_FL_P_RAILP_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_STATUS_FL_P_RAILP_POS, \ + ADS1X4S0X_REGISTER_STATUS_FL_P_RAILP_LENGTH) +#define ADS1X4S0X_REGISTER_STATUS_FL_P_RAILP_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_STATUS_FL_P_RAILP_POS, \ + ADS1X4S0X_REGISTER_STATUS_FL_P_RAILP_LENGTH) +#define ADS1X4S0X_REGISTER_STATUS_FL_P_RAILN_LENGTH 1 +#define ADS1X4S0X_REGISTER_STATUS_FL_P_RAILN_POS 4 +#define ADS1X4S0X_REGISTER_STATUS_FL_P_RAILN_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_STATUS_FL_P_RAILN_POS, \ + ADS1X4S0X_REGISTER_STATUS_FL_P_RAILN_LENGTH) +#define ADS1X4S0X_REGISTER_STATUS_FL_P_RAILN_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_STATUS_FL_P_RAILN_POS, \ + ADS1X4S0X_REGISTER_STATUS_FL_P_RAILN_LENGTH) +#define ADS1X4S0X_REGISTER_STATUS_FL_N_RAILP_LENGTH 1 +#define ADS1X4S0X_REGISTER_STATUS_FL_N_RAILP_POS 3 +#define ADS1X4S0X_REGISTER_STATUS_FL_N_RAILP_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_STATUS_FL_N_RAILP_POS, \ + ADS1X4S0X_REGISTER_STATUS_FL_N_RAILP_LENGTH) +#define ADS1X4S0X_REGISTER_STATUS_FL_N_RAILP_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_STATUS_FL_N_RAILP_POS, \ + ADS1X4S0X_REGISTER_STATUS_FL_N_RAILP_LENGTH) +#define ADS1X4S0X_REGISTER_STATUS_FL_N_RAILN_LENGTH 1 +#define ADS1X4S0X_REGISTER_STATUS_FL_N_RAILN_POS 2 +#define ADS1X4S0X_REGISTER_STATUS_FL_N_RAILN_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_STATUS_FL_N_RAILN_POS, \ + ADS1X4S0X_REGISTER_STATUS_FL_N_RAILN_LENGTH) +#define ADS1X4S0X_REGISTER_STATUS_FL_N_RAILN_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_STATUS_FL_N_RAILN_POS, \ + ADS1X4S0X_REGISTER_STATUS_FL_N_RAILN_LENGTH) +#define ADS1X4S0X_REGISTER_STATUS_FL_REF_L1_LENGTH 1 +#define ADS1X4S0X_REGISTER_STATUS_FL_REF_L1_POS 1 +#define ADS1X4S0X_REGISTER_STATUS_FL_REF_L1_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_STATUS_FL_REF_L1_POS, \ + ADS1X4S0X_REGISTER_STATUS_FL_REF_L1_LENGTH) +#define ADS1X4S0X_REGISTER_STATUS_FL_REF_L1_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_STATUS_FL_REF_L1_POS, \ + ADS1X4S0X_REGISTER_STATUS_FL_REF_L1_LENGTH) +#define ADS1X4S0X_REGISTER_STATUS_FL_REF_L0_LENGTH 1 +#define ADS1X4S0X_REGISTER_STATUS_FL_REF_L0_POS 0 +#define ADS1X4S0X_REGISTER_STATUS_FL_REF_L0_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_STATUS_FL_REF_L0_POS, \ + ADS1X4S0X_REGISTER_STATUS_FL_REF_L0_LENGTH) +#define ADS1X4S0X_REGISTER_STATUS_FL_REF_L0_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_STATUS_FL_REF_L0_POS, \ + ADS1X4S0X_REGISTER_STATUS_FL_REF_L0_LENGTH) +#define ADS1X4S0X_REGISTER_INPMUX_MUXP_LENGTH 4 +#define ADS1X4S0X_REGISTER_INPMUX_MUXP_POS 4 +#define ADS1X4S0X_REGISTER_INPMUX_MUXP_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_INPMUX_MUXP_POS, \ + ADS1X4S0X_REGISTER_INPMUX_MUXP_LENGTH) +#define ADS1X4S0X_REGISTER_INPMUX_MUXP_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_INPMUX_MUXP_POS, \ + ADS1X4S0X_REGISTER_INPMUX_MUXP_LENGTH) +#define ADS1X4S0X_REGISTER_INPMUX_MUXN_LENGTH 4 +#define ADS1X4S0X_REGISTER_INPMUX_MUXN_POS 0 +#define ADS1X4S0X_REGISTER_INPMUX_MUXN_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_INPMUX_MUXN_POS, \ + ADS1X4S0X_REGISTER_INPMUX_MUXN_LENGTH) +#define ADS1X4S0X_REGISTER_INPMUX_MUXN_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_INPMUX_MUXN_POS, \ + ADS1X4S0X_REGISTER_INPMUX_MUXN_LENGTH) +#define ADS1X4S0X_REGISTER_PGA_DELAY_LENGTH 3 +#define ADS1X4S0X_REGISTER_PGA_DELAY_POS 5 +#define ADS1X4S0X_REGISTER_PGA_DELAY_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_PGA_DELAY_POS, \ + ADS1X4S0X_REGISTER_PGA_DELAY_LENGTH) +#define ADS1X4S0X_REGISTER_PGA_DELAY_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_PGA_DELAY_POS, \ + ADS1X4S0X_REGISTER_PGA_DELAY_LENGTH) +#define ADS1X4S0X_REGISTER_PGA_PGA_EN_LENGTH 2 +#define ADS1X4S0X_REGISTER_PGA_PGA_EN_POS 3 +#define ADS1X4S0X_REGISTER_PGA_PGA_EN_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_PGA_PGA_EN_POS, \ + ADS1X4S0X_REGISTER_PGA_PGA_EN_LENGTH) +#define ADS1X4S0X_REGISTER_PGA_PGA_EN_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_PGA_PGA_EN_POS, \ + ADS1X4S0X_REGISTER_PGA_PGA_EN_LENGTH) +#define ADS1X4S0X_REGISTER_PGA_GAIN_LENGTH 3 +#define ADS1X4S0X_REGISTER_PGA_GAIN_POS 0 +#define ADS1X4S0X_REGISTER_PGA_GAIN_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_PGA_GAIN_POS, \ + ADS1X4S0X_REGISTER_PGA_GAIN_LENGTH) +#define ADS1X4S0X_REGISTER_PGA_GAIN_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_PGA_GAIN_POS, \ + ADS1X4S0X_REGISTER_PGA_GAIN_LENGTH) +#define ADS1X4S0X_REGISTER_DATARATE_G_CHOP_LENGTH 1 +#define ADS1X4S0X_REGISTER_DATARATE_G_CHOP_POS 7 +#define ADS1X4S0X_REGISTER_DATARATE_G_CHOP_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_DATARATE_G_CHOP_POS, \ + ADS1X4S0X_REGISTER_DATARATE_G_CHOP_LENGTH) +#define ADS1X4S0X_REGISTER_DATARATE_G_CHOP_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_DATARATE_G_CHOP_POS, \ + ADS1X4S0X_REGISTER_DATARATE_G_CHOP_LENGTH) +#define ADS1X4S0X_REGISTER_DATARATE_CLK_LENGTH 1 +#define ADS1X4S0X_REGISTER_DATARATE_CLK_POS 6 +#define ADS1X4S0X_REGISTER_DATARATE_CLK_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_DATARATE_CLK_POS, \ + ADS1X4S0X_REGISTER_DATARATE_CLK_LENGTH) +#define ADS1X4S0X_REGISTER_DATARATE_CLK_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_DATARATE_CLK_POS, \ + ADS1X4S0X_REGISTER_DATARATE_CLK_LENGTH) +#define ADS1X4S0X_REGISTER_DATARATE_MODE_LENGTH 1 +#define ADS1X4S0X_REGISTER_DATARATE_MODE_POS 5 +#define ADS1X4S0X_REGISTER_DATARATE_MODE_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_DATARATE_MODE_POS, \ + ADS1X4S0X_REGISTER_DATARATE_MODE_LENGTH) +#define ADS1X4S0X_REGISTER_DATARATE_MODE_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_DATARATE_MODE_POS, \ + ADS1X4S0X_REGISTER_DATARATE_MODE_LENGTH) +#define ADS1X4S0X_REGISTER_DATARATE_FILTER_LENGTH 1 +#define ADS1X4S0X_REGISTER_DATARATE_FILTER_POS 4 +#define ADS1X4S0X_REGISTER_DATARATE_FILTER_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_DATARATE_FILTER_POS, \ + ADS1X4S0X_REGISTER_DATARATE_FILTER_LENGTH) +#define ADS1X4S0X_REGISTER_DATARATE_FILTER_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_DATARATE_FILTER_POS, \ + ADS1X4S0X_REGISTER_DATARATE_FILTER_LENGTH) +#define ADS1X4S0X_REGISTER_DATARATE_DR_LENGTH 4 +#define ADS1X4S0X_REGISTER_DATARATE_DR_POS 0 +#define ADS1X4S0X_REGISTER_DATARATE_DR_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_DATARATE_DR_POS, \ + ADS1X4S0X_REGISTER_DATARATE_DR_LENGTH) +#define ADS1X4S0X_REGISTER_DATARATE_DR_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_DATARATE_DR_POS, \ + ADS1X4S0X_REGISTER_DATARATE_DR_LENGTH) +#define ADS1X4S0X_REGISTER_REF_FL_REF_EN_LENGTH 2 +#define ADS1X4S0X_REGISTER_REF_FL_REF_EN_POS 6 +#define ADS1X4S0X_REGISTER_REF_FL_REF_EN_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_REF_FL_REF_EN_POS, \ + ADS1X4S0X_REGISTER_REF_FL_REF_EN_LENGTH) +#define ADS1X4S0X_REGISTER_REF_FL_REF_EN_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_REF_FL_REF_EN_POS, \ + ADS1X4S0X_REGISTER_REF_FL_REF_EN_LENGTH) +#define ADS1X4S0X_REGISTER_REF_NOT_REFP_BUF_LENGTH 1 +#define ADS1X4S0X_REGISTER_REF_NOT_REFP_BUF_POS 5 +#define ADS1X4S0X_REGISTER_REF_NOT_REFP_BUF_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_REF_NOT_REFP_BUF_POS, \ + ADS1X4S0X_REGISTER_REF_NOT_REFP_BUF_LENGTH) +#define ADS1X4S0X_REGISTER_REF_NOT_REFP_BUF_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_REF_NOT_REFP_BUF_POS, \ + ADS1X4S0X_REGISTER_REF_NOT_REFP_BUF_LENGTH) +#define ADS1X4S0X_REGISTER_REF_NOT_REFN_BUF_LENGTH 1 +#define ADS1X4S0X_REGISTER_REF_NOT_REFN_BUF_POS 4 +#define ADS1X4S0X_REGISTER_REF_NOT_REFN_BUF_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_REF_NOT_REFN_BUF_POS, \ + ADS1X4S0X_REGISTER_REF_NOT_REFN_BUF_LENGTH) +#define ADS1X4S0X_REGISTER_REF_NOT_REFN_BUF_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_REF_NOT_REFN_BUF_POS, \ + ADS1X4S0X_REGISTER_REF_NOT_REFN_BUF_LENGTH) +#define ADS1X4S0X_REGISTER_REF_REFSEL_LENGTH 2 +#define ADS1X4S0X_REGISTER_REF_REFSEL_POS 2 +#define ADS1X4S0X_REGISTER_REF_REFSEL_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_REF_REFSEL_POS, \ + ADS1X4S0X_REGISTER_REF_REFSEL_LENGTH) +#define ADS1X4S0X_REGISTER_REF_REFSEL_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_REF_REFSEL_POS, \ + ADS1X4S0X_REGISTER_REF_REFSEL_LENGTH) +#define ADS1X4S0X_REGISTER_REF_REFCON_LENGTH 2 +#define ADS1X4S0X_REGISTER_REF_REFCON_POS 0 +#define ADS1X4S0X_REGISTER_REF_REFCON_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_REF_REFCON_POS, \ + ADS1X4S0X_REGISTER_REF_REFCON_LENGTH) +#define ADS1X4S0X_REGISTER_REF_REFCON_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_REF_REFCON_POS, \ + ADS1X4S0X_REGISTER_REF_REFCON_LENGTH) +#define ADS1X4S0X_REGISTER_IDACMAG_FL_RAIL_EN_LENGTH 1 +#define ADS1X4S0X_REGISTER_IDACMAG_FL_RAIL_EN_POS 7 +#define ADS1X4S0X_REGISTER_IDACMAG_FL_RAIL_EN_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_IDACMAG_FL_RAIL_EN_POS, \ + ADS1X4S0X_REGISTER_IDACMAG_FL_RAIL_EN_LENGTH) +#define ADS1X4S0X_REGISTER_IDACMAG_FL_RAIL_EN_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_IDACMAG_FL_RAIL_EN_POS, \ + ADS1X4S0X_REGISTER_IDACMAG_FL_RAIL_EN_LENGTH) +#define ADS1X4S0X_REGISTER_IDACMAG_PSW_LENGTH 1 +#define ADS1X4S0X_REGISTER_IDACMAG_PSW_POS 6 +#define ADS1X4S0X_REGISTER_IDACMAG_PSW_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_IDACMAG_PSW_POS, \ + ADS1X4S0X_REGISTER_IDACMAG_PSW_LENGTH) +#define ADS1X4S0X_REGISTER_IDACMAG_PSW_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_IDACMAG_PSW_POS, \ + ADS1X4S0X_REGISTER_IDACMAG_PSW_LENGTH) +#define ADS1X4S0X_REGISTER_IDACMAG_IMAG_LENGTH 4 +#define ADS1X4S0X_REGISTER_IDACMAG_IMAG_POS 0 +#define ADS1X4S0X_REGISTER_IDACMAG_IMAG_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_IDACMAG_IMAG_POS, \ + ADS1X4S0X_REGISTER_IDACMAG_IMAG_LENGTH) +#define ADS1X4S0X_REGISTER_IDACMAG_IMAG_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_IDACMAG_IMAG_POS, \ + ADS1X4S0X_REGISTER_IDACMAG_IMAG_LENGTH) +#define ADS1X4S0X_REGISTER_IDACMUX_I2MUX_LENGTH 4 +#define ADS1X4S0X_REGISTER_IDACMUX_I2MUX_POS 4 +#define ADS1X4S0X_REGISTER_IDACMUX_I2MUX_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_IDACMUX_I2MUX_POS, \ + ADS1X4S0X_REGISTER_IDACMUX_I2MUX_LENGTH) +#define ADS1X4S0X_REGISTER_IDACMUX_I2MUX_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_IDACMUX_I2MUX_POS, \ + ADS1X4S0X_REGISTER_IDACMUX_I2MUX_LENGTH) +#define ADS1X4S0X_REGISTER_IDACMUX_I1MUX_LENGTH 4 +#define ADS1X4S0X_REGISTER_IDACMUX_I1MUX_POS 0 +#define ADS1X4S0X_REGISTER_IDACMUX_I1MUX_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_IDACMUX_I1MUX_POS, \ + ADS1X4S0X_REGISTER_IDACMUX_I1MUX_LENGTH) +#define ADS1X4S0X_REGISTER_IDACMUX_I1MUX_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_IDACMUX_I1MUX_POS, \ + ADS1X4S0X_REGISTER_IDACMUX_I1MUX_LENGTH) +#define ADS1X4S0X_REGISTER_VBIAS_VB_LEVEL_LENGTH 1 +#define ADS1X4S0X_REGISTER_VBIAS_VB_LEVEL_POS 7 +#define ADS1X4S0X_REGISTER_VBIAS_VB_LEVEL_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_VBIAS_VB_LEVEL_POS, \ + ADS1X4S0X_REGISTER_VBIAS_VB_LEVEL_LENGTH) +#define ADS1X4S0X_REGISTER_VBIAS_VB_LEVEL_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_VBIAS_VB_LEVEL_POS, \ + ADS1X4S0X_REGISTER_VBIAS_VB_LEVEL_LENGTH) +#define ADS1X4S0X_REGISTER_GPIODAT_DIR_LENGTH 4 +#define ADS1X4S0X_REGISTER_GPIODAT_DIR_POS 4 +#define ADS1X4S0X_REGISTER_GPIODAT_DIR_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_GPIODAT_DIR_POS, \ + ADS1X4S0X_REGISTER_GPIODAT_DIR_LENGTH) +#define ADS1X4S0X_REGISTER_GPIODAT_DIR_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_GPIODAT_DIR_POS, \ + ADS1X4S0X_REGISTER_GPIODAT_DIR_LENGTH) +#define ADS1X4S0X_REGISTER_GPIODAT_DAT_LENGTH 4 +#define ADS1X4S0X_REGISTER_GPIODAT_DAT_POS 0 +#define ADS1X4S0X_REGISTER_GPIODAT_DAT_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_GPIODAT_DAT_POS, \ + ADS1X4S0X_REGISTER_GPIODAT_DAT_LENGTH) +#define ADS1X4S0X_REGISTER_GPIODAT_DAT_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_GPIODAT_DAT_POS, \ + ADS1X4S0X_REGISTER_GPIODAT_DAT_LENGTH) +#define ADS1X4S0X_REGISTER_GPIOCON_CON_LENGTH 4 +#define ADS1X4S0X_REGISTER_GPIOCON_CON_POS 0 +#define ADS1X4S0X_REGISTER_GPIOCON_CON_GET(value) \ + ADS1X4S0X_REGISTER_GET_VALUE(value, ADS1X4S0X_REGISTER_GPIOCON_CON_POS, \ + ADS1X4S0X_REGISTER_GPIOCON_CON_LENGTH) +#define ADS1X4S0X_REGISTER_GPIOCON_CON_SET(target, value) \ + ADS1X4S0X_REGISTER_SET_VALUE(target, value, ADS1X4S0X_REGISTER_GPIOCON_CON_POS, \ + ADS1X4S0X_REGISTER_GPIOCON_CON_LENGTH) + +/* + * - AIN0 as positive input + * - AIN1 as negative input + */ +#define ADS1X4S0X_REGISTER_INPMUX_SET_DEFAULTS(target) \ + ADS1X4S0X_REGISTER_INPMUX_MUXP_SET(target, 0b0000); \ + ADS1X4S0X_REGISTER_INPMUX_MUXN_SET(target, 0b0001) +/* + * - disable reference monitor + * - enable positive reference buffer + * - disable negative reference buffer + * - use internal reference + * - enable internal voltage reference + */ +#define ADS1X4S0X_REGISTER_REF_SET_DEFAULTS(target) \ + ADS1X4S0X_REGISTER_REF_FL_REF_EN_SET(target, 0b00); \ + ADS1X4S0X_REGISTER_REF_NOT_REFP_BUF_SET(target, 0b0); \ + ADS1X4S0X_REGISTER_REF_NOT_REFN_BUF_SET(target, 0b1); \ + ADS1X4S0X_REGISTER_REF_REFSEL_SET(target, 0b10); \ + ADS1X4S0X_REGISTER_REF_REFCON_SET(target, 0b01) +/* + * - disable global chop + * - use internal oscillator + * - single shot conversion mode + * - low latency filter + * - 20 samples per second + */ +#define ADS1X4S0X_REGISTER_DATARATE_SET_DEFAULTS(target) \ + ADS1X4S0X_REGISTER_DATARATE_G_CHOP_SET(target, 0b0); \ + ADS1X4S0X_REGISTER_DATARATE_CLK_SET(target, 0b0); \ + ADS1X4S0X_REGISTER_DATARATE_MODE_SET(target, 0b1); \ + ADS1X4S0X_REGISTER_DATARATE_FILTER_SET(target, 0b1); \ + ADS1X4S0X_REGISTER_DATARATE_DR_SET(target, 0b0100) +/* + * - delay of 14*t_mod + * - disable gain + * - gain 1 + */ +#define ADS1X4S0X_REGISTER_PGA_SET_DEFAULTS(target) \ + ADS1X4S0X_REGISTER_PGA_DELAY_SET(target, 0b000); \ + ADS1X4S0X_REGISTER_PGA_PGA_EN_SET(target, 0b00); \ + ADS1X4S0X_REGISTER_PGA_GAIN_SET(target, 0b000) +/* + * - disable PGA output rail flag + * - low-side power switch + * - IDAC off + */ +#define ADS1X4S0X_REGISTER_IDACMAG_SET_DEFAULTS(target) \ + ADS1X4S0X_REGISTER_IDACMAG_FL_RAIL_EN_SET(target, 0b0); \ + ADS1X4S0X_REGISTER_IDACMAG_PSW_SET(target, 0b0); \ + ADS1X4S0X_REGISTER_IDACMAG_IMAG_SET(target, 0b0000) +/* + * - disconnect IDAC1 + * - disconnect IDAC2 + */ +#define ADS1X4S0X_REGISTER_IDACMUX_SET_DEFAULTS(target) \ + ADS1X4S0X_REGISTER_IDACMUX_I1MUX_SET(target, 0b1111); \ + ADS1X4S0X_REGISTER_IDACMUX_I2MUX_SET(target, 0b1111) + +struct ads1x4s0x_config { + struct spi_dt_spec bus; +#if CONFIG_ADC_ASYNC + k_thread_stack_t *stack; +#endif + const struct gpio_dt_spec gpio_reset; + const struct gpio_dt_spec gpio_data_ready; + const struct gpio_dt_spec gpio_start_sync; + int idac_current; + uint8_t vbias_level; + uint8_t channels; + uint8_t resolution; +}; + +struct ads1x4s0x_data { + struct adc_context ctx; +#if CONFIG_ADC_ASYNC + struct k_thread thread; +#endif /* CONFIG_ADC_ASYNC */ + struct gpio_callback callback_data_ready; + struct k_sem data_ready_signal; + struct k_sem acquire_signal; + int16_t *buffer; + int16_t *buffer_ptr; +#if CONFIG_ADC_ADS1X4S0X_GPIO + struct k_mutex gpio_lock; + uint8_t gpio_enabled; /* one bit per GPIO, 1 = enabled */ + uint8_t gpio_direction; /* one bit per GPIO, 1 = input */ + uint8_t gpio_value; /* one bit per GPIO, 1 = high */ +#endif /* CONFIG_ADC_ADS1X4S0X_GPIO */ +}; + +static void ads1x4s0x_data_ready_handler(const struct device *dev, struct gpio_callback *gpio_cb, + uint32_t pins) +{ + ARG_UNUSED(dev); + ARG_UNUSED(pins); + + struct ads1x4s0x_data *data = + CONTAINER_OF(gpio_cb, struct ads1x4s0x_data, callback_data_ready); + + k_sem_give(&data->data_ready_signal); +} + +static int ads1x4s0x_read_register(const struct device *dev, + enum ads1x4s0x_register register_address, uint8_t *value) +{ + const struct ads1x4s0x_config *config = dev->config; + uint8_t buffer_tx[3]; + uint8_t buffer_rx[ARRAY_SIZE(buffer_tx)]; + const struct spi_buf tx_buf[] = {{ + .buf = buffer_tx, + .len = ARRAY_SIZE(buffer_tx), + }}; + const struct spi_buf rx_buf[] = {{ + .buf = buffer_rx, + .len = ARRAY_SIZE(buffer_rx), + }}; + const struct spi_buf_set tx = { + .buffers = tx_buf, + .count = ARRAY_SIZE(tx_buf), + }; + const struct spi_buf_set rx = { + .buffers = rx_buf, + .count = ARRAY_SIZE(rx_buf), + }; + + buffer_tx[0] = ((uint8_t)ADS1X4S0X_COMMAND_RREG) | ((uint8_t)register_address); + /* read one register */ + buffer_tx[1] = 0x00; + + int result = spi_transceive_dt(&config->bus, &tx, &rx); + + if (result != 0) { + LOG_ERR("%s: spi_transceive failed with error %i", dev->name, result); + return result; + } + + *value = buffer_rx[2]; + LOG_DBG("%s: read from register 0x%02X value 0x%02X", dev->name, register_address, *value); + + return 0; +} + +static int ads1x4s0x_write_register(const struct device *dev, + enum ads1x4s0x_register register_address, uint8_t value) +{ + const struct ads1x4s0x_config *config = dev->config; + uint8_t buffer_tx[3]; + const struct spi_buf tx_buf[] = {{ + .buf = buffer_tx, + .len = ARRAY_SIZE(buffer_tx), + }}; + const struct spi_buf_set tx = { + .buffers = tx_buf, + .count = ARRAY_SIZE(tx_buf), + }; + + buffer_tx[0] = ((uint8_t)ADS1X4S0X_COMMAND_WREG) | ((uint8_t)register_address); + /* write one register */ + buffer_tx[1] = 0x00; + buffer_tx[2] = value; + + LOG_DBG("%s: writing to register 0x%02X value 0x%02X", dev->name, register_address, value); + int result = spi_write_dt(&config->bus, &tx); + + if (result != 0) { + LOG_ERR("%s: spi_write failed with error %i", dev->name, result); + return result; + } + + return 0; +} + +static int ads1x4s0x_write_multiple_registers(const struct device *dev, + enum ads1x4s0x_register *register_addresses, + uint8_t *values, size_t count) +{ + const struct ads1x4s0x_config *config = dev->config; + uint8_t buffer_tx[2]; + const struct spi_buf tx_buf[] = { + { + .buf = buffer_tx, + .len = ARRAY_SIZE(buffer_tx), + }, + { + .buf = values, + .len = count, + }, + }; + const struct spi_buf_set tx = { + .buffers = tx_buf, + .count = ARRAY_SIZE(tx_buf), + }; + + if (count == 0) { + LOG_WRN("%s: ignoring the command to write 0 registers", dev->name); + return -EINVAL; + } + + buffer_tx[0] = ((uint8_t)ADS1X4S0X_COMMAND_WREG) | ((uint8_t)register_addresses[0]); + buffer_tx[1] = count - 1; + + LOG_HEXDUMP_DBG(register_addresses, count, "writing to registers"); + LOG_HEXDUMP_DBG(values, count, "values"); + + /* ensure that the register addresses are in the correct order */ + for (size_t i = 1; i < count; ++i) { + __ASSERT(register_addresses[i - 1] + 1 == register_addresses[i], + "register addresses are not consecutive"); + } + + int result = spi_write_dt(&config->bus, &tx); + + if (result != 0) { + LOG_ERR("%s: spi_write failed with error %i", dev->name, result); + return result; + } + + return 0; +} + +static int ads1x4s0x_send_command(const struct device *dev, enum ads1x4s0x_command command) +{ + const struct ads1x4s0x_config *config = dev->config; + uint8_t buffer_tx[1]; + const struct spi_buf tx_buf[] = {{ + .buf = buffer_tx, + .len = ARRAY_SIZE(buffer_tx), + }}; + const struct spi_buf_set tx = { + .buffers = tx_buf, + .count = ARRAY_SIZE(tx_buf), + }; + + buffer_tx[0] = (uint8_t)command; + + LOG_DBG("%s: sending command 0x%02X", dev->name, command); + int result = spi_write_dt(&config->bus, &tx); + + if (result != 0) { + LOG_ERR("%s: spi_write failed with error %i", dev->name, result); + return result; + } + + return 0; +} + +static int ads1x4s0x_channel_setup(const struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + const struct ads1x4s0x_config *config = dev->config; + uint8_t input_mux = 0; + uint8_t reference_control = 0; + uint8_t data_rate = 0; + uint8_t gain = 0; + uint8_t idac_magnitude = 0; + uint8_t idac_mux = 0; + uint8_t pin_selections[4]; + uint8_t vbias = 0; + size_t pin_selections_size; + int result; + enum ads1x4s0x_register register_addresses[7]; + uint8_t values[ARRAY_SIZE(register_addresses)]; + uint16_t acquisition_time_value = ADC_ACQ_TIME_VALUE(channel_cfg->acquisition_time); + uint16_t acquisition_time_unit = ADC_ACQ_TIME_UNIT(channel_cfg->acquisition_time); + + ADS1X4S0X_REGISTER_INPMUX_SET_DEFAULTS(gain); + ADS1X4S0X_REGISTER_REF_SET_DEFAULTS(reference_control); + ADS1X4S0X_REGISTER_DATARATE_SET_DEFAULTS(data_rate); + ADS1X4S0X_REGISTER_PGA_SET_DEFAULTS(gain); + ADS1X4S0X_REGISTER_IDACMAG_SET_DEFAULTS(idac_magnitude); + ADS1X4S0X_REGISTER_IDACMUX_SET_DEFAULTS(idac_mux); + + if (channel_cfg->channel_id != 0) { + LOG_ERR("%s: only one channel is supported", dev->name); + return -EINVAL; + } + + /* The ADS114 uses samples per seconds units with the lowest being 2.5SPS + * and with acquisition_time only having 14b for time, this will not fit + * within here for microsecond units. Use Tick units and allow the user to + * specify the ODR directly. + */ + if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT && + acquisition_time_unit != ADC_ACQ_TIME_TICKS) { + LOG_ERR("%s: invalid acquisition time %i", dev->name, + channel_cfg->acquisition_time); + return -EINVAL; + } + + if (channel_cfg->acquisition_time == ADC_ACQ_TIME_DEFAULT) { + ADS1X4S0X_REGISTER_DATARATE_DR_SET(data_rate, ADS1X4S0X_CONFIG_DR_20); + } else { + ADS1X4S0X_REGISTER_DATARATE_DR_SET(data_rate, acquisition_time_value); + } + + switch (channel_cfg->reference) { + case ADC_REF_INTERNAL: + /* disable negative reference buffer */ + ADS1X4S0X_REGISTER_REF_NOT_REFN_BUF_SET(reference_control, 0b1); + /* disable positive reference buffer */ + ADS1X4S0X_REGISTER_REF_NOT_REFP_BUF_SET(reference_control, 0b1); + /* use internal reference */ + ADS1X4S0X_REGISTER_REF_REFSEL_SET(reference_control, 0b10); + break; + case ADC_REF_EXTERNAL0: + /* enable negative reference buffer */ + ADS1X4S0X_REGISTER_REF_NOT_REFN_BUF_SET(reference_control, 0b0); + /* enable positive reference buffer */ + ADS1X4S0X_REGISTER_REF_NOT_REFP_BUF_SET(reference_control, 0b0); + /* use external reference 0*/ + ADS1X4S0X_REGISTER_REF_REFSEL_SET(reference_control, 0b00); + break; + case ADC_REF_EXTERNAL1: + /* enable negative reference buffer */ + ADS1X4S0X_REGISTER_REF_NOT_REFN_BUF_SET(reference_control, 0b0); + /* enable positive reference buffer */ + ADS1X4S0X_REGISTER_REF_NOT_REFP_BUF_SET(reference_control, 0b0); + /* use external reference 0*/ + ADS1X4S0X_REGISTER_REF_REFSEL_SET(reference_control, 0b01); + break; + default: + LOG_ERR("%s: reference %i is not supported", dev->name, channel_cfg->reference); + return -EINVAL; + } + + if (channel_cfg->differential) { + LOG_DBG("%s: configuring channel for a differential measurement from the pins (p, " + "n) (%i, %i)", + dev->name, channel_cfg->input_positive, channel_cfg->input_negative); + if (channel_cfg->input_positive >= ADS1X4S0X_INPUT_SELECTION_AINCOM) { + LOG_ERR("%s: positive channel input %i is invalid", dev->name, + channel_cfg->input_positive); + return -EINVAL; + } + + if (channel_cfg->input_negative >= ADS1X4S0X_INPUT_SELECTION_AINCOM) { + LOG_ERR("%s: negative channel input %i is invalid", dev->name, + channel_cfg->input_negative); + return -EINVAL; + } + + if (channel_cfg->input_positive == channel_cfg->input_negative) { + LOG_ERR("%s: negative and positive channel inputs must be different", + dev->name); + return -EINVAL; + } + + ADS1X4S0X_REGISTER_INPMUX_MUXP_SET(input_mux, channel_cfg->input_positive); + ADS1X4S0X_REGISTER_INPMUX_MUXN_SET(input_mux, channel_cfg->input_negative); + pin_selections[0] = channel_cfg->input_positive; + pin_selections[1] = channel_cfg->input_negative; + } else { + LOG_DBG("%s: configuring channel for single ended measurement from input %i", + dev->name, channel_cfg->input_positive); + if (channel_cfg->input_positive >= ADS1X4S0X_INPUT_SELECTION_AINCOM) { + LOG_ERR("%s: channel input %i is invalid", dev->name, + channel_cfg->input_positive); + return -EINVAL; + } + + ADS1X4S0X_REGISTER_INPMUX_MUXP_SET(input_mux, channel_cfg->input_positive); + ADS1X4S0X_REGISTER_INPMUX_MUXN_SET(input_mux, ADS1X4S0X_INPUT_SELECTION_AINCOM); + pin_selections[0] = channel_cfg->input_positive; + pin_selections[1] = ADS1X4S0X_INPUT_SELECTION_AINCOM; + } + + switch (channel_cfg->gain) { + case ADC_GAIN_1: + /* set gain value */ + ADS1X4S0X_REGISTER_PGA_GAIN_SET(gain, 0b000); + break; + case ADC_GAIN_2: + ADS1X4S0X_REGISTER_PGA_GAIN_SET(gain, 0b001); + break; + case ADC_GAIN_4: + ADS1X4S0X_REGISTER_PGA_GAIN_SET(gain, 0b010); + break; + case ADC_GAIN_8: + ADS1X4S0X_REGISTER_PGA_GAIN_SET(gain, 0b011); + break; + case ADC_GAIN_16: + ADS1X4S0X_REGISTER_PGA_GAIN_SET(gain, 0b100); + break; + case ADC_GAIN_32: + ADS1X4S0X_REGISTER_PGA_GAIN_SET(gain, 0b101); + break; + case ADC_GAIN_64: + ADS1X4S0X_REGISTER_PGA_GAIN_SET(gain, 0b110); + break; + case ADC_GAIN_128: + ADS1X4S0X_REGISTER_PGA_GAIN_SET(gain, 0b111); + break; + default: + LOG_ERR("%s: gain value %i not supported", dev->name, channel_cfg->gain); + return -EINVAL; + } + + if (channel_cfg->gain != ADC_GAIN_1) { + /* enable gain */ + ADS1X4S0X_REGISTER_PGA_PGA_EN_SET(gain, 0b01); + } + + switch (config->idac_current) { + case 0: + ADS1X4S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b0000); + break; + case 10: + ADS1X4S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b0001); + break; + case 50: + ADS1X4S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b0010); + break; + case 100: + ADS1X4S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b0011); + break; + case 250: + ADS1X4S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b0100); + break; + case 500: + ADS1X4S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b0101); + break; + case 750: + ADS1X4S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b0110); + break; + case 1000: + ADS1X4S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b0111); + break; + case 1500: + ADS1X4S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b1000); + break; + case 2000: + ADS1X4S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b1001); + break; + default: + LOG_ERR("%s: IDAC magnitude %i not supported", dev->name, config->idac_current); + return -EINVAL; + } + + if (channel_cfg->current_source_pin_set) { + LOG_DBG("%s: current source pin set to %i and %i", dev->name, + channel_cfg->current_source_pin[0], channel_cfg->current_source_pin[1]); + if (channel_cfg->current_source_pin[0] > 0b1111) { + LOG_ERR("%s: invalid selection %i for I1MUX", dev->name, + channel_cfg->current_source_pin[0]); + return -EINVAL; + } + + if (channel_cfg->current_source_pin[1] > 0b1111) { + LOG_ERR("%s: invalid selection %i for I2MUX", dev->name, + channel_cfg->current_source_pin[1]); + return -EINVAL; + } + + ADS1X4S0X_REGISTER_IDACMUX_I1MUX_SET(idac_mux, channel_cfg->current_source_pin[0]); + ADS1X4S0X_REGISTER_IDACMUX_I2MUX_SET(idac_mux, channel_cfg->current_source_pin[1]); + pin_selections[2] = channel_cfg->current_source_pin[0]; + pin_selections[3] = channel_cfg->current_source_pin[1]; + pin_selections_size = 4; + } else { + LOG_DBG("%s: current source pins not set", dev->name); + pin_selections_size = 2; + } + + for (size_t i = 0; i < pin_selections_size; ++i) { + if (pin_selections[i] > ADS1X4S0X_INPUT_SELECTION_AINCOM) { + continue; + } + + for (size_t j = i + 1; j < pin_selections_size; ++j) { + if (pin_selections[j] > ADS1X4S0X_INPUT_SELECTION_AINCOM) { + continue; + } + + if (pin_selections[i] == pin_selections[j]) { + LOG_ERR("%s: pins for inputs and current sources must be different", + dev->name); + return -EINVAL; + } + } + } + + ADS1X4S0X_REGISTER_VBIAS_VB_LEVEL_SET(vbias, config->vbias_level); + + if ((channel_cfg->vbias_pins & + ~GENMASK(ADS1X4S0X_VBIAS_PIN_MAX, ADS1X4S0X_VBIAS_PIN_MIN)) != 0) { + LOG_ERR("%s: invalid VBIAS pin selection 0x%08X", dev->name, + channel_cfg->vbias_pins); + return -EINVAL; + } + + vbias |= channel_cfg->vbias_pins; + + register_addresses[0] = ADS1X4S0X_REGISTER_INPMUX; + register_addresses[1] = ADS1X4S0X_REGISTER_PGA; + register_addresses[2] = ADS1X4S0X_REGISTER_DATARATE; + register_addresses[3] = ADS1X4S0X_REGISTER_REF; + register_addresses[4] = ADS1X4S0X_REGISTER_IDACMAG; + register_addresses[5] = ADS1X4S0X_REGISTER_IDACMUX; + register_addresses[6] = ADS1X4S0X_REGISTER_VBIAS; + BUILD_ASSERT(ARRAY_SIZE(register_addresses) == 7); + values[0] = input_mux; + values[1] = gain; + values[2] = data_rate; + values[3] = reference_control; + values[4] = idac_magnitude; + values[5] = idac_mux; + values[6] = vbias; + BUILD_ASSERT(ARRAY_SIZE(values) == 7); + + result = ads1x4s0x_write_multiple_registers(dev, register_addresses, values, + ARRAY_SIZE(values)); + + if (result != 0) { + LOG_ERR("%s: unable to configure registers", dev->name); + return result; + } + + return 0; +} + +static int ads1x4s0x_validate_buffer_size(const struct adc_sequence *sequence) +{ + const struct ads1x4s0x_config *config = dev->config; + size_t needed; + + needed = (config->resolution > 16) ? sizeof(int32_t) : sizeof(int16_t); + + if (sequence->options) { + needed *= (1 + sequence->options->extra_samplings); + } + + if (sequence->buffer_size < needed) { + return -ENOMEM; + } + + return 0; +} + +static int ads1x4s0x_validate_sequence(const struct device *dev, + const struct adc_sequence *sequence) +{ + if (sequence->resolution != ADS1X4S0X_RESOLUTION) { + LOG_ERR("%s: invalid resolution", dev->name); + return -EINVAL; + } + + if (sequence->channels != BIT(0)) { + LOG_ERR("%s: invalid channel", dev->name); + return -EINVAL; + } + + if (sequence->oversampling) { + LOG_ERR("%s: oversampling is not supported", dev->name); + return -EINVAL; + } + + return ads1x4s0x_validate_buffer_size(sequence); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat_sampling) +{ + struct ads1x4s0x_data *data = CONTAINER_OF(ctx, struct ads1x4s0x_data, ctx); + + if (repeat_sampling) { + data->buffer = data->buffer_ptr; + } +} + +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct ads1x4s0x_data *data = CONTAINER_OF(ctx, struct ads1x4s0x_data, ctx); + + data->buffer_ptr = data->buffer; + k_sem_give(&data->acquire_signal); +} + +static int ads1x4s0x_adc_start_read(const struct device *dev, const struct adc_sequence *sequence, + bool wait) +{ + int result; + struct ads1x4s0x_data *data = dev->data; + + result = ads1x4s0x_validate_sequence(dev, sequence); + + if (result != 0) { + LOG_ERR("%s: sequence validation failed", dev->name); + return result; + } + + data->buffer = sequence->buffer; + + adc_context_start_read(&data->ctx, sequence); + + if (wait) { + result = adc_context_wait_for_completion(&data->ctx); + } + + return result; +} + +static int ads1x4s0x_send_start_read(const struct device *dev) +{ + const struct ads1x4s0x_config *config = dev->config; + int result; + + if (config->gpio_start_sync.port == 0) { + result = ads1x4s0x_send_command(dev, ADS1X4S0X_COMMAND_START); + if (result != 0) { + LOG_ERR("%s: unable to send START/SYNC command", dev->name); + return result; + } + } else { + result = gpio_pin_set_dt(&config->gpio_start_sync, 1); + + if (result != 0) { + LOG_ERR("%s: unable to start ADC operation", dev->name); + return result; + } + + k_sleep(K_USEC(ADS1X4S0X_START_SYNC_PULSE_DURATION_IN_US + + ADS1X4S0X_SETUP_TIME_IN_US)); + + result = gpio_pin_set_dt(&config->gpio_start_sync, 0); + + if (result != 0) { + LOG_ERR("%s: unable to start ADC operation", dev->name); + return result; + } + } + + return 0; +} + +static int ads1x4s0x_wait_data_ready(const struct device *dev) +{ + struct ads1x4s0x_data *data = dev->data; + + return k_sem_take(&data->data_ready_signal, ADC_CONTEXT_WAIT_FOR_COMPLETION_TIMEOUT); +} + +static int ads1x4s0x_read_sample(const struct device *dev, uint16_t *buffer) +{ + const struct ads1x4s0x_config *config = dev->config; + uint8_t buffer_tx[3]; + uint8_t buffer_rx[ARRAY_SIZE(buffer_tx)]; + const struct spi_buf tx_buf[] = {{ + .buf = buffer_tx, + .len = 3, + }}; + const struct spi_buf rx_buf[] = {{ + .buf = buffer_rx, + .len = 3, + }}; + const struct spi_buf_set tx = { + .buffers = tx_buf, + .count = ARRAY_SIZE(tx_buf), + }; + const struct spi_buf_set rx = { + .buffers = rx_buf, + .count = ARRAY_SIZE(rx_buf), + }; + + buffer_tx[0] = (uint8_t)ADS1X4S0X_COMMAND_RDATA; + + int result = spi_transceive_dt(&config->bus, &tx, &rx); + + if (result != 0) { + LOG_ERR("%s: spi_transceive failed with error %i", dev->name, result); + return result; + } + + *buffer = sys_get_be16(buffer_rx + 1); + LOG_DBG("%s: read ADC sample %i", dev->name, *buffer); + + return 0; +} +#endif + +#if ADS1X4S0X_HAS_24_BIT_DEV +static int ads1x4s0x_read_sample_24(const struct device *dev, int32_t *buffer) +{ + const struct ads1x4s0x_config *config = dev->config; + uint8_t buffer_tx[5] = {0}; + uint8_t buffer_rx[ARRAY_SIZE(buffer_tx)]; + const struct spi_buf tx_buf[] = {{ + .buf = buffer_tx, + .len = 4, + }}; + const struct spi_buf rx_buf[] = {{ + .buf = buffer_rx, + .len = 4, + }}; + const struct spi_buf_set tx = { + .buffers = tx_buf, + .count = ARRAY_SIZE(tx_buf), + }; + const struct spi_buf_set rx = { + .buffers = rx_buf, + .count = ARRAY_SIZE(rx_buf), + }; + + buffer_tx[0] = (uint8_t)ADS1X4S0X_COMMAND_RDATA; + + int result = spi_transceive_dt(&config->bus, &tx, &rx); + + if (result != 0) { + LOG_ERR("%s: spi_transceive failed with error %i", dev->name, result); + return result; + } + + *buffer = (int32_t)sys_get_be32(buffer_rx + 1) >> 8; + + LOG_DBG("%s: read ADC sample 0x%02X%02X%02X", dev->name, *(buffer_rx + 1), *(buffer_rx + 2), + *(buffer_rx + 3)); + + return 0; +} +#endif + +static int ads1x4s0x_adc_perform_read(const struct device *dev) +{ + int result; + struct ads1x4s0x_data *data = dev->data; + + k_sem_take(&data->acquire_signal, K_FOREVER); + k_sem_reset(&data->data_ready_signal); + + result = ads1x4s0x_send_start_read(dev); + if (result != 0) { + LOG_ERR("%s: unable to start ADC conversion", dev->name); + adc_context_complete(&data->ctx, result); + return result; + } + + result = ads1x4s0x_wait_data_ready(dev); + if (result != 0) { + LOG_ERR("%s: waiting for data to be ready failed", dev->name); + adc_context_complete(&data->ctx, result); + return result; + } + + result = ads1x4s0x_read_sample(dev, data->buffer); + if (result != 0) { + LOG_ERR("%s: reading sample failed", dev->name); + adc_context_complete(&data->ctx, result); + return result; + } +#endif + +#if ADS1X4S0X_HAS_16_BIT_DEV + if (config->resolution == 16) { + result = ads1x4s0x_read_sample_16(dev, (int16_t *)data->buffer); + + if (result == 0) { + buffer = (int16_t *)buffer + 1; + adc_context_on_sampling_done(&data->ctx, dev); + return 0; + } + + } +#endif + + LOG_ERR("%s: reading sample failed", dev->name); + adc_context_complete(&data->ctx, result); + return result; +} + +#if CONFIG_ADC_ASYNC +static int ads1x4s0x_adc_read_async(const struct device *dev, const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + int result; + struct ads1x4s0x_data *data = dev->data; + + adc_context_lock(&data->ctx, true, async); + result = ads1x4s0x_adc_start_read(dev, sequence, true); + adc_context_release(&data->ctx, result); + + return result; +} + +static int ads1x4s0x_read(const struct device *dev, const struct adc_sequence *sequence) +{ + int result; + struct ads1x4s0x_data *data = dev->data; + + adc_context_lock(&data->ctx, false, NULL); + result = ads1x4s0x_adc_start_read(dev, sequence, true); + adc_context_release(&data->ctx, result); + + return result; +} + +#else +static int ads1x4s0x_read(const struct device *dev, const struct adc_sequence *sequence) +{ + int result; + struct ads1x4s0x_data *data = dev->data; + + adc_context_lock(&data->ctx, false, NULL); + result = ads1x4s0x_adc_start_read(dev, sequence, false); + + while (result == 0 && k_sem_take(&data->ctx.sync, K_NO_WAIT) != 0) { + result = ads1x4s0x_adc_perform_read(dev); + } + + adc_context_release(&data->ctx, result); + return result; +} +#endif + +#if CONFIG_ADC_ASYNC +static void ads1x4s0x_acquisition_thread(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; + + while (true) { + ads1x4s0x_adc_perform_read(dev); + } +} +#endif + +#ifdef CONFIG_ADC_ADS1X4S0X_GPIO +static int ads1x4s0x_gpio_write_config(const struct device *dev) +{ + struct ads1x4s0x_data *data = dev->data; + enum ads1x4s0x_register register_addresses[2]; + uint8_t register_values[ARRAY_SIZE(register_addresses)]; + uint8_t gpio_dat = 0; + uint8_t gpio_con = 0; + + ADS1X4S0X_REGISTER_GPIOCON_CON_SET(gpio_con, data->gpio_enabled); + ADS1X4S0X_REGISTER_GPIODAT_DAT_SET(gpio_dat, data->gpio_value); + ADS1X4S0X_REGISTER_GPIODAT_DIR_SET(gpio_dat, data->gpio_direction); + + register_values[0] = gpio_dat; + register_values[1] = gpio_con; + register_addresses[0] = ADS1X4S0X_REGISTER_GPIODAT; + register_addresses[1] = ADS1X4S0X_REGISTER_GPIOCON; + return ads1x4s0x_write_multiple_registers(dev, register_addresses, register_values, + ARRAY_SIZE(register_values)); +} + +static int ads1x4s0x_gpio_write_value(const struct device *dev) +{ + struct ads1x4s0x_data *data = dev->data; + uint8_t gpio_dat = 0; + + ADS1X4S0X_REGISTER_GPIODAT_DAT_SET(gpio_dat, data->gpio_value); + ADS1X4S0X_REGISTER_GPIODAT_DIR_SET(gpio_dat, data->gpio_direction); + + return ads1x4s0x_write_register(dev, ADS1X4S0X_REGISTER_GPIODAT, gpio_dat); +} + +int ads1x4s0x_gpio_set_output(const struct device *dev, uint8_t pin, bool initial_value) +{ + struct ads1x4s0x_data *data = dev->data; + int result = 0; + + if (pin > ADS1X4S0X_GPIO_MAX) { + LOG_ERR("%s: invalid pin %i", dev->name, pin); + return -EINVAL; + } + + k_mutex_lock(&data->gpio_lock, K_FOREVER); + + data->gpio_enabled |= BIT(pin); + data->gpio_direction &= ~BIT(pin); + + if (initial_value) { + data->gpio_value |= BIT(pin); + } else { + data->gpio_value &= ~BIT(pin); + } + + result = ads1x4s0x_gpio_write_config(dev); + + k_mutex_unlock(&data->gpio_lock); + + return result; +} + +int ads1x4s0x_gpio_set_input(const struct device *dev, uint8_t pin) +{ + struct ads1x4s0x_data *data = dev->data; + int result = 0; + + if (pin > ADS1X4S0X_GPIO_MAX) { + LOG_ERR("%s: invalid pin %i", dev->name, pin); + return -EINVAL; + } + + k_mutex_lock(&data->gpio_lock, K_FOREVER); + + data->gpio_enabled |= BIT(pin); + data->gpio_direction |= BIT(pin); + data->gpio_value &= ~BIT(pin); + + result = ads1x4s0x_gpio_write_config(dev); + + k_mutex_unlock(&data->gpio_lock); + + return result; +} + +int ads1x4s0x_gpio_deconfigure(const struct device *dev, uint8_t pin) +{ + struct ads1x4s0x_data *data = dev->data; + int result = 0; + + if (pin > ADS1X4S0X_GPIO_MAX) { + LOG_ERR("%s: invalid pin %i", dev->name, pin); + return -EINVAL; + } + + k_mutex_lock(&data->gpio_lock, K_FOREVER); + + data->gpio_enabled &= ~BIT(pin); + data->gpio_direction |= BIT(pin); + data->gpio_value &= ~BIT(pin); + + result = ads1x4s0x_gpio_write_config(dev); + + k_mutex_unlock(&data->gpio_lock); + + return result; +} + +int ads1x4s0x_gpio_set_pin_value(const struct device *dev, uint8_t pin, bool value) +{ + struct ads1x4s0x_data *data = dev->data; + int result = 0; + + if (pin > ADS1X4S0X_GPIO_MAX) { + LOG_ERR("%s: invalid pin %i", dev->name, pin); + return -EINVAL; + } + + k_mutex_lock(&data->gpio_lock, K_FOREVER); + + if ((BIT(pin) & data->gpio_enabled) == 0) { + LOG_ERR("%s: gpio pin %i not configured", dev->name, pin); + result = -EINVAL; + } else if ((BIT(pin) & data->gpio_direction) != 0) { + LOG_ERR("%s: gpio pin %i not configured as output", dev->name, pin); + result = -EINVAL; + } else { + data->gpio_value |= BIT(pin); + + result = ads1x4s0x_gpio_write_value(dev); + } + + k_mutex_unlock(&data->gpio_lock); + + return result; +} + +int ads1x4s0x_gpio_get_pin_value(const struct device *dev, uint8_t pin, bool *value) +{ + struct ads1x4s0x_data *data = dev->data; + int result = 0; + uint8_t gpio_dat; + + if (pin > ADS1X4S0X_GPIO_MAX) { + LOG_ERR("%s: invalid pin %i", dev->name, pin); + return -EINVAL; + } + + k_mutex_lock(&data->gpio_lock, K_FOREVER); + + if ((BIT(pin) & data->gpio_enabled) == 0) { + LOG_ERR("%s: gpio pin %i not configured", dev->name, pin); + result = -EINVAL; + } else if ((BIT(pin) & data->gpio_direction) == 0) { + LOG_ERR("%s: gpio pin %i not configured as input", dev->name, pin); + result = -EINVAL; + } else { + result = ads1x4s0x_read_register(dev, ADS1X4S0X_REGISTER_GPIODAT, &gpio_dat); + data->gpio_value = ADS1X4S0X_REGISTER_GPIODAT_DAT_GET(gpio_dat); + *value = (BIT(pin) & data->gpio_value) != 0; + } + + k_mutex_unlock(&data->gpio_lock); + + return result; +} + +int ads1x4s0x_gpio_port_get_raw(const struct device *dev, gpio_port_value_t *value) +{ + struct ads1x4s0x_data *data = dev->data; + int result = 0; + uint8_t gpio_dat; + + k_mutex_lock(&data->gpio_lock, K_FOREVER); + + result = ads1x4s0x_read_register(dev, ADS1X4S0X_REGISTER_GPIODAT, &gpio_dat); + data->gpio_value = ADS1X4S0X_REGISTER_GPIODAT_DAT_GET(gpio_dat); + *value = data->gpio_value; + + k_mutex_unlock(&data->gpio_lock); + + return result; +} + +int ads1x4s0x_gpio_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + struct ads1x4s0x_data *data = dev->data; + int result = 0; + + k_mutex_lock(&data->gpio_lock, K_FOREVER); + + data->gpio_value = ((data->gpio_value & ~mask) | (mask & value)) & data->gpio_enabled & + ~data->gpio_direction; + result = ads1x4s0x_gpio_write_value(dev); + + k_mutex_unlock(&data->gpio_lock); + + return result; +} + +int ads1x4s0x_gpio_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) +{ + struct ads1x4s0x_data *data = dev->data; + int result = 0; + + k_mutex_lock(&data->gpio_lock, K_FOREVER); + + data->gpio_value = (data->gpio_value ^ pins) & data->gpio_enabled & ~data->gpio_direction; + result = ads1x4s0x_gpio_write_value(dev); + + k_mutex_unlock(&data->gpio_lock); + + return result; +} + +#endif /* CONFIG_ADC_ADS1X4S0X_GPIO */ + +static int ads1x4s0x_init(const struct device *dev) +{ + uint8_t status = 0; + uint8_t reference_control = 0; + uint8_t reference_control_read; + int result; + const struct ads1x4s0x_config *config = dev->config; + struct ads1x4s0x_data *data = dev->data; + + adc_context_init(&data->ctx); + + k_sem_init(&data->data_ready_signal, 0, 1); + k_sem_init(&data->acquire_signal, 0, 1); + +#ifdef CONFIG_ADC_ADS1X4S0X_GPIO + k_mutex_init(&data->gpio_lock); +#endif /* CONFIG_ADC_ADS1X4S0X_GPIO */ + + if (!spi_is_ready_dt(&config->bus)) { + LOG_ERR("%s: SPI device is not ready", dev->name); + return -ENODEV; + } + + if (config->gpio_reset.port != NULL) { + result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE); + if (result != 0) { + LOG_ERR("%s: failed to initialize GPIO for reset", dev->name); + return result; + } + } + + if (config->gpio_start_sync.port != NULL) { + result = gpio_pin_configure_dt(&config->gpio_start_sync, GPIO_OUTPUT_INACTIVE); + if (result != 0) { + LOG_ERR("%s: failed to initialize GPIO for start/sync", dev->name); + return result; + } + } + + result = gpio_pin_configure_dt(&config->gpio_data_ready, GPIO_INPUT); + if (result != 0) { + LOG_ERR("%s: failed to initialize GPIO for data ready", dev->name); + return result; + } + + result = gpio_pin_interrupt_configure_dt(&config->gpio_data_ready, GPIO_INT_EDGE_TO_ACTIVE); + if (result != 0) { + LOG_ERR("%s: failed to configure data ready interrupt", dev->name); + return -EIO; + } + + gpio_init_callback(&data->callback_data_ready, ads1x4s0x_data_ready_handler, + BIT(config->gpio_data_ready.pin)); + result = gpio_add_callback(config->gpio_data_ready.port, &data->callback_data_ready); + if (result != 0) { + LOG_ERR("%s: failed to add data ready callback", dev->name); + return -EIO; + } + +#if CONFIG_ADC_ASYNC + k_tid_t tid = k_thread_create(&data->thread, config->stack, + CONFIG_ADC_ADS1X4S0X_ACQUISITION_THREAD_STACK_SIZE, + ads1x4s0x_acquisition_thread, (void *)dev, NULL, NULL, + CONFIG_ADC_ADS1X4S0X_ASYNC_THREAD_INIT_PRIO, 0, K_NO_WAIT); + k_thread_name_set(tid, "adc_ads1x4s0x"); +#endif + + k_busy_wait(ADS1X4S0X_POWER_ON_RESET_TIME_IN_US); + + if (config->gpio_reset.port == NULL) { + result = ads1x4s0x_send_command(dev, ADS1X4S0X_COMMAND_RESET); + if (result != 0) { + LOG_ERR("%s: unable to send RESET command", dev->name); + return result; + } + } else { + k_busy_wait(ADS1X4S0X_RESET_LOW_TIME_IN_US); + gpio_pin_set_dt(&config->gpio_reset, 0); + } + + k_busy_wait(ADS1X4S0X_RESET_DELAY_TIME_IN_US); + + result = ads1x4s0x_read_register(dev, ADS1X4S0X_REGISTER_STATUS, &status); + if (result != 0) { + LOG_ERR("%s: unable to read status register", dev->name); + return result; + } + + if (ADS1X4S0X_REGISTER_STATUS_NOT_RDY_GET(status) == 0x01) { + LOG_ERR("%s: ADS114 is not yet ready", dev->name); + return -EBUSY; + } + + /* + * Activate internal voltage reference during initialization to + * avoid the necessary setup time for it to settle later on. + */ + ADS1X4S0X_REGISTER_REF_SET_DEFAULTS(reference_control); + + result = ads1x4s0x_write_register(dev, ADS1X4S0X_REGISTER_REF, reference_control); + if (result != 0) { + LOG_ERR("%s: unable to set default reference control values", dev->name); + return result; + } + + /* + * Ensure that the internal voltage reference is active. + */ + result = ads1x4s0x_read_register(dev, ADS1X4S0X_REGISTER_REF, &reference_control_read); + if (result != 0) { + LOG_ERR("%s: unable to read reference control values", dev->name); + return result; + } + + if (reference_control != reference_control_read) { + LOG_ERR("%s: reference control register is incorrect: 0x%02X", dev->name, + reference_control_read); + return -EIO; + } + +#ifdef CONFIG_ADC_ADS1X4S0X_GPIO + data->gpio_enabled = 0x00; + data->gpio_direction = 0x0F; + data->gpio_value = 0x00; + + result = ads1x4s0x_gpio_write_config(dev); + + if (result != 0) { + LOG_ERR("%s: unable to configure defaults for GPIOs", dev->name); + return result; + } +#endif + + adc_context_unlock_unconditionally(&data->ctx); + + return result; +} + +static DEVICE_API(adc, api) = { + .channel_setup = ads1x4s0x_channel_setup, + .read = ads1x4s0x_read, + .ref_internal = ADS1X4S0X_REF_INTERNAL, +#ifdef CONFIG_ADC_ASYNC + .read_async = ads1x4s0x_adc_read_async, +#endif +}; +BUILD_ASSERT(CONFIG_ADC_INIT_PRIORITY > CONFIG_SPI_INIT_PRIORITY, + "CONFIG_ADC_INIT_PRIORITY must be higher than CONFIG_SPI_INIT_PRIORITY"); + +#define ADC_ADS1X4S0X_INST_DEFINE(n, name, ch, res) \ + IF_ENABLED( \ + CONFIG_ADC_ASYNC, \ + (static K_KERNEL_STACK_DEFINE( \ + thread_stack_##name##_##n, \ + CONFIG_ADC_ADS1X4S0X_ACQUISITION_THREAD_STACK_SIZE);) \ + ) \ + static const struct ads1x4s0x_config config_##name##_##n = { \ + .bus = SPI_DT_SPEC_INST_GET( \ + n, SPI_OP_MODE_MASTER | SPI_MODE_CPHA | SPI_WORD_SET(8), 0), \ + IF_ENABLED(CONFIG_ADC_ASYNC, (.stack = thread_stack_##n,)) \ + .gpio_reset = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {0}), \ + .gpio_data_ready = GPIO_DT_SPEC_INST_GET(n, drdy_gpios), \ + .gpio_start_sync = GPIO_DT_SPEC_INST_GET_OR(n, start_sync_gpios, {0}), \ + .idac_current = DT_INST_PROP(n, idac_current), \ + .vbias_level = DT_INST_PROP(n, vbias_level), \ + .vbias_level = DT_INST_PROP(n, vbias_level), \ + .resolution = res, \ + .channels = ch, \ + }; \ + static struct ads1x4s0x_data data_##name##_##n; \ + DEVICE_DT_INST_DEFINE(n, ads1x4s0x_init, NULL, &data_##name##_##n, &config_##name##_##n, \ + POST_KERNEL, CONFIG_ADC_INIT_PRIORITY, &api); + +/* + * ADS114S06: 16 bit, 6 channels + */ +#define DT_DRV_COMPAT ti_ads114s06 +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) +#define ADC_ADS114S06_INST_DEFINE(n) ADC_ADS1X4S0X_INST_DEFINE(n, ti_ads114s06, 6, 16) +DT_INST_FOREACH_STATUS_OKAY(ADC_ADS114S06_INST_DEFINE); +#endif + +/* + * ADS114S08: 16 bit, 12 channels + */ +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT ti_ads114s08 +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) +#define ADC_ADS114S08_INST_DEFINE(n) ADC_ADS1X4S0X_INST_DEFINE(n, ti_ads114s08, 12, 16) +DT_INST_FOREACH_STATUS_OKAY(ADC_ADS114S08_INST_DEFINE); +#endif + +#define ADC_ADS1X4S0X_INST_DEFINE(n) \ + IF_ENABLED( \ + CONFIG_ADC_ASYNC, \ + (static K_KERNEL_STACK_DEFINE( \ + thread_stack_##n, CONFIG_ADC_ADS1X4S0X_ACQUISITION_THREAD_STACK_SIZE);)) \ + static const struct ads1x4s0x_config config_##n = { \ + .bus = SPI_DT_SPEC_INST_GET( \ + n, SPI_OP_MODE_MASTER | SPI_MODE_CPHA | SPI_WORD_SET(8), 0), \ + IF_ENABLED(CONFIG_ADC_ASYNC, (.stack = thread_stack_##n,)) \ + .gpio_reset = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {0}), \ + .gpio_data_ready = GPIO_DT_SPEC_INST_GET(n, drdy_gpios), \ + .gpio_start_sync = GPIO_DT_SPEC_INST_GET_OR(n, start_sync_gpios, {0}), \ + .idac_current = DT_INST_PROP(n, idac_current), \ + .vbias_level = DT_INST_PROP(n, vbias_level), \ + }; \ + static struct ads1x4s0x_data data_##n; \ + DEVICE_DT_INST_DEFINE(n, ads1x4s0x_init, NULL, &data_##n, &config_##n, POST_KERNEL, \ + CONFIG_ADC_INIT_PRIORITY, &api); + +DT_INST_FOREACH_STATUS_OKAY(ADC_ADS1X4S0X_INST_DEFINE); diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index cd441db164e5..1f976d797fdc 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -7,7 +7,7 @@ zephyr_library() # zephyr-keep-sorted-start zephyr_library_sources_ifdef(CONFIG_GPIO_AD559X gpio_ad559x.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ADP5585 gpio_adp5585.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_ADS114S0X gpio_ads114s0x.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_ADS1X4S0X gpio_ads114s0x.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ALTERA_PIO gpio_altera_pio.c) zephyr_library_sources_ifdef(CONFIG_GPIO_AMBIQ gpio_ambiq.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ANDES_ATCGPIO100 gpio_andes_atcgpio100.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 90cad25cebe9..0b260ea957f4 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -97,7 +97,7 @@ config GPIO_ENABLE_DISABLE_INTERRUPT # zephyr-keep-sorted-start source "drivers/gpio/Kconfig.ad559x" source "drivers/gpio/Kconfig.adp5585" -source "drivers/gpio/Kconfig.ads114s0x" +source "drivers/gpio/Kconfig.ads1x4s0x" source "drivers/gpio/Kconfig.altera" source "drivers/gpio/Kconfig.ambiq" source "drivers/gpio/Kconfig.andes_atcgpio100" diff --git a/drivers/gpio/Kconfig.ads114s0x b/drivers/gpio/Kconfig.ads114s0x deleted file mode 100644 index 1dd642c6defa..000000000000 --- a/drivers/gpio/Kconfig.ads114s0x +++ /dev/null @@ -1,25 +0,0 @@ -# ADS114S0x GPIO configuration options - -# Copyright (c) 2023 SILA Embedded Solutions GmbH -# SPDX-License-Identifier: Apache-2.0 - -menuconfig GPIO_ADS114S0X - bool "ADS114S0x GPIO driver" - default y - depends on DT_HAS_TI_ADS114S0X_GPIO_ENABLED - depends on ADC_ADS114S0X_GPIO - help - Enable GPIO driver for ADS114S0x. - - The ADS114S0x is a multi-channel analog frontend (AFE). - - The GPIO port of the ADS114S0x (GPIO0 to GPIO3) is exposed as a - GPIO controller driver with read/write support. - -config GPIO_ADS114S0X_INIT_PRIORITY - int "Driver init priority" - default 99 - depends on GPIO_ADS114S0X - help - Device driver initialization priority. This driver must be - initialized after the ADS114S0x ADC driver. diff --git a/drivers/gpio/Kconfig.ads1x4s0x b/drivers/gpio/Kconfig.ads1x4s0x new file mode 100644 index 000000000000..39fca26923ee --- /dev/null +++ b/drivers/gpio/Kconfig.ads1x4s0x @@ -0,0 +1,25 @@ +# ADS1X4S0X GPIO configuration options + +# Copyright (c) 2023 SILA Embedded Solutions GmbH +# SPDX-License-Identifier: Apache-2.0 + +menuconfig GPIO_ADS1X4S0X + bool "ADS1X4S0X GPIO driver" + default y + depends on DT_HAS_TI_ADS1X4S0X_GPIO_ENABLED + depends on ADC_ADS1X4S0X_GPIO + help + Enable GPIO driver for ADS1X4S0X. + + The ADS1X4S0X is a multi-channel analog frontend (AFE). + + The GPIO port of the ADS1X4S0X (GPIO0 to GPIO3) is exposed as a + GPIO controller driver with read/write support. + +config GPIO_ADS1X4S0X_INIT_PRIORITY + int "Driver init priority" + default 99 + depends on GPIO_ADS1X4S0X + help + Device driver initialization priority. This driver must be + initialized after the ADS1X4S0X ADC driver. diff --git a/drivers/gpio/gpio_ads114s0x.c b/drivers/gpio/gpio_ads114s0x.c deleted file mode 100644 index 5c0cd261e268..000000000000 --- a/drivers/gpio/gpio_ads114s0x.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2023 SILA Embedded Solutions GmbH - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief GPIO driver for the ADS114S0x AFE. - */ - -#define DT_DRV_COMPAT ti_ads114s0x_gpio - -#include -#include - -#define LOG_LEVEL CONFIG_GPIO_LOG_LEVEL -#include -LOG_MODULE_REGISTER(gpio_ads114s0x); - -#include - -#include - -struct gpio_ads114s0x_config { - /* gpio_driver_config needs to be first */ - struct gpio_driver_config common; - const struct device *parent; -}; - -struct gpio_ads114s0x_data { - /* gpio_driver_data needs to be first */ - struct gpio_driver_data common; -}; - -static int gpio_ads114s0x_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) -{ - const struct gpio_ads114s0x_config *config = dev->config; - int err = 0; - - if ((flags & (GPIO_INPUT | GPIO_OUTPUT)) == GPIO_DISCONNECTED) { - return ads114s0x_gpio_deconfigure(config->parent, pin); - } - - if ((flags & GPIO_SINGLE_ENDED) != 0) { - return -ENOTSUP; - } - - if ((flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != 0) { - return -ENOTSUP; - } - - if (flags & GPIO_INT_ENABLE) { - /* ads114s0x GPIOs do not support interrupts */ - return -ENOTSUP; - } - - switch (flags & GPIO_DIR_MASK) { - case GPIO_INPUT: - err = ads114s0x_gpio_set_input(config->parent, pin); - break; - case GPIO_OUTPUT: - err = ads114s0x_gpio_set_output(config->parent, pin, - (flags & GPIO_OUTPUT_INIT_HIGH) != 0); - break; - default: - return -ENOTSUP; - } - - return err; -} - -static int gpio_ads114s0x_port_get_raw(const struct device *dev, gpio_port_value_t *value) -{ - const struct gpio_ads114s0x_config *config = dev->config; - - return ads114s0x_gpio_port_get_raw(config->parent, value); -} - -static int gpio_ads114s0x_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, - gpio_port_value_t value) -{ - const struct gpio_ads114s0x_config *config = dev->config; - - return ads114s0x_gpio_port_set_masked_raw(config->parent, mask, value); -} - -static int gpio_ads114s0x_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) -{ - const struct gpio_ads114s0x_config *config = dev->config; - - return ads114s0x_gpio_port_set_masked_raw(config->parent, pins, pins); -} - -static int gpio_ads114s0x_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) -{ - const struct gpio_ads114s0x_config *config = dev->config; - - return ads114s0x_gpio_port_set_masked_raw(config->parent, pins, 0); -} - -static int gpio_ads114s0x_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) -{ - const struct gpio_ads114s0x_config *config = dev->config; - - return ads114s0x_gpio_port_toggle_bits(config->parent, pins); -} - -static int gpio_ads114s0x_init(const struct device *dev) -{ - const struct gpio_ads114s0x_config *config = dev->config; - - if (!device_is_ready(config->parent)) { - LOG_ERR("parent ads114s0x device '%s' not ready", config->parent->name); - return -EINVAL; - } - - return 0; -} - -static const struct gpio_driver_api gpio_ads114s0x_api = { - .pin_configure = gpio_ads114s0x_config, - .port_set_masked_raw = gpio_ads114s0x_port_set_masked_raw, - .port_set_bits_raw = gpio_ads114s0x_port_set_bits_raw, - .port_clear_bits_raw = gpio_ads114s0x_port_clear_bits_raw, - .port_toggle_bits = gpio_ads114s0x_port_toggle_bits, - .port_get_raw = gpio_ads114s0x_port_get_raw, -}; - -BUILD_ASSERT(CONFIG_GPIO_ADS114S0X_INIT_PRIORITY > CONFIG_ADC_INIT_PRIORITY, - "ADS114S0X GPIO driver must be initialized after ADS114S0X ADC driver"); - -#define GPIO_ADS114S0X_DEVICE(id) \ - static const struct gpio_ads114s0x_config gpio_ads114s0x_##id##_cfg = { \ - .common = {.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(id)}, \ - .parent = DEVICE_DT_GET(DT_INST_BUS(id)), \ - }; \ - \ - static struct gpio_ads114s0x_data gpio_ads114s0x_##id##_data; \ - \ - DEVICE_DT_INST_DEFINE(id, gpio_ads114s0x_init, NULL, &gpio_ads114s0x_##id##_data, \ - &gpio_ads114s0x_##id##_cfg, POST_KERNEL, \ - CONFIG_GPIO_ADS114S0X_INIT_PRIORITY, &gpio_ads114s0x_api); - -DT_INST_FOREACH_STATUS_OKAY(GPIO_ADS114S0X_DEVICE) diff --git a/drivers/gpio/gpio_ads1x4s0x.c b/drivers/gpio/gpio_ads1x4s0x.c new file mode 100644 index 000000000000..81ed760adccf --- /dev/null +++ b/drivers/gpio/gpio_ads1x4s0x.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2023 SILA Embedded Solutions GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief GPIO driver for the ADS1X4S0X AFE. + */ + +#define DT_DRV_COMPAT ti_ads1x4s0x_gpio + +#include +#include + +#define LOG_LEVEL CONFIG_GPIO_LOG_LEVEL +#include +LOG_MODULE_REGISTER(gpio_ads1x4s0x); + +#include + +#include + +struct gpio_ads1x4s0x_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + const struct device *parent; +}; + +struct gpio_ads1x4s0x_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; +}; + +static int gpio_ads1x4s0x_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + const struct gpio_ads1x4s0x_config *config = dev->config; + int err = 0; + + if ((flags & (GPIO_INPUT | GPIO_OUTPUT)) == GPIO_DISCONNECTED) { + return ads1x4s0x_gpio_deconfigure(config->parent, pin); + } + + if ((flags & GPIO_SINGLE_ENDED) != 0) { + return -ENOTSUP; + } + + if ((flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != 0) { + return -ENOTSUP; + } + + if (flags & GPIO_INT_ENABLE) { + /* ads1x4s0x GPIOs do not support interrupts */ + return -ENOTSUP; + } + + switch (flags & GPIO_DIR_MASK) { + case GPIO_INPUT: + err = ads1x4s0x_gpio_set_input(config->parent, pin); + break; + case GPIO_OUTPUT: + err = ads1x4s0x_gpio_set_output(config->parent, pin, + (flags & GPIO_OUTPUT_INIT_HIGH) != 0); + break; + default: + return -ENOTSUP; + } + + return err; +} + +static int gpio_ads1x4s0x_port_get_raw(const struct device *dev, gpio_port_value_t *value) +{ + const struct gpio_ads1x4s0x_config *config = dev->config; + + return ads1x4s0x_gpio_port_get_raw(config->parent, value); +} + +static int gpio_ads1x4s0x_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + const struct gpio_ads1x4s0x_config *config = dev->config; + + return ads1x4s0x_gpio_port_set_masked_raw(config->parent, mask, value); +} + +static int gpio_ads1x4s0x_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + const struct gpio_ads1x4s0x_config *config = dev->config; + + return ads1x4s0x_gpio_port_set_masked_raw(config->parent, pins, pins); +} + +static int gpio_ads1x4s0x_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + const struct gpio_ads1x4s0x_config *config = dev->config; + + return ads1x4s0x_gpio_port_set_masked_raw(config->parent, pins, 0); +} + +static int gpio_ads1x4s0x_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) +{ + const struct gpio_ads1x4s0x_config *config = dev->config; + + return ads1x4s0x_gpio_port_toggle_bits(config->parent, pins); +} + +static int gpio_ads1x4s0x_init(const struct device *dev) +{ + const struct gpio_ads1x4s0x_config *config = dev->config; + + if (!device_is_ready(config->parent)) { + LOG_ERR("parent ads1x4s0x device '%s' not ready", config->parent->name); + return -EINVAL; + } + + return 0; +} + +static DEVICE_API(gpio, gpio_ads1x4s0x_api) = { + .pin_configure = gpio_ads1x4s0x_config, + .port_set_masked_raw = gpio_ads1x4s0x_port_set_masked_raw, + .port_set_bits_raw = gpio_ads1x4s0x_port_set_bits_raw, + .port_clear_bits_raw = gpio_ads1x4s0x_port_clear_bits_raw, + .port_toggle_bits = gpio_ads1x4s0x_port_toggle_bits, + .port_get_raw = gpio_ads1x4s0x_port_get_raw, +}; + +BUILD_ASSERT(CONFIG_GPIO_ADS1X4S0X_INIT_PRIORITY > CONFIG_ADC_INIT_PRIORITY, + "ADS1X4S0X GPIO driver must be initialized after ADS1X4S0X ADC driver"); + +#define GPIO_ADS1X4S0X_DEVICE(id) \ + static const struct gpio_ads1x4s0x_config gpio_ads1x4s0x_##id##_cfg = { \ + .common = {.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(id)}, \ + .parent = DEVICE_DT_GET(DT_INST_BUS(id)), \ + }; \ + \ + static struct gpio_ads1x4s0x_data gpio_ads1x4s0x_##id##_data; \ + \ + DEVICE_DT_INST_DEFINE(id, gpio_ads1x4s0x_init, NULL, &gpio_ads1x4s0x_##id##_data, \ + &gpio_ads1x4s0x_##id##_cfg, POST_KERNEL, \ + CONFIG_GPIO_ADS1X4S0X_INIT_PRIORITY, &gpio_ads1x4s0x_api); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_ADS1X4S0X_DEVICE) diff --git a/dts/bindings/adc/ti,ads114s06.yaml b/dts/bindings/adc/ti,ads114s06.yaml new file mode 100644 index 000000000000..7a9d65e12691 --- /dev/null +++ b/dts/bindings/adc/ti,ads114s06.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 The Zephyr Project Contributors +# SPDX-License-Identifier: Apache-2.0 + +description: Texas Instrument 6 channels 16 bit SPI ADC + +compatible: "ti,ads114s06" + +include: ti,ads1x4s0x-base.yaml diff --git a/dts/bindings/adc/ti,ads114s08.yaml b/dts/bindings/adc/ti,ads114s08.yaml index cf91c11652b7..45a376e50e37 100644 --- a/dts/bindings/adc/ti,ads114s08.yaml +++ b/dts/bindings/adc/ti,ads114s08.yaml @@ -5,54 +5,4 @@ description: Texas Instrument 12 channels 16 bit SPI ADC compatible: "ti,ads114s08" -include: [adc-controller.yaml, spi-device.yaml] - -bus: ads114s0x - -properties: - "#io-channel-cells": - const: 1 - - reset-gpios: - type: phandle-array - description: "GPIO for reset" - - drdy-gpios: - type: phandle-array - required: true - description: | - GPIO for data ready, becomes active when a conversion result is ready - - start-sync-gpios: - type: phandle-array - description: | - GPIO for start/sync, used to signal the ADC that a conversion should be started - - idac-current: - type: int - enum: - - 0 - - 10 - - 50 - - 100 - - 250 - - 500 - - 750 - - 1000 - - 1500 - - 2000 - default: 0 - description: | - IDAC current in microampere, the default value turns the current source off - - vbias-level: - type: int - enum: - - 0 - - 1 - default: 0 - description: | - bias voltage level: 0 - (AVDD+AVSS)/2, 1 - (AVDD+AVSS)/12 - -io-channel-cells: - - input +include: ti,ads1x4s0x-base.yaml diff --git a/dts/bindings/adc/ti,ads124s06.yaml b/dts/bindings/adc/ti,ads124s06.yaml new file mode 100644 index 000000000000..ca113e746264 --- /dev/null +++ b/dts/bindings/adc/ti,ads124s06.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 The Zephyr Project Contributors +# SPDX-License-Identifier: Apache-2.0 + +description: Texas Instrument 6 channels 24 bit SPI ADC + +compatible: "ti,ads124s06" + +include: ti,ads1x4s0x-base.yaml diff --git a/dts/bindings/adc/ti,ads124s08.yaml b/dts/bindings/adc/ti,ads124s08.yaml new file mode 100644 index 000000000000..ab38b3f89258 --- /dev/null +++ b/dts/bindings/adc/ti,ads124s08.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 The Zephyr Project Contributors +# SPDX-License-Identifier: Apache-2.0 + +description: Texas Instrument 12 channels 24 bit SPI ADC + +compatible: "ti,ads124s08" + +include: ti,ads1x4s0x-base.yaml diff --git a/dts/bindings/adc/ti,ads1x4s0x-base.yaml b/dts/bindings/adc/ti,ads1x4s0x-base.yaml new file mode 100644 index 000000000000..be1070a76ee5 --- /dev/null +++ b/dts/bindings/adc/ti,ads1x4s0x-base.yaml @@ -0,0 +1,54 @@ +# Copyright (c) 2023 SILA Embedded Solutions GmbH +# SPDX-License-Identifier: Apache-2.0 + +include: [adc-controller.yaml, spi-device.yaml] + +bus: ads1x4s0x + +properties: + "#io-channel-cells": + const: 1 + + reset-gpios: + type: phandle-array + description: "GPIO for reset" + + drdy-gpios: + type: phandle-array + required: true + description: | + GPIO for data ready, becomes active when a conversion result is ready + + start-sync-gpios: + type: phandle-array + description: | + GPIO for start/sync, used to signal the ADC that a conversion should be started + + idac-current: + type: int + enum: + - 0 + - 10 + - 50 + - 100 + - 250 + - 500 + - 750 + - 1000 + - 1500 + - 2000 + default: 0 + description: | + IDAC current in microampere, the default value turns the current source off + + vbias-level: + type: int + enum: + - 0 + - 1 + default: 0 + description: | + bias voltage level: 0 - (AVDD+AVSS)/2, 1 - (AVDD+AVSS)/12 + +io-channel-cells: + - input diff --git a/dts/bindings/gpio/ti,ads114s0x-gpio.yaml b/dts/bindings/gpio/ti,ads1x4s0x-gpio.yaml similarity index 87% rename from dts/bindings/gpio/ti,ads114s0x-gpio.yaml rename to dts/bindings/gpio/ti,ads1x4s0x-gpio.yaml index 62a7a483aa13..b7ec4e3daffd 100644 --- a/dts/bindings/gpio/ti,ads114s0x-gpio.yaml +++ b/dts/bindings/gpio/ti,ads1x4s0x-gpio.yaml @@ -6,11 +6,11 @@ description: TI ADS114S0x GPIO controller binding -compatible: "ti,ads114s0x-gpio" +compatible: "ti,ads1x4s0x-gpio" include: [gpio-controller.yaml, base.yaml] -on-bus: ads114s0x +on-bus: ads1x4s0x properties: "#gpio-cells": diff --git a/include/zephyr/drivers/adc/ads114s0x.h b/include/zephyr/drivers/adc/ads114s0x.h deleted file mode 100644 index af8cae7a96a5..000000000000 --- a/include/zephyr/drivers/adc/ads114s0x.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2023 SILA Embedded Solutions GmbH - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_INCLUDE_DRIVERS_ADC_ADS114S0X_H_ -#define ZEPHYR_INCLUDE_DRIVERS_ADC_ADS114S0X_H_ - -#include -#include - -int ads114s0x_gpio_set_output(const struct device *dev, uint8_t pin, bool initial_value); - -int ads114s0x_gpio_set_input(const struct device *dev, uint8_t pin); - -int ads114s0x_gpio_deconfigure(const struct device *dev, uint8_t pin); - -int ads114s0x_gpio_set_pin_value(const struct device *dev, uint8_t pin, - bool value); - -int ads114s0x_gpio_get_pin_value(const struct device *dev, uint8_t pin, - bool *value); - -int ads114s0x_gpio_port_get_raw(const struct device *dev, - gpio_port_value_t *value); - -int ads114s0x_gpio_port_set_masked_raw(const struct device *dev, - gpio_port_pins_t mask, - gpio_port_value_t value); - -int ads114s0x_gpio_port_toggle_bits(const struct device *dev, - gpio_port_pins_t pins); - -#endif /* ZEPHYR_INCLUDE_DRIVERS_ADC_ADS114S0X_H_ */ diff --git a/include/zephyr/drivers/adc/ads1x4s0x.h b/include/zephyr/drivers/adc/ads1x4s0x.h new file mode 100644 index 000000000000..2f4c7a148290 --- /dev/null +++ b/include/zephyr/drivers/adc/ads1x4s0x.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 SILA Embedded Solutions GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_ADC_ADS1X4S0X_H_ +#define ZEPHYR_INCLUDE_DRIVERS_ADC_ADS1X4S0X_H_ + +#include +#include + +int ads1x4s0x_gpio_set_output(const struct device *dev, uint8_t pin, bool initial_value); + +int ads1x4s0x_gpio_set_input(const struct device *dev, uint8_t pin); + +int ads1x4s0x_gpio_deconfigure(const struct device *dev, uint8_t pin); + +int ads1x4s0x_gpio_set_pin_value(const struct device *dev, uint8_t pin, + bool value); + +int ads1x4s0x_gpio_get_pin_value(const struct device *dev, uint8_t pin, + bool *value); + +int ads1x4s0x_gpio_port_get_raw(const struct device *dev, + gpio_port_value_t *value); + +int ads1x4s0x_gpio_port_set_masked_raw(const struct device *dev, + gpio_port_pins_t mask, + gpio_port_value_t value); + +int ads1x4s0x_gpio_port_toggle_bits(const struct device *dev, + gpio_port_pins_t pins); + +#endif /* ZEPHYR_INCLUDE_DRIVERS_ADC_ADS1X4S0X_H_ */ diff --git a/include/zephyr/dt-bindings/adc/ads114s0x_adc.h b/include/zephyr/dt-bindings/adc/ads114s0x_adc.h deleted file mode 100644 index c54b1c4c07bf..000000000000 --- a/include/zephyr/dt-bindings/adc/ads114s0x_adc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2023 SILA Embedded Solutions GmbH - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ADC_ADS114S0X_ADC_H_ -#define ZEPHYR_INCLUDE_DT_BINDINGS_ADC_ADS114S0X_ADC_H_ - -/* - * These are the available data rates described as samples per second. They - * can be used with the time unit ticks for the acquisition time. - */ -#define ADS114S0X_CONFIG_DR_2_5 0 -#define ADS114S0X_CONFIG_DR_5 1 -#define ADS114S0X_CONFIG_DR_10 2 -#define ADS114S0X_CONFIG_DR_16_6 3 -#define ADS114S0X_CONFIG_DR_20 4 -#define ADS114S0X_CONFIG_DR_50 5 -#define ADS114S0X_CONFIG_DR_60 6 -#define ADS114S0X_CONFIG_DR_100 7 -#define ADS114S0X_CONFIG_DR_200 8 -#define ADS114S0X_CONFIG_DR_400 9 -#define ADS114S0X_CONFIG_DR_800 10 -#define ADS114S0X_CONFIG_DR_1000 11 -#define ADS114S0X_CONFIG_DR_2000 12 -#define ADS114S0X_CONFIG_DR_4000 13 - -#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ADC_ADS114S0X_ADC_H_ */ diff --git a/include/zephyr/dt-bindings/adc/ads1x4s0x_adc.h b/include/zephyr/dt-bindings/adc/ads1x4s0x_adc.h new file mode 100644 index 000000000000..51367aa0447b --- /dev/null +++ b/include/zephyr/dt-bindings/adc/ads1x4s0x_adc.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 SILA Embedded Solutions GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ADC_ADS1X4S0X_ADC_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ADC_ADS1X4S0X_ADC_H_ + +/* + * These are the available data rates described as samples per second. They + * can be used with the time unit ticks for the acquisition time. + */ +#define ADS1X4S0X_CONFIG_DR_2_5 0 +#define ADS1X4S0X_CONFIG_DR_5 1 +#define ADS1X4S0X_CONFIG_DR_10 2 +#define ADS1X4S0X_CONFIG_DR_16_6 3 +#define ADS1X4S0X_CONFIG_DR_20 4 +#define ADS1X4S0X_CONFIG_DR_50 5 +#define ADS1X4S0X_CONFIG_DR_60 6 +#define ADS1X4S0X_CONFIG_DR_100 7 +#define ADS1X4S0X_CONFIG_DR_200 8 +#define ADS1X4S0X_CONFIG_DR_400 9 +#define ADS1X4S0X_CONFIG_DR_800 10 +#define ADS1X4S0X_CONFIG_DR_1000 11 +#define ADS1X4S0X_CONFIG_DR_2000 12 +#define ADS1X4S0X_CONFIG_DR_4000 13 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ADC_ADS1X4S0X_ADC_H_ */ diff --git a/tests/drivers/build_all/gpio/adc_ads1145s0x_gpio.overlay b/tests/drivers/build_all/gpio/adc_ads1145s0x_gpio.overlay index dc473f7bf0d9..b35942081234 100644 --- a/tests/drivers/build_all/gpio/adc_ads1145s0x_gpio.overlay +++ b/tests/drivers/build_all/gpio/adc_ads1145s0x_gpio.overlay @@ -1,21 +1,51 @@ -&test_spi { - test_spi_ads114s08: ads114s08@0 { - compatible = "ti,ads114s08"; - status = "okay"; - spi-max-frequency = <10000000>; - reg = <0x00>; +/* + * Copyright (c) 2024 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + test { #address-cells = <1>; - #size-cells = <0>; - #io-channel-cells = <1>; - reset-gpios = <&test_gpio 0 0>; - drdy-gpios = <&test_gpio 0 0>; - start-sync-gpios = <&test_gpio 0 0>; + #size-cells = <1>; - test_spi_ads114s08_gpio: ads114s0x_gpio { - compatible = "ti,ads114s0x-gpio"; + test_gpio: gpio@deadbeef { + compatible = "vnd,gpio"; gpio-controller; - ngpios = <4>; - #gpio-cells = <2>; + reg = <0xdeadbeef 0x1000>; + #gpio-cells = <0x2>; + status = "okay"; + }; + + test_spi: spi@33334444 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "vnd,spi"; + reg = <0x33334444 0x1000>; + status = "okay"; + clock-frequency = <2000000>; + + cs-gpios = <&test_gpio 0 0>; + + test_spi_ads114s08: ads114s08@0 { + compatible = "ti,ads114s08"; + status = "okay"; + spi-max-frequency = <10000000>; + reg = <0x00>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + reset-gpios = <&test_gpio 0 0>; + drdy-gpios = <&test_gpio 0 0>; + start-sync-gpios = <&test_gpio 0 0>; + + test_spi_ads114s08_gpio: ads114s0x_gpio { + compatible = "ti,ads1x4s0x-gpio"; + gpio-controller; + ngpios = <4>; + #gpio-cells = <2>; + }; + }; }; }; }; diff --git a/tests/drivers/build_all/gpio/adc_ads1x4s0x_gpio.overlay b/tests/drivers/build_all/gpio/adc_ads1x4s0x_gpio.overlay new file mode 100644 index 000000000000..9d1f353542e8 --- /dev/null +++ b/tests/drivers/build_all/gpio/adc_ads1x4s0x_gpio.overlay @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + test { + #address-cells = <1>; + #size-cells = <1>; + + test_gpio: gpio@deadbeef { + compatible = "vnd,gpio"; + gpio-controller; + reg = <0xdeadbeef 0x1000>; + #gpio-cells = <0x2>; + status = "okay"; + }; + + test_spi: spi@33334444 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "vnd,spi"; + reg = <0x33334444 0x1000>; + status = "okay"; + clock-frequency = <2000000>; + + cs-gpios = <&test_gpio 0 0>; + + test_spi_ads114s08: ads114s08@0 { + compatible = "ti,ads114s08"; + status = "okay"; + spi-max-frequency = <10000000>; + reg = <0x00>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + reset-gpios = <&test_gpio 0 0>; + drdy-gpios = <&test_gpio 0 0>; + start-sync-gpios = <&test_gpio 0 0>; + + test_spi_ads114s08_gpio: ads1x4s0x_gpio { + compatible = "ti,ads1x4s0x-gpio"; + gpio-controller; + ngpios = <4>; + #gpio-cells = <2>; + }; + }; + + test_spi_ads124s08: ads124s08@0 { + compatible = "ti,ads124s08"; + status = "okay"; + spi-max-frequency = <10000000>; + reg = <0x00>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + reset-gpios = <&test_gpio 0 0>; + drdy-gpios = <&test_gpio 0 0>; + start-sync-gpios = <&test_gpio 0 0>; + + test_spi_ads124s08_gpio: ads1x4s0x_gpio { + compatible = "ti,ads1x4s0x-gpio"; + gpio-controller; + ngpios = <4>; + #gpio-cells = <2>; + }; + }; + + test_spi_ads114s06: ads114s06@0 { + compatible = "ti,ads114s06"; + status = "okay"; + spi-max-frequency = <10000000>; + reg = <0x00>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + reset-gpios = <&test_gpio 0 0>; + drdy-gpios = <&test_gpio 0 0>; + start-sync-gpios = <&test_gpio 0 0>; + + test_spi_ads114s06_gpio: ads1x4s0x_gpio { + compatible = "ti,ads1x4s0x-gpio"; + gpio-controller; + ngpios = <4>; + #gpio-cells = <2>; + }; + }; + + test_spi_ads124s06: ads124s06@0 { + compatible = "ti,ads124s06"; + status = "okay"; + spi-max-frequency = <10000000>; + reg = <0x00>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + reset-gpios = <&test_gpio 0 0>; + drdy-gpios = <&test_gpio 0 0>; + start-sync-gpios = <&test_gpio 0 0>; + + test_spi_ads124s06_gpio: ads1x4s0x_gpio { + compatible = "ti,ads1x4s0x-gpio"; + gpio-controller; + ngpios = <4>; + #gpio-cells = <2>; + }; + }; + }; + }; +}; diff --git a/tests/drivers/build_all/gpio/testcase.yaml b/tests/drivers/build_all/gpio/testcase.yaml index 6b87243550dc..01c46b456743 100644 --- a/tests/drivers/build_all/gpio/testcase.yaml +++ b/tests/drivers/build_all/gpio/testcase.yaml @@ -24,7 +24,7 @@ tests: depends_on: gpio extra_args: DTC_OVERLAY_FILE="altera.overlay" - drivers.gpio.build.adc_ads1145s0x_gpio: + drivers.gpio.build.adc_ads1x4s0x_gpio: min_ram: 32 platform_allow: m5stack_core2/esp32/procpu nrf52840dk/nrf52840 depends_on: @@ -32,8 +32,27 @@ tests: - adc - spi extra_args: - - DTC_OVERLAY_FILE="app.overlay;adc_ads1145s0x_gpio.overlay" - - CONF_FILE="adc_ads1145s0x_gpio.conf" + - DTC_OVERLAY_FILE="adc_ads1x4s0x_gpio.overlay" + extra_configs: + - CONFIG_ADC=y + - CONFIG_ADC_INIT_PRIORITY=80 + - CONFIG_ADC_ADS1X4S0X_GPIO=y + + drivers.gpio.build.adc_lmp90xxx_gpio: + min_ram: 32 + platform_allow: + - native_sim + - native_sim/native/64 + depends_on: + - gpio + - adc + - spi + extra_args: + - DTC_OVERLAY_FILE="adc_lmp90xxx_gpio.overlay" + extra_configs: + - CONFIG_ADC=y + - CONFIG_ADC_INIT_PRIORITY=80 + - CONFIG_ADC_LMP90XXX_GPIO=y drivers.gpio.build.iproc: platform_allow: qemu_cortex_m3