From 17b1912bc3512eadc25c19c1d95606a17173e154 Mon Sep 17 00:00:00 2001 From: Jeppe Odgaard Date: Wed, 24 Jan 2024 09:05:09 +0100 Subject: [PATCH] drivers: ad559x: add i2c bus support Rename ad5592 files in dts, driver and include to ad559x and add support for I2C bus which is required for AD5593. Signed-off-by: Jeppe Odgaard --- CODEOWNERS | 8 +- drivers/adc/CMakeLists.txt | 2 +- drivers/adc/Kconfig | 2 +- .../adc/{Kconfig.ad5592 => Kconfig.ad559x} | 16 +- drivers/adc/adc_ad5592.c | 255 ---------------- drivers/adc/adc_ad559x.c | 273 ++++++++++++++++++ drivers/adc/adc_shell.c | 2 +- drivers/dac/CMakeLists.txt | 2 +- drivers/dac/Kconfig | 2 +- drivers/dac/Kconfig.ad5592 | 10 - drivers/dac/Kconfig.ad559x | 10 + drivers/dac/dac_ad5592.c | 107 ------- drivers/dac/dac_ad559x.c | 110 +++++++ drivers/gpio/CMakeLists.txt | 2 +- drivers/gpio/Kconfig | 2 +- drivers/gpio/Kconfig.ad5592 | 10 - drivers/gpio/Kconfig.ad559x | 10 + drivers/gpio/gpio_ad5592.c | 227 --------------- drivers/gpio/gpio_ad559x.c | 236 +++++++++++++++ drivers/mfd/CMakeLists.txt | 4 +- drivers/mfd/Kconfig | 2 +- drivers/mfd/Kconfig.ad5592 | 10 - drivers/mfd/Kconfig.ad559x | 25 ++ drivers/mfd/mfd_ad5592.c | 182 ------------ drivers/mfd/mfd_ad559x.c | 110 +++++++ drivers/mfd/mfd_ad559x.h | 65 +++++ drivers/mfd/mfd_ad559x_i2c.c | 79 +++++ drivers/mfd/mfd_ad559x_spi.c | 114 ++++++++ ...di,ad5592-adc.yaml => adi,ad559x-adc.yaml} | 4 +- ...di,ad5592-dac.yaml => adi,ad559x-dac.yaml} | 4 +- ...,ad5592-gpio.yaml => adi,ad559x-gpio.yaml} | 4 +- ...adi,ad5592.yaml => adi,ad559x-common.yaml} | 6 +- dts/bindings/mfd/adi,ad559x-i2c.yaml | 8 + dts/bindings/mfd/adi,ad559x-spi.yaml | 8 + include/zephyr/drivers/mfd/ad5592.h | 91 ------ include/zephyr/drivers/mfd/ad559x.h | 136 +++++++++ .../build_all/adc/boards/native_sim.overlay | 8 +- tests/drivers/build_all/dac/app.overlay | 8 +- tests/drivers/build_all/gpio/app.overlay | 8 +- 39 files changed, 1226 insertions(+), 936 deletions(-) rename drivers/adc/{Kconfig.ad5592 => Kconfig.ad559x} (59%) delete mode 100644 drivers/adc/adc_ad5592.c create mode 100644 drivers/adc/adc_ad559x.c delete mode 100644 drivers/dac/Kconfig.ad5592 create mode 100644 drivers/dac/Kconfig.ad559x delete mode 100644 drivers/dac/dac_ad5592.c create mode 100644 drivers/dac/dac_ad559x.c delete mode 100644 drivers/gpio/Kconfig.ad5592 create mode 100644 drivers/gpio/Kconfig.ad559x delete mode 100644 drivers/gpio/gpio_ad5592.c create mode 100644 drivers/gpio/gpio_ad559x.c delete mode 100644 drivers/mfd/Kconfig.ad5592 create mode 100644 drivers/mfd/Kconfig.ad559x delete mode 100644 drivers/mfd/mfd_ad5592.c create mode 100644 drivers/mfd/mfd_ad559x.c create mode 100644 drivers/mfd/mfd_ad559x.h create mode 100644 drivers/mfd/mfd_ad559x_i2c.c create mode 100644 drivers/mfd/mfd_ad559x_spi.c rename dts/bindings/adc/{adi,ad5592-adc.yaml => adi,ad559x-adc.yaml} (73%) rename dts/bindings/dac/{adi,ad5592-dac.yaml => adi,ad559x-dac.yaml} (73%) rename dts/bindings/gpio/{adi,ad5592-gpio.yaml => adi,ad559x-gpio.yaml} (66%) rename dts/bindings/mfd/{adi,ad5592.yaml => adi,ad559x-common.yaml} (59%) create mode 100644 dts/bindings/mfd/adi,ad559x-i2c.yaml create mode 100644 dts/bindings/mfd/adi,ad559x-spi.yaml delete mode 100644 include/zephyr/drivers/mfd/ad5592.h create mode 100644 include/zephyr/drivers/mfd/ad559x.h diff --git a/CODEOWNERS b/CODEOWNERS index 0a30b6f34c..60ce1a2533 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -167,7 +167,7 @@ /drivers/adc/*ads114s0x* @benediktibk /drivers/adc/*max11102_17* @benediktibk /drivers/adc/*kb1200* @ene-steven -/drivers/adc/adc_ad5592.c @bbilas +/drivers/adc/adc_ad559x.c @bbilas /drivers/audio/*nrfx* @anangl /drivers/auxdisplay/*pt6314* @xingrz /drivers/auxdisplay/* @thedjnK @@ -192,7 +192,7 @@ /drivers/display/*rm68200* @mmahadevan108 /drivers/display/display_ili9342c.* @extremegtx /drivers/dac/*ad56xx* @benediktibk -/drivers/dac/dac_ad5592.c @bbilas +/drivers/dac/dac_ad559x.c @bbilas /drivers/dai/ @kv2019i @marcinszkudlinski @abonislawski /drivers/dai/intel/ @kv2019i @marcinszkudlinski @abonislawski /drivers/dai/intel/ssp/ @kv2019i @marcinszkudlinski @abonislawski @@ -244,7 +244,7 @@ /drivers/gpio/*pcal64xxa* @benediktibk /drivers/gpio/*kb1200* @ene-steven /drivers/gpio/gpio_altera_pio.c @shilinte -/drivers/gpio/gpio_ad5592.c @bbilas +/drivers/gpio/gpio_ad559x.c @bbilas /drivers/i2c/i2c_common.c @sjg20 /drivers/i2c/i2c_emul.c @sjg20 /drivers/i2c/i2c_ite_enhance.c @GTLin08 @@ -284,7 +284,7 @@ /drivers/kscan/*ft5336* @MaureenHelm /drivers/kscan/*ht16k33* @henrikbrixandersen /drivers/led_strip/ @mbolivar-ampere -/drivers/mfd/mfd_ad5592.c @bbilas +/drivers/mfd/mfd_ad559x.c @bbilas /drivers/mfd/mfd_max20335.c @bbilas /drivers/misc/ft8xx/ @hubertmis /drivers/modem/hl7800.c @rerickson1 diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index edc1baf898..ae0ebcb5b5 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -46,7 +46,7 @@ zephyr_library_sources_ifdef(CONFIG_ADC_TLA2021 adc_tla2021.c) zephyr_library_sources_ifdef(CONFIG_ADC_NXP_S32_ADC_SAR adc_nxp_s32_adc_sar.c) zephyr_library_sources_ifdef(CONFIG_ADC_MAX1125X adc_max1125x.c) zephyr_library_sources_ifdef(CONFIG_ADC_MAX11102_17 adc_max11102_17.c) -zephyr_library_sources_ifdef(CONFIG_ADC_AD5592 adc_ad5592.c) +zephyr_library_sources_ifdef(CONFIG_ADC_AD559X adc_ad559x.c) zephyr_library_sources_ifdef(CONFIG_ADC_LTC2451 adc_ltc2451.c) zephyr_library_sources_ifdef(CONFIG_ADC_NUMAKER adc_numaker.c) zephyr_library_sources_ifdef(CONFIG_ADC_ENE_KB1200 adc_ene_kb1200.c) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index fb4aa3681b..1f13203c48 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -120,7 +120,7 @@ source "drivers/adc/Kconfig.max1125x" source "drivers/adc/Kconfig.max11102_17" -source "drivers/adc/Kconfig.ad5592" +source "drivers/adc/Kconfig.ad559x" source "drivers/adc/Kconfig.ltc2451" diff --git a/drivers/adc/Kconfig.ad5592 b/drivers/adc/Kconfig.ad559x similarity index 59% rename from drivers/adc/Kconfig.ad5592 rename to drivers/adc/Kconfig.ad559x index 92b80f3421..7c5f65bb74 100644 --- a/drivers/adc/Kconfig.ad5592 +++ b/drivers/adc/Kconfig.ad559x @@ -1,25 +1,25 @@ # Copyright (c) 2023 Grinn # SPDX -License-Identifier: Apache-2.0 -config ADC_AD5592 - bool "AD5592 ADC driver" +config ADC_AD559X + bool "AD559x ADC driver" default y - depends on DT_HAS_ADI_AD5592_ADC_ENABLED + depends on DT_HAS_ADI_AD559X_ADC_ENABLED select MFD help - Enable the AD5592 ADC driver. + Enable the AD559x ADC driver. -config ADC_AD5592_ACQUISITION_THREAD_STACK_SIZE +config ADC_AD559X_ACQUISITION_THREAD_STACK_SIZE int "Stack size for the ADC data acquisition thread" - depends on ADC_AD5592 + depends on ADC_AD559X default 384 help Size of the stack used for the internal data acquisition thread. -config ADC_AD5592_ACQUISITION_THREAD_PRIO +config ADC_AD559X_ACQUISITION_THREAD_PRIO int "Priority for the ADC data acquisition thread" - depends on ADC_AD5592 + depends on ADC_AD559X default 0 help Priority level for the internal ADC data acquisition thread. diff --git a/drivers/adc/adc_ad5592.c b/drivers/adc/adc_ad5592.c deleted file mode 100644 index b804e62e9a..0000000000 --- a/drivers/adc/adc_ad5592.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (c) 2023 Grinn - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT adi_ad5592_adc - -#include -#include -#include - -#include - -#define ADC_CONTEXT_USES_KERNEL_TIMER -#include "adc_context.h" - -#include -LOG_MODULE_REGISTER(adc_ad5592, CONFIG_ADC_LOG_LEVEL); - -#define AD5592_ADC_RESOLUTION 12U -#define AD5592_ADC_MAX_VAL 4096 - -struct adc_ad5592_config { - const struct device *mfd_dev; -}; - -struct adc_ad5592_data { - struct adc_context ctx; - const struct device *dev; - uint8_t adc_conf; - uint16_t *buffer; - uint16_t *repeat_buffer; - uint8_t channels; - struct k_thread thread; - struct k_sem sem; - - K_KERNEL_STACK_MEMBER(stack, CONFIG_ADC_AD5592_ACQUISITION_THREAD_STACK_SIZE); -}; - -static int adc_ad5592_channel_setup(const struct device *dev, - const struct adc_channel_cfg *channel_cfg) -{ - const struct adc_ad5592_config *config = dev->config; - struct adc_ad5592_data *data = dev->data; - - if (channel_cfg->channel_id >= AD5592_PIN_MAX) { - LOG_ERR("invalid channel id %d", channel_cfg->channel_id); - return -EINVAL; - } - - data->adc_conf |= BIT(channel_cfg->channel_id); - - return mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_ADC_CONFIG, data->adc_conf); -} - -static int adc_ad5592_validate_buffer_size(const struct device *dev, - const struct adc_sequence *sequence) -{ - uint8_t channels; - size_t needed; - - channels = POPCOUNT(sequence->channels); - needed = channels * sizeof(uint16_t); - - if (sequence->buffer_size < needed) { - return -ENOMEM; - } - - return 0; -} - -static int adc_ad5592_start_read(const struct device *dev, const struct adc_sequence *sequence) -{ - struct adc_ad5592_data *data = dev->data; - int ret; - - if (sequence->resolution != AD5592_ADC_RESOLUTION) { - LOG_ERR("invalid resolution %d", sequence->resolution); - return -EINVAL; - } - - if (find_msb_set(sequence->channels) > AD5592_PIN_MAX) { - LOG_ERR("invalid channels in mask: 0x%08x", sequence->channels); - return -EINVAL; - } - - ret = adc_ad5592_validate_buffer_size(dev, sequence); - if (ret < 0) { - LOG_ERR("insufficient buffer size"); - return ret; - } - - data->buffer = sequence->buffer; - adc_context_start_read(&data->ctx, sequence); - - return adc_context_wait_for_completion(&data->ctx); -} - -static int adc_ad5592_read_channel(const struct device *dev, uint8_t channel, uint16_t *result) -{ - const struct adc_ad5592_config *config = dev->config; - uint16_t val; - int ret; - - ret = mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_SEQ_ADC, BIT(channel)); - if (ret < 0) { - return ret; - } - - /* - * Invalid data: - * See Figure 46. Single-Channel ADC Conversion Sequence. - * The first conversion result always returns invalid data. - */ - (void) mfd_ad5592_read_raw(config->mfd_dev, &val); - - ret = mfd_ad5592_read_raw(config->mfd_dev, &val); - if (ret < 0) { - return ret; - } - - val = sys_be16_to_cpu(val); - if (channel >= 1) { - val -= channel * AD5592_ADC_MAX_VAL; - } - - *result = val; - - return 0; -} - -static void adc_context_start_sampling(struct adc_context *ctx) -{ - struct adc_ad5592_data *data = CONTAINER_OF(ctx, struct adc_ad5592_data, ctx); - - data->channels = ctx->sequence.channels; - data->repeat_buffer = data->buffer; - - k_sem_give(&data->sem); -} - -static void adc_context_update_buffer_pointer(struct adc_context *ctx, - bool repeat_sampling) -{ - struct adc_ad5592_data *data = CONTAINER_OF(ctx, struct adc_ad5592_data, ctx); - - if (repeat_sampling) { - data->buffer = data->repeat_buffer; - } -} - -static void adc_ad5592_acquisition_thread(struct adc_ad5592_data *data) -{ - uint16_t result; - uint8_t channel; - int ret; - - while (true) { - k_sem_take(&data->sem, K_FOREVER); - - while (data->channels != 0) { - channel = find_lsb_set(data->channels) - 1; - - ret = adc_ad5592_read_channel(data->dev, channel, &result); - if (ret < 0) { - LOG_ERR("failed to read channel %d (ret %d)", channel, ret); - adc_context_complete(&data->ctx, ret); - break; - } - - *data->buffer++ = result; - WRITE_BIT(data->channels, channel, 0); - } - - adc_context_on_sampling_done(&data->ctx, data->dev); - } -} - -static int adc_ad5592_read_async(const struct device *dev, - const struct adc_sequence *sequence, - struct k_poll_signal *async) -{ - struct adc_ad5592_data *data = dev->data; - int ret; - - adc_context_lock(&data->ctx, async ? true : false, async); - ret = adc_ad5592_start_read(dev, sequence); - adc_context_release(&data->ctx, ret); - - return ret; -} - -static int adc_ad5592_read(const struct device *dev, - const struct adc_sequence *sequence) -{ - return adc_ad5592_read_async(dev, sequence, NULL); -} - -static int adc_ad5592_init(const struct device *dev) -{ - const struct adc_ad5592_config *config = dev->config; - struct adc_ad5592_data *data = dev->data; - k_tid_t tid; - int ret; - - if (!device_is_ready(config->mfd_dev)) { - return -ENODEV; - } - - ret = mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_PD_REF_CTRL, AD5592_EN_REF); - if (ret < 0) { - return ret; - } - - data->dev = dev; - - k_sem_init(&data->sem, 0, 1); - adc_context_init(&data->ctx); - - tid = k_thread_create(&data->thread, data->stack, - K_KERNEL_STACK_SIZEOF(data->stack), - (k_thread_entry_t)adc_ad5592_acquisition_thread, data, NULL, NULL, - CONFIG_ADC_AD5592_ACQUISITION_THREAD_PRIO, 0, K_NO_WAIT); - - ret = k_thread_name_set(tid, "adc_ad5592"); - if (ret < 0) { - return ret; - } - - adc_context_unlock_unconditionally(&data->ctx); - - return 0; -} - -static const struct adc_driver_api adc_ad5592_api = { - .channel_setup = adc_ad5592_channel_setup, - .read = adc_ad5592_read, -#ifdef CONFIG_ADC_ASYNC - .read_async = adc_ad5592_read_async, -#endif -}; - -#define ADC_AD5592_DEFINE(inst) \ - static const struct adc_ad5592_config adc_ad5592_config##inst = { \ - .mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ - }; \ - \ - static struct adc_ad5592_data adc_ad5592_data##inst; \ - \ - DEVICE_DT_INST_DEFINE(inst, adc_ad5592_init, NULL, \ - &adc_ad5592_data##inst, &adc_ad5592_config##inst, \ - POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \ - &adc_ad5592_api); - -DT_INST_FOREACH_STATUS_OKAY(ADC_AD5592_DEFINE) diff --git a/drivers/adc/adc_ad559x.c b/drivers/adc/adc_ad559x.c new file mode 100644 index 0000000000..43db99ac40 --- /dev/null +++ b/drivers/adc/adc_ad559x.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_ad559x_adc + +#include +#include +#include + +#include + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" + +#include +LOG_MODULE_REGISTER(adc_ad559x, CONFIG_ADC_LOG_LEVEL); + +#define AD559X_ADC_RD_POINTER_SIZE 1 +#define AD559X_ADC_RD_POINTER 0x40 + +#define AD559X_ADC_RESOLUTION 12U + +struct adc_ad559x_config { + const struct device *mfd_dev; +}; + +struct adc_ad559x_data { + struct adc_context ctx; + const struct device *dev; + uint8_t adc_conf; + uint16_t *buffer; + uint16_t *repeat_buffer; + uint8_t channels; + struct k_thread thread; + struct k_sem sem; + + K_KERNEL_STACK_MEMBER(stack, CONFIG_ADC_AD559X_ACQUISITION_THREAD_STACK_SIZE); +}; + +static int adc_ad559x_channel_setup(const struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + const struct adc_ad559x_config *config = dev->config; + struct adc_ad559x_data *data = dev->data; + + if (channel_cfg->channel_id >= AD559X_PIN_MAX) { + LOG_ERR("invalid channel id %d", channel_cfg->channel_id); + return -EINVAL; + } + + data->adc_conf |= BIT(channel_cfg->channel_id); + + return mfd_ad559x_write_reg(config->mfd_dev, AD559X_REG_ADC_CONFIG, data->adc_conf); +} + +static int adc_ad559x_validate_buffer_size(const struct device *dev, + const struct adc_sequence *sequence) +{ + uint8_t channels; + size_t needed; + + channels = POPCOUNT(sequence->channels); + needed = channels * sizeof(uint16_t); + + if (sequence->buffer_size < needed) { + return -ENOMEM; + } + + return 0; +} + +static int adc_ad559x_start_read(const struct device *dev, const struct adc_sequence *sequence) +{ + struct adc_ad559x_data *data = dev->data; + int ret; + + if (sequence->resolution != AD559X_ADC_RESOLUTION) { + LOG_ERR("invalid resolution %d", sequence->resolution); + return -EINVAL; + } + + if (find_msb_set(sequence->channels) > AD559X_PIN_MAX) { + LOG_ERR("invalid channels in mask: 0x%08x", sequence->channels); + return -EINVAL; + } + + ret = adc_ad559x_validate_buffer_size(dev, sequence); + if (ret < 0) { + LOG_ERR("insufficient buffer size"); + return ret; + } + + data->buffer = sequence->buffer; + adc_context_start_read(&data->ctx, sequence); + + return adc_context_wait_for_completion(&data->ctx); +} + +static int adc_ad559x_read_channel(const struct device *dev, uint8_t channel, uint16_t *result) +{ + const struct adc_ad559x_config *config = dev->config; + uint16_t val; + int ret; + + /* Select channel */ + ret = mfd_ad559x_write_reg(config->mfd_dev, AD559X_REG_SEQ_ADC, BIT(channel)); + if (ret < 0) { + return ret; + } + + if (mfd_ad559x_has_pointer_byte_map(config->mfd_dev)) { + /* Start readback */ + val = AD559X_ADC_RD_POINTER; + ret = mfd_ad559x_write_raw(config->mfd_dev, (uint8_t *)&val, + AD559X_ADC_RD_POINTER_SIZE); + if (ret < 0) { + return ret; + } + + /* Read channel */ + ret = mfd_ad559x_read_raw(config->mfd_dev, (uint8_t *)&val, sizeof(val)); + if (ret < 0) { + return ret; + } + + *result = sys_get_be16((uint8_t *)&val); + + } else { + /* + * Invalid data: + * See Figure 46. Single-Channel ADC Conversion Sequence. + * The first conversion result always returns invalid data. + */ + (void)mfd_ad559x_read_raw(config->mfd_dev, (uint8_t *)&val, sizeof(val)); + + ret = mfd_ad559x_read_raw(config->mfd_dev, (uint8_t *)&val, sizeof(val)); + if (ret < 0) { + return ret; + } + + val = sys_be16_to_cpu(val); + if (channel >= 1) { + val -= channel * BIT(AD559X_ADC_RESOLUTION); + } + + *result = val; + } + + return 0; +} + +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct adc_ad559x_data *data = CONTAINER_OF(ctx, struct adc_ad559x_data, ctx); + + data->channels = ctx->sequence.channels; + data->repeat_buffer = data->buffer; + + k_sem_give(&data->sem); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat_sampling) +{ + struct adc_ad559x_data *data = CONTAINER_OF(ctx, struct adc_ad559x_data, ctx); + + if (repeat_sampling) { + data->buffer = data->repeat_buffer; + } +} + +static void adc_ad559x_acquisition_thread(struct adc_ad559x_data *data) +{ + uint16_t result; + uint8_t channel; + int ret; + + while (true) { + k_sem_take(&data->sem, K_FOREVER); + + while (data->channels != 0) { + channel = find_lsb_set(data->channels) - 1; + + ret = adc_ad559x_read_channel(data->dev, channel, &result); + if (ret < 0) { + LOG_ERR("failed to read channel %d (ret %d)", channel, ret); + adc_context_complete(&data->ctx, ret); + break; + } + + *data->buffer++ = result; + WRITE_BIT(data->channels, channel, 0); + } + + adc_context_on_sampling_done(&data->ctx, data->dev); + } +} + +static int adc_ad559x_read_async(const struct device *dev, const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + struct adc_ad559x_data *data = dev->data; + int ret; + + adc_context_lock(&data->ctx, async ? true : false, async); + ret = adc_ad559x_start_read(dev, sequence); + adc_context_release(&data->ctx, ret); + + return ret; +} + +static int adc_ad559x_read(const struct device *dev, const struct adc_sequence *sequence) +{ + return adc_ad559x_read_async(dev, sequence, NULL); +} + +static int adc_ad559x_init(const struct device *dev) +{ + const struct adc_ad559x_config *config = dev->config; + struct adc_ad559x_data *data = dev->data; + k_tid_t tid; + int ret; + + if (!device_is_ready(config->mfd_dev)) { + return -ENODEV; + } + + ret = mfd_ad559x_write_reg(config->mfd_dev, AD559X_REG_PD_REF_CTRL, AD559X_EN_REF); + if (ret < 0) { + return ret; + } + + data->dev = dev; + + k_sem_init(&data->sem, 0, 1); + adc_context_init(&data->ctx); + + tid = k_thread_create(&data->thread, data->stack, + K_KERNEL_STACK_SIZEOF(data->stack), + (k_thread_entry_t)adc_ad559x_acquisition_thread, data, NULL, NULL, + CONFIG_ADC_AD559X_ACQUISITION_THREAD_PRIO, 0, K_NO_WAIT); + + ret = k_thread_name_set(tid, "adc_ad559x"); + if (ret < 0) { + return ret; + } + + adc_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +static const struct adc_driver_api adc_ad559x_api = { + .channel_setup = adc_ad559x_channel_setup, + .read = adc_ad559x_read, +#ifdef CONFIG_ADC_ASYNC + .read_async = adc_ad559x_read_async, +#endif +}; + +#define ADC_AD559X_DEFINE(inst) \ + static const struct adc_ad559x_config adc_ad559x_config##inst = { \ + .mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + }; \ + \ + static struct adc_ad559x_data adc_ad559x_data##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, adc_ad559x_init, NULL, &adc_ad559x_data##inst, \ + &adc_ad559x_config##inst, POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \ + &adc_ad559x_api); + +DT_INST_FOREACH_STATUS_OKAY(ADC_AD559X_DEFINE) diff --git a/drivers/adc/adc_shell.c b/drivers/adc/adc_shell.c index bc002d7697..0b6951d990 100644 --- a/drivers/adc/adc_shell.c +++ b/drivers/adc/adc_shell.c @@ -75,7 +75,7 @@ static struct adc_hdl { uint8_t resolution; } adc_list[] = { /* zephyr-keep-sorted-start */ - DT_FOREACH_STATUS_OKAY(adi_ad5592_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(adi_ad559x_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(atmel_sam0_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(atmel_sam_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(atmel_sam_afec, ADC_HDL_LIST_ENTRY) diff --git a/drivers/dac/CMakeLists.txt b/drivers/dac/CMakeLists.txt index c84b0d9d78..4e1f72bb71 100644 --- a/drivers/dac/CMakeLists.txt +++ b/drivers/dac/CMakeLists.txt @@ -18,6 +18,6 @@ zephyr_library_sources_ifdef(CONFIG_DAC_MCP4725 dac_mcp4725.c) zephyr_library_sources_ifdef(CONFIG_DAC_MCP4728 dac_mcp4728.c) zephyr_library_sources_ifdef(CONFIG_DAC_GD32 dac_gd32.c) zephyr_library_sources_ifdef(CONFIG_DAC_ESP32 dac_esp32.c) -zephyr_library_sources_ifdef(CONFIG_DAC_AD5592 dac_ad5592.c) +zephyr_library_sources_ifdef(CONFIG_DAC_AD559X dac_ad559x.c) zephyr_library_sources_ifdef(CONFIG_DAC_AD56XX dac_ad56xx.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE dac_handlers.c) diff --git a/drivers/dac/Kconfig b/drivers/dac/Kconfig index 3735a11aa2..97edb2c0bc 100644 --- a/drivers/dac/Kconfig +++ b/drivers/dac/Kconfig @@ -53,6 +53,6 @@ source "drivers/dac/Kconfig.esp32" source "drivers/dac/Kconfig.ad56xx" -source "drivers/dac/Kconfig.ad5592" +source "drivers/dac/Kconfig.ad559x" endif # DAC diff --git a/drivers/dac/Kconfig.ad5592 b/drivers/dac/Kconfig.ad5592 deleted file mode 100644 index 1010992fb7..0000000000 --- a/drivers/dac/Kconfig.ad5592 +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2023 Grinn -# SPDX -License-Identifier: Apache-2.0 - -config DAC_AD5592 - bool "AD5592 DAC driver" - default y - depends on DT_HAS_ADI_AD5592_DAC_ENABLED - select MFD - help - Enable the AD5592 DAC driver. diff --git a/drivers/dac/Kconfig.ad559x b/drivers/dac/Kconfig.ad559x new file mode 100644 index 0000000000..5266680199 --- /dev/null +++ b/drivers/dac/Kconfig.ad559x @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Grinn +# SPDX -License-Identifier: Apache-2.0 + +config DAC_AD559X + bool "AD559x DAC driver" + default y + depends on DT_HAS_ADI_AD559X_DAC_ENABLED + select MFD + help + Enable the AD559x DAC driver. diff --git a/drivers/dac/dac_ad5592.c b/drivers/dac/dac_ad5592.c deleted file mode 100644 index 653df85dd5..0000000000 --- a/drivers/dac/dac_ad5592.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2023 Grinn - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT adi_ad5592_dac - -#include -#include -#include - -#include - -#include -LOG_MODULE_REGISTER(dac_ad5592, CONFIG_DAC_LOG_LEVEL); - -#define AD5592_DAC_RESOLUTION 12 -#define AD5592_DAC_WR_MSB_BIT BIT(15) -#define AD5592_DAC_CHANNEL_SHIFT_VAL 12 - -struct dac_ad5592_config { - const struct device *mfd_dev; -}; - -struct dac_ad5592_data { - uint8_t dac_conf; -}; - -static int dac_ad5592_channel_setup(const struct device *dev, - const struct dac_channel_cfg *channel_cfg) -{ - const struct dac_ad5592_config *config = dev->config; - struct dac_ad5592_data *data = dev->data; - - if (channel_cfg->channel_id >= AD5592_PIN_MAX) { - LOG_ERR("Invalid channel number %d", channel_cfg->channel_id); - return -EINVAL; - } - - if (channel_cfg->resolution != AD5592_DAC_RESOLUTION) { - LOG_ERR("Invalid resolution %d", channel_cfg->resolution); - return -EINVAL; - } - - data->dac_conf |= BIT(channel_cfg->channel_id); - - return mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_LDAC_EN, data->dac_conf); -} - -static int dac_ad5592_write_value(const struct device *dev, uint8_t channel, - uint32_t value) -{ - const struct dac_ad5592_config *config = dev->config; - uint16_t msg; - - if (channel >= AD5592_PIN_MAX) { - LOG_ERR("Invalid channel number %d", channel); - return -EINVAL; - } - - if (value >= (1 << AD5592_DAC_RESOLUTION)) { - LOG_ERR("Value %d out of range", value); - return -EINVAL; - } - - msg = sys_cpu_to_be16(AD5592_DAC_WR_MSB_BIT | - channel << AD5592_DAC_CHANNEL_SHIFT_VAL | - value); - - return mfd_ad5592_write_raw(config->mfd_dev, msg); -} - -static const struct dac_driver_api dac_ad5592_api = { - .channel_setup = dac_ad5592_channel_setup, - .write_value = dac_ad5592_write_value, -}; - -static int dac_ad5592_init(const struct device *dev) -{ - const struct dac_ad5592_config *config = dev->config; - int ret; - - if (!device_is_ready(config->mfd_dev)) { - return -ENODEV; - } - - ret = mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_PD_REF_CTRL, AD5592_EN_REF); - if (ret < 0) { - return ret; - } - - return 0; -} - -#define DAC_AD5592_DEFINE(inst) \ - static const struct dac_ad5592_config dac_ad5592_config##inst = { \ - .mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ - }; \ - \ - struct dac_ad5592_data dac_ad5592_data##inst; \ - \ - DEVICE_DT_INST_DEFINE(inst, dac_ad5592_init, NULL, \ - &dac_ad5592_data##inst, &dac_ad5592_config##inst, \ - POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \ - &dac_ad5592_api); - -DT_INST_FOREACH_STATUS_OKAY(DAC_AD5592_DEFINE) diff --git a/drivers/dac/dac_ad559x.c b/drivers/dac/dac_ad559x.c new file mode 100644 index 0000000000..0dc1c3caa2 --- /dev/null +++ b/drivers/dac/dac_ad559x.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_ad559x_dac + +#include +#include +#include + +#include + +#include +LOG_MODULE_REGISTER(dac_ad559x, CONFIG_DAC_LOG_LEVEL); + +#define AD559X_DAC_RESOLUTION 12 +#define AD559X_DAC_WR_POINTER 0x10 +#define AD559X_DAC_WR_MSB_BIT BIT(15) +#define AD559X_DAC_CHANNEL_SHIFT_VAL 12 + +struct dac_ad559x_config { + const struct device *mfd_dev; +}; + +struct dac_ad559x_data { + uint8_t dac_conf; +}; + +static int dac_ad559x_channel_setup(const struct device *dev, + const struct dac_channel_cfg *channel_cfg) +{ + const struct dac_ad559x_config *config = dev->config; + struct dac_ad559x_data *data = dev->data; + + if (channel_cfg->channel_id >= AD559X_PIN_MAX) { + LOG_ERR("Invalid channel number %d", channel_cfg->channel_id); + return -EINVAL; + } + + if (channel_cfg->resolution != AD559X_DAC_RESOLUTION) { + LOG_ERR("Invalid resolution %d", channel_cfg->resolution); + return -EINVAL; + } + + data->dac_conf |= BIT(channel_cfg->channel_id); + + return mfd_ad559x_write_reg(config->mfd_dev, AD559X_REG_LDAC_EN, data->dac_conf); +} + +static int dac_ad559x_write_value(const struct device *dev, uint8_t channel, uint32_t value) +{ + const struct dac_ad559x_config *config = dev->config; + uint16_t msg; + + if (channel >= AD559X_PIN_MAX) { + LOG_ERR("Invalid channel number %d", channel); + return -EINVAL; + } + + if (value >= (1 << AD559X_DAC_RESOLUTION)) { + LOG_ERR("Value %d out of range", value); + return -EINVAL; + } + + if (mfd_ad559x_has_pointer_byte_map(config->mfd_dev)) { + return mfd_ad559x_write_reg(config->mfd_dev, AD559X_DAC_WR_POINTER | channel, + value); + } else { + msg = sys_cpu_to_be16(AD559X_DAC_WR_MSB_BIT | + channel << AD559X_DAC_CHANNEL_SHIFT_VAL | value); + + return mfd_ad559x_write_raw(config->mfd_dev, (uint8_t *)&msg, sizeof(msg)); + } +} + +static const struct dac_driver_api dac_ad559x_api = { + .channel_setup = dac_ad559x_channel_setup, + .write_value = dac_ad559x_write_value, +}; + +static int dac_ad559x_init(const struct device *dev) +{ + const struct dac_ad559x_config *config = dev->config; + int ret; + + if (!device_is_ready(config->mfd_dev)) { + return -ENODEV; + } + + ret = mfd_ad559x_write_reg(config->mfd_dev, AD559X_REG_PD_REF_CTRL, AD559X_EN_REF); + if (ret < 0) { + return ret; + } + + return 0; +} + +#define DAC_AD559X_DEFINE(inst) \ + static const struct dac_ad559x_config dac_ad559x_config##inst = { \ + .mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + }; \ + \ + struct dac_ad559x_data dac_ad559x_data##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, dac_ad559x_init, NULL, &dac_ad559x_data##inst, \ + &dac_ad559x_config##inst, POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \ + &dac_ad559x_api); + +DT_INST_FOREACH_STATUS_OKAY(DAC_AD559X_DEFINE) diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 8d019f91ab..2143d019cb 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -4,7 +4,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/gpio.h) zephyr_library() -zephyr_library_sources_ifdef(CONFIG_GPIO_AD5592 gpio_ad5592.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_AD559X gpio_ad559x.c) zephyr_library_sources_ifdef(CONFIG_GPIO_AXP192 gpio_axp192.c) zephyr_library_sources_ifdef(CONFIG_GPIO_TELINK_B91 gpio_b91.c) zephyr_library_sources_ifdef(CONFIG_GPIO_INFINEON_CAT1 gpio_ifx_cat1.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index fb481cb229..2ca6da678c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -87,7 +87,7 @@ config GPIO_ENABLE_DISABLE_INTERRUPT pending register, etc. The driver must implement it to work. -source "drivers/gpio/Kconfig.ad5592" +source "drivers/gpio/Kconfig.ad559x" source "drivers/gpio/Kconfig.axp192" diff --git a/drivers/gpio/Kconfig.ad5592 b/drivers/gpio/Kconfig.ad5592 deleted file mode 100644 index c2654d1857..0000000000 --- a/drivers/gpio/Kconfig.ad5592 +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2023 Grinn -# SPDX-License-Identifier: Apache-2.0 - -config GPIO_AD5592 - bool "AD5592 GPIO driver" - default y - depends on DT_HAS_ADI_AD5592_GPIO_ENABLED - select MFD - help - Enable the AD5592 GPIO driver. diff --git a/drivers/gpio/Kconfig.ad559x b/drivers/gpio/Kconfig.ad559x new file mode 100644 index 0000000000..68879b4884 --- /dev/null +++ b/drivers/gpio/Kconfig.ad559x @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Grinn +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_AD559X + bool "AD559x GPIO driver" + default y + depends on DT_HAS_ADI_AD559X_GPIO_ENABLED + select MFD + help + Enable the AD559x GPIO driver. diff --git a/drivers/gpio/gpio_ad5592.c b/drivers/gpio/gpio_ad5592.c deleted file mode 100644 index a8b30ddcee..0000000000 --- a/drivers/gpio/gpio_ad5592.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (c) 2023 Grinn - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT adi_ad5592_gpio - -#include -#include -#include -#include - -#include - -struct gpio_ad5592_config { - /* gpio_driver_config needs to be first */ - struct gpio_driver_config common; - const struct device *mfd_dev; -}; - -struct gpio_ad5592_data { - /* gpio_driver_data needs to be first */ - struct gpio_driver_data common; - uint8_t gpio_val; - uint8_t gpio_out; - uint8_t gpio_in; - uint8_t gpio_pull_down; -}; - -static int gpio_ad5592_port_get_raw(const struct device *dev, uint32_t *value) -{ - const struct gpio_ad5592_config *config = dev->config; - struct gpio_ad5592_data *drv_data = dev->data; - uint16_t data; - int ret; - - if (k_is_in_isr()) { - return -EWOULDBLOCK; - } - - ret = mfd_ad5592_read_reg(config->mfd_dev, - AD5592_REG_GPIO_INPUT_EN, drv_data->gpio_in, &data); - if (ret < 0) { - return ret; - } - - *value = (uint32_t)data; - - return 0; -} - -static int gpio_ad5592_port_set_bits_raw(const struct device *dev, - gpio_port_pins_t pins) -{ - struct gpio_ad5592_data *data = dev->data; - const struct gpio_ad5592_config *config = dev->config; - - if (k_is_in_isr()) { - return -EWOULDBLOCK; - } - - data->gpio_val |= (uint8_t)pins; - - return mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_GPIO_SET, data->gpio_val); -} - -static int gpio_ad5592_port_clear_bits_raw(const struct device *dev, - gpio_port_pins_t pins) -{ - struct gpio_ad5592_data *data = dev->data; - const struct gpio_ad5592_config *config = dev->config; - - if (k_is_in_isr()) { - return -EWOULDBLOCK; - } - - data->gpio_val &= ~(uint8_t)pins; - - return mfd_ad5592_write_reg(config->mfd_dev, AD5592_REG_GPIO_SET, data->gpio_val); -} - -static inline int gpio_ad5592_configure(const struct device *dev, - gpio_pin_t pin, gpio_flags_t flags) -{ - struct gpio_ad5592_data *data = dev->data; - const struct gpio_ad5592_config *config = dev->config; - uint8_t val; - int ret; - - if (k_is_in_isr()) { - return -EWOULDBLOCK; - } - - if (pin >= AD5592_PIN_MAX) { - return -EINVAL; - } - - val = BIT(pin); - if ((flags & GPIO_OUTPUT) != 0U) { - data->gpio_in &= ~val; - data->gpio_out |= val; - - if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) { - ret = gpio_ad5592_port_set_bits_raw( - dev, (gpio_port_pins_t)BIT(pin)); - if (ret < 0) { - return ret; - } - } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) { - ret = gpio_ad5592_port_clear_bits_raw( - dev, (gpio_port_pins_t)BIT(pin)); - if (ret < 0) { - return ret; - } - } - - ret = mfd_ad5592_write_reg(config->mfd_dev, - AD5592_REG_GPIO_OUTPUT_EN, data->gpio_out); - if (ret < 0) { - return ret; - } - - ret = mfd_ad5592_write_reg(config->mfd_dev, - AD5592_REG_GPIO_INPUT_EN, data->gpio_in); - } else if ((flags & GPIO_INPUT) != 0U) { - data->gpio_in |= val; - data->gpio_out &= ~val; - - if ((flags & GPIO_PULL_DOWN) != 0U) { - data->gpio_pull_down |= val; - - ret = mfd_ad5592_write_reg(config->mfd_dev, - AD5592_REG_GPIO_PULLDOWN, - data->gpio_pull_down); - if (ret < 0) { - return ret; - } - } else if ((flags & GPIO_PULL_UP) != 0U) { - return -ENOTSUP; - } - - ret = mfd_ad5592_write_reg(config->mfd_dev, - AD5592_REG_GPIO_OUTPUT_EN, data->gpio_out); - if (ret < 0) { - return ret; - } - - ret = mfd_ad5592_write_reg(config->mfd_dev, - AD5592_REG_GPIO_INPUT_EN, data->gpio_in); - } else { - return -ENOTSUP; - } - - return ret; -} - -static int gpio_ad5592_port_set_masked_raw(const struct device *dev, - gpio_port_pins_t mask, - gpio_port_value_t value) -{ - ARG_UNUSED(dev); - ARG_UNUSED(mask); - ARG_UNUSED(value); - - return -ENOTSUP; -} - -static int gpio_ad5592_port_toggle_bits(const struct device *dev, - gpio_port_pins_t pins) -{ - ARG_UNUSED(dev); - ARG_UNUSED(pins); - - return -ENOTSUP; -} - -static int gpio_ad5592_pin_interrupt_configure(const struct device *dev, - gpio_pin_t pin, - enum gpio_int_mode mode, - enum gpio_int_trig trig) -{ - ARG_UNUSED(dev); - ARG_UNUSED(pin); - ARG_UNUSED(mode); - ARG_UNUSED(trig); - - return -ENOTSUP; -} - -static const struct gpio_driver_api gpio_ad5592_api = { - .pin_configure = gpio_ad5592_configure, - .port_get_raw = gpio_ad5592_port_get_raw, - .port_set_masked_raw = gpio_ad5592_port_set_masked_raw, - .port_set_bits_raw = gpio_ad5592_port_set_bits_raw, - .port_clear_bits_raw = gpio_ad5592_port_clear_bits_raw, - .port_toggle_bits = gpio_ad5592_port_toggle_bits, - .pin_interrupt_configure = gpio_ad5592_pin_interrupt_configure, -}; - -static int gpio_ad5592_init(const struct device *dev) -{ - const struct gpio_ad5592_config *config = dev->config; - - if (!device_is_ready(config->mfd_dev)) { - return -ENODEV; - } - - return 0; -} - -#define GPIO_AD5592_DEFINE(inst) \ - static const struct gpio_ad5592_config gpio_ad5592_config##inst = { \ - .common = { \ - .port_pin_mask = \ - GPIO_PORT_PIN_MASK_FROM_DT_INST(inst), \ - }, \ - .mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ - }; \ - \ - static struct gpio_ad5592_data gpio_ad5592_data##inst; \ - \ - DEVICE_DT_INST_DEFINE(inst, gpio_ad5592_init, NULL, \ - &gpio_ad5592_data##inst, &gpio_ad5592_config##inst, \ - POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \ - &gpio_ad5592_api); - -DT_INST_FOREACH_STATUS_OKAY(GPIO_AD5592_DEFINE) diff --git a/drivers/gpio/gpio_ad559x.c b/drivers/gpio/gpio_ad559x.c new file mode 100644 index 0000000000..afa3d1be10 --- /dev/null +++ b/drivers/gpio/gpio_ad559x.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_ad559x_gpio + +#include +#include +#include +#include + +#include + +#define AD559X_GPIO_RD_POINTER 0x60 + +struct gpio_ad559x_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + const struct device *mfd_dev; +}; + +struct gpio_ad559x_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + uint8_t gpio_val; + uint8_t gpio_out; + uint8_t gpio_in; + uint8_t gpio_pull_down; +}; + +static int gpio_ad559x_port_get_raw(const struct device *dev, uint32_t *value) +{ + const struct gpio_ad559x_config *config = dev->config; + struct gpio_ad559x_data *drv_data = dev->data; + uint16_t data; + int ret; + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + if (mfd_ad559x_has_pointer_byte_map(config->mfd_dev)) { + ret = mfd_ad559x_read_reg(config->mfd_dev, AD559X_GPIO_RD_POINTER, 0, &data); + /* LSB contains port information. Clear the MSB. */ + data &= BIT_MASK(AD559X_PIN_MAX); + } else { + ret = mfd_ad559x_read_reg(config->mfd_dev, AD559X_REG_GPIO_INPUT_EN, + drv_data->gpio_in, &data); + } + + if (ret < 0) { + return ret; + } + + *value = (uint32_t)data; + + return 0; +} + +static int gpio_ad559x_port_set_bits_raw(const struct device *dev, + gpio_port_pins_t pins) +{ + struct gpio_ad559x_data *data = dev->data; + const struct gpio_ad559x_config *config = dev->config; + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + data->gpio_val |= (uint8_t)pins; + + return mfd_ad559x_write_reg(config->mfd_dev, AD559X_REG_GPIO_SET, data->gpio_val); +} + +static int gpio_ad559x_port_clear_bits_raw(const struct device *dev, + gpio_port_pins_t pins) +{ + struct gpio_ad559x_data *data = dev->data; + const struct gpio_ad559x_config *config = dev->config; + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + data->gpio_val &= ~(uint8_t)pins; + + return mfd_ad559x_write_reg(config->mfd_dev, AD559X_REG_GPIO_SET, data->gpio_val); +} + +static inline int gpio_ad559x_configure(const struct device *dev, + gpio_pin_t pin, gpio_flags_t flags) +{ + struct gpio_ad559x_data *data = dev->data; + const struct gpio_ad559x_config *config = dev->config; + uint8_t val; + int ret; + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + if (pin >= AD559X_PIN_MAX) { + return -EINVAL; + } + + val = BIT(pin); + if ((flags & GPIO_OUTPUT) != 0U) { + data->gpio_in &= ~val; + data->gpio_out |= val; + + if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) { + ret = gpio_ad559x_port_set_bits_raw( + dev, (gpio_port_pins_t)BIT(pin)); + if (ret < 0) { + return ret; + } + } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) { + ret = gpio_ad559x_port_clear_bits_raw( + dev, (gpio_port_pins_t)BIT(pin)); + if (ret < 0) { + return ret; + } + } + + ret = mfd_ad559x_write_reg(config->mfd_dev, + AD559X_REG_GPIO_OUTPUT_EN, data->gpio_out); + if (ret < 0) { + return ret; + } + + ret = mfd_ad559x_write_reg(config->mfd_dev, + AD559X_REG_GPIO_INPUT_EN, data->gpio_in); + } else if ((flags & GPIO_INPUT) != 0U) { + data->gpio_in |= val; + data->gpio_out &= ~val; + + if ((flags & GPIO_PULL_DOWN) != 0U) { + data->gpio_pull_down |= val; + + ret = mfd_ad559x_write_reg(config->mfd_dev, + AD559X_REG_GPIO_PULLDOWN, + data->gpio_pull_down); + if (ret < 0) { + return ret; + } + } else if ((flags & GPIO_PULL_UP) != 0U) { + return -ENOTSUP; + } + + ret = mfd_ad559x_write_reg(config->mfd_dev, + AD559X_REG_GPIO_OUTPUT_EN, data->gpio_out); + if (ret < 0) { + return ret; + } + + ret = mfd_ad559x_write_reg(config->mfd_dev, + AD559X_REG_GPIO_INPUT_EN, data->gpio_in); + } else { + return -ENOTSUP; + } + + return ret; +} + +static int gpio_ad559x_port_set_masked_raw(const struct device *dev, + gpio_port_pins_t mask, + gpio_port_value_t value) +{ + ARG_UNUSED(dev); + ARG_UNUSED(mask); + ARG_UNUSED(value); + + return -ENOTSUP; +} + +static int gpio_ad559x_port_toggle_bits(const struct device *dev, + gpio_port_pins_t pins) +{ + ARG_UNUSED(dev); + ARG_UNUSED(pins); + + return -ENOTSUP; +} + +static int gpio_ad559x_pin_interrupt_configure(const struct device *dev, + gpio_pin_t pin, + enum gpio_int_mode mode, + enum gpio_int_trig trig) +{ + ARG_UNUSED(dev); + ARG_UNUSED(pin); + ARG_UNUSED(mode); + ARG_UNUSED(trig); + + return -ENOTSUP; +} + +static const struct gpio_driver_api gpio_ad559x_api = { + .pin_configure = gpio_ad559x_configure, + .port_get_raw = gpio_ad559x_port_get_raw, + .port_set_masked_raw = gpio_ad559x_port_set_masked_raw, + .port_set_bits_raw = gpio_ad559x_port_set_bits_raw, + .port_clear_bits_raw = gpio_ad559x_port_clear_bits_raw, + .port_toggle_bits = gpio_ad559x_port_toggle_bits, + .pin_interrupt_configure = gpio_ad559x_pin_interrupt_configure, +}; + +static int gpio_ad559x_init(const struct device *dev) +{ + const struct gpio_ad559x_config *config = dev->config; + + if (!device_is_ready(config->mfd_dev)) { + return -ENODEV; + } + + return 0; +} + +#define GPIO_AD559X_DEFINE(inst) \ + static const struct gpio_ad559x_config gpio_ad559x_config##inst = { \ + .common = { \ + .port_pin_mask = \ + GPIO_PORT_PIN_MASK_FROM_DT_INST(inst), \ + }, \ + .mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + }; \ + \ + static struct gpio_ad559x_data gpio_ad559x_data##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, gpio_ad559x_init, NULL, \ + &gpio_ad559x_data##inst, &gpio_ad559x_config##inst, \ + POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \ + &gpio_ad559x_api); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_AD559X_DEFINE) diff --git a/drivers/mfd/CMakeLists.txt b/drivers/mfd/CMakeLists.txt index 135643a14a..486d37f611 100644 --- a/drivers/mfd/CMakeLists.txt +++ b/drivers/mfd/CMakeLists.txt @@ -8,7 +8,9 @@ zephyr_library_sources_ifdef(CONFIG_MFD_NCT38XX mfd_nct38xx.c) zephyr_library_sources_ifdef(CONFIG_MFD_NPM1300 mfd_npm1300.c) zephyr_library_sources_ifdef(CONFIG_MFD_NPM6001 mfd_npm6001.c) zephyr_library_sources_ifdef(CONFIG_MFD_AXP192 mfd_axp192.c) -zephyr_library_sources_ifdef(CONFIG_MFD_AD5592 mfd_ad5592.c) +zephyr_library_sources_ifdef(CONFIG_MFD_AD559X mfd_ad559x.c) +zephyr_library_sources_ifdef(CONFIG_MFD_AD559X_BUS_I2C mfd_ad559x_i2c.c) +zephyr_library_sources_ifdef(CONFIG_MFD_AD559X_BUS_SPI mfd_ad559x_spi.c) zephyr_library_sources_ifdef(CONFIG_MFD_MAX31790 mfd_max31790.c) zephyr_library_sources_ifdef(CONFIG_NXP_LP_FLEXCOMM mfd_nxp_lp_flexcomm.c) zephyr_library_sources_ifdef(CONFIG_MFD_BD8LB600FS mfd_bd8lb600fs.c) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 724359a8bc..f24d9378dc 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -18,7 +18,7 @@ config MFD_INIT_PRIORITY help Multi-function devices initialization priority. -source "drivers/mfd/Kconfig.ad5592" +source "drivers/mfd/Kconfig.ad559x" source "drivers/mfd/Kconfig.axp192" source "drivers/mfd/Kconfig.bd8lb600fs" source "drivers/mfd/Kconfig.max20335" diff --git a/drivers/mfd/Kconfig.ad5592 b/drivers/mfd/Kconfig.ad5592 deleted file mode 100644 index 8b94f5517c..0000000000 --- a/drivers/mfd/Kconfig.ad5592 +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2023 Grinn -# SPDX -License-Identifier: Apache-2.0 - -config MFD_AD5592 - bool "Analog AD5592 SPI configurable ADC/DAC/GPIO chip" - default y - depends on DT_HAS_ADI_AD5592_ENABLED - depends on SPI - help - Enable driver for Analog AD5592. diff --git a/drivers/mfd/Kconfig.ad559x b/drivers/mfd/Kconfig.ad559x new file mode 100644 index 0000000000..1597f60e3b --- /dev/null +++ b/drivers/mfd/Kconfig.ad559x @@ -0,0 +1,25 @@ +# Copyright (c) 2023 Grinn +# SPDX -License-Identifier: Apache-2.0 + +menuconfig MFD_AD559X + bool "Analog AD559x I2C/SPI configurable ADC/DAC/GPIO chip" + default y + depends on DT_HAS_ADI_AD559X_ENABLED + help + Enable driver for Analog AD5592 or Analog AD5593. + +if MFD_AD559X + +config MFD_AD559X_BUS_I2C + bool "Analog AD559x I2C bus support" + default y + depends on $(dt_compat_on_bus,$(DT_COMPAT_ADI_AD559X),i2c) + depends on I2C + +config MFD_AD559X_BUS_SPI + bool "Analog AD559x SPI bus support" + default y + depends on $(dt_compat_on_bus,$(DT_COMPAT_ADI_AD559X),spi) + depends on SPI + +endif # MFD_AD559X diff --git a/drivers/mfd/mfd_ad5592.c b/drivers/mfd/mfd_ad5592.c deleted file mode 100644 index 2c320fa549..0000000000 --- a/drivers/mfd/mfd_ad5592.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 2023 Grinn - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT adi_ad5592 - -#include -#include -#include -#include - -#include - -#define AD5592_GPIO_READBACK_EN BIT(10) -#define AD5592_LDAC_READBACK_EN BIT(6) -#define AD5592_REG_SOFTWARE_RESET 0x0FU -#define AD5592_SOFTWARE_RESET_MAGIC_VAL 0x5AC -#define AD5592_REG_VAL_MASK 0x3FF -#define AD5592_REG_RESET_VAL_MASK 0x7FF -#define AD5592_REG_SHIFT_VAL 11 -#define AD5592_REG_READBACK_SHIFT_VAL 2 - -#define AD5592_SPI_SPEC_CONF (SPI_WORD_SET(8) | SPI_TRANSFER_MSB | \ - SPI_OP_MODE_MASTER | SPI_MODE_CPOL) - -struct mfd_ad5592_config { - struct gpio_dt_spec reset_gpio; - struct spi_dt_spec bus; -}; - -int mfd_ad5592_read_raw(const struct device *dev, uint16_t *val) -{ - const struct mfd_ad5592_config *config = dev->config; - uint16_t nop_msg = 0; - - struct spi_buf tx_buf[] = { - { - .buf = &nop_msg, - .len = sizeof(nop_msg) - } - }; - - const struct spi_buf_set tx = { - .buffers = tx_buf, - .count = 1 - }; - - struct spi_buf rx_buf[] = { - { - .buf = val, - .len = sizeof(uint16_t) - } - }; - - const struct spi_buf_set rx = { - .buffers = rx_buf, - .count = 1 - }; - - return spi_transceive_dt(&config->bus, &tx, &rx); -} - -int mfd_ad5592_write_raw(const struct device *dev, uint16_t val) -{ - const struct mfd_ad5592_config *config = dev->config; - - struct spi_buf tx_buf[] = { - { - .buf = &val, - .len = sizeof(val) - } - }; - - const struct spi_buf_set tx = { - .buffers = tx_buf, - .count = 1 - }; - - return spi_write_dt(&config->bus, &tx); -} - -int mfd_ad5592_read_reg(const struct device *dev, uint8_t reg, uint8_t reg_data, uint16_t *val) -{ - uint16_t data; - uint16_t msg; - int ret; - - switch (reg) { - case AD5592_REG_GPIO_INPUT_EN: - msg = sys_cpu_to_be16(AD5592_GPIO_READBACK_EN | - (AD5592_REG_GPIO_INPUT_EN << AD5592_REG_SHIFT_VAL) | - reg_data); - break; - default: - msg = sys_cpu_to_be16(AD5592_LDAC_READBACK_EN | - (AD5592_REG_READ_AND_LDAC << AD5592_REG_SHIFT_VAL) | - reg << AD5592_REG_READBACK_SHIFT_VAL); - break; - } - - ret = mfd_ad5592_write_raw(dev, msg); - if (ret < 0) { - return ret; - } - - ret = mfd_ad5592_read_raw(dev, &data); - if (ret < 0) { - return ret; - } - - *val = sys_be16_to_cpu(data); - - return 0; -} - -int mfd_ad5592_write_reg(const struct device *dev, uint8_t reg, uint16_t val) -{ - uint16_t write_mask; - uint16_t msg; - - switch (reg) { - case AD5592_REG_SOFTWARE_RESET: - write_mask = AD5592_REG_RESET_VAL_MASK; - break; - default: - write_mask = AD5592_REG_VAL_MASK; - break; - } - - msg = sys_cpu_to_be16((reg << AD5592_REG_SHIFT_VAL) | (val & write_mask)); - - return mfd_ad5592_write_raw(dev, msg); -} - -static int mfd_add592_software_reset(const struct device *dev) -{ - return mfd_ad5592_write_reg(dev, - AD5592_REG_SOFTWARE_RESET, - AD5592_SOFTWARE_RESET_MAGIC_VAL); -} - -static int mfd_ad5592_init(const struct device *dev) -{ - const struct mfd_ad5592_config *config = dev->config; - int ret; - - if (!spi_is_ready_dt(&config->bus)) { - return -ENODEV; - } - - if (!gpio_is_ready_dt(&config->reset_gpio)) { - return -ENODEV; - } - - ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE); - if (ret < 0) { - return ret; - } - - ret = mfd_add592_software_reset(dev); - if (ret < 0) { - return ret; - } - - return 0; -} - -#define MFD_AD5592_DEFINE(inst) \ - static const struct mfd_ad5592_config mfd_ad5592_config_##inst = { \ - .reset_gpio = GPIO_DT_SPEC_INST_GET(inst, reset_gpios), \ - .bus = SPI_DT_SPEC_INST_GET(inst, AD5592_SPI_SPEC_CONF, 0), \ - }; \ - \ - DEVICE_DT_INST_DEFINE(inst, mfd_ad5592_init, NULL, \ - NULL, \ - &mfd_ad5592_config_##inst, \ - POST_KERNEL, \ - CONFIG_MFD_INIT_PRIORITY, \ - NULL); - -DT_INST_FOREACH_STATUS_OKAY(MFD_AD5592_DEFINE); diff --git a/drivers/mfd/mfd_ad559x.c b/drivers/mfd/mfd_ad559x.c new file mode 100644 index 0000000000..1d298e8eda --- /dev/null +++ b/drivers/mfd/mfd_ad559x.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_ad559x + +#include +#include +#include + +#include + +#include "mfd_ad559x.h" + +bool mfd_ad559x_has_pointer_byte_map(const struct device *dev) +{ + const struct mfd_ad559x_config *config = dev->config; + + return config->has_pointer_byte_map; +} + +int mfd_ad559x_read_raw(const struct device *dev, uint8_t *val, size_t len) +{ + struct mfd_ad559x_data *data = dev->data; + + return data->transfer_function->read_raw(dev, val, len); +} + +int mfd_ad559x_write_raw(const struct device *dev, uint8_t *val, size_t len) +{ + struct mfd_ad559x_data *data = dev->data; + + return data->transfer_function->write_raw(dev, val, len); +} + +int mfd_ad559x_read_reg(const struct device *dev, uint8_t reg, uint8_t reg_data, uint16_t *val) +{ + struct mfd_ad559x_data *data = dev->data; + + return data->transfer_function->read_reg(dev, reg, reg_data, val); +} + +int mfd_ad559x_write_reg(const struct device *dev, uint8_t reg, uint16_t val) +{ + struct mfd_ad559x_data *data = dev->data; + + return data->transfer_function->write_reg(dev, reg, val); +} + +static int mfd_add559x_software_reset(const struct device *dev) +{ + return mfd_ad559x_write_reg(dev, AD559X_REG_SOFTWARE_RESET, + AD559X_SOFTWARE_RESET_MAGIC_VAL); +} + +static int mfd_ad559x_init(const struct device *dev) +{ + const struct mfd_ad559x_config *config = dev->config; + int ret; + + ret = config->bus_init(dev); + if (ret < 0) { + return ret; + } + + if (!gpio_is_ready_dt(&config->reset_gpio)) { + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + return ret; + } + + ret = mfd_add559x_software_reset(dev); + if (ret < 0) { + return ret; + } + + return 0; +} + +#define MDF_AD559X_DEFINE_I2C_BUS(inst) \ + .i2c = I2C_DT_SPEC_INST_GET(inst), .bus_init = mfd_ad559x_i2c_init, \ + .has_pointer_byte_map = true + +#define MDF_AD559X_DEFINE_SPI_BUS_FLAGS \ + (SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_OP_MODE_MASTER | SPI_MODE_CPOL) + +#define MDF_AD559X_DEFINE_SPI_BUS(inst) \ + .spi = SPI_DT_SPEC_INST_GET(inst, MDF_AD559X_DEFINE_SPI_BUS_FLAGS, 0), \ + .bus_init = mfd_ad559x_spi_init, .has_pointer_byte_map = false + +#define MFD_AD559X_DEFINE_BUS(inst) \ + COND_CODE_1(DT_INST_ON_BUS(inst, i2c), (MDF_AD559X_DEFINE_I2C_BUS(inst)), \ + (MDF_AD559X_DEFINE_SPI_BUS(inst))) + +#define MFD_AD559X_DEFINE(inst) \ + static struct mfd_ad559x_data mfd_ad559x_data_##inst; \ + static const struct mfd_ad559x_config mfd_ad559x_config_##inst = { \ + .reset_gpio = GPIO_DT_SPEC_INST_GET(inst, reset_gpios), \ + MFD_AD559X_DEFINE_BUS(inst), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, mfd_ad559x_init, NULL, &mfd_ad559x_data_##inst, \ + &mfd_ad559x_config_##inst, POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(MFD_AD559X_DEFINE); diff --git a/drivers/mfd/mfd_ad559x.h b/drivers/mfd/mfd_ad559x.h new file mode 100644 index 0000000000..feea3db070 --- /dev/null +++ b/drivers/mfd/mfd_ad559x.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024 Vitrolife A/S + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_MFD_AD559X_H_ +#define ZEPHYR_DRIVERS_MFD_AD559X_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define DT_DRV_COMPAT adi_ad559x + +#include +#include + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ + +#define AD559X_GPIO_READBACK_EN BIT(10) +#define AD559X_LDAC_READBACK_EN BIT(6) +#define AD559X_REG_SOFTWARE_RESET 0x0FU +#define AD559X_SOFTWARE_RESET_MAGIC_VAL 0x5AC +#define AD559X_REG_VAL_MASK 0x3FF +#define AD559X_REG_RESET_VAL_MASK 0x7FF +#define AD559X_REG_SHIFT_VAL 11 +#define AD559X_REG_READBACK_SHIFT_VAL 2 + +struct mfd_ad559x_transfer_function { + int (*read_raw)(const struct device *dev, uint8_t *val, size_t len); + int (*write_raw)(const struct device *dev, uint8_t *val, size_t len); + int (*read_reg)(const struct device *dev, uint8_t reg, uint8_t reg_data, uint16_t *val); + int (*write_reg)(const struct device *dev, uint8_t reg, uint16_t val); +}; + +struct mfd_ad559x_config { + struct gpio_dt_spec reset_gpio; +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + struct i2c_dt_spec i2c; +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + struct spi_dt_spec spi; +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ + int (*bus_init)(const struct device *dev); + bool has_pointer_byte_map; +}; + +struct mfd_ad559x_data { + const struct mfd_ad559x_transfer_function *transfer_function; +}; + +int mfd_ad559x_i2c_init(const struct device *dev); +int mfd_ad559x_spi_init(const struct device *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_MFD_AD559X_H_*/ diff --git a/drivers/mfd/mfd_ad559x_i2c.c b/drivers/mfd/mfd_ad559x_i2c.c new file mode 100644 index 0000000000..a18ecbc142 --- /dev/null +++ b/drivers/mfd/mfd_ad559x_i2c.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024, Vitrolife A/S + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include + +#include "mfd_ad559x.h" + +static int mfd_ad559x_i2c_read_raw(const struct device *dev, uint8_t *val, size_t len) +{ + const struct mfd_ad559x_config *config = dev->config; + + return i2c_read_dt(&config->i2c, val, len); +} + +static int mfd_ad559x_i2c_write_raw(const struct device *dev, uint8_t *val, size_t len) +{ + const struct mfd_ad559x_config *config = dev->config; + + return i2c_write_dt(&config->i2c, val, len); +} + +static int mfd_ad559x_i2c_read_reg(const struct device *dev, uint8_t reg, uint8_t reg_data, + uint16_t *val) +{ + const struct mfd_ad559x_config *config = dev->config; + uint8_t buf[sizeof(*val)]; + int ret; + + ARG_UNUSED(reg_data); + + __ASSERT((reg & 0xf0) == 0, "reg bits [7:4] should be 0: 0x%x", reg); + + ret = i2c_write_read_dt(&config->i2c, ®, sizeof(reg), buf, sizeof(buf)); + if (ret < 0) { + return ret; + } + + *val = sys_get_be16(buf); + + return 0; +} + +static int mfd_ad559x_i2c_write_reg(const struct device *dev, uint8_t reg, uint16_t val) +{ + uint8_t buf[sizeof(reg) + sizeof(val)]; + + buf[0] = reg; + sys_put_be16(val, &buf[1]); + + return mfd_ad559x_i2c_write_raw(dev, buf, sizeof(buf)); +} + +static const struct mfd_ad559x_transfer_function mfd_ad559x_i2c_transfer_function = { + .read_raw = mfd_ad559x_i2c_read_raw, + .write_raw = mfd_ad559x_i2c_write_raw, + .read_reg = mfd_ad559x_i2c_read_reg, + .write_reg = mfd_ad559x_i2c_write_reg, +}; + +int mfd_ad559x_i2c_init(const struct device *dev) +{ + const struct mfd_ad559x_config *config = dev->config; + struct mfd_ad559x_data *data = dev->data; + + data->transfer_function = &mfd_ad559x_i2c_transfer_function; + + if (!i2c_is_ready_dt(&config->i2c)) { + return -ENODEV; + } + + return 0; +} diff --git a/drivers/mfd/mfd_ad559x_spi.c b/drivers/mfd/mfd_ad559x_spi.c new file mode 100644 index 0000000000..60b0b58fc6 --- /dev/null +++ b/drivers/mfd/mfd_ad559x_spi.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#include "mfd_ad559x.h" + +static int mfd_ad559x_spi_read_raw(const struct device *dev, uint8_t *val, size_t len) +{ + const struct mfd_ad559x_config *config = dev->config; + uint16_t nop_msg = 0; + + struct spi_buf tx_buf[] = {{.buf = &nop_msg, .len = sizeof(nop_msg)}}; + + const struct spi_buf_set tx = {.buffers = tx_buf, .count = 1}; + + struct spi_buf rx_buf[] = {{.buf = val, .len = len}}; + + const struct spi_buf_set rx = {.buffers = rx_buf, .count = 1}; + + return spi_transceive_dt(&config->spi, &tx, &rx); +} + +static int mfd_ad559x_spi_write_raw(const struct device *dev, uint8_t *val, size_t len) +{ + const struct mfd_ad559x_config *config = dev->config; + + struct spi_buf tx_buf[] = {{.buf = val, .len = len}}; + + const struct spi_buf_set tx = {.buffers = tx_buf, .count = 1}; + + return spi_write_dt(&config->spi, &tx); +} + +static int mfd_ad559x_spi_read_reg(const struct device *dev, uint8_t reg, uint8_t reg_data, + uint16_t *val) +{ + uint16_t data; + uint16_t msg; + int ret; + + switch (reg) { + case AD559X_REG_GPIO_INPUT_EN: + msg = sys_cpu_to_be16(AD559X_GPIO_READBACK_EN | + (AD559X_REG_GPIO_INPUT_EN << AD559X_REG_SHIFT_VAL) | + reg_data); + break; + default: + msg = sys_cpu_to_be16(AD559X_LDAC_READBACK_EN | + (AD559X_REG_READ_AND_LDAC << AD559X_REG_SHIFT_VAL) | + reg << AD559X_REG_READBACK_SHIFT_VAL); + break; + } + + ret = mfd_ad559x_spi_write_raw(dev, (uint8_t *)&msg, sizeof(msg)); + if (ret < 0) { + return ret; + } + + ret = mfd_ad559x_spi_read_raw(dev, (uint8_t *)&data, sizeof(data)); + if (ret < 0) { + return ret; + } + + *val = sys_be16_to_cpu(data); + + return 0; +} + +static int mfd_ad559x_spi_write_reg(const struct device *dev, uint8_t reg, uint16_t val) +{ + uint16_t write_mask; + uint16_t msg; + + switch (reg) { + case AD559X_REG_SOFTWARE_RESET: + write_mask = AD559X_REG_RESET_VAL_MASK; + break; + default: + write_mask = AD559X_REG_VAL_MASK; + break; + } + + msg = sys_cpu_to_be16((reg << AD559X_REG_SHIFT_VAL) | (val & write_mask)); + + return mfd_ad559x_spi_write_raw(dev, (uint8_t *)&msg, sizeof(msg)); +} + +static const struct mfd_ad559x_transfer_function mfd_ad559x_spi_transfer_function = { + .read_raw = mfd_ad559x_spi_read_raw, + .write_raw = mfd_ad559x_spi_write_raw, + .read_reg = mfd_ad559x_spi_read_reg, + .write_reg = mfd_ad559x_spi_write_reg, +}; + +int mfd_ad559x_spi_init(const struct device *dev) +{ + const struct mfd_ad559x_config *config = dev->config; + struct mfd_ad559x_data *data = dev->data; + + data->transfer_function = &mfd_ad559x_spi_transfer_function; + + if (!spi_is_ready_dt(&config->spi)) { + return -ENODEV; + } + + return 0; +} diff --git a/dts/bindings/adc/adi,ad5592-adc.yaml b/dts/bindings/adc/adi,ad559x-adc.yaml similarity index 73% rename from dts/bindings/adc/adi,ad5592-adc.yaml rename to dts/bindings/adc/adi,ad559x-adc.yaml index 2432b55d25..6dc71d8598 100644 --- a/dts/bindings/adc/adi,ad5592-adc.yaml +++ b/dts/bindings/adc/adi,ad559x-adc.yaml @@ -1,9 +1,9 @@ # Copyright (c) 2023 Grinn # SPDX-License-Identifier: Apache-2.0 -description: AD5592 ADC Controller +description: AD559x ADC Controller -compatible: "adi,ad5592-adc" +compatible: "adi,ad559x-adc" include: adc-controller.yaml diff --git a/dts/bindings/dac/adi,ad5592-dac.yaml b/dts/bindings/dac/adi,ad559x-dac.yaml similarity index 73% rename from dts/bindings/dac/adi,ad5592-dac.yaml rename to dts/bindings/dac/adi,ad559x-dac.yaml index 3ac8087b91..43cb0aed29 100644 --- a/dts/bindings/dac/adi,ad5592-dac.yaml +++ b/dts/bindings/dac/adi,ad559x-dac.yaml @@ -1,9 +1,9 @@ # Copyright (c) 2023 Grinn # SPDX-License-Identifier: Apache-2.0 -description: AD5592 DAC Controller +description: AD559x DAC Controller -compatible: "adi,ad5592-dac" +compatible: "adi,ad559x-dac" include: dac-controller.yaml diff --git a/dts/bindings/gpio/adi,ad5592-gpio.yaml b/dts/bindings/gpio/adi,ad559x-gpio.yaml similarity index 66% rename from dts/bindings/gpio/adi,ad5592-gpio.yaml rename to dts/bindings/gpio/adi,ad559x-gpio.yaml index b815f557c5..1588a587bf 100644 --- a/dts/bindings/gpio/adi,ad5592-gpio.yaml +++ b/dts/bindings/gpio/adi,ad559x-gpio.yaml @@ -1,9 +1,9 @@ # Copyright (c) 2023 Grinn # SPDX-License-Identifier: Apache-2.0 -description: AD5592 GPIO Controller +description: AD559x GPIO Controller -compatible: "adi,ad5592-gpio" +compatible: "adi,ad559x-gpio" include: gpio-controller.yaml diff --git a/dts/bindings/mfd/adi,ad5592.yaml b/dts/bindings/mfd/adi,ad559x-common.yaml similarity index 59% rename from dts/bindings/mfd/adi,ad5592.yaml rename to dts/bindings/mfd/adi,ad559x-common.yaml index d3e404ec14..0d41a6fefb 100644 --- a/dts/bindings/mfd/adi,ad5592.yaml +++ b/dts/bindings/mfd/adi,ad559x-common.yaml @@ -1,11 +1,7 @@ # Copyright (C) 2023 Grinn # SPDX-License-Identifier: Apache-2.0 -description: Analog AD5592 ADC/DAC/GPIO chip - -compatible: "adi,ad5592" - -include: spi-device.yaml +description: Analog AD559x ADC/DAC/GPIO chip common properties properties: reset-gpios: diff --git a/dts/bindings/mfd/adi,ad559x-i2c.yaml b/dts/bindings/mfd/adi,ad559x-i2c.yaml new file mode 100644 index 0000000000..0a43eac86b --- /dev/null +++ b/dts/bindings/mfd/adi,ad559x-i2c.yaml @@ -0,0 +1,8 @@ +# Copyright (C) 2024, Vitrolife A/S +# SPDX-License-Identifier: Apache-2.0 + +description: Analog AD559X ADC/DAC/GPIO chip via I2C bus + +compatible: "adi,ad559x" + +include: [i2c-device.yaml, "adi,ad559x-common.yaml"] diff --git a/dts/bindings/mfd/adi,ad559x-spi.yaml b/dts/bindings/mfd/adi,ad559x-spi.yaml new file mode 100644 index 0000000000..bc6ee3cec9 --- /dev/null +++ b/dts/bindings/mfd/adi,ad559x-spi.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024, Vitrolife A/S +# SPDX-License-Identifier: Apache-2.0 + +description: Analog AD559X ADC/DAC/GPIO chip via SPI bus + +compatible: "adi,ad559x" + +include: [spi-device.yaml, "adi,ad559x-common.yaml"] diff --git a/include/zephyr/drivers/mfd/ad5592.h b/include/zephyr/drivers/mfd/ad5592.h deleted file mode 100644 index 014ccdd02b..0000000000 --- a/include/zephyr/drivers/mfd/ad5592.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2023 Grinn - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_INCLUDE_DRIVERS_MFD_AD5592_H_ -#define ZEPHYR_INCLUDE_DRIVERS_MFD_AD5592_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#define AD5592_REG_SEQ_ADC 0x02U -#define AD5592_REG_ADC_CONFIG 0x04U -#define AD5592_REG_LDAC_EN 0x05U -#define AD5592_REG_GPIO_PULLDOWN 0x06U -#define AD5592_REG_READ_AND_LDAC 0x07U -#define AD5592_REG_GPIO_OUTPUT_EN 0x08U -#define AD5592_REG_GPIO_SET 0x09U -#define AD5592_REG_GPIO_INPUT_EN 0x0AU -#define AD5592_REG_PD_REF_CTRL 0x0BU - -#define AD5592_EN_REF BIT(9) - -#define AD5592_PIN_MAX 8U - -/** - * @defgroup mdf_interface_ad5592 MFD AD5592 interface - * @ingroup mfd_interfaces - * @{ - */ - -/** - * @brief Read raw data from the chip - * - * @param[in] dev Pointer to MFD device - * @param[in] val Pointer to data buffer - * - * @retval 0 if success - * @retval negative errno if failure - */ -int mfd_ad5592_read_raw(const struct device *dev, uint16_t *val); - -/** - * @brief Write raw data to chip - * - * @param[in] dev Pointer to MFD device - * @param[in] val Data to be written - * - * - * @retval 0 if success - * @retval negative errno if failure - */ -int mfd_ad5592_write_raw(const struct device *dev, uint16_t val); - -/** - * @brief Read data from provided register - * - * @param[in] dev Pointer to MFD device - * @param[in] reg Register to be read - * @param[in] reg_data Additional data passed to selected register - * @param[in] val Pointer to data buffer - * - * @retval 0 if success - * @retval negative errno if failure - */ -int mfd_ad5592_read_reg(const struct device *dev, uint8_t reg, uint8_t reg_data, uint16_t *val); - -/** - * @brief Write data to provided register - * - * @param[in] dev Pointer to MFD device - * @param[in] reg Register to be written - * @param[in] val Data to be written - * - * @retval 0 if success - * @retval negative errno if failure - */ -int mfd_ad5592_write_reg(const struct device *dev, uint8_t reg, uint16_t val); - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* ZEPHYR_INCLUDE_DRIVERS_MFD_AD5952_H_ */ diff --git a/include/zephyr/drivers/mfd/ad559x.h b/include/zephyr/drivers/mfd/ad559x.h new file mode 100644 index 0000000000..095cdd3e62 --- /dev/null +++ b/include/zephyr/drivers/mfd/ad559x.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2023 Grinn + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_MFD_AD559X_H_ +#define ZEPHYR_INCLUDE_DRIVERS_MFD_AD559X_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define AD559X_REG_SEQ_ADC 0x02U +#define AD559X_REG_ADC_CONFIG 0x04U +#define AD559X_REG_LDAC_EN 0x05U +#define AD559X_REG_GPIO_PULLDOWN 0x06U +#define AD559X_REG_READ_AND_LDAC 0x07U +#define AD559X_REG_GPIO_OUTPUT_EN 0x08U +#define AD559X_REG_GPIO_SET 0x09U +#define AD559X_REG_GPIO_INPUT_EN 0x0AU +#define AD559X_REG_PD_REF_CTRL 0x0BU + +#define AD559X_EN_REF BIT(9) + +#define AD559X_PIN_MAX 8U + +/** + * @defgroup mdf_interface_ad559x MFD AD559X interface + * @ingroup mfd_interfaces + * @{ + */ + +/** + * @brief Check if the chip has a pointer byte map + * + * @param[in] dev Pointer to MFD device + * + * @retval true if chip has a pointer byte map, false if it has normal register map + */ +bool mfd_ad559x_has_pointer_byte_map(const struct device *dev); + +/** + * @brief Read raw data from the chip + * + * @param[in] dev Pointer to MFD device + * @param[in] val Pointer to data buffer + * @param[in] len Number of bytes to be read + * + * @retval 0 if success + * @retval negative errno if failure + */ +int mfd_ad559x_read_raw(const struct device *dev, uint8_t *val, size_t len); + +/** + * @brief Write raw data to chip + * + * @param[in] dev Pointer to MFD device + * @param[in] val Data to be written + * @param[in] len Number of bytes to be written + * + * @retval 0 if success + * @retval negative errno if failure + */ +int mfd_ad559x_write_raw(const struct device *dev, uint8_t *val, size_t len); + +/** + * @brief Read data from provided register + * + * @param[in] dev Pointer to MFD device + * @param[in] reg Register to be read + * @param[in] reg_data Additional data passed to selected register + * @param[in] val Pointer to data buffer + * + * @retval 0 if success + * @retval negative errno if failure + */ +int mfd_ad559x_read_reg(const struct device *dev, uint8_t reg, uint8_t reg_data, uint16_t *val); + +/** + * @brief Write data to provided register + * + * @param[in] dev Pointer to MFD device + * @param[in] reg Register to be written + * @param[in] val Data to be written + * + * @retval 0 if success + * @retval negative errno if failure + */ +int mfd_ad559x_write_reg(const struct device *dev, uint8_t reg, uint16_t val); + +/** + * @brief Read ADC channel data from the chip + * + * @param[in] dev Pointer to MFD device + * @param[in] channel Channel to read + * @param[out] result ADC channel value read + * + * @retval 0 if success + * @retval negative errno if failure + */ +int mfd_ad559x_read_adc_chan(const struct device *dev, uint8_t channel, uint16_t *result); + +/** + * @brief Write ADC channel data to the chip + * + * @param[in] dev Pointer to MFD device + * @param[in] channel Channel to write to + * @param[in] value DAC channel value + * + * @retval 0 if success + * @retval negative errno if failure + */ +int mfd_ad559x_write_dac_chan(const struct device *dev, uint8_t channel, uint16_t value); + +/** + * @brief Read GPIO port from the chip + * + * @param[in] dev Pointer to MFD device + * @param[in] gpio GPIO to read + * @param[in] value DAC channel value + * + * @retval 0 if success + * @retval negative errno if failure + */ +int mfd_ad559x_gpio_port_get_raw(const struct device *dev, uint8_t gpio, uint16_t *value); +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_MFD_AD559X_H_ */ diff --git a/tests/drivers/build_all/adc/boards/native_sim.overlay b/tests/drivers/build_all/adc/boards/native_sim.overlay index ff4f0702b6..e06e950486 100644 --- a/tests/drivers/build_all/adc/boards/native_sim.overlay +++ b/tests/drivers/build_all/adc/boards/native_sim.overlay @@ -315,15 +315,15 @@ #io-channel-cells = <1>; }; - test_spi_ad5592: ad5592@16 { - compatible = "adi,ad5592"; + test_spi_ad559x: ad559x@16 { + compatible = "adi,ad559x"; status = "okay"; reg = <0x16>; spi-max-frequency = <0>; reset-gpios = <&test_gpio 0 0>; - ad5592_adc: adc-controller { - compatible = "adi,ad5592-adc"; + ad559x_adc: adc-controller { + compatible = "adi,ad559x-adc"; #io-channel-cells = <1>; }; }; diff --git a/tests/drivers/build_all/dac/app.overlay b/tests/drivers/build_all/dac/app.overlay index 9767e3b961..df5cf7a40a 100644 --- a/tests/drivers/build_all/dac/app.overlay +++ b/tests/drivers/build_all/dac/app.overlay @@ -235,15 +235,15 @@ reset-gpios = <&test_gpio 0 0>; }; - test_spi_ad5592: ad5592@10 { - compatible = "adi,ad5592"; + test_spi_ad559x: ad559x@10 { + compatible = "adi,ad559x"; status = "okay"; reg = <0x10>; spi-max-frequency = <0>; reset-gpios = <&test_gpio 0 0>; - ad5592_dac: dac-controller { - compatible = "adi,ad5592-dac"; + ad559x_dac: dac-controller { + compatible = "adi,ad559x-dac"; #io-channel-cells = <1>; }; }; diff --git a/tests/drivers/build_all/gpio/app.overlay b/tests/drivers/build_all/gpio/app.overlay index b594214586..73689fb6c9 100644 --- a/tests/drivers/build_all/gpio/app.overlay +++ b/tests/drivers/build_all/gpio/app.overlay @@ -268,15 +268,15 @@ }; }; - test_spi_ad5592: ad5592@3 { - compatible = "adi,ad5592"; + test_spi_ad559x: ad559x@3 { + compatible = "adi,ad559x"; status = "okay"; reg = <0x03>; spi-max-frequency = <0>; reset-gpios = <&test_gpio 0 0>; - ad5592_gpio: gpio-controller { - compatible = "adi,ad5592-gpio"; + ad559x_gpio: gpio-controller { + compatible = "adi,ad559x-gpio"; gpio-controller; #gpio-cells = <2>; ngpios = <8>;