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 <jeppe.odgaard@prevas.dk>
This commit is contained in:
Jeppe Odgaard 2024-01-24 09:05:09 +01:00 committed by Maureen Helm
parent 2a5dc2a0df
commit 17b1912bc3
39 changed files with 1226 additions and 936 deletions

View file

@ -167,7 +167,7 @@
/drivers/adc/*ads114s0x* @benediktibk /drivers/adc/*ads114s0x* @benediktibk
/drivers/adc/*max11102_17* @benediktibk /drivers/adc/*max11102_17* @benediktibk
/drivers/adc/*kb1200* @ene-steven /drivers/adc/*kb1200* @ene-steven
/drivers/adc/adc_ad5592.c @bbilas /drivers/adc/adc_ad559x.c @bbilas
/drivers/audio/*nrfx* @anangl /drivers/audio/*nrfx* @anangl
/drivers/auxdisplay/*pt6314* @xingrz /drivers/auxdisplay/*pt6314* @xingrz
/drivers/auxdisplay/* @thedjnK /drivers/auxdisplay/* @thedjnK
@ -192,7 +192,7 @@
/drivers/display/*rm68200* @mmahadevan108 /drivers/display/*rm68200* @mmahadevan108
/drivers/display/display_ili9342c.* @extremegtx /drivers/display/display_ili9342c.* @extremegtx
/drivers/dac/*ad56xx* @benediktibk /drivers/dac/*ad56xx* @benediktibk
/drivers/dac/dac_ad5592.c @bbilas /drivers/dac/dac_ad559x.c @bbilas
/drivers/dai/ @kv2019i @marcinszkudlinski @abonislawski /drivers/dai/ @kv2019i @marcinszkudlinski @abonislawski
/drivers/dai/intel/ @kv2019i @marcinszkudlinski @abonislawski /drivers/dai/intel/ @kv2019i @marcinszkudlinski @abonislawski
/drivers/dai/intel/ssp/ @kv2019i @marcinszkudlinski @abonislawski /drivers/dai/intel/ssp/ @kv2019i @marcinszkudlinski @abonislawski
@ -244,7 +244,7 @@
/drivers/gpio/*pcal64xxa* @benediktibk /drivers/gpio/*pcal64xxa* @benediktibk
/drivers/gpio/*kb1200* @ene-steven /drivers/gpio/*kb1200* @ene-steven
/drivers/gpio/gpio_altera_pio.c @shilinte /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_common.c @sjg20
/drivers/i2c/i2c_emul.c @sjg20 /drivers/i2c/i2c_emul.c @sjg20
/drivers/i2c/i2c_ite_enhance.c @GTLin08 /drivers/i2c/i2c_ite_enhance.c @GTLin08
@ -284,7 +284,7 @@
/drivers/kscan/*ft5336* @MaureenHelm /drivers/kscan/*ft5336* @MaureenHelm
/drivers/kscan/*ht16k33* @henrikbrixandersen /drivers/kscan/*ht16k33* @henrikbrixandersen
/drivers/led_strip/ @mbolivar-ampere /drivers/led_strip/ @mbolivar-ampere
/drivers/mfd/mfd_ad5592.c @bbilas /drivers/mfd/mfd_ad559x.c @bbilas
/drivers/mfd/mfd_max20335.c @bbilas /drivers/mfd/mfd_max20335.c @bbilas
/drivers/misc/ft8xx/ @hubertmis /drivers/misc/ft8xx/ @hubertmis
/drivers/modem/hl7800.c @rerickson1 /drivers/modem/hl7800.c @rerickson1

View file

@ -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_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_MAX1125X adc_max1125x.c)
zephyr_library_sources_ifdef(CONFIG_ADC_MAX11102_17 adc_max11102_17.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_LTC2451 adc_ltc2451.c)
zephyr_library_sources_ifdef(CONFIG_ADC_NUMAKER adc_numaker.c) zephyr_library_sources_ifdef(CONFIG_ADC_NUMAKER adc_numaker.c)
zephyr_library_sources_ifdef(CONFIG_ADC_ENE_KB1200 adc_ene_kb1200.c) zephyr_library_sources_ifdef(CONFIG_ADC_ENE_KB1200 adc_ene_kb1200.c)

View file

@ -120,7 +120,7 @@ source "drivers/adc/Kconfig.max1125x"
source "drivers/adc/Kconfig.max11102_17" source "drivers/adc/Kconfig.max11102_17"
source "drivers/adc/Kconfig.ad5592" source "drivers/adc/Kconfig.ad559x"
source "drivers/adc/Kconfig.ltc2451" source "drivers/adc/Kconfig.ltc2451"

View file

@ -1,25 +1,25 @@
# Copyright (c) 2023 Grinn # Copyright (c) 2023 Grinn
# SPDX -License-Identifier: Apache-2.0 # SPDX -License-Identifier: Apache-2.0
config ADC_AD5592 config ADC_AD559X
bool "AD5592 ADC driver" bool "AD559x ADC driver"
default y default y
depends on DT_HAS_ADI_AD5592_ADC_ENABLED depends on DT_HAS_ADI_AD559X_ADC_ENABLED
select MFD select MFD
help 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" int "Stack size for the ADC data acquisition thread"
depends on ADC_AD5592 depends on ADC_AD559X
default 384 default 384
help help
Size of the stack used for the internal data acquisition Size of the stack used for the internal data acquisition
thread. thread.
config ADC_AD5592_ACQUISITION_THREAD_PRIO config ADC_AD559X_ACQUISITION_THREAD_PRIO
int "Priority for the ADC data acquisition thread" int "Priority for the ADC data acquisition thread"
depends on ADC_AD5592 depends on ADC_AD559X
default 0 default 0
help help
Priority level for the internal ADC data acquisition thread. Priority level for the internal ADC data acquisition thread.

View file

@ -1,255 +0,0 @@
/*
* Copyright (c) 2023 Grinn
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT adi_ad5592_adc
#include <zephyr/drivers/adc.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/drivers/mfd/ad5592.h>
#define ADC_CONTEXT_USES_KERNEL_TIMER
#include "adc_context.h"
#include <zephyr/logging/log.h>
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)

273
drivers/adc/adc_ad559x.c Normal file
View file

@ -0,0 +1,273 @@
/*
* Copyright (c) 2023 Grinn
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT adi_ad559x_adc
#include <zephyr/drivers/adc.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/drivers/mfd/ad559x.h>
#define ADC_CONTEXT_USES_KERNEL_TIMER
#include "adc_context.h"
#include <zephyr/logging/log.h>
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)

View file

@ -75,7 +75,7 @@ static struct adc_hdl {
uint8_t resolution; uint8_t resolution;
} adc_list[] = { } adc_list[] = {
/* zephyr-keep-sorted-start */ /* 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_sam0_adc, ADC_HDL_LIST_ENTRY)
DT_FOREACH_STATUS_OKAY(atmel_sam_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) DT_FOREACH_STATUS_OKAY(atmel_sam_afec, ADC_HDL_LIST_ENTRY)

View file

@ -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_MCP4728 dac_mcp4728.c)
zephyr_library_sources_ifdef(CONFIG_DAC_GD32 dac_gd32.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_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_DAC_AD56XX dac_ad56xx.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE dac_handlers.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE dac_handlers.c)

View file

@ -53,6 +53,6 @@ source "drivers/dac/Kconfig.esp32"
source "drivers/dac/Kconfig.ad56xx" source "drivers/dac/Kconfig.ad56xx"
source "drivers/dac/Kconfig.ad5592" source "drivers/dac/Kconfig.ad559x"
endif # DAC endif # DAC

View file

@ -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.

View file

@ -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.

View file

@ -1,107 +0,0 @@
/*
* Copyright (c) 2023 Grinn
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT adi_ad5592_dac
#include <zephyr/drivers/dac.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/drivers/mfd/ad5592.h>
#include <zephyr/logging/log.h>
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)

110
drivers/dac/dac_ad559x.c Normal file
View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2023 Grinn
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT adi_ad559x_dac
#include <zephyr/drivers/dac.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/drivers/mfd/ad559x.h>
#include <zephyr/logging/log.h>
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)

View file

@ -4,7 +4,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/gpio.h)
zephyr_library() 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_AXP192 gpio_axp192.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_TELINK_B91 gpio_b91.c) zephyr_library_sources_ifdef(CONFIG_GPIO_TELINK_B91 gpio_b91.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_INFINEON_CAT1 gpio_ifx_cat1.c) zephyr_library_sources_ifdef(CONFIG_GPIO_INFINEON_CAT1 gpio_ifx_cat1.c)

View file

@ -87,7 +87,7 @@ config GPIO_ENABLE_DISABLE_INTERRUPT
pending register, etc. The driver must implement it to work. 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" source "drivers/gpio/Kconfig.axp192"

View file

@ -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.

View file

@ -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.

View file

@ -1,227 +0,0 @@
/*
* Copyright (c) 2023 Grinn
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT adi_ad5592_gpio
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/gpio/gpio_utils.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/drivers/mfd/ad5592.h>
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)

236
drivers/gpio/gpio_ad559x.c Normal file
View file

@ -0,0 +1,236 @@
/*
* Copyright (c) 2023 Grinn
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT adi_ad559x_gpio
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/gpio/gpio_utils.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/drivers/mfd/ad559x.h>
#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)

View file

@ -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_NPM1300 mfd_npm1300.c)
zephyr_library_sources_ifdef(CONFIG_MFD_NPM6001 mfd_npm6001.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_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_MFD_MAX31790 mfd_max31790.c)
zephyr_library_sources_ifdef(CONFIG_NXP_LP_FLEXCOMM mfd_nxp_lp_flexcomm.c) zephyr_library_sources_ifdef(CONFIG_NXP_LP_FLEXCOMM mfd_nxp_lp_flexcomm.c)
zephyr_library_sources_ifdef(CONFIG_MFD_BD8LB600FS mfd_bd8lb600fs.c) zephyr_library_sources_ifdef(CONFIG_MFD_BD8LB600FS mfd_bd8lb600fs.c)

View file

@ -18,7 +18,7 @@ config MFD_INIT_PRIORITY
help help
Multi-function devices initialization priority. Multi-function devices initialization priority.
source "drivers/mfd/Kconfig.ad5592" source "drivers/mfd/Kconfig.ad559x"
source "drivers/mfd/Kconfig.axp192" source "drivers/mfd/Kconfig.axp192"
source "drivers/mfd/Kconfig.bd8lb600fs" source "drivers/mfd/Kconfig.bd8lb600fs"
source "drivers/mfd/Kconfig.max20335" source "drivers/mfd/Kconfig.max20335"

View file

@ -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.

View file

@ -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

View file

@ -1,182 +0,0 @@
/*
* Copyright (c) 2023 Grinn
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT adi_ad5592
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/drivers/mfd/ad5592.h>
#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);

110
drivers/mfd/mfd_ad559x.c Normal file
View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2023 Grinn
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT adi_ad559x
#include <zephyr/drivers/gpio.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/drivers/mfd/ad559x.h>
#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);

65
drivers/mfd/mfd_ad559x.h Normal file
View file

@ -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 <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
#include <zephyr/drivers/i2c.h>
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
#include <zephyr/drivers/spi.h>
#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_*/

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2024, Vitrolife A/S
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/device.h>
#include <zephyr/drivers/mfd/ad559x.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/util_macro.h>
#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, &reg, 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;
}

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2023 Grinn
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/device.h>
#include <zephyr/drivers/mfd/ad559x.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/sys/byteorder.h>
#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;
}

