drivers: dac: dac_ad569x: Support for AD569x DACs.
Added support for Analog Devices AD5691 / AD5692 / AD5693 DACs. Signed-off-by: Jan Kubiznak <jan.kubiznak@deveritec.com>
This commit is contained in:
parent
65abd2186c
commit
030a8b1830
|
@ -21,4 +21,5 @@ 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_AD559X dac_ad559x.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_DAC_AD56XX dac_ad56xx.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_DAC_AD569X dac_ad569x.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE dac_handlers.c)
|
||||
|
|
|
@ -57,4 +57,6 @@ source "drivers/dac/Kconfig.ad56xx"
|
|||
|
||||
source "drivers/dac/Kconfig.ad559x"
|
||||
|
||||
source "drivers/dac/Kconfig.ad569x"
|
||||
|
||||
endif # DAC
|
||||
|
|
10
drivers/dac/Kconfig.ad569x
Normal file
10
drivers/dac/Kconfig.ad569x
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Copyright (c) 2024 Jan Kubiznak <jan.kubiznak@deveritec.com>
|
||||
# SPDX -License-Identifier: Apache-2.0
|
||||
|
||||
config DAC_AD569X
|
||||
bool "Analog Devices AD5691 / AD5692 / AD5693 DAC driver"
|
||||
default y
|
||||
select I2C
|
||||
depends on DT_HAS_ADI_AD5691_ENABLED || DT_HAS_ADI_AD5692_ENABLED || DT_HAS_ADI_AD5693_ENABLED
|
||||
help
|
||||
Enable the driver for the Analog Devices AD569X.
|
192
drivers/dac/dac_ad569x.c
Normal file
192
drivers/dac/dac_ad569x.c
Normal file
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Jan Kubiznak <jan.kubiznak@deveritec.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/drivers/dac.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
|
||||
LOG_MODULE_REGISTER(dac_ad569x, CONFIG_DAC_LOG_LEVEL);
|
||||
|
||||
#define AD569X_CTRL_GAIN(x) FIELD_PREP(BIT(11), x)
|
||||
#define AD569X_CTRL_REF(x) FIELD_PREP(BIT(12), x)
|
||||
#define AD569X_CTRL_PD(x) FIELD_PREP(BIT_MASK(2) << 13, x)
|
||||
#define AD569X_CTRL_RESET(x) FIELD_PREP(BIT(15), x)
|
||||
|
||||
#define AD569X_CMD_WRITE 0x10
|
||||
#define AD569X_CMD_UPDATE 0x20
|
||||
#define AD569X_CMD_WRITE_AND_UPDATE 0x30
|
||||
#define AD569X_CMD_CONFIGURE 0x40
|
||||
|
||||
#define AD569X_CTRL_NO_RESET 0x00
|
||||
#define AD569X_CTRL_PERFORM_RESET 0x01
|
||||
|
||||
struct ad569x_config {
|
||||
struct i2c_dt_spec bus;
|
||||
uint8_t resolution;
|
||||
uint8_t gain;
|
||||
uint8_t voltage_reference;
|
||||
uint8_t power_down_mode;
|
||||
};
|
||||
|
||||
static int ad569x_write(const struct device *dev, uint8_t command, uint16_t value)
|
||||
{
|
||||
const struct ad569x_config *config = dev->config;
|
||||
|
||||
uint8_t tx_data[3];
|
||||
|
||||
tx_data[0] = command;
|
||||
sys_put_be16(value, tx_data + 1);
|
||||
|
||||
return i2c_write_dt(&config->bus, tx_data, sizeof(tx_data));
|
||||
}
|
||||
|
||||
static int ad569x_read(const struct device *dev, uint16_t *value)
|
||||
{
|
||||
const struct ad569x_config *config = dev->config;
|
||||
|
||||
uint8_t rx_data[2];
|
||||
int ret;
|
||||
|
||||
ret = i2c_read_dt(&config->bus, rx_data, sizeof(rx_data));
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
*value = sys_get_be16(rx_data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad569x_channel_setup(const struct device *dev, const struct dac_channel_cfg *channel_cfg)
|
||||
{
|
||||
const struct ad569x_config *config = dev->config;
|
||||
|
||||
if (channel_cfg->channel_id > 0) {
|
||||
LOG_ERR("invalid channel %d", channel_cfg->channel_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (channel_cfg->resolution != config->resolution) {
|
||||
LOG_ERR("invalid resolution %d", channel_cfg->resolution);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad569x_sw_reset(const struct device *dev)
|
||||
{
|
||||
uint16_t reg = AD569X_CTRL_RESET(AD569X_CTRL_PERFORM_RESET);
|
||||
int ret;
|
||||
|
||||
LOG_DBG("reset %s", dev->name);
|
||||
|
||||
/* Ignore return value, since device gives NAK after receiving RESET request */
|
||||
ad569x_write(dev, AD569X_CMD_CONFIGURE, reg);
|
||||
|
||||
/* Check that DAC output is reset */
|
||||
ret = ad569x_read(dev, ®);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("failed to read value");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (reg != 0) {
|
||||
LOG_ERR("failed to reset DAC output");
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad569x_write_value(const struct device *dev, uint8_t channel, uint32_t value)
|
||||
{
|
||||
const struct ad569x_config *config = dev->config;
|
||||
|
||||
if (channel > 0) {
|
||||
LOG_ERR("invalid channel %d", channel);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (value > (BIT(config->resolution) - 1)) {
|
||||
LOG_ERR("invalid value %d", value);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ad569x_write(dev, AD569X_CMD_WRITE_AND_UPDATE, value);
|
||||
}
|
||||
|
||||
static int ad569x_init(const struct device *dev)
|
||||
{
|
||||
const struct ad569x_config *config = dev->config;
|
||||
int ret;
|
||||
|
||||
if (!i2c_is_ready_dt(&config->bus)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = ad569x_sw_reset(dev);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("failed to perform sw reset");
|
||||
return ret;
|
||||
}
|
||||
|
||||
LOG_DBG("configure %s: gain %d, voltage reference %d, power down mode %d", dev->name,
|
||||
config->gain, config->voltage_reference, config->power_down_mode);
|
||||
|
||||
uint16_t ctrl_reg = AD569X_CTRL_GAIN(config->gain) |
|
||||
AD569X_CTRL_REF(config->voltage_reference) |
|
||||
AD569X_CTRL_PD(config->power_down_mode);
|
||||
|
||||
ret = ad569x_write(dev, AD569X_CMD_CONFIGURE, ctrl_reg);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("failed to configure the device");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dac_driver_api ad569x_driver_api = {
|
||||
.channel_setup = ad569x_channel_setup,
|
||||
.write_value = ad569x_write_value,
|
||||
};
|
||||
|
||||
#define INST_DT_AD569X(index, name, res) \
|
||||
static const struct ad569x_config config_##name##_##index = { \
|
||||
.bus = I2C_DT_SPEC_INST_GET(index), \
|
||||
.resolution = res, \
|
||||
.gain = DT_INST_ENUM_IDX(index, gain), \
|
||||
.voltage_reference = DT_INST_ENUM_IDX(index, voltage_reference), \
|
||||
.power_down_mode = DT_INST_ENUM_IDX(index, power_down_mode), \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(index, ad569x_init, NULL, NULL, &config_##name##_##index, \
|
||||
POST_KERNEL, CONFIG_DAC_INIT_PRIORITY, &ad569x_driver_api);
|
||||
|
||||
#define DT_DRV_COMPAT adi_ad5691
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
#define DAC_AD5691_RESOLUTION 12
|
||||
DT_INST_FOREACH_STATUS_OKAY_VARGS(INST_DT_AD569X, DT_DRV_COMPAT, DAC_AD5691_RESOLUTION)
|
||||
#endif
|
||||
#undef DT_DRV_COMPAT
|
||||
|
||||
#define DT_DRV_COMPAT adi_ad5692
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
#define DAC_AD5692_RESOLUTION 14
|
||||
DT_INST_FOREACH_STATUS_OKAY_VARGS(INST_DT_AD569X, DT_DRV_COMPAT, DAC_AD5692_RESOLUTION)
|
||||
#endif
|
||||
#undef DT_DRV_COMPAT
|
||||
|
||||
#define DT_DRV_COMPAT adi_ad5693
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
#define DAC_AD5693_RESOLUTION 16
|
||||
DT_INST_FOREACH_STATUS_OKAY_VARGS(INST_DT_AD569X, DT_DRV_COMPAT, DAC_AD5693_RESOLUTION)
|
||||
#endif
|
||||
#undef DT_DRV_COMPAT
|
8
dts/bindings/dac/adi,ad5691.yaml
Normal file
8
dts/bindings/dac/adi,ad5691.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2024 Jan Kubiznak <jan.kubiznak@deveritec.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Driver for AD5691 (12-bit) DAC.
|
||||
|
||||
compatible: "adi,ad5691"
|
||||
|
||||
include: adi,ad569x-base.yaml
|
8
dts/bindings/dac/adi,ad5692.yaml
Normal file
8
dts/bindings/dac/adi,ad5692.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2024 Jan Kubiznak <jan.kubiznak@deveritec.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Driver for AD5692 (14-bit) DAC.
|
||||
|
||||
compatible: "adi,ad5692"
|
||||
|
||||
include: adi,ad569x-base.yaml
|
8
dts/bindings/dac/adi,ad5693.yaml
Normal file
8
dts/bindings/dac/adi,ad5693.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2024 Jan Kubiznak <jan.kubiznak@deveritec.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Driver for AD5693 (16-bit) DAC.
|
||||
|
||||
compatible: "adi,ad5693"
|
||||
|
||||
include: adi,ad569x-base.yaml
|
61
dts/bindings/dac/adi,ad569x-base.yaml
Normal file
61
dts/bindings/dac/adi,ad569x-base.yaml
Normal file
|
@ -0,0 +1,61 @@
|
|||
# Copyright (c) 2024 Jan Kubiznak <jan.kubiznak@deveritec.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
include: [dac-controller.yaml]
|
||||
|
||||
properties:
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
resolution:
|
||||
type: int
|
||||
required: true
|
||||
description: DAC resolution.
|
||||
|
||||
voltage-reference-mv:
|
||||
type: int
|
||||
required: true
|
||||
description: DAC reference voltage in mV.
|
||||
|
||||
voltage-reference:
|
||||
type: string
|
||||
default: "internal"
|
||||
enum:
|
||||
- "internal"
|
||||
- "external"
|
||||
description: |
|
||||
DAC voltage reference select.
|
||||
- Internal voltage reference - 2.5V (reg: 0).
|
||||
- External voltage reference (reg: 1).
|
||||
The default corresponds to the reset value of the register field.
|
||||
|
||||
gain:
|
||||
type: string
|
||||
default: "gain-1"
|
||||
enum:
|
||||
- "gain-1"
|
||||
- "gain-2"
|
||||
description: |
|
||||
Gain selection bit.
|
||||
- Gain of 1 (reg: 0).
|
||||
- Gain of 2 (reg: 1).
|
||||
The default corresponds to the reset value of the register field.
|
||||
|
||||
power-down-mode:
|
||||
type: string
|
||||
default: "normal"
|
||||
enum:
|
||||
- "normal"
|
||||
- "power-down-1k"
|
||||
- "power-down-100k"
|
||||
- "power-down-3-state"
|
||||
description: |
|
||||
Power-down mode select.
|
||||
- Normal mode (reg: 0).
|
||||
- 1 kOhm output impedance (reg: 1).
|
||||
- 100 kOhm output impedance (reg: 2).
|
||||
- Three-state output impedance (reg: 3).
|
||||
The default corresponds to the reset value of the register field.
|
||||
|
||||
io-channel-cells:
|
||||
- output
|
|
@ -76,6 +76,33 @@
|
|||
voltage-reference = "internal";
|
||||
output-gain = "mul2";
|
||||
};
|
||||
|
||||
test_ad5691: ad5691@4a {
|
||||
status = "okay";
|
||||
compatible = "adi,ad5691";
|
||||
reg = <0x4a>;
|
||||
resolution = <12>;
|
||||
voltage-reference-mv = <2500>;
|
||||
#io-channel-cells = < 1 >;
|
||||
};
|
||||
|
||||
test_ad5692: ad5692@4b {
|
||||
status = "okay";
|
||||
compatible = "adi,ad5692";
|
||||
reg = <0x4b>;
|
||||
resolution = <14>;
|
||||
voltage-reference-mv = <2500>;
|
||||
#io-channel-cells = < 1 >;
|
||||
};
|
||||
|
||||
test_ad5693: ad5693@4c {
|
||||
status = "okay";
|
||||
compatible = "adi,ad5693";
|
||||
reg = <0x4c>;
|
||||
resolution = <16>;
|
||||
voltage-reference-mv = <2500>;
|
||||
#io-channel-cells = < 1 >;
|
||||
};
|
||||
};
|
||||
|
||||
test_spi: spi@33334444 {
|
||||
|
|
Loading…
Reference in a new issue