View file

@ -1,9 +1,9 @@
# Copyright (c) 2023 Grinn # Copyright (c) 2023 Grinn
# SPDX-License-Identifier: Apache-2.0 # 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 include: adc-controller.yaml

View file

@ -1,9 +1,9 @@
# Copyright (c) 2023 Grinn # Copyright (c) 2023 Grinn
# SPDX-License-Identifier: Apache-2.0 # 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 include: dac-controller.yaml

View file

@ -1,9 +1,9 @@
# Copyright (c) 2023 Grinn # Copyright (c) 2023 Grinn
# SPDX-License-Identifier: Apache-2.0 # 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 include: gpio-controller.yaml

View file

@ -1,11 +1,7 @@
# Copyright (C) 2023 Grinn # Copyright (C) 2023 Grinn
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
description: Analog AD5592 ADC/DAC/GPIO chip description: Analog AD559x ADC/DAC/GPIO chip common properties
compatible: "adi,ad5592"
include: spi-device.yaml
properties: properties:
reset-gpios: reset-gpios:

View file

@ -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"]

View file

@ -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"]

View file

@ -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 <zephyr/device.h>
#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_ */

View file

@ -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 <zephyr/device.h>
#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_ */

View file

@ -315,15 +315,15 @@
#io-channel-cells = <1>; #io-channel-cells = <1>;
}; };
test_spi_ad5592: ad5592@16 { test_spi_ad559x: ad559x@16 {
compatible = "adi,ad5592"; compatible = "adi,ad559x";
status = "okay"; status = "okay";
reg = <0x16>; reg = <0x16>;
spi-max-frequency = <0>; spi-max-frequency = <0>;
reset-gpios = <&test_gpio 0 0>; reset-gpios = <&test_gpio 0 0>;
ad5592_adc: adc-controller { ad559x_adc: adc-controller {
compatible = "adi,ad5592-adc"; compatible = "adi,ad559x-adc";
#io-channel-cells = <1>; #io-channel-cells = <1>;
}; };
}; };

View file

@ -235,15 +235,15 @@
reset-gpios = <&test_gpio 0 0>; reset-gpios = <&test_gpio 0 0>;
}; };
test_spi_ad5592: ad5592@10 { test_spi_ad559x: ad559x@10 {
compatible = "adi,ad5592"; compatible = "adi,ad559x";
status = "okay"; status = "okay";
reg = <0x10>; reg = <0x10>;
spi-max-frequency = <0>; spi-max-frequency = <0>;
reset-gpios = <&test_gpio 0 0>; reset-gpios = <&test_gpio 0 0>;
ad5592_dac: dac-controller { ad559x_dac: dac-controller {
compatible = "adi,ad5592-dac"; compatible = "adi,ad559x-dac";
#io-channel-cells = <1>; #io-channel-cells = <1>;
}; };
}; };

View file

@ -268,15 +268,15 @@
}; };
}; };
test_spi_ad5592: ad5592@3 { test_spi_ad559x: ad559x@3 {
compatible = "adi,ad5592"; compatible = "adi,ad559x";
status = "okay"; status = "okay";
reg = <0x03>; reg = <0x03>;
spi-max-frequency = <0>; spi-max-frequency = <0>;
reset-gpios = <&test_gpio 0 0>; reset-gpios = <&test_gpio 0 0>;
ad5592_gpio: gpio-controller { ad559x_gpio: gpio-controller {
compatible = "adi,ad5592-gpio"; compatible = "adi,ad559x-gpio";
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
ngpios = <8>; ngpios = <8>;