aboutsummaryrefslogtreecommitdiff
path: root/drivers/iio/dac
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/dac')
-rw-r--r--drivers/iio/dac/Kconfig32
-rw-r--r--drivers/iio/dac/Makefile3
-rw-r--r--drivers/iio/dac/ad3552r-common.c249
-rw-r--r--drivers/iio/dac/ad3552r-hs.c529
-rw-r--r--drivers/iio/dac/ad3552r-hs.h19
-rw-r--r--drivers/iio/dac/ad3552r.c557
-rw-r--r--drivers/iio/dac/ad3552r.h228
-rw-r--r--drivers/iio/dac/ad5380.c85
-rw-r--r--drivers/iio/dac/ad5421.c2
-rw-r--r--drivers/iio/dac/ad5446.c77
-rw-r--r--drivers/iio/dac/ad5504.c61
-rw-r--r--drivers/iio/dac/ad5592r-base.c4
-rw-r--r--drivers/iio/dac/ad5592r.c2
-rw-r--r--drivers/iio/dac/ad5593r.c2
-rw-r--r--drivers/iio/dac/ad5624r.h1
-rw-r--r--drivers/iio/dac/ad5624r_spi.c71
-rw-r--r--drivers/iio/dac/ad5686-spi.c2
-rw-r--r--drivers/iio/dac/ad5686.c4
-rw-r--r--drivers/iio/dac/ad5696-i2c.c2
-rw-r--r--drivers/iio/dac/ad5755.c11
-rw-r--r--drivers/iio/dac/ad5761.c109
-rw-r--r--drivers/iio/dac/ad5770r.c44
-rw-r--r--drivers/iio/dac/ad5791.c205
-rw-r--r--drivers/iio/dac/ad8460.c951
-rw-r--r--drivers/iio/dac/ad9739a.c2
-rw-r--r--drivers/iio/dac/adi-axi-dac.c453
-rw-r--r--drivers/iio/dac/dpot-dac.c2
-rw-r--r--drivers/iio/dac/lpc18xx_dac.c6
-rw-r--r--drivers/iio/dac/m62332.c2
-rw-r--r--drivers/iio/dac/max517.c2
-rw-r--r--drivers/iio/dac/stm32-dac-core.c2
-rw-r--r--drivers/iio/dac/stm32-dac.c2
-rw-r--r--drivers/iio/dac/vf610_dac.c2
33 files changed, 2664 insertions, 1059 deletions
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 9f5d5ebb8653..5d01ba4edbf3 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -6,9 +6,28 @@
menu "Digital to analog converters"
+config AD3552R_HS
+ tristate "Analog Devices AD3552R DAC High Speed driver"
+ select AD3552R_LIB
+ select IIO_BACKEND
+ help
+ Say yes here to build support for Analog Devices AD3552R
+ Digital to Analog Converter High Speed driver.
+
+ The driver requires the assistance of an IP core to operate,
+ since data is streamed into target device via DMA, sent over a
+ QSPI + DDR (Double Data Rate) bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad3552r-hs.
+
+config AD3552R_LIB
+ tristate
+
config AD3552R
tristate "Analog Devices AD3552R DAC driver"
depends on SPI_MASTER
+ select AD3552R_LIB
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
@@ -306,6 +325,19 @@ config AD7303
To compile this driver as module choose M here: the module will be called
ad7303.
+config AD8460
+ tristate "Analog Devices AD8460 DAC driver"
+ depends on SPI
+ select REGMAP_SPI
+ select IIO_BUFFER
+ select IIO_BUFFER_DMAENGINE
+ help
+ Say yes here to build support for Analog Devices AD8460 Digital to
+ Analog Converters (DAC).
+
+ To compile this driver as a module choose M here: the module will be called
+ ad8460.
+
config AD8801
tristate "Analog Devices AD8801/AD8803 DAC driver"
depends on SPI_MASTER
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 2cf148f16306..414c152be779 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -4,6 +4,8 @@
#
# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_AD3552R_HS) += ad3552r-hs.o
+obj-$(CONFIG_AD3552R_LIB) += ad3552r-common.o
obj-$(CONFIG_AD3552R) += ad3552r.o
obj-$(CONFIG_AD5360) += ad5360.o
obj-$(CONFIG_AD5380) += ad5380.o
@@ -28,6 +30,7 @@ obj-$(CONFIG_AD5686_SPI) += ad5686-spi.o
obj-$(CONFIG_AD5696_I2C) += ad5696-i2c.o
obj-$(CONFIG_AD7293) += ad7293.o
obj-$(CONFIG_AD7303) += ad7303.o
+obj-$(CONFIG_AD8460) += ad8460.o
obj-$(CONFIG_AD8801) += ad8801.o
obj-$(CONFIG_AD9739A) += ad9739a.o
obj-$(CONFIG_ADI_AXI_DAC) += adi-axi-dac.o
diff --git a/drivers/iio/dac/ad3552r-common.c b/drivers/iio/dac/ad3552r-common.c
new file mode 100644
index 000000000000..0f495df2e5ce
--- /dev/null
+++ b/drivers/iio/dac/ad3552r-common.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (c) 2010-2024 Analog Devices Inc.
+// Copyright (c) 2024 Baylibre, SAS
+
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+
+#include "ad3552r.h"
+
+const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2] = {
+ [AD3552R_CH_OUTPUT_RANGE_0__2P5V] = { 0, 2500 },
+ [AD3552R_CH_OUTPUT_RANGE_0__5V] = { 0, 5000 },
+ [AD3552R_CH_OUTPUT_RANGE_0__10V] = { 0, 10000 },
+ [AD3552R_CH_OUTPUT_RANGE_NEG_5__5V] = { -5000, 5000 },
+ [AD3552R_CH_OUTPUT_RANGE_NEG_10__10V] = { -10000, 10000 }
+};
+EXPORT_SYMBOL_NS_GPL(ad3552r_ch_ranges, "IIO_AD3552R");
+
+const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2] = {
+ [AD3542R_CH_OUTPUT_RANGE_0__2P5V] = { 0, 2500 },
+ [AD3542R_CH_OUTPUT_RANGE_0__3V] = { 0, 3000 },
+ [AD3542R_CH_OUTPUT_RANGE_0__5V] = { 0, 5000 },
+ [AD3542R_CH_OUTPUT_RANGE_0__10V] = { 0, 10000 },
+ [AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = { -2500, 7500 },
+ [AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = { -5000, 5000 }
+};
+EXPORT_SYMBOL_NS_GPL(ad3542r_ch_ranges, "IIO_AD3552R");
+
+/* Gain * AD3552R_GAIN_SCALE */
+static const s32 gains_scaling_table[] = {
+ [AD3552R_CH_GAIN_SCALING_1] = 1000,
+ [AD3552R_CH_GAIN_SCALING_0_5] = 500,
+ [AD3552R_CH_GAIN_SCALING_0_25] = 250,
+ [AD3552R_CH_GAIN_SCALING_0_125] = 125
+};
+
+u16 ad3552r_calc_custom_gain(u8 p, u8 n, s16 goffs)
+{
+ return FIELD_PREP(AD3552R_MASK_CH_RANGE_OVERRIDE, 1) |
+ FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_P, p) |
+ FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_N, n) |
+ FIELD_PREP(AD3552R_MASK_CH_OFFSET_BIT_8, abs(goffs)) |
+ FIELD_PREP(AD3552R_MASK_CH_OFFSET_POLARITY, goffs < 0);
+}
+EXPORT_SYMBOL_NS_GPL(ad3552r_calc_custom_gain, "IIO_AD3552R");
+
+static void ad3552r_get_custom_range(struct ad3552r_ch_data *ch_data,
+ s32 *v_min, s32 *v_max)
+{
+ s64 vref, tmp, common, offset, gn, gp;
+ /*
+ * From datasheet formula (In Volts):
+ * Vmin = 2.5 + [(GainN + Offset / 1024) * 2.5 * Rfb * 1.03]
+ * Vmax = 2.5 - [(GainP + Offset / 1024) * 2.5 * Rfb * 1.03]
+ * Calculus are converted to milivolts
+ */
+ vref = 2500;
+ /* 2.5 * 1.03 * 1000 (To mV) */
+ common = 2575 * ch_data->rfb;
+ offset = ch_data->gain_offset;
+
+ gn = gains_scaling_table[ch_data->n];
+ tmp = (1024 * gn + AD3552R_GAIN_SCALE * offset) * common;
+ tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE);
+ *v_max = vref + tmp;
+
+ gp = gains_scaling_table[ch_data->p];
+ tmp = (1024 * gp - AD3552R_GAIN_SCALE * offset) * common;
+ tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE);
+ *v_min = vref - tmp;
+}
+
+void ad3552r_calc_gain_and_offset(struct ad3552r_ch_data *ch_data,
+ const struct ad3552r_model_data *model_data)
+{
+ s32 idx, v_max, v_min, span, rem;
+ s64 tmp;
+
+ if (ch_data->range_override) {
+ ad3552r_get_custom_range(ch_data, &v_min, &v_max);
+ } else {
+ /* Normal range */
+ idx = ch_data->range;
+ v_min = model_data->ranges_table[idx][0];
+ v_max = model_data->ranges_table[idx][1];
+ }
+
+ /*
+ * From datasheet formula:
+ * Vout = Span * (D / 65536) + Vmin
+ * Converted to scale and offset:
+ * Scale = Span / 65536
+ * Offset = 65536 * Vmin / Span
+ *
+ * Reminders are in micros in order to be printed as
+ * IIO_VAL_INT_PLUS_MICRO
+ */
+ span = v_max - v_min;
+ ch_data->scale_int = div_s64_rem(span, 65536, &rem);
+ /* Do operations in microvolts */
+ ch_data->scale_dec = DIV_ROUND_CLOSEST((s64)rem * 1000000, 65536);
+
+ ch_data->offset_int = div_s64_rem(v_min * 65536, span, &rem);
+ tmp = (s64)rem * 1000000;
+ ch_data->offset_dec = div_s64(tmp, span);
+}
+EXPORT_SYMBOL_NS_GPL(ad3552r_calc_gain_and_offset, "IIO_AD3552R");
+
+int ad3552r_get_ref_voltage(struct device *dev, u32 *val)
+{
+ int voltage;
+ int delta = 100000;
+
+ voltage = devm_regulator_get_enable_read_voltage(dev, "vref");
+ if (voltage < 0 && voltage != -ENODEV)
+ return dev_err_probe(dev, voltage,
+ "Error getting vref voltage\n");
+
+ if (voltage == -ENODEV) {
+ if (device_property_read_bool(dev, "adi,vref-out-en"))
+ *val = AD3552R_INTERNAL_VREF_PIN_2P5V;
+ else
+ *val = AD3552R_INTERNAL_VREF_PIN_FLOATING;
+
+ return 0;
+ }
+
+ if (voltage > 2500000 + delta || voltage < 2500000 - delta) {
+ dev_warn(dev, "vref-supply must be 2.5V");
+ return -EINVAL;
+ }
+
+ *val = AD3552R_EXTERNAL_VREF_PIN_INPUT;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(ad3552r_get_ref_voltage, "IIO_AD3552R");
+
+int ad3552r_get_drive_strength(struct device *dev, u32 *val)
+{
+ int err;
+ u32 drive_strength;
+
+ err = device_property_read_u32(dev, "adi,sdo-drive-strength",
+ &drive_strength);
+ if (err)
+ return err;
+
+ if (drive_strength > 3) {
+ dev_err_probe(dev, -EINVAL,
+ "adi,sdo-drive-strength must be less than 4\n");
+ return -EINVAL;
+ }
+
+ *val = drive_strength;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(ad3552r_get_drive_strength, "IIO_AD3552R");
+
+int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child,
+ u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs)
+{
+ int err;
+ u32 val;
+ struct fwnode_handle *gain_child __free(fwnode_handle) =
+ fwnode_get_named_child_node(child,
+ "custom-output-range-config");
+
+ if (!gain_child)
+ return dev_err_probe(dev, -EINVAL,
+ "custom-output-range-config mandatory\n");
+
+ err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val);
+ if (err)
+ return dev_err_probe(dev, err,
+ "adi,gain-scaling-p mandatory\n");
+ *gs_p = val;
+
+ err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val);
+ if (err)
+ return dev_err_probe(dev, err,
+ "adi,gain-scaling-n property mandatory\n");
+ *gs_n = val;
+
+ err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val);
+ if (err)
+ return dev_err_probe(dev, err,
+ "adi,rfb-ohms mandatory\n");
+ *rfb = val;
+
+ err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val);
+ if (err)
+ return dev_err_probe(dev, err,
+ "adi,gain-offset mandatory\n");
+ *goffs = val;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(ad3552r_get_custom_gain, "IIO_AD3552R");
+
+static int ad3552r_find_range(const struct ad3552r_model_data *model_info,
+ s32 *vals)
+{
+ int i;
+
+ for (i = 0; i < model_info->num_ranges; i++)
+ if (vals[0] == model_info->ranges_table[i][0] * 1000 &&
+ vals[1] == model_info->ranges_table[i][1] * 1000)
+ return i;
+
+ return -EINVAL;
+}
+
+int ad3552r_get_output_range(struct device *dev,
+ const struct ad3552r_model_data *model_info,
+ struct fwnode_handle *child, u32 *val)
+{
+ int ret;
+ s32 vals[2];
+
+ /* This property is optional, so returning -ENOENT if missing */
+ if (!fwnode_property_present(child, "adi,output-range-microvolt"))
+ return -ENOENT;
+
+ ret = fwnode_property_read_u32_array(child,
+ "adi,output-range-microvolt",
+ vals, 2);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "invalid adi,output-range-microvolt\n");
+
+ ret = ad3552r_find_range(model_info, vals);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "invalid adi,output-range-microvolt value\n");
+
+ *val = ret;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(ad3552r_get_output_range, "IIO_AD3552R");
+
+MODULE_DESCRIPTION("ad3552r common functions");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/dac/ad3552r-hs.c b/drivers/iio/dac/ad3552r-hs.c
new file mode 100644
index 000000000000..216c634f3eaf
--- /dev/null
+++ b/drivers/iio/dac/ad3552r-hs.c
@@ -0,0 +1,529 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Analog Devices AD3552R
+ * Digital to Analog converter driver, High Speed version
+ *
+ * Copyright 2024 Analog Devices Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/backend.h>
+#include <linux/iio/buffer.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/units.h>
+
+#include "ad3552r.h"
+#include "ad3552r-hs.h"
+
+struct ad3552r_hs_state {
+ const struct ad3552r_model_data *model_data;
+ struct gpio_desc *reset_gpio;
+ struct device *dev;
+ struct iio_backend *back;
+ bool single_channel;
+ struct ad3552r_ch_data ch_data[AD3552R_MAX_CH];
+ struct ad3552r_hs_platform_data *data;
+};
+
+static int ad3552r_qspi_update_reg_bits(struct ad3552r_hs_state *st,
+ u32 reg, u32 mask, u32 val,
+ size_t xfer_size)
+{
+ u32 rval;
+ int ret;
+
+ ret = st->data->bus_reg_read(st->back, reg, &rval, xfer_size);
+ if (ret)
+ return ret;
+
+ rval = (rval & ~mask) | val;
+
+ return st->data->bus_reg_write(st->back, reg, rval, xfer_size);
+}
+
+static int ad3552r_hs_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct ad3552r_hs_state *st = iio_priv(indio_dev);
+ int ret;
+ int ch = chan->channel;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ /*
+ * Using 4 lanes (QSPI), then using 2 as DDR mode is
+ * considered always on (considering buffering mode always).
+ */
+ *val = DIV_ROUND_CLOSEST(st->data->bus_sample_data_clock_hz *
+ 4 * 2, chan->scan_type.realbits);
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_RAW:
+ ret = st->data->bus_reg_read(st->back,
+ AD3552R_REG_ADDR_CH_DAC_16B(chan->channel),
+ val, 2);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = st->ch_data[ch].scale_int;
+ *val2 = st->ch_data[ch].scale_dec;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = st->ch_data[ch].offset_int;
+ *val2 = st->ch_data[ch].offset_dec;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad3552r_hs_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ad3552r_hs_state *st = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ return st->data->bus_reg_write(st->back,
+ AD3552R_REG_ADDR_CH_DAC_16B(chan->channel),
+ val, 2);
+ }
+ unreachable();
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad3552r_hs_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ad3552r_hs_state *st = iio_priv(indio_dev);
+ struct iio_backend_data_fmt fmt = {
+ .type = IIO_BACKEND_DATA_UNSIGNED
+ };
+ int loop_len, val, ret;
+
+ switch (*indio_dev->active_scan_mask) {
+ case AD3552R_CH0_ACTIVE:
+ st->single_channel = true;
+ loop_len = 2;
+ val = AD3552R_REG_ADDR_CH_DAC_16B(0);
+ break;
+ case AD3552R_CH1_ACTIVE:
+ st->single_channel = true;
+ loop_len = 2;
+ val = AD3552R_REG_ADDR_CH_DAC_16B(1);
+ break;
+ case AD3552R_CH0_ACTIVE | AD3552R_CH1_ACTIVE:
+ st->single_channel = false;
+ loop_len = 4;
+ val = AD3552R_REG_ADDR_CH_DAC_16B(1);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_STREAM_MODE,
+ loop_len, 1);
+ if (ret)
+ return ret;
+
+ /* Inform DAC chip to switch into DDR mode */
+ ret = ad3552r_qspi_update_reg_bits(st,
+ AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+ AD3552R_MASK_SPI_CONFIG_DDR,
+ AD3552R_MASK_SPI_CONFIG_DDR, 1);
+ if (ret)
+ return ret;
+
+ /* Inform DAC IP to go for DDR mode from now on */
+ ret = iio_backend_ddr_enable(st->back);
+ if (ret) {
+ dev_err(st->dev, "could not set DDR mode, not streaming");
+ goto exit_err;
+ }
+
+ ret = iio_backend_data_transfer_addr(st->back, val);
+ if (ret)
+ goto exit_err;
+
+ ret = iio_backend_data_format_set(st->back, 0, &fmt);
+ if (ret)
+ goto exit_err;
+
+ ret = iio_backend_data_stream_enable(st->back);
+ if (ret)
+ goto exit_err;
+
+ return 0;
+
+exit_err:
+ ad3552r_qspi_update_reg_bits(st,
+ AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+ AD3552R_MASK_SPI_CONFIG_DDR,
+ 0, 1);
+
+ iio_backend_ddr_disable(st->back);
+
+ return ret;
+}
+
+static int ad3552r_hs_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ad3552r_hs_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = iio_backend_data_stream_disable(st->back);
+ if (ret)
+ return ret;
+
+ /* Inform DAC to set in SDR mode */
+ ret = ad3552r_qspi_update_reg_bits(st,
+ AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+ AD3552R_MASK_SPI_CONFIG_DDR,
+ 0, 1);
+ if (ret)
+ return ret;
+
+ ret = iio_backend_ddr_disable(st->back);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static inline int ad3552r_hs_set_output_range(struct ad3552r_hs_state *st,
+ int ch, unsigned int mode)
+{
+ int val;
+
+ if (ch == 0)
+ val = FIELD_PREP(AD3552R_MASK_CH0_RANGE, mode);
+ else
+ val = FIELD_PREP(AD3552R_MASK_CH1_RANGE, mode);
+
+ return ad3552r_qspi_update_reg_bits(st,
+ AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE,
+ AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch),
+ val, 1);
+}
+
+static int ad3552r_hs_reset(struct ad3552r_hs_state *st)
+{
+ int ret;
+
+ st->reset_gpio = devm_gpiod_get_optional(st->dev,
+ "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(st->reset_gpio))
+ return PTR_ERR(st->reset_gpio);
+
+ if (st->reset_gpio) {
+ fsleep(10);
+ gpiod_set_value_cansleep(st->reset_gpio, 0);
+ } else {
+ ret = ad3552r_qspi_update_reg_bits(st,
+ AD3552R_REG_ADDR_INTERFACE_CONFIG_A,
+ AD3552R_MASK_SOFTWARE_RESET,
+ AD3552R_MASK_SOFTWARE_RESET, 1);
+ if (ret)
+ return ret;
+ }
+ msleep(100);
+
+ return 0;
+}
+
+static int ad3552r_hs_scratch_pad_test(struct ad3552r_hs_state *st)
+{
+ int ret, val;
+
+ ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_SCRATCH_PAD,
+ AD3552R_SCRATCH_PAD_TEST_VAL1, 1);
+ if (ret)
+ return ret;
+
+ ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_SCRATCH_PAD,
+ &val, 1);
+ if (ret)
+ return ret;
+
+ if (val != AD3552R_SCRATCH_PAD_TEST_VAL1)
+ return dev_err_probe(st->dev, -EIO,
+ "SCRATCH_PAD_TEST mismatch. Expected 0x%x, Read 0x%x\n",
+ AD3552R_SCRATCH_PAD_TEST_VAL1, val);
+
+ ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_SCRATCH_PAD,
+ AD3552R_SCRATCH_PAD_TEST_VAL2, 1);
+ if (ret)
+ return ret;
+
+ ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_SCRATCH_PAD,
+ &val, 1);
+ if (ret)
+ return ret;
+
+ if (val != AD3552R_SCRATCH_PAD_TEST_VAL2)
+ return dev_err_probe(st->dev, -EIO,
+ "SCRATCH_PAD_TEST mismatch. Expected 0x%x, Read 0x%x\n",
+ AD3552R_SCRATCH_PAD_TEST_VAL2, val);
+
+ return 0;
+}
+
+static int ad3552r_hs_setup_custom_gain(struct ad3552r_hs_state *st,
+ int ch, u16 gain, u16 offset)
+{
+ int ret;
+
+ ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_CH_OFFSET(ch),
+ offset, 1);
+ if (ret)
+ return ret;
+
+ return st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_CH_GAIN(ch),
+ gain, 1);
+}
+
+static int ad3552r_hs_setup(struct ad3552r_hs_state *st)
+{
+ u16 id;
+ u16 gain = 0, offset = 0;
+ u32 ch, val, range;
+ int ret;
+
+ ret = ad3552r_hs_reset(st);
+ if (ret)
+ return ret;
+
+ ret = iio_backend_ddr_disable(st->back);
+ if (ret)
+ return ret;
+
+ ret = ad3552r_hs_scratch_pad_test(st);
+ if (ret)
+ return ret;
+
+ ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_PRODUCT_ID_L,
+ &val, 1);
+ if (ret)
+ return ret;
+
+ id = val;
+
+ ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_PRODUCT_ID_H,
+ &val, 1);
+ if (ret)
+ return ret;
+
+ id |= val << 8;
+ if (id != st->model_data->chip_id)
+ dev_info(st->dev, "Chip ID error. Expected 0x%x, Read 0x%x\n",
+ AD3552R_ID, id);
+
+ ret = st->data->bus_reg_write(st->back,
+ AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
+ 0, 1);
+ if (ret)
+ return ret;
+
+ ret = st->data->bus_reg_write(st->back,
+ AD3552R_REG_ADDR_TRANSFER_REGISTER,
+ FIELD_PREP(AD3552R_MASK_MULTI_IO_MODE,
+ AD3552R_QUAD_SPI) |
+ AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE, 1);
+ if (ret)
+ return ret;
+
+ ret = iio_backend_data_source_set(st->back, 0, IIO_BACKEND_EXTERNAL);
+ if (ret)
+ return ret;
+
+ ret = iio_backend_data_source_set(st->back, 1, IIO_BACKEND_EXTERNAL);
+ if (ret)
+ return ret;
+
+ ret = ad3552r_get_ref_voltage(st->dev, &val);
+ if (ret < 0)
+ return ret;
+
+ val = ret;
+
+ ret = ad3552r_qspi_update_reg_bits(st,
+ AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
+ AD3552R_MASK_REFERENCE_VOLTAGE_SEL,
+ val, 1);
+ if (ret)
+ return ret;
+
+ ret = ad3552r_get_drive_strength(st->dev, &val);
+ if (!ret) {
+ ret = ad3552r_qspi_update_reg_bits(st,
+ AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+ AD3552R_MASK_SDO_DRIVE_STRENGTH,
+ val, 1);
+ if (ret)
+ return ret;
+ }
+
+ device_for_each_child_node_scoped(st->dev, child) {
+ ret = fwnode_property_read_u32(child, "reg", &ch);
+ if (ret)
+ return dev_err_probe(st->dev, ret,
+ "reg property missing\n");
+
+ ret = ad3552r_get_output_range(st->dev, st->model_data, child,
+ &range);
+ if (ret && ret != -ENOENT)
+ return ret;
+ if (ret == -ENOENT) {
+ ret = ad3552r_get_custom_gain(st->dev, child,
+ &st->ch_data[ch].p,
+ &st->ch_data[ch].n,
+ &st->ch_data[ch].rfb,
+ &st->ch_data[ch].gain_offset);
+ if (ret)
+ return ret;
+
+ gain = ad3552r_calc_custom_gain(st->ch_data[ch].p,
+ st->ch_data[ch].n,
+ st->ch_data[ch].gain_offset);
+ offset = abs(st->ch_data[ch].gain_offset);
+
+ st->ch_data[ch].range_override = 1;
+
+ ret = ad3552r_hs_setup_custom_gain(st, ch, gain,
+ offset);
+ if (ret)
+ return ret;
+ } else {
+ st->ch_data[ch].range = range;
+
+ ret = ad3552r_hs_set_output_range(st, ch, range);
+ if (ret)
+ return ret;
+ }
+
+ ad3552r_calc_gain_and_offset(&st->ch_data[ch], st->model_data);
+ }
+
+ return 0;
+}
+
+static const struct iio_buffer_setup_ops ad3552r_hs_buffer_setup_ops = {
+ .postenable = ad3552r_hs_buffer_postenable,
+ .predisable = ad3552r_hs_buffer_predisable,
+};
+
+#define AD3552R_CHANNEL(ch) { \
+ .type = IIO_VOLTAGE, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
+ .output = 1, \
+ .indexed = 1, \
+ .channel = (ch), \
+ .scan_index = (ch), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_BE, \
+ } \
+}
+
+static const struct iio_chan_spec ad3552r_hs_channels[] = {
+ AD3552R_CHANNEL(0),
+ AD3552R_CHANNEL(1),
+};
+
+static const struct iio_info ad3552r_hs_info = {
+ .read_raw = &ad3552r_hs_read_raw,
+ .write_raw = &ad3552r_hs_write_raw,
+};
+
+static int ad3552r_hs_probe(struct platform_device *pdev)
+{
+ struct ad3552r_hs_state *st;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ st->dev = &pdev->dev;
+
+ st->data = dev_get_platdata(st->dev);
+ if (!st->data)
+ return dev_err_probe(st->dev, -ENODEV, "No platform data !");
+
+ st->back = devm_iio_backend_get(&pdev->dev, NULL);
+ if (IS_ERR(st->back))
+ return PTR_ERR(st->back);
+
+ ret = devm_iio_backend_enable(&pdev->dev, st->back);
+ if (ret)
+ return ret;
+
+ st->model_data = device_get_match_data(&pdev->dev);
+ if (!st->model_data)
+ return -ENODEV;
+
+ indio_dev->name = "ad3552r";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->setup_ops = &ad3552r_hs_buffer_setup_ops;
+ indio_dev->channels = ad3552r_hs_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad3552r_hs_channels);
+ indio_dev->info = &ad3552r_hs_info;
+
+ ret = devm_iio_backend_request_buffer(&pdev->dev, st->back, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = ad3552r_hs_setup(st);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(&pdev->dev, indio_dev);
+}
+
+static const struct ad3552r_model_data ad3552r_model_data = {
+ .model_name = "ad3552r",
+ .chip_id = AD3552R_ID,
+ .num_hw_channels = 2,
+ .ranges_table = ad3552r_ch_ranges,
+ .num_ranges = ARRAY_SIZE(ad3552r_ch_ranges),
+};
+
+static const struct of_device_id ad3552r_hs_of_id[] = {
+ { .compatible = "adi,ad3552r", .data = &ad3552r_model_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad3552r_hs_of_id);
+
+static struct platform_driver ad3552r_hs_driver = {
+ .driver = {
+ .name = "ad3552r-hs",
+ .of_match_table = ad3552r_hs_of_id,
+ },
+ .probe = ad3552r_hs_probe,
+};
+module_platform_driver(ad3552r_hs_driver);
+
+MODULE_AUTHOR("Dragos Bogdan <[email protected]>");
+MODULE_AUTHOR("Angelo Dureghello <[email protected]>");
+MODULE_DESCRIPTION("AD3552R Driver - High Speed version");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_BACKEND");
+MODULE_IMPORT_NS("IIO_AD3552R");
diff --git a/drivers/iio/dac/ad3552r-hs.h b/drivers/iio/dac/ad3552r-hs.h
new file mode 100644
index 000000000000..724261d38dea
--- /dev/null
+++ b/drivers/iio/dac/ad3552r-hs.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2024 Analog Devices Inc.
+ * Copyright (c) 2024 Baylibre, SAS
+ */
+#ifndef __LINUX_PLATFORM_DATA_AD3552R_HS_H__
+#define __LINUX_PLATFORM_DATA_AD3552R_HS_H__
+
+struct iio_backend;
+
+struct ad3552r_hs_platform_data {
+ int (*bus_reg_read)(struct iio_backend *back, u32 reg, u32 *val,
+ size_t data_size);
+ int (*bus_reg_write)(struct iio_backend *back, u32 reg, u32 val,
+ size_t data_size);
+ u32 bus_sample_data_clock_hz;
+};
+
+#endif /* __LINUX_PLATFORM_DATA_AD3552R_HS_H__ */
diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c
index 7d61b2fe6624..e7206af53af6 100644
--- a/drivers/iio/dac/ad3552r.c
+++ b/drivers/iio/dac/ad3552r.c
@@ -6,271 +6,15 @@
* Copyright 2021 Analog Devices Inc.
*/
#include <linux/unaligned.h>
+#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
-#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
-/* Register addresses */
-/* Primary address space */
-#define AD3552R_REG_ADDR_INTERFACE_CONFIG_A 0x00
-#define AD3552R_MASK_SOFTWARE_RESET (BIT(7) | BIT(0))
-#define AD3552R_MASK_ADDR_ASCENSION BIT(5)
-#define AD3552R_MASK_SDO_ACTIVE BIT(4)
-#define AD3552R_REG_ADDR_INTERFACE_CONFIG_B 0x01
-#define AD3552R_MASK_SINGLE_INST BIT(7)
-#define AD3552R_MASK_SHORT_INSTRUCTION BIT(3)
-#define AD3552R_REG_ADDR_DEVICE_CONFIG 0x02
-#define AD3552R_MASK_DEVICE_STATUS(n) BIT(4 + (n))
-#define AD3552R_MASK_CUSTOM_MODES GENMASK(3, 2)
-#define AD3552R_MASK_OPERATING_MODES GENMASK(1, 0)
-#define AD3552R_REG_ADDR_CHIP_TYPE 0x03
-#define AD3552R_MASK_CLASS GENMASK(7, 0)
-#define AD3552R_REG_ADDR_PRODUCT_ID_L 0x04
-#define AD3552R_REG_ADDR_PRODUCT_ID_H 0x05
-#define AD3552R_REG_ADDR_CHIP_GRADE 0x06
-#define AD3552R_MASK_GRADE GENMASK(7, 4)
-#define AD3552R_MASK_DEVICE_REVISION GENMASK(3, 0)
-#define AD3552R_REG_ADDR_SCRATCH_PAD 0x0A
-#define AD3552R_REG_ADDR_SPI_REVISION 0x0B
-#define AD3552R_REG_ADDR_VENDOR_L 0x0C
-#define AD3552R_REG_ADDR_VENDOR_H 0x0D
-#define AD3552R_REG_ADDR_STREAM_MODE 0x0E
-#define AD3552R_MASK_LENGTH GENMASK(7, 0)
-#define AD3552R_REG_ADDR_TRANSFER_REGISTER 0x0F
-#define AD3552R_MASK_MULTI_IO_MODE GENMASK(7, 6)
-#define AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE BIT(2)
-#define AD3552R_REG_ADDR_INTERFACE_CONFIG_C 0x10
-#define AD3552R_MASK_CRC_ENABLE (GENMASK(7, 6) |\
- GENMASK(1, 0))
-#define AD3552R_MASK_STRICT_REGISTER_ACCESS BIT(5)
-#define AD3552R_REG_ADDR_INTERFACE_STATUS_A 0x11
-#define AD3552R_MASK_INTERFACE_NOT_READY BIT(7)
-#define AD3552R_MASK_CLOCK_COUNTING_ERROR BIT(5)
-#define AD3552R_MASK_INVALID_OR_NO_CRC BIT(3)
-#define AD3552R_MASK_WRITE_TO_READ_ONLY_REGISTER BIT(2)
-#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS BIT(1)
-#define AD3552R_MASK_REGISTER_ADDRESS_INVALID BIT(0)
-#define AD3552R_REG_ADDR_INTERFACE_CONFIG_D 0x14
-#define AD3552R_MASK_ALERT_ENABLE_PULLUP BIT(6)
-#define AD3552R_MASK_MEM_CRC_EN BIT(4)
-#define AD3552R_MASK_SDO_DRIVE_STRENGTH GENMASK(3, 2)
-#define AD3552R_MASK_DUAL_SPI_SYNCHROUNOUS_EN BIT(1)
-#define AD3552R_MASK_SPI_CONFIG_DDR BIT(0)
-#define AD3552R_REG_ADDR_SH_REFERENCE_CONFIG 0x15
-#define AD3552R_MASK_IDUMP_FAST_MODE BIT(6)
-#define AD3552R_MASK_SAMPLE_HOLD_DIFFERENTIAL_USER_EN BIT(5)
-#define AD3552R_MASK_SAMPLE_HOLD_USER_TRIM GENMASK(4, 3)
-#define AD3552R_MASK_SAMPLE_HOLD_USER_ENABLE BIT(2)
-#define AD3552R_MASK_REFERENCE_VOLTAGE_SEL GENMASK(1, 0)
-#define AD3552R_REG_ADDR_ERR_ALARM_MASK 0x16
-#define AD3552R_MASK_REF_RANGE_ALARM BIT(6)
-#define AD3552R_MASK_CLOCK_COUNT_ERR_ALARM BIT(5)
-#define AD3552R_MASK_MEM_CRC_ERR_ALARM BIT(4)
-#define AD3552R_MASK_SPI_CRC_ERR_ALARM BIT(3)
-#define AD3552R_MASK_WRITE_TO_READ_ONLY_ALARM BIT(2)
-#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS_ALARM BIT(1)
-#define AD3552R_MASK_REGISTER_ADDRESS_INVALID_ALARM BIT(0)
-#define AD3552R_REG_ADDR_ERR_STATUS 0x17
-#define AD3552R_MASK_REF_RANGE_ERR_STATUS BIT(6)
-#define AD3552R_MASK_DUAL_SPI_STREAM_EXCEEDS_DAC_ERR_STATUS BIT(5)
-#define AD3552R_MASK_MEM_CRC_ERR_STATUS BIT(4)
-#define AD3552R_MASK_RESET_STATUS BIT(0)
-#define AD3552R_REG_ADDR_POWERDOWN_CONFIG 0x18
-#define AD3552R_MASK_CH_DAC_POWERDOWN(ch) BIT(4 + (ch))
-#define AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch) BIT(ch)
-#define AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE 0x19
-#define AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch) ((ch) ? GENMASK(7, 4) :\
- GENMASK(3, 0))
-#define AD3552R_REG_ADDR_CH_OFFSET(ch) (0x1B + (ch) * 2)
-#define AD3552R_MASK_CH_OFFSET_BITS_0_7 GENMASK(7, 0)
-#define AD3552R_REG_ADDR_CH_GAIN(ch) (0x1C + (ch) * 2)
-#define AD3552R_MASK_CH_RANGE_OVERRIDE BIT(7)
-#define AD3552R_MASK_CH_GAIN_SCALING_N GENMASK(6, 5)
-#define AD3552R_MASK_CH_GAIN_SCALING_P GENMASK(4, 3)
-#define AD3552R_MASK_CH_OFFSET_POLARITY BIT(2)
-#define AD3552R_MASK_CH_OFFSET_BIT_8 BIT(0)
-/*
- * Secondary region
- * For multibyte registers specify the highest address because the access is
- * done in descending order
- */
-#define AD3552R_SECONDARY_REGION_START 0x28
-#define AD3552R_REG_ADDR_HW_LDAC_16B 0x28
-#define AD3552R_REG_ADDR_CH_DAC_16B(ch) (0x2C - (1 - ch) * 2)
-#define AD3552R_REG_ADDR_DAC_PAGE_MASK_16B 0x2E
-#define AD3552R_REG_ADDR_CH_SELECT_16B 0x2F
-#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_16B 0x31
-#define AD3552R_REG_ADDR_SW_LDAC_16B 0x32
-#define AD3552R_REG_ADDR_CH_INPUT_16B(ch) (0x36 - (1 - ch) * 2)
-/* 3 bytes registers */
-#define AD3552R_REG_START_24B 0x37
-#define AD3552R_REG_ADDR_HW_LDAC_24B 0x37
-#define AD3552R_REG_ADDR_CH_DAC_24B(ch) (0x3D - (1 - ch) * 3)
-#define AD3552R_REG_ADDR_DAC_PAGE_MASK_24B 0x40
-#define AD3552R_REG_ADDR_CH_SELECT_24B 0x41
-#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B 0x44
-#define AD3552R_REG_ADDR_SW_LDAC_24B 0x45
-#define AD3552R_REG_ADDR_CH_INPUT_24B(ch) (0x4B - (1 - ch) * 3)
-
-/* Useful defines */
-#define AD3552R_MAX_CH 2
-#define AD3552R_MASK_CH(ch) BIT(ch)
-#define AD3552R_MASK_ALL_CH GENMASK(1, 0)
-#define AD3552R_MAX_REG_SIZE 3
-#define AD3552R_READ_BIT BIT(7)
-#define AD3552R_ADDR_MASK GENMASK(6, 0)
-#define AD3552R_MASK_DAC_12B 0xFFF0
-#define AD3552R_DEFAULT_CONFIG_B_VALUE 0x8
-#define AD3552R_SCRATCH_PAD_TEST_VAL1 0x34
-#define AD3552R_SCRATCH_PAD_TEST_VAL2 0xB2
-#define AD3552R_GAIN_SCALE 1000
-#define AD3552R_LDAC_PULSE_US 100
-
-enum ad3552r_ch_vref_select {
- /* Internal source with Vref I/O floating */
- AD3552R_INTERNAL_VREF_PIN_FLOATING,
- /* Internal source with Vref I/O at 2.5V */
- AD3552R_INTERNAL_VREF_PIN_2P5V,
- /* External source with Vref I/O as input */
- AD3552R_EXTERNAL_VREF_PIN_INPUT
-};
-
-enum ad3552r_id {
- AD3541R_ID = 0x400b,
- AD3542R_ID = 0x4009,
- AD3551R_ID = 0x400a,
- AD3552R_ID = 0x4008,
-};
-
-enum ad3552r_ch_output_range {
- /* Range from 0 V to 2.5 V. Requires Rfb1x connection */
- AD3552R_CH_OUTPUT_RANGE_0__2P5V,
- /* Range from 0 V to 5 V. Requires Rfb1x connection */
- AD3552R_CH_OUTPUT_RANGE_0__5V,
- /* Range from 0 V to 10 V. Requires Rfb2x connection */
- AD3552R_CH_OUTPUT_RANGE_0__10V,
- /* Range from -5 V to 5 V. Requires Rfb2x connection */
- AD3552R_CH_OUTPUT_RANGE_NEG_5__5V,
- /* Range from -10 V to 10 V. Requires Rfb4x connection */
- AD3552R_CH_OUTPUT_RANGE_NEG_10__10V,
-};
-
-static const s32 ad3552r_ch_ranges[][2] = {
- [AD3552R_CH_OUTPUT_RANGE_0__2P5V] = {0, 2500},
- [AD3552R_CH_OUTPUT_RANGE_0__5V] = {0, 5000},
- [AD3552R_CH_OUTPUT_RANGE_0__10V] = {0, 10000},
- [AD3552R_CH_OUTPUT_RANGE_NEG_5__5V] = {-5000, 5000},
- [AD3552R_CH_OUTPUT_RANGE_NEG_10__10V] = {-10000, 10000}
-};
-
-enum ad3542r_ch_output_range {
- /* Range from 0 V to 2.5 V. Requires Rfb1x connection */
- AD3542R_CH_OUTPUT_RANGE_0__2P5V,
- /* Range from 0 V to 3 V. Requires Rfb1x connection */
- AD3542R_CH_OUTPUT_RANGE_0__3V,
- /* Range from 0 V to 5 V. Requires Rfb1x connection */
- AD3542R_CH_OUTPUT_RANGE_0__5V,
- /* Range from 0 V to 10 V. Requires Rfb2x connection */
- AD3542R_CH_OUTPUT_RANGE_0__10V,
- /* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */
- AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V,
- /* Range from -5 V to 5 V. Requires Rfb2x connection */
- AD3542R_CH_OUTPUT_RANGE_NEG_5__5V,
-};
-
-static const s32 ad3542r_ch_ranges[][2] = {
- [AD3542R_CH_OUTPUT_RANGE_0__2P5V] = {0, 2500},
- [AD3542R_CH_OUTPUT_RANGE_0__3V] = {0, 3000},
- [AD3542R_CH_OUTPUT_RANGE_0__5V] = {0, 5000},
- [AD3542R_CH_OUTPUT_RANGE_0__10V] = {0, 10000},
- [AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = {-2500, 7500},
- [AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = {-5000, 5000}
-};
-
-enum ad3552r_ch_gain_scaling {
- /* Gain scaling of 1 */
- AD3552R_CH_GAIN_SCALING_1,
- /* Gain scaling of 0.5 */
- AD3552R_CH_GAIN_SCALING_0_5,
- /* Gain scaling of 0.25 */
- AD3552R_CH_GAIN_SCALING_0_25,
- /* Gain scaling of 0.125 */
- AD3552R_CH_GAIN_SCALING_0_125,
-};
-
-/* Gain * AD3552R_GAIN_SCALE */
-static const s32 gains_scaling_table[] = {
- [AD3552R_CH_GAIN_SCALING_1] = 1000,
- [AD3552R_CH_GAIN_SCALING_0_5] = 500,
- [AD3552R_CH_GAIN_SCALING_0_25] = 250,
- [AD3552R_CH_GAIN_SCALING_0_125] = 125
-};
-
-enum ad3552r_dev_attributes {
- /* - Direct register values */
- /* From 0-3 */
- AD3552R_SDO_DRIVE_STRENGTH,
- /*
- * 0 -> Internal Vref, vref_io pin floating (default)
- * 1 -> Internal Vref, vref_io driven by internal vref
- * 2 or 3 -> External Vref
- */
- AD3552R_VREF_SELECT,
- /* Read registers in ascending order if set. Else descending */
- AD3552R_ADDR_ASCENSION,
-};
-
-enum ad3552r_ch_attributes {
- /* DAC powerdown */
- AD3552R_CH_DAC_POWERDOWN,
- /* DAC amplifier powerdown */
- AD3552R_CH_AMPLIFIER_POWERDOWN,
- /* Select the output range. Select from enum ad3552r_ch_output_range */
- AD3552R_CH_OUTPUT_RANGE_SEL,
- /*
- * Over-rider the range selector in order to manually set the output
- * voltage range
- */
- AD3552R_CH_RANGE_OVERRIDE,
- /* Manually set the offset voltage */
- AD3552R_CH_GAIN_OFFSET,
- /* Sets the polarity of the offset. */
- AD3552R_CH_GAIN_OFFSET_POLARITY,
- /* PDAC gain scaling */
- AD3552R_CH_GAIN_SCALING_P,
- /* NDAC gain scaling */
- AD3552R_CH_GAIN_SCALING_N,
- /* Rfb value */
- AD3552R_CH_RFB,
- /* Channel select. When set allow Input -> DAC and Mask -> DAC */
- AD3552R_CH_SELECT,
-};
-
-struct ad3552r_ch_data {
- s32 scale_int;
- s32 scale_dec;
- s32 offset_int;
- s32 offset_dec;
- s16 gain_offset;
- u16 rfb;
- u8 n;
- u8 p;
- u8 range;
- bool range_override;
-};
-
-struct ad3552r_model_data {
- const char *model_name;
- enum ad3552r_id chip_id;
- unsigned int num_hw_channels;
- const s32 (*ranges_table)[2];
- int num_ranges;
- bool requires_output_range;
-};
+#include "ad3552r.h"
struct ad3552r_desc {
const struct ad3552r_model_data *model_data;
@@ -285,45 +29,6 @@ struct ad3552r_desc {
unsigned int num_ch;
};
-static const u16 addr_mask_map[][2] = {
- [AD3552R_ADDR_ASCENSION] = {
- AD3552R_REG_ADDR_INTERFACE_CONFIG_A,
- AD3552R_MASK_ADDR_ASCENSION
- },
- [AD3552R_SDO_DRIVE_STRENGTH] = {
- AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
- AD3552R_MASK_SDO_DRIVE_STRENGTH
- },
- [AD3552R_VREF_SELECT] = {
- AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
- AD3552R_MASK_REFERENCE_VOLTAGE_SEL
- },
-};
-
-/* 0 -> reg addr, 1->ch0 mask, 2->ch1 mask */
-static const u16 addr_mask_map_ch[][3] = {
- [AD3552R_CH_DAC_POWERDOWN] = {
- AD3552R_REG_ADDR_POWERDOWN_CONFIG,
- AD3552R_MASK_CH_DAC_POWERDOWN(0),
- AD3552R_MASK_CH_DAC_POWERDOWN(1)
- },
- [AD3552R_CH_AMPLIFIER_POWERDOWN] = {
- AD3552R_REG_ADDR_POWERDOWN_CONFIG,
- AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(0),
- AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(1)
- },
- [AD3552R_CH_OUTPUT_RANGE_SEL] = {
- AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE,
- AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0),
- AD3552R_MASK_CH_OUTPUT_RANGE_SEL(1)
- },
- [AD3552R_CH_SELECT] = {
- AD3552R_REG_ADDR_CH_SELECT_16B,
- AD3552R_MASK_CH(0),
- AD3552R_MASK_CH(1)
- }
-};
-
static u8 _ad3552r_reg_len(u8 addr)
{
switch (addr) {
@@ -399,11 +104,6 @@ static int ad3552r_read_reg(struct ad3552r_desc *dac, u8 addr, u16 *val)
return 0;
}
-static u16 ad3552r_field_prep(u16 val, u16 mask)
-{
- return (val << __ffs(mask)) & mask;
-}
-
/* Update field of a register, shift val if needed */
static int ad3552r_update_reg_field(struct ad3552r_desc *dac, u8 addr, u16 mask,
u16 val)
@@ -416,21 +116,11 @@ static int ad3552r_update_reg_field(struct ad3552r_desc *dac, u8 addr, u16 mask,
return ret;
reg &= ~mask;
- reg |= ad3552r_field_prep(val, mask);
+ reg |= val;
return ad3552r_write_reg(dac, addr, reg);
}
-static int ad3552r_set_ch_value(struct ad3552r_desc *dac,
- enum ad3552r_ch_attributes attr,
- u8 ch,
- u16 val)
-{
- /* Update register related to attributes in chip */
- return ad3552r_update_reg_field(dac, addr_mask_map_ch[attr][0],
- addr_mask_map_ch[attr][ch + 1], val);
-}
-
#define AD3552R_CH_DAC(_idx) ((struct iio_chan_spec) { \
.type = IIO_VOLTAGE, \
.output = true, \
@@ -510,8 +200,14 @@ static int ad3552r_write_raw(struct iio_dev *indio_dev,
val);
break;
case IIO_CHAN_INFO_ENABLE:
- err = ad3552r_set_ch_value(dac, AD3552R_CH_DAC_POWERDOWN,
- chan->channel, !val);
+ if (chan->channel == 0)
+ val = FIELD_PREP(AD3552R_MASK_CH_DAC_POWERDOWN(0), !val);
+ else
+ val = FIELD_PREP(AD3552R_MASK_CH_DAC_POWERDOWN(1), !val);
+
+ err = ad3552r_update_reg_field(dac, AD3552R_REG_ADDR_POWERDOWN_CONFIG,
+ AD3552R_MASK_CH_DAC_POWERDOWN(chan->channel),
+ val);
break;
default:
err = -EINVAL;
@@ -715,83 +411,9 @@ static int ad3552r_reset(struct ad3552r_desc *dac)
}
return ad3552r_update_reg_field(dac,
- addr_mask_map[AD3552R_ADDR_ASCENSION][0],
- addr_mask_map[AD3552R_ADDR_ASCENSION][1],
- val);
-}
-
-static void ad3552r_get_custom_range(struct ad3552r_desc *dac, s32 i, s32 *v_min,
- s32 *v_max)
-{
- s64 vref, tmp, common, offset, gn, gp;
- /*
- * From datasheet formula (In Volts):
- * Vmin = 2.5 + [(GainN + Offset / 1024) * 2.5 * Rfb * 1.03]
- * Vmax = 2.5 - [(GainP + Offset / 1024) * 2.5 * Rfb * 1.03]
- * Calculus are converted to milivolts
- */
- vref = 2500;
- /* 2.5 * 1.03 * 1000 (To mV) */
- common = 2575 * dac->ch_data[i].rfb;
- offset = dac->ch_data[i].gain_offset;
-
- gn = gains_scaling_table[dac->ch_data[i].n];
- tmp = (1024 * gn + AD3552R_GAIN_SCALE * offset) * common;
- tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE);
- *v_max = vref + tmp;
-
- gp = gains_scaling_table[dac->ch_data[i].p];
- tmp = (1024 * gp - AD3552R_GAIN_SCALE * offset) * common;
- tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE);
- *v_min = vref - tmp;
-}
-
-static void ad3552r_calc_gain_and_offset(struct ad3552r_desc *dac, s32 ch)
-{
- s32 idx, v_max, v_min, span, rem;
- s64 tmp;
-
- if (dac->ch_data[ch].range_override) {
- ad3552r_get_custom_range(dac, ch, &v_min, &v_max);
- } else {
- /* Normal range */
- idx = dac->ch_data[ch].range;
- v_min = dac->model_data->ranges_table[idx][0];
- v_max = dac->model_data->ranges_table[idx][1];
- }
-
- /*
- * From datasheet formula:
- * Vout = Span * (D / 65536) + Vmin
- * Converted to scale and offset:
- * Scale = Span / 65536
- * Offset = 65536 * Vmin / Span
- *
- * Reminders are in micros in order to be printed as
- * IIO_VAL_INT_PLUS_MICRO
- */
- span = v_max - v_min;
- dac->ch_data[ch].scale_int = div_s64_rem(span, 65536, &rem);
- /* Do operations in microvolts */
- dac->ch_data[ch].scale_dec = DIV_ROUND_CLOSEST((s64)rem * 1000000,
- 65536);
-
- dac->ch_data[ch].offset_int = div_s64_rem(v_min * 65536, span, &rem);
- tmp = (s64)rem * 1000000;
- dac->ch_data[ch].offset_dec = div_s64(tmp, span);
-}
-
-static int ad3552r_find_range(const struct ad3552r_model_data *model_data,
- s32 *vals)
-{
- int i;
-
- for (i = 0; i < model_data->num_ranges; i++)
- if (vals[0] == model_data->ranges_table[i][0] * 1000 &&
- vals[1] == model_data->ranges_table[i][1] * 1000)
- return i;
-
- return -EINVAL;
+ AD3552R_REG_ADDR_INTERFACE_CONFIG_A,
+ AD3552R_MASK_ADDR_ASCENSION,
+ FIELD_PREP(AD3552R_MASK_ADDR_ASCENSION, val));
}
static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac,
@@ -799,57 +421,30 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac,
u32 ch)
{
struct device *dev = &dac->spi->dev;
- u32 val;
int err;
u8 addr;
- u16 reg = 0, offset;
-
- struct fwnode_handle *gain_child __free(fwnode_handle)
- = fwnode_get_named_child_node(child,
- "custom-output-range-config");
- if (!gain_child)
- return dev_err_probe(dev, -EINVAL,
- "mandatory custom-output-range-config property missing\n");
-
- dac->ch_data[ch].range_override = 1;
- reg |= ad3552r_field_prep(1, AD3552R_MASK_CH_RANGE_OVERRIDE);
-
- err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val);
- if (err)
- return dev_err_probe(dev, err,
- "mandatory adi,gain-scaling-p property missing\n");
- reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_P);
- dac->ch_data[ch].p = val;
-
- err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val);
- if (err)
- return dev_err_probe(dev, err,
- "mandatory adi,gain-scaling-n property missing\n");
- reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_N);
- dac->ch_data[ch].n = val;
-
- err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val);
- if (err)
- return dev_err_probe(dev, err,
- "mandatory adi,rfb-ohms property missing\n");
- dac->ch_data[ch].rfb = val;
+ u16 reg;
- err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val);
+ err = ad3552r_get_custom_gain(dev, child,
+ &dac->ch_data[ch].p,
+ &dac->ch_data[ch].n,
+ &dac->ch_data[ch].rfb,
+ &dac->ch_data[ch].gain_offset);
if (err)
- return dev_err_probe(dev, err,
- "mandatory adi,gain-offset property missing\n");
- dac->ch_data[ch].gain_offset = val;
+ return err;
- offset = abs((s32)val);
- reg |= ad3552r_field_prep((offset >> 8), AD3552R_MASK_CH_OFFSET_BIT_8);
+ dac->ch_data[ch].range_override = 1;
- reg |= ad3552r_field_prep((s32)val < 0, AD3552R_MASK_CH_OFFSET_POLARITY);
addr = AD3552R_REG_ADDR_CH_GAIN(ch);
err = ad3552r_write_reg(dac, addr,
- offset & AD3552R_MASK_CH_OFFSET_BITS_0_7);
+ abs((s32)dac->ch_data[ch].gain_offset) &
+ AD3552R_MASK_CH_OFFSET_BITS_0_7);
if (err)
return dev_err_probe(dev, err, "Error writing register\n");
+ reg = ad3552r_calc_custom_gain(dac->ch_data[ch].p, dac->ch_data[ch].n,
+ dac->ch_data[ch].gain_offset);
+
err = ad3552r_write_reg(dac, addr, reg);
if (err)
return dev_err_probe(dev, err, "Error writing register\n");
@@ -860,49 +455,31 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac,
static int ad3552r_configure_device(struct ad3552r_desc *dac)
{
struct device *dev = &dac->spi->dev;
- int err, cnt = 0, voltage, delta = 100000;
- u32 vals[2], val, ch;
+ int err, cnt = 0;
+ u32 val, ch;
dac->gpio_ldac = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_HIGH);
if (IS_ERR(dac->gpio_ldac))
return dev_err_probe(dev, PTR_ERR(dac->gpio_ldac),
"Error getting gpio ldac");
- voltage = devm_regulator_get_enable_read_voltage(dev, "vref");
- if (voltage < 0 && voltage != -ENODEV)
- return dev_err_probe(dev, voltage, "Error getting vref voltage\n");
-
- if (voltage == -ENODEV) {
- if (device_property_read_bool(dev, "adi,vref-out-en"))
- val = AD3552R_INTERNAL_VREF_PIN_2P5V;
- else
- val = AD3552R_INTERNAL_VREF_PIN_FLOATING;
- } else {
- if (voltage > 2500000 + delta || voltage < 2500000 - delta) {
- dev_warn(dev, "vref-supply must be 2.5V");
- return -EINVAL;
- }
- val = AD3552R_EXTERNAL_VREF_PIN_INPUT;
- }
+ err = ad3552r_get_ref_voltage(dev, &val);
+ if (err < 0)
+ return err;
err = ad3552r_update_reg_field(dac,
- addr_mask_map[AD3552R_VREF_SELECT][0],
- addr_mask_map[AD3552R_VREF_SELECT][1],
- val);
+ AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
+ AD3552R_MASK_REFERENCE_VOLTAGE_SEL,
+ FIELD_PREP(AD3552R_MASK_REFERENCE_VOLTAGE_SEL, val));
if (err)
return err;
- err = device_property_read_u32(dev, "adi,sdo-drive-strength", &val);
+ err = ad3552r_get_drive_strength(dev, &val);
if (!err) {
- if (val > 3) {
- dev_err(dev, "adi,sdo-drive-strength must be less than 4\n");
- return -EINVAL;
- }
-
err = ad3552r_update_reg_field(dac,
- addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][0],
- addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][1],
- val);
+ AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+ AD3552R_MASK_SDO_DRIVE_STRENGTH,
+ FIELD_PREP(AD3552R_MASK_SDO_DRIVE_STRENGTH, val));
if (err)
return err;
}
@@ -923,24 +500,21 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
"reg must be less than %d\n",
dac->model_data->num_hw_channels);
- if (fwnode_property_present(child, "adi,output-range-microvolt")) {
- err = fwnode_property_read_u32_array(child,
- "adi,output-range-microvolt",
- vals,
- 2);
- if (err)
- return dev_err_probe(dev, err,
- "adi,output-range-microvolt property could not be parsed\n");
-
- err = ad3552r_find_range(dac->model_data, vals);
- if (err < 0)
- return dev_err_probe(dev, err,
- "Invalid adi,output-range-microvolt value\n");
-
- val = err;
- err = ad3552r_set_ch_value(dac,
- AD3552R_CH_OUTPUT_RANGE_SEL,
- ch, val);
+ err = ad3552r_get_output_range(dev, dac->model_data,
+ child, &val);
+ if (err && err != -ENOENT)
+ return err;
+
+ if (!err) {
+ if (ch == 0)
+ val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0), val);
+ else
+ val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(1), val);
+
+ err = ad3552r_update_reg_field(dac,
+ AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE,
+ AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch),
+ val);
if (err)
return err;
@@ -955,10 +529,17 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
return err;
}
- ad3552r_calc_gain_and_offset(dac, ch);
+ ad3552r_calc_gain_and_offset(&dac->ch_data[ch], dac->model_data);
dac->enabled_ch |= BIT(ch);
- err = ad3552r_set_ch_value(dac, AD3552R_CH_SELECT, ch, 1);
+ if (ch == 0)
+ val = FIELD_PREP(AD3552R_MASK_CH(0), 1);
+ else
+ val = FIELD_PREP(AD3552R_MASK_CH(1), 1);
+
+ err = ad3552r_update_reg_field(dac,
+ AD3552R_REG_ADDR_CH_SELECT_16B,
+ AD3552R_MASK_CH(ch), val);
if (err < 0)
return err;
@@ -970,8 +551,15 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
/* Disable unused channels */
for_each_clear_bit(ch, &dac->enabled_ch,
dac->model_data->num_hw_channels) {
- err = ad3552r_set_ch_value(dac, AD3552R_CH_AMPLIFIER_POWERDOWN,
- ch, 1);
+ if (ch == 0)
+ val = FIELD_PREP(AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(0), 1);
+ else
+ val = FIELD_PREP(AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(1), 1);
+
+ err = ad3552r_update_reg_field(dac,
+ AD3552R_REG_ADDR_POWERDOWN_CONFIG,
+ AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch),
+ val);
if (err)
return err;
}
@@ -1140,3 +728,4 @@ module_spi_driver(ad3552r_driver);
MODULE_AUTHOR("Mihail Chindris <[email protected]>");
MODULE_DESCRIPTION("Analog Device AD3552R DAC");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_AD3552R");
diff --git a/drivers/iio/dac/ad3552r.h b/drivers/iio/dac/ad3552r.h
new file mode 100644
index 000000000000..fd5a3dfd1d1c
--- /dev/null
+++ b/drivers/iio/dac/ad3552r.h
@@ -0,0 +1,228 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * AD3552R Digital <-> Analog converters common header
+ *
+ * Copyright 2021-2024 Analog Devices Inc.
+ * Author: Angelo Dureghello <[email protected]>
+ */
+
+#ifndef __DRIVERS_IIO_DAC_AD3552R_H__
+#define __DRIVERS_IIO_DAC_AD3552R_H__
+
+/* Register addresses */
+/* Primary address space */
+#define AD3552R_REG_ADDR_INTERFACE_CONFIG_A 0x00
+#define AD3552R_MASK_SOFTWARE_RESET (BIT(7) | BIT(0))
+#define AD3552R_MASK_ADDR_ASCENSION BIT(5)
+#define AD3552R_MASK_SDO_ACTIVE BIT(4)
+#define AD3552R_REG_ADDR_INTERFACE_CONFIG_B 0x01
+#define AD3552R_MASK_SINGLE_INST BIT(7)
+#define AD3552R_MASK_SHORT_INSTRUCTION BIT(3)
+#define AD3552R_REG_ADDR_DEVICE_CONFIG 0x02
+#define AD3552R_MASK_DEVICE_STATUS(n) BIT(4 + (n))
+#define AD3552R_MASK_CUSTOM_MODES GENMASK(3, 2)
+#define AD3552R_MASK_OPERATING_MODES GENMASK(1, 0)
+#define AD3552R_REG_ADDR_CHIP_TYPE 0x03
+#define AD3552R_MASK_CLASS GENMASK(7, 0)
+#define AD3552R_REG_ADDR_PRODUCT_ID_L 0x04
+#define AD3552R_REG_ADDR_PRODUCT_ID_H 0x05
+#define AD3552R_REG_ADDR_CHIP_GRADE 0x06
+#define AD3552R_MASK_GRADE GENMASK(7, 4)
+#define AD3552R_MASK_DEVICE_REVISION GENMASK(3, 0)
+#define AD3552R_REG_ADDR_SCRATCH_PAD 0x0A
+#define AD3552R_REG_ADDR_SPI_REVISION 0x0B
+#define AD3552R_REG_ADDR_VENDOR_L 0x0C
+#define AD3552R_REG_ADDR_VENDOR_H 0x0D
+#define AD3552R_REG_ADDR_STREAM_MODE 0x0E
+#define AD3552R_MASK_LENGTH GENMASK(7, 0)
+#define AD3552R_REG_ADDR_TRANSFER_REGISTER 0x0F
+#define AD3552R_MASK_MULTI_IO_MODE GENMASK(7, 6)
+#define AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE BIT(2)
+#define AD3552R_REG_ADDR_INTERFACE_CONFIG_C 0x10
+#define AD3552R_MASK_CRC_ENABLE \
+ (GENMASK(7, 6) | GENMASK(1, 0))
+#define AD3552R_MASK_STRICT_REGISTER_ACCESS BIT(5)
+#define AD3552R_REG_ADDR_INTERFACE_STATUS_A 0x11
+#define AD3552R_MASK_INTERFACE_NOT_READY BIT(7)
+#define AD3552R_MASK_CLOCK_COUNTING_ERROR BIT(5)
+#define AD3552R_MASK_INVALID_OR_NO_CRC BIT(3)
+#define AD3552R_MASK_WRITE_TO_READ_ONLY_REGISTER BIT(2)
+#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS BIT(1)
+#define AD3552R_MASK_REGISTER_ADDRESS_INVALID BIT(0)
+#define AD3552R_REG_ADDR_INTERFACE_CONFIG_D 0x14
+#define AD3552R_MASK_ALERT_ENABLE_PULLUP BIT(6)
+#define AD3552R_MASK_MEM_CRC_EN BIT(4)
+#define AD3552R_MASK_SDO_DRIVE_STRENGTH GENMASK(3, 2)
+#define AD3552R_MASK_DUAL_SPI_SYNCHROUNOUS_EN BIT(1)
+#define AD3552R_MASK_SPI_CONFIG_DDR BIT(0)
+#define AD3552R_REG_ADDR_SH_REFERENCE_CONFIG 0x15
+#define AD3552R_MASK_IDUMP_FAST_MODE BIT(6)
+#define AD3552R_MASK_SAMPLE_HOLD_DIFF_USER_EN BIT(5)
+#define AD3552R_MASK_SAMPLE_HOLD_USER_TRIM GENMASK(4, 3)
+#define AD3552R_MASK_SAMPLE_HOLD_USER_ENABLE BIT(2)
+#define AD3552R_MASK_REFERENCE_VOLTAGE_SEL GENMASK(1, 0)
+#define AD3552R_REG_ADDR_ERR_ALARM_MASK 0x16
+#define AD3552R_MASK_REF_RANGE_ALARM BIT(6)
+#define AD3552R_MASK_CLOCK_COUNT_ERR_ALARM BIT(5)
+#define AD3552R_MASK_MEM_CRC_ERR_ALARM BIT(4)
+#define AD3552R_MASK_SPI_CRC_ERR_ALARM BIT(3)
+#define AD3552R_MASK_WRITE_TO_READ_ONLY_ALARM BIT(2)
+#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS_ALARM BIT(1)
+#define AD3552R_MASK_REGISTER_ADDRESS_INVALID_ALARM BIT(0)
+#define AD3552R_REG_ADDR_ERR_STATUS 0x17
+#define AD3552R_MASK_REF_RANGE_ERR_STATUS BIT(6)
+#define AD3552R_MASK_STREAM_EXCEEDS_DAC_ERR_STATUS BIT(5)
+#define AD3552R_MASK_MEM_CRC_ERR_STATUS BIT(4)
+#define AD3552R_MASK_RESET_STATUS BIT(0)
+#define AD3552R_REG_ADDR_POWERDOWN_CONFIG 0x18
+#define AD3552R_MASK_CH_DAC_POWERDOWN(ch) BIT(4 + (ch))
+#define AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch) BIT(ch)
+#define AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE 0x19
+#define AD3552R_MASK_CH0_RANGE GENMASK(2, 0)
+#define AD3552R_MASK_CH1_RANGE GENMASK(6, 4)
+#define AD3552R_MASK_CH_OUTPUT_RANGE GENMASK(7, 0)
+#define AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch) \
+ ((ch) ? GENMASK(7, 4) : GENMASK(3, 0))
+#define AD3552R_REG_ADDR_CH_OFFSET(ch) (0x1B + (ch) * 2)
+#define AD3552R_MASK_CH_OFFSET_BITS_0_7 GENMASK(7, 0)
+#define AD3552R_REG_ADDR_CH_GAIN(ch) (0x1C + (ch) * 2)
+#define AD3552R_MASK_CH_RANGE_OVERRIDE BIT(7)
+#define AD3552R_MASK_CH_GAIN_SCALING_N GENMASK(6, 5)
+#define AD3552R_MASK_CH_GAIN_SCALING_P GENMASK(4, 3)
+#define AD3552R_MASK_CH_OFFSET_POLARITY BIT(2)
+#define AD3552R_MASK_CH_OFFSET_BIT_8 BIT(8)
+/*
+ * Secondary region
+ * For multibyte registers specify the highest address because the access is
+ * done in descending order
+ */
+#define AD3552R_SECONDARY_REGION_START 0x28
+#define AD3552R_REG_ADDR_HW_LDAC_16B 0x28
+#define AD3552R_REG_ADDR_CH_DAC_16B(ch) (0x2C - (1 - (ch)) * 2)
+#define AD3552R_REG_ADDR_DAC_PAGE_MASK_16B 0x2E
+#define AD3552R_REG_ADDR_CH_SELECT_16B 0x2F
+#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_16B 0x31
+#define AD3552R_REG_ADDR_SW_LDAC_16B 0x32
+#define AD3552R_REG_ADDR_CH_INPUT_16B(ch) (0x36 - (1 - (ch)) * 2)
+/* 3 bytes registers */
+#define AD3552R_REG_START_24B 0x37
+#define AD3552R_REG_ADDR_HW_LDAC_24B 0x37
+#define AD3552R_REG_ADDR_CH_DAC_24B(ch) (0x3D - (1 - (ch)) * 3)
+#define AD3552R_REG_ADDR_DAC_PAGE_MASK_24B 0x40
+#define AD3552R_REG_ADDR_CH_SELECT_24B 0x41
+#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B 0x44
+#define AD3552R_REG_ADDR_SW_LDAC_24B 0x45
+#define AD3552R_REG_ADDR_CH_INPUT_24B(ch) (0x4B - (1 - (ch)) * 3)
+
+#define AD3552R_MAX_CH 2
+#define AD3552R_MASK_CH(ch) BIT(ch)
+#define AD3552R_MASK_ALL_CH GENMASK(1, 0)
+#define AD3552R_MAX_REG_SIZE 3
+#define AD3552R_READ_BIT BIT(7)
+#define AD3552R_ADDR_MASK GENMASK(6, 0)
+#define AD3552R_MASK_DAC_12B GENMASK(15, 4)
+#define AD3552R_DEFAULT_CONFIG_B_VALUE 0x8
+#define AD3552R_SCRATCH_PAD_TEST_VAL1 0x34
+#define AD3552R_SCRATCH_PAD_TEST_VAL2 0xB2
+#define AD3552R_GAIN_SCALE 1000
+#define AD3552R_LDAC_PULSE_US 100
+
+#define AD3552R_CH0_ACTIVE BIT(0)
+#define AD3552R_CH1_ACTIVE BIT(1)
+
+#define AD3552R_MAX_RANGES 5
+#define AD3542R_MAX_RANGES 6
+#define AD3552R_QUAD_SPI 2
+
+extern const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2];
+extern const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2];
+
+enum ad3552r_id {
+ AD3541R_ID = 0x400b,
+ AD3542R_ID = 0x4009,
+ AD3551R_ID = 0x400a,
+ AD3552R_ID = 0x4008,
+};
+
+struct ad3552r_model_data {
+ const char *model_name;
+ enum ad3552r_id chip_id;
+ unsigned int num_hw_channels;
+ const s32 (*ranges_table)[2];
+ int num_ranges;
+ bool requires_output_range;
+};
+
+struct ad3552r_ch_data {
+ s32 scale_int;
+ s32 scale_dec;
+ s32 offset_int;
+ s32 offset_dec;
+ s16 gain_offset;
+ u16 rfb;
+ u8 n;
+ u8 p;
+ u8 range;
+ bool range_override;
+};
+
+enum ad3552r_ch_gain_scaling {
+ /* Gain scaling of 1 */
+ AD3552R_CH_GAIN_SCALING_1,
+ /* Gain scaling of 0.5 */
+ AD3552R_CH_GAIN_SCALING_0_5,
+ /* Gain scaling of 0.25 */
+ AD3552R_CH_GAIN_SCALING_0_25,
+ /* Gain scaling of 0.125 */
+ AD3552R_CH_GAIN_SCALING_0_125,
+};
+
+enum ad3552r_ch_vref_select {
+ /* Internal source with Vref I/O floating */
+ AD3552R_INTERNAL_VREF_PIN_FLOATING,
+ /* Internal source with Vref I/O at 2.5V */
+ AD3552R_INTERNAL_VREF_PIN_2P5V,
+ /* External source with Vref I/O as input */
+ AD3552R_EXTERNAL_VREF_PIN_INPUT
+};
+
+enum ad3542r_ch_output_range {
+ /* Range from 0 V to 2.5 V. Requires Rfb1x connection */
+ AD3542R_CH_OUTPUT_RANGE_0__2P5V,
+ /* Range from 0 V to 3 V. Requires Rfb1x connection */
+ AD3542R_CH_OUTPUT_RANGE_0__3V,
+ /* Range from 0 V to 5 V. Requires Rfb1x connection */
+ AD3542R_CH_OUTPUT_RANGE_0__5V,
+ /* Range from 0 V to 10 V. Requires Rfb2x connection */
+ AD3542R_CH_OUTPUT_RANGE_0__10V,
+ /* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */
+ AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V,
+ /* Range from -5 V to 5 V. Requires Rfb2x connection */
+ AD3542R_CH_OUTPUT_RANGE_NEG_5__5V,
+};
+
+enum ad3552r_ch_output_range {
+ /* Range from 0 V to 2.5 V. Requires Rfb1x connection */
+ AD3552R_CH_OUTPUT_RANGE_0__2P5V,
+ /* Range from 0 V to 5 V. Requires Rfb1x connection */
+ AD3552R_CH_OUTPUT_RANGE_0__5V,
+ /* Range from 0 V to 10 V. Requires Rfb2x connection */
+ AD3552R_CH_OUTPUT_RANGE_0__10V,
+ /* Range from -5 V to 5 V. Requires Rfb2x connection */
+ AD3552R_CH_OUTPUT_RANGE_NEG_5__5V,
+ /* Range from -10 V to 10 V. Requires Rfb4x connection */
+ AD3552R_CH_OUTPUT_RANGE_NEG_10__10V,
+};
+
+int ad3552r_get_output_range(struct device *dev,
+ const struct ad3552r_model_data *model_info,
+ struct fwnode_handle *child, u32 *val);
+int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child,
+ u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs);
+u16 ad3552r_calc_custom_gain(u8 p, u8 n, s16 goffs);
+int ad3552r_get_ref_voltage(struct device *dev, u32 *val);
+int ad3552r_get_drive_strength(struct device *dev, u32 *val);
+void ad3552r_calc_gain_and_offset(struct ad3552r_ch_data *ch_data,
+ const struct ad3552r_model_data *model_data);
+
+#endif /* __DRIVERS_IIO_DAC_AD3552R_H__ */
diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c
index 2e3e33f92bc0..392a1c7aee03 100644
--- a/drivers/iio/dac/ad5380.c
+++ b/drivers/iio/dac/ad5380.c
@@ -47,7 +47,6 @@ struct ad5380_chip_info {
* struct ad5380_state - driver instance specific data
* @regmap: regmap instance used by the device
* @chip_info: chip model specific constants, available modes etc
- * @vref_reg: vref supply regulator
* @vref: actual reference voltage used in uA
* @pwr_down: whether the chip is currently in power down mode
* @lock: lock to protect the data buffer during regmap ops
@@ -55,7 +54,6 @@ struct ad5380_chip_info {
struct ad5380_state {
struct regmap *regmap;
const struct ad5380_chip_info *chip_info;
- struct regulator *vref_reg;
int vref;
bool pwr_down;
struct mutex lock;
@@ -341,14 +339,14 @@ static const struct ad5380_chip_info ad5380_chip_info_tbl[] = {
},
};
-static int ad5380_alloc_channels(struct iio_dev *indio_dev)
+static int ad5380_alloc_channels(struct device *dev, struct iio_dev *indio_dev)
{
struct ad5380_state *st = iio_priv(indio_dev);
struct iio_chan_spec *channels;
unsigned int i;
- channels = kcalloc(st->chip_info->num_channels,
- sizeof(struct iio_chan_spec), GFP_KERNEL);
+ channels = devm_kcalloc(dev, st->chip_info->num_channels,
+ sizeof(struct iio_chan_spec), GFP_KERNEL);
if (!channels)
return -ENOMEM;
@@ -379,7 +377,6 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap,
}
st = iio_priv(indio_dev);
- dev_set_drvdata(dev, indio_dev);
st->chip_info = &ad5380_chip_info_tbl[type];
st->regmap = regmap;
@@ -391,68 +388,32 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap,
mutex_init(&st->lock);
- ret = ad5380_alloc_channels(indio_dev);
- if (ret) {
- dev_err(dev, "Failed to allocate channel spec: %d\n", ret);
- return ret;
- }
+ ret = ad5380_alloc_channels(dev, indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to allocate channel spec\n");
if (st->chip_info->int_vref == 2500)
ctrl |= AD5380_CTRL_INT_VREF_2V5;
- st->vref_reg = devm_regulator_get(dev, "vref");
- if (!IS_ERR(st->vref_reg)) {
- ret = regulator_enable(st->vref_reg);
- if (ret) {
- dev_err(dev, "Failed to enable vref regulators: %d\n",
- ret);
- goto error_free_reg;
- }
-
- ret = regulator_get_voltage(st->vref_reg);
- if (ret < 0)
- goto error_disable_reg;
-
- st->vref = ret / 1000;
- } else {
+ ret = devm_regulator_get_enable_read_voltage(dev, "vref");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "Failed to get vref voltage\n");
+ if (ret == -ENODEV) {
st->vref = st->chip_info->int_vref;
ctrl |= AD5380_CTRL_INT_VREF_EN;
+ } else {
+ st->vref = ret / 1000;
}
ret = regmap_write(st->regmap, AD5380_REG_SF_CTRL, ctrl);
- if (ret) {
- dev_err(dev, "Failed to write to device: %d\n", ret);
- goto error_disable_reg;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to write to device\n");
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(dev, "Failed to register iio device: %d\n", ret);
- goto error_disable_reg;
- }
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register iio device\n");
return 0;
-
-error_disable_reg:
- if (!IS_ERR(st->vref_reg))
- regulator_disable(st->vref_reg);
-error_free_reg:
- kfree(indio_dev->channels);
-
- return ret;
-}
-
-static void ad5380_remove(struct device *dev)
-{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad5380_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
-
- kfree(indio_dev->channels);
-
- if (!IS_ERR(st->vref_reg))
- regulator_disable(st->vref_reg);
}
static bool ad5380_reg_false(struct device *dev, unsigned int reg)
@@ -486,11 +447,6 @@ static int ad5380_spi_probe(struct spi_device *spi)
return ad5380_probe(&spi->dev, regmap, id->driver_data, id->name);
}
-static void ad5380_spi_remove(struct spi_device *spi)
-{
- ad5380_remove(&spi->dev);
-}
-
static const struct spi_device_id ad5380_spi_ids[] = {
{ "ad5380-3", ID_AD5380_3 },
{ "ad5380-5", ID_AD5380_5 },
@@ -517,7 +473,6 @@ static struct spi_driver ad5380_spi_driver = {
.name = "ad5380",
},
.probe = ad5380_spi_probe,
- .remove = ad5380_spi_remove,
.id_table = ad5380_spi_ids,
};
@@ -559,11 +514,6 @@ static int ad5380_i2c_probe(struct i2c_client *i2c)
return ad5380_probe(&i2c->dev, regmap, id->driver_data, id->name);
}
-static void ad5380_i2c_remove(struct i2c_client *i2c)
-{
- ad5380_remove(&i2c->dev);
-}
-
static const struct i2c_device_id ad5380_i2c_ids[] = {
{ "ad5380-3", ID_AD5380_3 },
{ "ad5380-5", ID_AD5380_5 },
@@ -590,7 +540,6 @@ static struct i2c_driver ad5380_i2c_driver = {
.name = "ad5380",
},
.probe = ad5380_i2c_probe,
- .remove = ad5380_i2c_remove,
.id_table = ad5380_i2c_ids,
};
diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c
index 7644acfd879e..1462ee640b16 100644
--- a/drivers/iio/dac/ad5421.c
+++ b/drivers/iio/dac/ad5421.c
@@ -384,7 +384,7 @@ static int ad5421_write_raw(struct iio_dev *indio_dev,
static int ad5421_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
- enum iio_event_direction dir, int state)
+ enum iio_event_direction dir, bool state)
{
struct ad5421_state *st = iio_priv(indio_dev);
unsigned int mask;
diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c
index 708629efc157..6ad99f97eed5 100644
--- a/drivers/iio/dac/ad5446.c
+++ b/drivers/iio/dac/ad5446.c
@@ -32,7 +32,6 @@
* struct ad5446_state - driver instance specific data
* @dev: this device
* @chip_info: chip model specific constants, available modes etc
- * @reg: supply regulator
* @vref_mv: actual reference voltage used
* @cached_val: store/retrieve values during power down
* @pwr_down_mode: power down mode (1k, 100k or tristate)
@@ -43,7 +42,6 @@
struct ad5446_state {
struct device *dev;
const struct ad5446_chip_info *chip_info;
- struct regulator *reg;
unsigned short vref_mv;
unsigned cached_val;
unsigned pwr_down_mode;
@@ -226,32 +224,15 @@ static int ad5446_probe(struct device *dev, const char *name,
{
struct ad5446_state *st;
struct iio_dev *indio_dev;
- struct regulator *reg;
- int ret, voltage_uv = 0;
-
- reg = devm_regulator_get(dev, "vcc");
- if (!IS_ERR(reg)) {
- ret = regulator_enable(reg);
- if (ret)
- return ret;
-
- ret = regulator_get_voltage(reg);
- if (ret < 0)
- goto error_disable_reg;
-
- voltage_uv = ret;
- }
+ int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_disable_reg;
- }
+ if (!indio_dev)
+ return -ENOMEM;
+
st = iio_priv(indio_dev);
st->chip_info = chip_info;
- dev_set_drvdata(dev, indio_dev);
- st->reg = reg;
st->dev = dev;
indio_dev->name = name;
@@ -264,33 +245,19 @@ static int ad5446_probe(struct device *dev, const char *name,
st->pwr_down_mode = MODE_PWRDWN_1k;
- if (st->chip_info->int_vref_mv)
- st->vref_mv = st->chip_info->int_vref_mv;
- else if (voltage_uv)
- st->vref_mv = voltage_uv / 1000;
- else
- dev_warn(dev, "reference voltage unspecified\n");
-
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_disable_reg;
-
- return 0;
-
-error_disable_reg:
- if (!IS_ERR(reg))
- regulator_disable(reg);
- return ret;
-}
-
-static void ad5446_remove(struct device *dev)
-{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad5446_state *st = iio_priv(indio_dev);
+ ret = devm_regulator_get_enable_read_voltage(dev, "vcc");
+ if (ret < 0 && ret != -ENODEV)
+ return ret;
+ if (ret == -ENODEV) {
+ if (chip_info->int_vref_mv)
+ st->vref_mv = chip_info->int_vref_mv;
+ else
+ dev_warn(dev, "reference voltage unspecified\n");
+ } else {
+ st->vref_mv = ret / 1000;
+ }
- iio_device_unregister(indio_dev);
- if (!IS_ERR(st->reg))
- regulator_disable(st->reg);
+ return devm_iio_device_register(dev, indio_dev);
}
#if IS_ENABLED(CONFIG_SPI_MASTER)
@@ -491,18 +458,12 @@ static int ad5446_spi_probe(struct spi_device *spi)
&ad5446_spi_chip_info[id->driver_data]);
}
-static void ad5446_spi_remove(struct spi_device *spi)
-{
- ad5446_remove(&spi->dev);
-}
-
static struct spi_driver ad5446_spi_driver = {
.driver = {
.name = "ad5446",
.of_match_table = ad5446_of_ids,
},
.probe = ad5446_spi_probe,
- .remove = ad5446_spi_remove,
.id_table = ad5446_spi_ids,
};
@@ -575,11 +536,6 @@ static int ad5446_i2c_probe(struct i2c_client *i2c)
&ad5446_i2c_chip_info[id->driver_data]);
}
-static void ad5446_i2c_remove(struct i2c_client *i2c)
-{
- ad5446_remove(&i2c->dev);
-}
-
static const struct i2c_device_id ad5446_i2c_ids[] = {
{"ad5301", ID_AD5602},
{"ad5311", ID_AD5612},
@@ -596,7 +552,6 @@ static struct i2c_driver ad5446_i2c_driver = {
.name = "ad5446",
},
.probe = ad5446_i2c_probe,
- .remove = ad5446_i2c_remove,
.id_table = ad5446_i2c_ids,
};
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c
index e6c5be728bb2..ff0765c8af47 100644
--- a/drivers/iio/dac/ad5504.c
+++ b/drivers/iio/dac/ad5504.c
@@ -270,38 +270,29 @@ static const struct iio_chan_spec ad5504_channels[] = {
static int ad5504_probe(struct spi_device *spi)
{
- struct ad5504_platform_data *pdata = spi->dev.platform_data;
+ const struct ad5504_platform_data *pdata = dev_get_platdata(&spi->dev);
struct iio_dev *indio_dev;
struct ad5504_state *st;
- struct regulator *reg;
- int ret, voltage_uv = 0;
+ int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
- reg = devm_regulator_get(&spi->dev, "vcc");
- if (!IS_ERR(reg)) {
- ret = regulator_enable(reg);
- if (ret)
- return ret;
- ret = regulator_get_voltage(reg);
- if (ret < 0)
- goto error_disable_reg;
+ st = iio_priv(indio_dev);
- voltage_uv = ret;
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vcc");
+ if (ret < 0 && ret != -ENODEV)
+ return ret;
+ if (ret == -ENODEV) {
+ if (pdata->vref_mv)
+ st->vref_mv = pdata->vref_mv;
+ else
+ dev_warn(&spi->dev, "reference voltage unspecified\n");
+ } else {
+ st->vref_mv = ret / 1000;
}
- spi_set_drvdata(spi, indio_dev);
- st = iio_priv(indio_dev);
- if (voltage_uv)
- st->vref_mv = voltage_uv / 1000;
- else if (pdata)
- st->vref_mv = pdata->vref_mv;
- else
- dev_warn(&spi->dev, "reference voltage unspecified\n");
-
- st->reg = reg;
st->spi = spi;
indio_dev->name = spi_get_device_id(st->spi)->name;
indio_dev->info = &ad5504_info;
@@ -320,31 +311,10 @@ static int ad5504_probe(struct spi_device *spi)
spi_get_device_id(st->spi)->name,
indio_dev);
if (ret)
- goto error_disable_reg;
+ return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_disable_reg;
-
- return 0;
-
-error_disable_reg:
- if (!IS_ERR(reg))
- regulator_disable(reg);
-
- return ret;
-}
-
-static void ad5504_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ad5504_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
-
- if (!IS_ERR(st->reg))
- regulator_disable(st->reg);
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad5504_id[] = {
@@ -359,7 +329,6 @@ static struct spi_driver ad5504_driver = {
.name = "ad5504",
},
.probe = ad5504_probe,
- .remove = ad5504_remove,
.id_table = ad5504_id,
};
module_spi_driver(ad5504_driver);
diff --git a/drivers/iio/dac/ad5592r-base.c b/drivers/iio/dac/ad5592r-base.c
index 4763402dbcd6..50d19304bacb 100644
--- a/drivers/iio/dac/ad5592r-base.c
+++ b/drivers/iio/dac/ad5592r-base.c
@@ -665,7 +665,7 @@ error_disable_reg:
return ret;
}
-EXPORT_SYMBOL_NS_GPL(ad5592r_probe, IIO_AD5592R);
+EXPORT_SYMBOL_NS_GPL(ad5592r_probe, "IIO_AD5592R");
void ad5592r_remove(struct device *dev)
{
@@ -679,7 +679,7 @@ void ad5592r_remove(struct device *dev)
if (st->reg)
regulator_disable(st->reg);
}
-EXPORT_SYMBOL_NS_GPL(ad5592r_remove, IIO_AD5592R);
+EXPORT_SYMBOL_NS_GPL(ad5592r_remove, "IIO_AD5592R");
MODULE_AUTHOR("Paul Cercueil <[email protected]>");
MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters");
diff --git a/drivers/iio/dac/ad5592r.c b/drivers/iio/dac/ad5592r.c
index 32d950bbb1ca..fd82d8701322 100644
--- a/drivers/iio/dac/ad5592r.c
+++ b/drivers/iio/dac/ad5592r.c
@@ -168,4 +168,4 @@ module_spi_driver(ad5592r_spi_driver);
MODULE_AUTHOR("Paul Cercueil <[email protected]>");
MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters");
MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(IIO_AD5592R);
+MODULE_IMPORT_NS("IIO_AD5592R");
diff --git a/drivers/iio/dac/ad5593r.c b/drivers/iio/dac/ad5593r.c
index 62e1fbb9e910..ddd13ad821a7 100644
--- a/drivers/iio/dac/ad5593r.c
+++ b/drivers/iio/dac/ad5593r.c
@@ -147,4 +147,4 @@ module_i2c_driver(ad5593r_driver);
MODULE_AUTHOR("Paul Cercueil <[email protected]>");
MODULE_DESCRIPTION("Analog Devices AD5593R multi-channel converters");
MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(IIO_AD5592R);
+MODULE_IMPORT_NS("IIO_AD5592R");
diff --git a/drivers/iio/dac/ad5624r.h b/drivers/iio/dac/ad5624r.h
index 13964f3a22a4..14a439b06eb6 100644
--- a/drivers/iio/dac/ad5624r.h
+++ b/drivers/iio/dac/ad5624r.h
@@ -54,7 +54,6 @@ struct ad5624r_chip_info {
struct ad5624r_state {
struct spi_device *us;
const struct ad5624r_chip_info *chip_info;
- struct regulator *reg;
unsigned short vref_mv;
unsigned pwr_down_mask;
unsigned pwr_down_mode;
diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c
index 9304d0499bae..2fd38ac8f698 100644
--- a/drivers/iio/dac/ad5624r_spi.c
+++ b/drivers/iio/dac/ad5624r_spi.c
@@ -223,50 +223,26 @@ static int ad5624r_probe(struct spi_device *spi)
{
struct ad5624r_state *st;
struct iio_dev *indio_dev;
- int ret, voltage_uv = 0;
+ bool external_vref;
+ int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
- st->reg = devm_regulator_get_optional(&spi->dev, "vref");
- if (!IS_ERR(st->reg)) {
- ret = regulator_enable(st->reg);
- if (ret)
- return ret;
-
- ret = regulator_get_voltage(st->reg);
- if (ret < 0)
- goto error_disable_reg;
-
- voltage_uv = ret;
- } else {
- if (PTR_ERR(st->reg) != -ENODEV)
- return PTR_ERR(st->reg);
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
+ if (ret == -ENODEV)
/* Backwards compatibility. This naming is not correct */
- st->reg = devm_regulator_get_optional(&spi->dev, "vcc");
- if (!IS_ERR(st->reg)) {
- ret = regulator_enable(st->reg);
- if (ret)
- return ret;
-
- ret = regulator_get_voltage(st->reg);
- if (ret < 0)
- goto error_disable_reg;
-
- voltage_uv = ret;
- }
- }
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vcc");
+ if (ret < 0 && ret != -ENODEV)
+ return ret;
+
+ external_vref = ret != -ENODEV;
+ st->vref_mv = external_vref ? ret / 1000 : st->chip_info->int_vref_mv;
- spi_set_drvdata(spi, indio_dev);
st->chip_info =
&ad5624r_chip_info_tbl[spi_get_device_id(spi)->driver_data];
- if (voltage_uv)
- st->vref_mv = voltage_uv / 1000;
- else
- st->vref_mv = st->chip_info->int_vref_mv;
-
st->us = spi;
indio_dev->name = spi_get_device_id(spi)->name;
@@ -276,31 +252,11 @@ static int ad5624r_probe(struct spi_device *spi)
indio_dev->num_channels = AD5624R_DAC_CHANNELS;
ret = ad5624r_spi_write(spi, AD5624R_CMD_INTERNAL_REFER_SETUP, 0,
- !!voltage_uv, 16);
- if (ret)
- goto error_disable_reg;
-
- ret = iio_device_register(indio_dev);
+ external_vref, 16);
if (ret)
- goto error_disable_reg;
-
- return 0;
-
-error_disable_reg:
- if (!IS_ERR(st->reg))
- regulator_disable(st->reg);
-
- return ret;
-}
-
-static void ad5624r_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ad5624r_state *st = iio_priv(indio_dev);
+ return ret;
- iio_device_unregister(indio_dev);
- if (!IS_ERR(st->reg))
- regulator_disable(st->reg);
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad5624r_id[] = {
@@ -319,7 +275,6 @@ static struct spi_driver ad5624r_driver = {
.name = "ad5624r",
},
.probe = ad5624r_probe,
- .remove = ad5624r_remove,
.id_table = ad5624r_id,
};
module_spi_driver(ad5624r_driver);
diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c
index 8ba2ea70451a..39b5dad0d6a5 100644
--- a/drivers/iio/dac/ad5686-spi.c
+++ b/drivers/iio/dac/ad5686-spi.c
@@ -135,4 +135,4 @@ module_spi_driver(ad5686_spi_driver);
MODULE_AUTHOR("Stefan Popa <[email protected]>");
MODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs");
MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(IIO_AD5686);
+MODULE_IMPORT_NS("IIO_AD5686");
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
index 57cc0f0eedc6..8dc578b08784 100644
--- a/drivers/iio/dac/ad5686.c
+++ b/drivers/iio/dac/ad5686.c
@@ -543,7 +543,7 @@ error_disable_reg:
regulator_disable(st->reg);
return ret;
}
-EXPORT_SYMBOL_NS_GPL(ad5686_probe, IIO_AD5686);
+EXPORT_SYMBOL_NS_GPL(ad5686_probe, "IIO_AD5686");
void ad5686_remove(struct device *dev)
{
@@ -554,7 +554,7 @@ void ad5686_remove(struct device *dev)
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
}
-EXPORT_SYMBOL_NS_GPL(ad5686_remove, IIO_AD5686);
+EXPORT_SYMBOL_NS_GPL(ad5686_remove, "IIO_AD5686");
MODULE_AUTHOR("Michael Hennerich <[email protected]>");
MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC");
diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c
index 81541f755a3e..bbcda246c547 100644
--- a/drivers/iio/dac/ad5696-i2c.c
+++ b/drivers/iio/dac/ad5696-i2c.c
@@ -125,4 +125,4 @@ module_i2c_driver(ad5686_i2c_driver);
MODULE_AUTHOR("Stefan Popa <[email protected]>");
MODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs");
MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(IIO_AD5686);
+MODULE_IMPORT_NS("IIO_AD5686");
diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c
index 0b24cb19ac9d..05e80b6ae2cc 100644
--- a/drivers/iio/dac/ad5755.c
+++ b/drivers/iio/dac/ad5755.c
@@ -699,7 +699,6 @@ static const struct ad5755_platform_data ad5755_default_pdata = {
static struct ad5755_platform_data *ad5755_parse_fw(struct device *dev)
{
- struct fwnode_handle *pp;
struct ad5755_platform_data *pdata;
unsigned int tmp;
unsigned int tmparray[3];
@@ -746,11 +745,12 @@ static struct ad5755_platform_data *ad5755_parse_fw(struct device *dev)
}
devnr = 0;
- device_for_each_child_node(dev, pp) {
+ device_for_each_child_node_scoped(dev, pp) {
if (devnr >= AD5755_NUM_CHANNELS) {
dev_err(dev,
"There are too many channels defined in DT\n");
- goto error_out;
+ devm_kfree(dev, pdata);
+ return NULL;
}
pdata->dac[devnr].mode = AD5755_MODE_CURRENT_4mA_20mA;
@@ -800,11 +800,6 @@ static struct ad5755_platform_data *ad5755_parse_fw(struct device *dev)
}
return pdata;
-
- error_out:
- fwnode_handle_put(pp);
- devm_kfree(dev, pdata);
- return NULL;
}
static int ad5755_probe(struct spi_device *spi)
diff --git a/drivers/iio/dac/ad5761.c b/drivers/iio/dac/ad5761.c
index 6aa1a068adb0..0aa5ba7f4654 100644
--- a/drivers/iio/dac/ad5761.c
+++ b/drivers/iio/dac/ad5761.c
@@ -53,7 +53,6 @@ enum ad5761_supported_device_ids {
/**
* struct ad5761_state - driver instance specific data
* @spi: spi_device
- * @vref_reg: reference voltage regulator
* @use_intref: true when the internal voltage reference is used
* @vref: actual voltage reference in mVolts
* @range: output range mode used
@@ -62,7 +61,6 @@ enum ad5761_supported_device_ids {
*/
struct ad5761_state {
struct spi_device *spi;
- struct regulator *vref_reg;
struct mutex lock;
bool use_intref;
@@ -287,63 +285,6 @@ static const struct ad5761_chip_info ad5761_chip_infos[] = {
},
};
-static int ad5761_get_vref(struct ad5761_state *st,
- const struct ad5761_chip_info *chip_info)
-{
- int ret;
-
- st->vref_reg = devm_regulator_get_optional(&st->spi->dev, "vref");
- if (PTR_ERR(st->vref_reg) == -ENODEV) {
- /* Use Internal regulator */
- if (!chip_info->int_vref) {
- dev_err(&st->spi->dev,
- "Voltage reference not found\n");
- return -EIO;
- }
-
- st->use_intref = true;
- st->vref = chip_info->int_vref;
- return 0;
- }
-
- if (IS_ERR(st->vref_reg)) {
- dev_err(&st->spi->dev,
- "Error getting voltage reference regulator\n");
- return PTR_ERR(st->vref_reg);
- }
-
- ret = regulator_enable(st->vref_reg);
- if (ret) {
- dev_err(&st->spi->dev,
- "Failed to enable voltage reference\n");
- return ret;
- }
-
- ret = regulator_get_voltage(st->vref_reg);
- if (ret < 0) {
- dev_err(&st->spi->dev,
- "Failed to get voltage reference value\n");
- goto disable_regulator_vref;
- }
-
- if (ret < 2000000 || ret > 3000000) {
- dev_warn(&st->spi->dev,
- "Invalid external voltage ref. value %d uV\n", ret);
- ret = -EIO;
- goto disable_regulator_vref;
- }
-
- st->vref = ret / 1000;
- st->use_intref = false;
-
- return 0;
-
-disable_regulator_vref:
- regulator_disable(st->vref_reg);
- st->vref_reg = NULL;
- return ret;
-}
-
static int ad5761_probe(struct spi_device *spi)
{
struct iio_dev *iio_dev;
@@ -361,11 +302,28 @@ static int ad5761_probe(struct spi_device *spi)
st = iio_priv(iio_dev);
st->spi = spi;
- spi_set_drvdata(spi, iio_dev);
- ret = ad5761_get_vref(st, chip_info);
- if (ret)
- return ret;
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to get voltage reference value\n");
+ if (ret == -ENODEV) {
+ /* Use Internal regulator */
+ if (!chip_info->int_vref)
+ return dev_err_probe(&spi->dev, -EIO,
+ "Voltage reference not found\n");
+
+ st->use_intref = true;
+ st->vref = chip_info->int_vref;
+ } else {
+ if (ret < 2000000 || ret > 3000000)
+ return dev_err_probe(&spi->dev, -EIO,
+ "Invalid external voltage ref. value %d uV\n",
+ ret);
+
+ st->use_intref = false;
+ st->vref = ret / 1000;
+ }
if (pdata)
voltage_range = pdata->voltage_range;
@@ -374,35 +332,15 @@ static int ad5761_probe(struct spi_device *spi)
ret = ad5761_spi_set_range(st, voltage_range);
if (ret)
- goto disable_regulator_err;
+ return ret;
iio_dev->info = &ad5761_info;
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->channels = &chip_info->channel;
iio_dev->num_channels = 1;
iio_dev->name = spi_get_device_id(st->spi)->name;
- ret = iio_device_register(iio_dev);
- if (ret)
- goto disable_regulator_err;
-
- return 0;
-
-disable_regulator_err:
- if (!IS_ERR_OR_NULL(st->vref_reg))
- regulator_disable(st->vref_reg);
-
- return ret;
-}
-
-static void ad5761_remove(struct spi_device *spi)
-{
- struct iio_dev *iio_dev = spi_get_drvdata(spi);
- struct ad5761_state *st = iio_priv(iio_dev);
-
- iio_device_unregister(iio_dev);
- if (!IS_ERR_OR_NULL(st->vref_reg))
- regulator_disable(st->vref_reg);
+ return devm_iio_device_register(&spi->dev, iio_dev);
}
static const struct spi_device_id ad5761_id[] = {
@@ -419,7 +357,6 @@ static struct spi_driver ad5761_driver = {
.name = "ad5761",
},
.probe = ad5761_probe,
- .remove = ad5761_remove,
.id_table = ad5761_id,
};
module_spi_driver(ad5761_driver);
diff --git a/drivers/iio/dac/ad5770r.c b/drivers/iio/dac/ad5770r.c
index c360ebf5297a..25cf11d0471b 100644
--- a/drivers/iio/dac/ad5770r.c
+++ b/drivers/iio/dac/ad5770r.c
@@ -17,6 +17,7 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
+#include <linux/unaligned.h>
#define ADI_SPI_IF_CONFIG_A 0x00
#define ADI_SPI_IF_CONFIG_B 0x01
@@ -121,7 +122,6 @@ struct ad5770r_out_range {
* struct ad5770r_state - driver instance specific data
* @spi: spi_device
* @regmap: regmap
- * @vref_reg: fixed regulator for reference configuration
* @gpio_reset: gpio descriptor
* @output_mode: array contains channels output ranges
* @vref: reference value
@@ -133,7 +133,6 @@ struct ad5770r_out_range {
struct ad5770r_state {
struct spi_device *spi;
struct regmap *regmap;
- struct regulator *vref_reg;
struct gpio_desc *gpio_reset;
struct ad5770r_out_range output_mode[AD5770R_MAX_CHANNELS];
int vref;
@@ -325,7 +324,7 @@ static int ad5770r_read_raw(struct iio_dev *indio_dev,
if (ret)
return 0;
- buf16 = st->transf_buf[0] + (st->transf_buf[1] << 8);
+ buf16 = get_unaligned_le16(st->transf_buf);
*val = buf16 >> 2;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
@@ -590,13 +589,6 @@ static int ad5770r_init(struct ad5770r_state *st)
return ret;
}
-static void ad5770r_disable_regulator(void *data)
-{
- struct ad5770r_state *st = data;
-
- regulator_disable(st->vref_reg);
-}
-
static int ad5770r_probe(struct spi_device *spi)
{
struct ad5770r_state *st;
@@ -621,34 +613,12 @@ static int ad5770r_probe(struct spi_device *spi)
}
st->regmap = regmap;
- st->vref_reg = devm_regulator_get_optional(&spi->dev, "vref");
- if (!IS_ERR(st->vref_reg)) {
- ret = regulator_enable(st->vref_reg);
- if (ret) {
- dev_err(&spi->dev,
- "Failed to enable vref regulators: %d\n", ret);
- return ret;
- }
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(&spi->dev, ret, "Failed to get vref voltage\n");
- ret = devm_add_action_or_reset(&spi->dev,
- ad5770r_disable_regulator,
- st);
- if (ret < 0)
- return ret;
-
- ret = regulator_get_voltage(st->vref_reg);
- if (ret < 0)
- return ret;
-
- st->vref = ret / 1000;
- } else {
- if (PTR_ERR(st->vref_reg) == -ENODEV) {
- st->vref = AD5770R_LOW_VREF_mV;
- st->internal_ref = true;
- } else {
- return PTR_ERR(st->vref_reg);
- }
- }
+ st->internal_ref = ret == -ENODEV;
+ st->vref = st->internal_ref ? AD5770R_LOW_VREF_mV : ret / 1000;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &ad5770r_info;
diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c
index 75b549827e15..57374f78f6b8 100644
--- a/drivers/iio/dac/ad5791.c
+++ b/drivers/iio/dac/ad5791.c
@@ -9,6 +9,7 @@
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/device.h>
+#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
@@ -61,11 +62,14 @@
/**
* struct ad5791_chip_info - chip specific information
+ * @name: name of the dac chip
+ * @channel: channel specification
* @get_lin_comp: function pointer to the device specific function
*/
-
struct ad5791_chip_info {
- int (*get_lin_comp) (unsigned int span);
+ const char *name;
+ const struct iio_chan_spec channel;
+ int (*get_lin_comp)(unsigned int span);
};
/**
@@ -73,6 +77,9 @@ struct ad5791_chip_info {
* @spi: spi_device
* @reg_vdd: positive supply regulator
* @reg_vss: negative supply regulator
+ * @gpio_reset: reset gpio
+ * @gpio_clear: clear gpio
+ * @gpio_ldac: load dac gpio
* @chip_info: chip model specific constants
* @vref_mv: actual reference voltage used
* @vref_neg_mv: voltage of the negative supply
@@ -85,6 +92,9 @@ struct ad5791_state {
struct spi_device *spi;
struct regulator *reg_vdd;
struct regulator *reg_vss;
+ struct gpio_desc *gpio_reset;
+ struct gpio_desc *gpio_clear;
+ struct gpio_desc *gpio_ldac;
const struct ad5791_chip_info *chip_info;
unsigned short vref_mv;
unsigned int vref_neg_mv;
@@ -98,13 +108,6 @@ struct ad5791_state {
} data[3] __aligned(IIO_DMA_MINALIGN);
};
-enum ad5791_supported_device_ids {
- ID_AD5760,
- ID_AD5780,
- ID_AD5781,
- ID_AD5791,
-};
-
static int ad5791_spi_write(struct ad5791_state *st, u8 addr, u32 val)
{
st->data[0].d32 = cpu_to_be32(AD5791_CMD_WRITE |
@@ -228,20 +231,6 @@ static int ad5780_get_lin_comp(unsigned int span)
else
return AD5780_LINCOMP_10_20;
}
-static const struct ad5791_chip_info ad5791_chip_info_tbl[] = {
- [ID_AD5760] = {
- .get_lin_comp = ad5780_get_lin_comp,
- },
- [ID_AD5780] = {
- .get_lin_comp = ad5780_get_lin_comp,
- },
- [ID_AD5781] = {
- .get_lin_comp = ad5791_get_lin_comp,
- },
- [ID_AD5791] = {
- .get_lin_comp = ad5791_get_lin_comp,
- },
-};
static int ad5791_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
@@ -289,30 +278,34 @@ static const struct iio_chan_spec_ext_info ad5791_ext_info[] = {
{ },
};
-#define AD5791_CHAN(bits, _shift) { \
- .type = IIO_VOLTAGE, \
- .output = 1, \
- .indexed = 1, \
- .address = AD5791_ADDR_DAC0, \
- .channel = 0, \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
- BIT(IIO_CHAN_INFO_OFFSET), \
- .scan_type = { \
- .sign = 'u', \
- .realbits = (bits), \
- .storagebits = 24, \
- .shift = (_shift), \
- }, \
- .ext_info = ad5791_ext_info, \
+#define AD5791_DEFINE_CHIP_INFO(_name, bits, _shift, _lin_comp) \
+static const struct ad5791_chip_info _name##_chip_info = { \
+ .name = #_name, \
+ .get_lin_comp = &(_lin_comp), \
+ .channel = { \
+ .type = IIO_VOLTAGE, \
+ .output = 1, \
+ .indexed = 1, \
+ .address = AD5791_ADDR_DAC0, \
+ .channel = 0, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = (bits), \
+ .storagebits = 24, \
+ .shift = (_shift), \
+ }, \
+ .ext_info = ad5791_ext_info, \
+ }, \
}
-static const struct iio_chan_spec ad5791_channels[] = {
- [ID_AD5760] = AD5791_CHAN(16, 4),
- [ID_AD5780] = AD5791_CHAN(18, 2),
- [ID_AD5781] = AD5791_CHAN(18, 2),
- [ID_AD5791] = AD5791_CHAN(20, 0)
-};
+AD5791_DEFINE_CHIP_INFO(ad5760, 16, 4, ad5780_get_lin_comp);
+AD5791_DEFINE_CHIP_INFO(ad5780, 18, 2, ad5780_get_lin_comp);
+AD5791_DEFINE_CHIP_INFO(ad5781, 18, 2, ad5791_get_lin_comp);
+AD5791_DEFINE_CHIP_INFO(ad5790, 20, 0, ad5791_get_lin_comp);
+AD5791_DEFINE_CHIP_INFO(ad5791, 20, 0, ad5791_get_lin_comp);
static int ad5791_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
@@ -341,7 +334,7 @@ static const struct iio_info ad5791_info = {
static int ad5791_probe(struct spi_device *spi)
{
- struct ad5791_platform_data *pdata = spi->dev.platform_data;
+ const struct ad5791_platform_data *pdata = dev_get_platdata(&spi->dev);
struct iio_dev *indio_dev;
struct ad5791_state *st;
int ret, pos_voltage_uv = 0, neg_voltage_uv = 0;
@@ -351,31 +344,21 @@ static int ad5791_probe(struct spi_device *spi)
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
- st->reg_vdd = devm_regulator_get(&spi->dev, "vdd");
- if (!IS_ERR(st->reg_vdd)) {
- ret = regulator_enable(st->reg_vdd);
- if (ret)
- return ret;
-
- ret = regulator_get_voltage(st->reg_vdd);
- if (ret < 0)
- goto error_disable_reg_pos;
-
- pos_voltage_uv = ret;
- }
- st->reg_vss = devm_regulator_get(&spi->dev, "vss");
- if (!IS_ERR(st->reg_vss)) {
- ret = regulator_enable(st->reg_vss);
- if (ret)
- goto error_disable_reg_pos;
+ st->gpio_reset = devm_gpiod_get_optional(&spi->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(st->gpio_reset))
+ return PTR_ERR(st->gpio_reset);
- ret = regulator_get_voltage(st->reg_vss);
- if (ret < 0)
- goto error_disable_reg_neg;
+ st->gpio_clear = devm_gpiod_get_optional(&spi->dev, "clear",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(st->gpio_clear))
+ return PTR_ERR(st->gpio_clear);
- neg_voltage_uv = ret;
- }
+ st->gpio_ldac = devm_gpiod_get_optional(&spi->dev, "ldac",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(st->gpio_ldac))
+ return PTR_ERR(st->gpio_ldac);
st->pwr_down = true;
st->spi = spi;
@@ -386,7 +369,17 @@ static int ad5791_probe(struct spi_device *spi)
use_rbuf_gain2 = device_property_read_bool(&spi->dev,
"adi,rbuf-gain2-en");
- if (!IS_ERR(st->reg_vss) && !IS_ERR(st->reg_vdd)) {
+ pos_voltage_uv = devm_regulator_get_enable_read_voltage(&spi->dev, "vdd");
+ if (pos_voltage_uv < 0 && pos_voltage_uv != -ENODEV)
+ return dev_err_probe(&spi->dev, pos_voltage_uv,
+ "failed to get vdd voltage\n");
+
+ neg_voltage_uv = devm_regulator_get_enable_read_voltage(&spi->dev, "vss");
+ if (neg_voltage_uv < 0 && neg_voltage_uv != -ENODEV)
+ return dev_err_probe(&spi->dev, neg_voltage_uv,
+ "failed to get vss voltage\n");
+
+ if (neg_voltage_uv >= 0 && pos_voltage_uv >= 0) {
st->vref_mv = (pos_voltage_uv + neg_voltage_uv) / 1000;
st->vref_neg_mv = neg_voltage_uv / 1000;
} else if (pdata) {
@@ -396,13 +389,18 @@ static int ad5791_probe(struct spi_device *spi)
dev_warn(&spi->dev, "reference voltage unspecified\n");
}
- ret = ad5791_spi_write(st, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET);
- if (ret)
- goto error_disable_reg_neg;
-
- st->chip_info = &ad5791_chip_info_tbl[spi_get_device_id(spi)
- ->driver_data];
+ if (st->gpio_reset) {
+ fsleep(20);
+ gpiod_set_value_cansleep(st->gpio_reset, 0);
+ } else {
+ ret = ad5791_spi_write(st, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret, "fail to reset\n");
+ }
+ st->chip_info = spi_get_device_match_data(spi);
+ if (!st->chip_info)
+ return dev_err_probe(&spi->dev, -EINVAL, "no chip info\n");
st->ctrl = AD5761_CTRL_LINCOMP(st->chip_info->get_lin_comp(st->vref_mv))
| (use_rbuf_gain2 ? 0 : AD5791_CTRL_RBUF) |
@@ -411,59 +409,42 @@ static int ad5791_probe(struct spi_device *spi)
ret = ad5791_spi_write(st, AD5791_ADDR_CTRL, st->ctrl |
AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI);
if (ret)
- goto error_disable_reg_neg;
+ return dev_err_probe(&spi->dev, ret, "fail to write ctrl register\n");
- spi_set_drvdata(spi, indio_dev);
indio_dev->info = &ad5791_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels
- = &ad5791_channels[spi_get_device_id(spi)->driver_data];
+ indio_dev->channels = &st->chip_info->channel;
indio_dev->num_channels = 1;
- indio_dev->name = spi_get_device_id(st->spi)->name;
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_disable_reg_neg;
-
- return 0;
-
-error_disable_reg_neg:
- if (!IS_ERR(st->reg_vss))
- regulator_disable(st->reg_vss);
-error_disable_reg_pos:
- if (!IS_ERR(st->reg_vdd))
- regulator_disable(st->reg_vdd);
- return ret;
+ indio_dev->name = st->chip_info->name;
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
-static void ad5791_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ad5791_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- if (!IS_ERR(st->reg_vdd))
- regulator_disable(st->reg_vdd);
-
- if (!IS_ERR(st->reg_vss))
- regulator_disable(st->reg_vss);
-}
+static const struct of_device_id ad5791_of_match[] = {
+ { .compatible = "adi,ad5760", .data = &ad5760_chip_info },
+ { .compatible = "adi,ad5780", .data = &ad5780_chip_info },
+ { .compatible = "adi,ad5781", .data = &ad5781_chip_info },
+ { .compatible = "adi,ad5790", .data = &ad5790_chip_info },
+ { .compatible = "adi,ad5791", .data = &ad5791_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad5791_of_match);
static const struct spi_device_id ad5791_id[] = {
- {"ad5760", ID_AD5760},
- {"ad5780", ID_AD5780},
- {"ad5781", ID_AD5781},
- {"ad5790", ID_AD5791},
- {"ad5791", ID_AD5791},
- {}
+ { "ad5760", (kernel_ulong_t)&ad5760_chip_info },
+ { "ad5780", (kernel_ulong_t)&ad5780_chip_info },
+ { "ad5781", (kernel_ulong_t)&ad5781_chip_info },
+ { "ad5790", (kernel_ulong_t)&ad5790_chip_info },
+ { "ad5791", (kernel_ulong_t)&ad5791_chip_info },
+ { }
};
MODULE_DEVICE_TABLE(spi, ad5791_id);
static struct spi_driver ad5791_driver = {
.driver = {
.name = "ad5791",
+ .of_match_table = ad5791_of_match,
},
.probe = ad5791_probe,
- .remove = ad5791_remove,
.id_table = ad5791_id,
};
module_spi_driver(ad5791_driver);
diff --git a/drivers/iio/dac/ad8460.c b/drivers/iio/dac/ad8460.c
new file mode 100644
index 000000000000..535ee3105af6
--- /dev/null
+++ b/drivers/iio/dac/ad8460.c
@@ -0,0 +1,951 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AD8460 Waveform generator DAC Driver
+ *
+ * Copyright (C) 2024 Analog Devices, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/buffer-dma.h>
+#include <linux/iio/buffer-dmaengine.h>
+#include <linux/iio/consumer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+
+#define AD8460_CTRL_REG(x) (x)
+#define AD8460_HVDAC_DATA_WORD(x) (0x60 + (2 * (x)))
+
+#define AD8460_HV_RESET_MSK BIT(7)
+#define AD8460_HV_SLEEP_MSK BIT(4)
+#define AD8460_WAVE_GEN_MODE_MSK BIT(0)
+
+#define AD8460_HVDAC_SLEEP_MSK BIT(3)
+
+#define AD8460_FAULT_ARM_MSK BIT(7)
+#define AD8460_FAULT_LIMIT_MSK GENMASK(6, 0)
+
+#define AD8460_APG_MODE_ENABLE_MSK BIT(5)
+#define AD8460_PATTERN_DEPTH_MSK GENMASK(3, 0)
+
+#define AD8460_QUIESCENT_CURRENT_MSK GENMASK(7, 0)
+
+#define AD8460_SHUTDOWN_FLAG_MSK BIT(7)
+
+#define AD8460_DATA_BYTE_LOW_MSK GENMASK(7, 0)
+#define AD8460_DATA_BYTE_HIGH_MSK GENMASK(5, 0)
+#define AD8460_DATA_BYTE_FULL_MSK GENMASK(13, 0)
+
+#define AD8460_DEFAULT_FAULT_PROTECT 0x00
+#define AD8460_DATA_BYTE_WORD_LENGTH 2
+#define AD8460_NUM_DATA_WORDS 16
+#define AD8460_NOMINAL_VOLTAGE_SPAN 80
+#define AD8460_MIN_EXT_RESISTOR_OHMS 2000
+#define AD8460_MAX_EXT_RESISTOR_OHMS 20000
+#define AD8460_MIN_VREFIO_UV 120000
+#define AD8460_MAX_VREFIO_UV 1200000
+#define AD8460_ABS_MAX_OVERVOLTAGE_UV 55000000
+#define AD8460_ABS_MAX_OVERCURRENT_UA 1000000
+#define AD8460_MAX_OVERTEMPERATURE_MC 150000
+#define AD8460_MIN_OVERTEMPERATURE_MC 20000
+#define AD8460_CURRENT_LIMIT_CONV(x) ((x) / 15625)
+#define AD8460_VOLTAGE_LIMIT_CONV(x) ((x) / 1953000)
+#define AD8460_TEMP_LIMIT_CONV(x) (((x) + 266640) / 6510)
+
+enum ad8460_fault_type {
+ AD8460_OVERCURRENT_SRC,
+ AD8460_OVERCURRENT_SNK,
+ AD8460_OVERVOLTAGE_POS,
+ AD8460_OVERVOLTAGE_NEG,
+ AD8460_OVERTEMPERATURE,
+};
+
+struct ad8460_state {
+ struct spi_device *spi;
+ struct regmap *regmap;
+ struct iio_channel *tmp_adc_channel;
+ struct clk *sync_clk;
+ /* lock to protect against multiple access to the device and shared data */
+ struct mutex lock;
+ int refio_1p2v_mv;
+ u32 ext_resistor_ohms;
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ __le16 spi_tx_buf __aligned(IIO_DMA_MINALIGN);
+};
+
+static int ad8460_hv_reset(struct ad8460_state *state)
+{
+ int ret;
+
+ ret = regmap_set_bits(state->regmap, AD8460_CTRL_REG(0x00),
+ AD8460_HV_RESET_MSK);
+ if (ret)
+ return ret;
+
+ fsleep(20);
+
+ return regmap_clear_bits(state->regmap, AD8460_CTRL_REG(0x00),
+ AD8460_HV_RESET_MSK);
+}
+
+static int ad8460_reset(const struct ad8460_state *state)
+{
+ struct device *dev = &state->spi->dev;
+ struct gpio_desc *reset;
+
+ reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(reset))
+ return dev_err_probe(dev, PTR_ERR(reset),
+ "Failed to get reset gpio");
+ if (reset) {
+ /* minimum duration of 10ns */
+ ndelay(10);
+ gpiod_set_value_cansleep(reset, 1);
+ return 0;
+ }
+
+ /* bring all registers to their default state */
+ return regmap_write(state->regmap, AD8460_CTRL_REG(0x03), 1);
+}
+
+static int ad8460_enable_apg_mode(struct ad8460_state *state, int val)
+{
+ int ret;
+
+ ret = regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x02),
+ AD8460_APG_MODE_ENABLE_MSK,
+ FIELD_PREP(AD8460_APG_MODE_ENABLE_MSK, val));
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x00),
+ AD8460_WAVE_GEN_MODE_MSK,
+ FIELD_PREP(AD8460_WAVE_GEN_MODE_MSK, val));
+}
+
+static int ad8460_read_shutdown_flag(struct ad8460_state *state, u64 *flag)
+{
+ int ret, val;
+
+ ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x0E), &val);
+ if (ret)
+ return ret;
+
+ *flag = FIELD_GET(AD8460_SHUTDOWN_FLAG_MSK, val);
+ return 0;
+}
+
+static int ad8460_get_hvdac_word(struct ad8460_state *state, int index, int *val)
+{
+ int ret;
+
+ ret = regmap_bulk_read(state->regmap, AD8460_HVDAC_DATA_WORD(index),
+ &state->spi_tx_buf, AD8460_DATA_BYTE_WORD_LENGTH);
+ if (ret)
+ return ret;
+
+ *val = le16_to_cpu(state->spi_tx_buf);
+
+ return ret;
+}
+
+static int ad8460_set_hvdac_word(struct ad8460_state *state, int index, int val)
+{
+ state->spi_tx_buf = cpu_to_le16(FIELD_PREP(AD8460_DATA_BYTE_FULL_MSK, val));
+
+ return regmap_bulk_write(state->regmap, AD8460_HVDAC_DATA_WORD(index),
+ &state->spi_tx_buf, AD8460_DATA_BYTE_WORD_LENGTH);
+}
+
+static ssize_t ad8460_dac_input_read(struct iio_dev *indio_dev, uintptr_t private,
+ const struct iio_chan_spec *chan, char *buf)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+ unsigned int reg;
+ int ret;
+
+ ret = ad8460_get_hvdac_word(state, private, &reg);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%u\n", reg);
+}
+
+static ssize_t ad8460_dac_input_write(struct iio_dev *indio_dev, uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf, size_t len)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+ unsigned int reg;
+ int ret;
+
+ ret = kstrtou32(buf, 10, &reg);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&state->lock);
+
+ return ad8460_set_hvdac_word(state, private, reg);
+}
+
+static ssize_t ad8460_read_symbol(struct iio_dev *indio_dev, uintptr_t private,
+ const struct iio_chan_spec *chan, char *buf)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x02), &reg);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%lu\n", FIELD_GET(AD8460_PATTERN_DEPTH_MSK, reg));
+}
+
+static ssize_t ad8460_write_symbol(struct iio_dev *indio_dev, uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf, size_t len)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+ uint16_t sym;
+ int ret;
+
+ ret = kstrtou16(buf, 10, &sym);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&state->lock);
+
+ return regmap_update_bits(state->regmap,
+ AD8460_CTRL_REG(0x02),
+ AD8460_PATTERN_DEPTH_MSK,
+ FIELD_PREP(AD8460_PATTERN_DEPTH_MSK, sym));
+}
+
+static ssize_t ad8460_read_toggle_en(struct iio_dev *indio_dev, uintptr_t private,
+ const struct iio_chan_spec *chan, char *buf)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x02), &reg);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%ld\n", FIELD_GET(AD8460_APG_MODE_ENABLE_MSK, reg));
+}
+
+static ssize_t ad8460_write_toggle_en(struct iio_dev *indio_dev, uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf, size_t len)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+ bool toggle_en;
+ int ret;
+
+ ret = kstrtobool(buf, &toggle_en);
+ if (ret)
+ return ret;
+
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+ return ad8460_enable_apg_mode(state, toggle_en);
+ unreachable();
+}
+
+static ssize_t ad8460_read_powerdown(struct iio_dev *indio_dev, uintptr_t private,
+ const struct iio_chan_spec *chan, char *buf)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x01), &reg);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%ld\n", FIELD_GET(AD8460_HVDAC_SLEEP_MSK, reg));
+}
+
+static ssize_t ad8460_write_powerdown(struct iio_dev *indio_dev, uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf, size_t len)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+ bool pwr_down;
+ u64 sdn_flag;
+ int ret;
+
+ ret = kstrtobool(buf, &pwr_down);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&state->lock);
+
+ /*
+ * If powerdown is set, HVDAC is enabled and the HV driver is
+ * enabled via HV_RESET in case it is in shutdown mode,
+ * If powerdown is cleared, HVDAC is set to shutdown state
+ * as well as the HV driver. Quiescent current decreases and ouput is
+ * floating (high impedance).
+ */
+
+ ret = regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x01),
+ AD8460_HVDAC_SLEEP_MSK,
+ FIELD_PREP(AD8460_HVDAC_SLEEP_MSK, pwr_down));
+ if (ret)
+ return ret;
+
+ if (!pwr_down) {
+ ret = ad8460_read_shutdown_flag(state, &sdn_flag);
+ if (ret)
+ return ret;
+
+ if (sdn_flag) {
+ ret = ad8460_hv_reset(state);
+ if (ret)
+ return ret;
+ }
+ }
+
+ ret = regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x00),
+ AD8460_HV_SLEEP_MSK,
+ FIELD_PREP(AD8460_HV_SLEEP_MSK, !pwr_down));
+ if (ret)
+ return ret;
+
+ return len;
+}
+
+static const char * const ad8460_powerdown_modes[] = {
+ "three_state",
+};
+
+static int ad8460_get_powerdown_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ return 0;
+}
+
+static int ad8460_set_powerdown_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int type)
+{
+ return 0;
+}
+
+static int ad8460_set_sample(struct ad8460_state *state, int val)
+{
+ int ret;
+
+ ret = ad8460_enable_apg_mode(state, 1);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&state->lock);
+ ret = ad8460_set_hvdac_word(state, 0, val);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x02),
+ AD8460_PATTERN_DEPTH_MSK,
+ FIELD_PREP(AD8460_PATTERN_DEPTH_MSK, 0));
+}
+
+static int ad8460_set_fault_threshold(struct ad8460_state *state,
+ enum ad8460_fault_type fault,
+ unsigned int threshold)
+{
+ return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x08 + fault),
+ AD8460_FAULT_LIMIT_MSK,
+ FIELD_PREP(AD8460_FAULT_LIMIT_MSK, threshold));
+}
+
+static int ad8460_get_fault_threshold(struct ad8460_state *state,
+ enum ad8460_fault_type fault,
+ unsigned int *threshold)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x08 + fault), &val);
+ if (ret)
+ return ret;
+
+ *threshold = FIELD_GET(AD8460_FAULT_LIMIT_MSK, val);
+
+ return ret;
+}
+
+static int ad8460_set_fault_threshold_en(struct ad8460_state *state,
+ enum ad8460_fault_type fault, bool en)
+{
+ return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x08 + fault),
+ AD8460_FAULT_ARM_MSK,
+ FIELD_PREP(AD8460_FAULT_ARM_MSK, en));
+}
+
+static int ad8460_get_fault_threshold_en(struct ad8460_state *state,
+ enum ad8460_fault_type fault, bool *en)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x08 + fault), &val);
+ if (ret)
+ return ret;
+
+ *en = FIELD_GET(AD8460_FAULT_ARM_MSK, val);
+
+ return 0;
+}
+
+static int ad8460_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2,
+ long mask)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+ return ad8460_set_sample(state, val);
+ unreachable();
+ case IIO_CURRENT:
+ return regmap_write(state->regmap, AD8460_CTRL_REG(0x04),
+ FIELD_PREP(AD8460_QUIESCENT_CURRENT_MSK, val));
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad8460_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+ int data, ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ scoped_guard(mutex, &state->lock) {
+ ret = ad8460_get_hvdac_word(state, 0, &data);
+ if (ret)
+ return ret;
+ }
+ *val = data;
+ return IIO_VAL_INT;
+ case IIO_CURRENT:
+ ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x04),
+ &data);
+ if (ret)
+ return ret;
+ *val = data;
+ return IIO_VAL_INT;
+ case IIO_TEMP:
+ ret = iio_read_channel_raw(state->tmp_adc_channel, &data);
+ if (ret)
+ return ret;
+ *val = data;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = clk_get_rate(state->sync_clk);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ /*
+ * vCONV = vNOMINAL_SPAN * (DAC_CODE / 2**14) - 40V
+ * vMAX = vNOMINAL_SPAN * (2**14 / 2**14) - 40V
+ * vMIN = vNOMINAL_SPAN * (0 / 2**14) - 40V
+ * vADJ = vCONV * (2000 / rSET) * (vREF / 1.2)
+ * vSPAN = vADJ_MAX - vADJ_MIN
+ * See datasheet page 49, section FULL-SCALE REDUCTION
+ */
+ *val = AD8460_NOMINAL_VOLTAGE_SPAN * 2000 * state->refio_1p2v_mv;
+ *val2 = state->ext_resistor_ohms * 1200;
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad8460_select_fault_type(int chan_type, enum iio_event_direction dir)
+{
+ switch (chan_type) {
+ case IIO_VOLTAGE:
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ return AD8460_OVERVOLTAGE_POS;
+ case IIO_EV_DIR_FALLING:
+ return AD8460_OVERVOLTAGE_NEG;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CURRENT:
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ return AD8460_OVERCURRENT_SRC;
+ case IIO_EV_DIR_FALLING:
+ return AD8460_OVERCURRENT_SNK;
+ default:
+ return -EINVAL;
+ }
+ case IIO_TEMP:
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ return AD8460_OVERTEMPERATURE;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad8460_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info, int val, int val2)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+ int fault;
+
+ if (type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+
+ if (info != IIO_EV_INFO_VALUE)
+ return -EINVAL;
+
+ fault = ad8460_select_fault_type(chan->type, dir);
+ if (fault < 0)
+ return fault;
+
+ return ad8460_set_fault_threshold(state, fault, val);
+}
+
+static int ad8460_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info, int *val, int *val2)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+ int fault;
+
+ if (type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+
+ if (info != IIO_EV_INFO_VALUE)
+ return -EINVAL;
+
+ fault = ad8460_select_fault_type(chan->type, dir);
+ if (fault < 0)
+ return fault;
+
+ return ad8460_get_fault_threshold(state, fault, val);
+}
+
+static int ad8460_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir, bool val)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+ int fault;
+
+ if (type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+
+ fault = ad8460_select_fault_type(chan->type, dir);
+ if (fault < 0)
+ return fault;
+
+ return ad8460_set_fault_threshold_en(state, fault, val);
+}
+
+static int ad8460_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+ int fault, ret;
+ bool en;
+
+ if (type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+
+ fault = ad8460_select_fault_type(chan->type, dir);
+ if (fault < 0)
+ return fault;
+
+ ret = ad8460_get_fault_threshold_en(state, fault, &en);
+ if (ret)
+ return ret;
+
+ return en;
+}
+
+static int ad8460_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int writeval, unsigned int *readval)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+
+ if (readval)
+ return regmap_read(state->regmap, reg, readval);
+
+ return regmap_write(state->regmap, reg, writeval);
+}
+
+static int ad8460_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+
+ return ad8460_enable_apg_mode(state, 0);
+}
+
+static int ad8460_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ struct ad8460_state *state = iio_priv(indio_dev);
+
+ return ad8460_enable_apg_mode(state, 1);
+}
+
+static const struct iio_buffer_setup_ops ad8460_buffer_setup_ops = {
+ .preenable = &ad8460_buffer_preenable,
+ .postdisable = &ad8460_buffer_postdisable,
+};
+
+static const struct iio_info ad8460_info = {
+ .read_raw = &ad8460_read_raw,
+ .write_raw = &ad8460_write_raw,
+ .write_event_value = &ad8460_write_event_value,
+ .read_event_value = &ad8460_read_event_value,
+ .write_event_config = &ad8460_write_event_config,
+ .read_event_config = &ad8460_read_event_config,
+ .debugfs_reg_access = &ad8460_reg_access,
+};
+
+static const struct iio_enum ad8460_powerdown_mode_enum = {
+ .items = ad8460_powerdown_modes,
+ .num_items = ARRAY_SIZE(ad8460_powerdown_modes),
+ .get = ad8460_get_powerdown_mode,
+ .set = ad8460_set_powerdown_mode,
+};
+
+#define AD8460_CHAN_EXT_INFO(_name, _what, _read, _write) { \
+ .name = (_name), \
+ .read = (_read), \
+ .write = (_write), \
+ .private = (_what), \
+ .shared = IIO_SEPARATE, \
+}
+
+static const struct iio_chan_spec_ext_info ad8460_ext_info[] = {
+ AD8460_CHAN_EXT_INFO("raw0", 0, ad8460_dac_input_read,
+ ad8460_dac_input_write),
+ AD8460_CHAN_EXT_INFO("raw1", 1, ad8460_dac_input_read,
+ ad8460_dac_input_write),
+ AD8460_CHAN_EXT_INFO("raw2", 2, ad8460_dac_input_read,
+ ad8460_dac_input_write),
+ AD8460_CHAN_EXT_INFO("raw3", 3, ad8460_dac_input_read,
+ ad8460_dac_input_write),
+ AD8460_CHAN_EXT_INFO("raw4", 4, ad8460_dac_input_read,
+ ad8460_dac_input_write),
+ AD8460_CHAN_EXT_INFO("raw5", 5, ad8460_dac_input_read,
+ ad8460_dac_input_write),
+ AD8460_CHAN_EXT_INFO("raw6", 6, ad8460_dac_input_read,
+ ad8460_dac_input_write),
+ AD8460_CHAN_EXT_INFO("raw7", 7, ad8460_dac_input_read,
+ ad8460_dac_input_write),
+ AD8460_CHAN_EXT_INFO("raw8", 8, ad8460_dac_input_read,
+ ad8460_dac_input_write),
+ AD8460_CHAN_EXT_INFO("raw9", 9, ad8460_dac_input_read,
+ ad8460_dac_input_write),
+ AD8460_CHAN_EXT_INFO("raw10", 10, ad8460_dac_input_read,
+ ad8460_dac_input_write),
+ AD8460_CHAN_EXT_INFO("raw11", 11, ad8460_dac_input_read,
+ ad8460_dac_input_write),
+ AD8460_CHAN_EXT_INFO("raw12", 12, ad8460_dac_input_read,
+ ad8460_dac_input_write),
+ AD8460_CHAN_EXT_INFO("raw13", 13, ad8460_dac_input_read,
+ ad8460_dac_input_write),
+ AD8460_CHAN_EXT_INFO("raw14", 14, ad8460_dac_input_read,
+ ad8460_dac_input_write),
+ AD8460_CHAN_EXT_INFO("raw15", 15, ad8460_dac_input_read,
+ ad8460_dac_input_write),
+ AD8460_CHAN_EXT_INFO("toggle_en", 0, ad8460_read_toggle_en,
+ ad8460_write_toggle_en),
+ AD8460_CHAN_EXT_INFO("symbol", 0, ad8460_read_symbol,
+ ad8460_write_symbol),
+ AD8460_CHAN_EXT_INFO("powerdown", 0, ad8460_read_powerdown,
+ ad8460_write_powerdown),
+ IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad8460_powerdown_mode_enum),
+ IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE,
+ &ad8460_powerdown_mode_enum),
+ { }
+};
+
+static const struct iio_event_spec ad8460_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_ENABLE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
+#define AD8460_VOLTAGE_CHAN { \
+ .type = IIO_VOLTAGE, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .output = 1, \
+ .indexed = 1, \
+ .channel = 0, \
+ .scan_index = 0, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 14, \
+ .storagebits = 16, \
+ .endianness = IIO_CPU, \
+ }, \
+ .ext_info = ad8460_ext_info, \
+ .event_spec = ad8460_events, \
+ .num_event_specs = ARRAY_SIZE(ad8460_events), \
+}
+
+#define AD8460_CURRENT_CHAN { \
+ .type = IIO_CURRENT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .output = 1, \
+ .indexed = 1, \
+ .channel = 0, \
+ .scan_index = -1, \
+ .event_spec = ad8460_events, \
+ .num_event_specs = ARRAY_SIZE(ad8460_events), \
+}
+
+#define AD8460_TEMP_CHAN { \
+ .type = IIO_TEMP, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .indexed = 1, \
+ .channel = 0, \
+ .scan_index = -1, \
+ .event_spec = ad8460_events, \
+ .num_event_specs = 1, \
+}
+
+static const struct iio_chan_spec ad8460_channels[] = {
+ AD8460_VOLTAGE_CHAN,
+ AD8460_CURRENT_CHAN,
+};
+
+static const struct iio_chan_spec ad8460_channels_with_tmp_adc[] = {
+ AD8460_VOLTAGE_CHAN,
+ AD8460_CURRENT_CHAN,
+ AD8460_TEMP_CHAN,
+};
+
+static const struct regmap_config ad8460_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x7F,
+};
+
+static const char * const ad8460_supplies[] = {
+ "avdd_3p3v", "dvdd_3p3v", "vcc_5v", "hvcc", "hvee", "vref_5v"
+};
+
+static int ad8460_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct ad8460_state *state;
+ struct iio_dev *indio_dev;
+ u32 tmp[2], temp;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ state = iio_priv(indio_dev);
+
+ indio_dev->name = "ad8460";
+ indio_dev->info = &ad8460_info;
+
+ state->spi = spi;
+
+ state->regmap = devm_regmap_init_spi(spi, &ad8460_regmap_config);
+ if (IS_ERR(state->regmap))
+ return dev_err_probe(dev, PTR_ERR(state->regmap),
+ "Failed to initialize regmap");
+
+ ret = devm_mutex_init(dev, &state->lock);
+ if (ret)
+ return ret;
+
+ state->sync_clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(state->sync_clk))
+ return dev_err_probe(dev, PTR_ERR(state->sync_clk),
+ "Failed to get sync clk\n");
+
+ state->tmp_adc_channel = devm_iio_channel_get(dev, "ad8460-tmp");
+ if (IS_ERR(state->tmp_adc_channel)) {
+ if (PTR_ERR(state->tmp_adc_channel) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ indio_dev->channels = ad8460_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad8460_channels);
+ } else {
+ indio_dev->channels = ad8460_channels_with_tmp_adc;
+ indio_dev->num_channels = ARRAY_SIZE(ad8460_channels_with_tmp_adc);
+ }
+
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad8460_supplies),
+ ad8460_supplies);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to enable power supplies\n");
+
+ ret = devm_regulator_get_enable_read_voltage(dev, "refio_1p2v");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "Failed to get reference voltage\n");
+
+ state->refio_1p2v_mv = ret == -ENODEV ? 1200 : ret / 1000;
+
+ if (!in_range(state->refio_1p2v_mv, AD8460_MIN_VREFIO_UV / 1000,
+ AD8460_MAX_VREFIO_UV / 1000))
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid ref voltage range(%u mV) [%u mV, %u mV]\n",
+ state->refio_1p2v_mv,
+ AD8460_MIN_VREFIO_UV / 1000,
+ AD8460_MAX_VREFIO_UV / 1000);
+
+ ret = device_property_read_u32(dev, "adi,external-resistor-ohms",
+ &state->ext_resistor_ohms);
+ if (ret)
+ state->ext_resistor_ohms = 2000;
+ else if (!in_range(state->ext_resistor_ohms, AD8460_MIN_EXT_RESISTOR_OHMS,
+ AD8460_MAX_EXT_RESISTOR_OHMS))
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid resistor set range(%u) [%u, %u]\n",
+ state->ext_resistor_ohms,
+ AD8460_MIN_EXT_RESISTOR_OHMS,
+ AD8460_MAX_EXT_RESISTOR_OHMS);
+
+ ret = device_property_read_u32_array(dev, "adi,range-microamp",
+ tmp, ARRAY_SIZE(tmp));
+ if (!ret) {
+ if (in_range(tmp[1], 0, AD8460_ABS_MAX_OVERCURRENT_UA))
+ regmap_write(state->regmap, AD8460_CTRL_REG(0x08),
+ FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) |
+ AD8460_CURRENT_LIMIT_CONV(tmp[1]));
+
+ if (in_range(tmp[0], -AD8460_ABS_MAX_OVERCURRENT_UA, 0))
+ regmap_write(state->regmap, AD8460_CTRL_REG(0x09),
+ FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) |
+ AD8460_CURRENT_LIMIT_CONV(abs(tmp[0])));
+ }
+
+ ret = device_property_read_u32_array(dev, "adi,range-microvolt",
+ tmp, ARRAY_SIZE(tmp));
+ if (!ret) {
+ if (in_range(tmp[1], 0, AD8460_ABS_MAX_OVERVOLTAGE_UV))
+ regmap_write(state->regmap, AD8460_CTRL_REG(0x0A),
+ FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) |
+ AD8460_VOLTAGE_LIMIT_CONV(tmp[1]));
+
+ if (in_range(tmp[0], -AD8460_ABS_MAX_OVERVOLTAGE_UV, 0))
+ regmap_write(state->regmap, AD8460_CTRL_REG(0x0B),
+ FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) |
+ AD8460_VOLTAGE_LIMIT_CONV(abs(tmp[0])));
+ }
+
+ ret = device_property_read_u32(dev, "adi,max-millicelsius", &temp);
+ if (!ret) {
+ if (in_range(temp, AD8460_MIN_OVERTEMPERATURE_MC,
+ AD8460_MAX_OVERTEMPERATURE_MC))
+ regmap_write(state->regmap, AD8460_CTRL_REG(0x0C),
+ FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) |
+ AD8460_TEMP_LIMIT_CONV(abs(temp)));
+ }
+
+ ret = ad8460_reset(state);
+ if (ret)
+ return ret;
+
+ /* Enables DAC by default */
+ ret = regmap_clear_bits(state->regmap, AD8460_CTRL_REG(0x01),
+ AD8460_HVDAC_SLEEP_MSK);
+ if (ret)
+ return ret;
+
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->setup_ops = &ad8460_buffer_setup_ops;
+
+ ret = devm_iio_dmaengine_buffer_setup_ext(dev, indio_dev, "tx",
+ IIO_BUFFER_DIRECTION_OUT);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to get DMA buffer\n");
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id ad8460_of_match[] = {
+ { .compatible = "adi,ad8460" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad8460_of_match);
+
+static const struct spi_device_id ad8460_spi_match[] = {
+ { .name = "ad8460" },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad8460_spi_match);
+
+static struct spi_driver ad8460_driver = {
+ .driver = {
+ .name = "ad8460",
+ .of_match_table = ad8460_of_match,
+ },
+ .probe = ad8460_probe,
+ .id_table = ad8460_spi_match,
+};
+module_spi_driver(ad8460_driver);
+
+MODULE_AUTHOR("Mariel Tinaco <[email protected]");
+MODULE_DESCRIPTION("AD8460 DAC driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");
diff --git a/drivers/iio/dac/ad9739a.c b/drivers/iio/dac/ad9739a.c
index 615d1a196db3..b6a65359b0b4 100644
--- a/drivers/iio/dac/ad9739a.c
+++ b/drivers/iio/dac/ad9739a.c
@@ -466,4 +466,4 @@ MODULE_AUTHOR("Dragos Bogdan <[email protected]>");
MODULE_AUTHOR("Nuno Sa <[email protected]>");
MODULE_DESCRIPTION("Analog Devices AD9739 DAC");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(IIO_BACKEND);
+MODULE_IMPORT_NS("IIO_BACKEND");
diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c
index 0cb00f3bec04..b143f7ed6847 100644
--- a/drivers/iio/dac/adi-axi-dac.c
+++ b/drivers/iio/dac/adi-axi-dac.c
@@ -29,44 +29,77 @@
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
+#include "ad3552r-hs.h"
+
/*
* Register definitions:
* https://wiki.analog.com/resources/fpga/docs/axi_dac_ip#register_map
*/
/* Base controls */
-#define AXI_DAC_REG_CONFIG 0x0c
-#define AXI_DDS_DISABLE BIT(6)
+#define AXI_DAC_CONFIG_REG 0x0c
+#define AXI_DAC_CONFIG_DDS_DISABLE BIT(6)
/* DAC controls */
-#define AXI_DAC_REG_RSTN 0x0040
-#define AXI_DAC_RSTN_CE_N BIT(2)
-#define AXI_DAC_RSTN_MMCM_RSTN BIT(1)
-#define AXI_DAC_RSTN_RSTN BIT(0)
-#define AXI_DAC_REG_CNTRL_1 0x0044
-#define AXI_DAC_SYNC BIT(0)
-#define AXI_DAC_REG_CNTRL_2 0x0048
-#define ADI_DAC_R1_MODE BIT(4)
-#define AXI_DAC_DRP_STATUS 0x0074
-#define AXI_DAC_DRP_LOCKED BIT(17)
+#define AXI_DAC_RSTN_REG 0x0040
+#define AXI_DAC_RSTN_CE_N BIT(2)
+#define AXI_DAC_RSTN_MMCM_RSTN BIT(1)
+#define AXI_DAC_RSTN_RSTN BIT(0)
+#define AXI_DAC_CNTRL_1_REG 0x0044
+#define AXI_DAC_CNTRL_1_SYNC BIT(0)
+#define AXI_DAC_CNTRL_2_REG 0x0048
+#define AXI_DAC_CNTRL_2_SDR_DDR_N BIT(16)
+#define AXI_DAC_CNTRL_2_SYMB_8B BIT(14)
+#define ADI_DAC_CNTRL_2_R1_MODE BIT(5)
+#define AXI_DAC_CNTRL_2_UNSIGNED_DATA BIT(4)
+#define AXI_DAC_STATUS_1_REG 0x0054
+#define AXI_DAC_STATUS_2_REG 0x0058
+#define AXI_DAC_DRP_STATUS_REG 0x0074
+#define AXI_DAC_DRP_STATUS_DRP_LOCKED BIT(17)
+#define AXI_DAC_CUSTOM_RD_REG 0x0080
+#define AXI_DAC_CUSTOM_WR_REG 0x0084
+#define AXI_DAC_CUSTOM_WR_DATA_8 GENMASK(23, 16)
+#define AXI_DAC_CUSTOM_WR_DATA_16 GENMASK(23, 8)
+#define AXI_DAC_UI_STATUS_REG 0x0088
+#define AXI_DAC_UI_STATUS_IF_BUSY BIT(4)
+#define AXI_DAC_CUSTOM_CTRL_REG 0x008C
+#define AXI_DAC_CUSTOM_CTRL_ADDRESS GENMASK(31, 24)
+#define AXI_DAC_CUSTOM_CTRL_SYNCED_TRANSFER BIT(2)
+#define AXI_DAC_CUSTOM_CTRL_STREAM BIT(1)
+#define AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA BIT(0)
+
+#define AXI_DAC_CUSTOM_CTRL_STREAM_ENABLE (AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA | \
+ AXI_DAC_CUSTOM_CTRL_STREAM)
+
/* DAC Channel controls */
-#define AXI_DAC_REG_CHAN_CNTRL_1(c) (0x0400 + (c) * 0x40)
-#define AXI_DAC_REG_CHAN_CNTRL_3(c) (0x0408 + (c) * 0x40)
-#define AXI_DAC_SCALE_SIGN BIT(15)
-#define AXI_DAC_SCALE_INT BIT(14)
-#define AXI_DAC_SCALE GENMASK(14, 0)
-#define AXI_DAC_REG_CHAN_CNTRL_2(c) (0x0404 + (c) * 0x40)
-#define AXI_DAC_REG_CHAN_CNTRL_4(c) (0x040c + (c) * 0x40)
-#define AXI_DAC_PHASE GENMASK(31, 16)
-#define AXI_DAC_FREQUENCY GENMASK(15, 0)
-#define AXI_DAC_REG_CHAN_CNTRL_7(c) (0x0418 + (c) * 0x40)
-#define AXI_DAC_DATA_SEL GENMASK(3, 0)
+#define AXI_DAC_CHAN_CNTRL_1_REG(c) (0x0400 + (c) * 0x40)
+#define AXI_DAC_CHAN_CNTRL_3_REG(c) (0x0408 + (c) * 0x40)
+#define AXI_DAC_CHAN_CNTRL_3_SCALE_SIGN BIT(15)
+#define AXI_DAC_CHAN_CNTRL_3_SCALE_INT BIT(14)
+#define AXI_DAC_CHAN_CNTRL_3_SCALE GENMASK(14, 0)
+#define AXI_DAC_CHAN_CNTRL_2_REG(c) (0x0404 + (c) * 0x40)
+#define AXI_DAC_CHAN_CNTRL_2_PHASE GENMASK(31, 16)
+#define AXI_DAC_CHAN_CNTRL_2_FREQUENCY GENMASK(15, 0)
+#define AXI_DAC_CHAN_CNTRL_4_REG(c) (0x040c + (c) * 0x40)
+#define AXI_DAC_CHAN_CNTRL_7_REG(c) (0x0418 + (c) * 0x40)
+#define AXI_DAC_CHAN_CNTRL_7_DATA_SEL GENMASK(3, 0)
+
+#define AXI_DAC_RD_ADDR(x) (BIT(7) | (x))
/* 360 degrees in rad */
-#define AXI_DAC_2_PI_MEGA 6283190
+#define AXI_DAC_2_PI_MEGA 6283190
+
enum {
AXI_DAC_DATA_INTERNAL_TONE,
AXI_DAC_DATA_DMA = 2,
+ AXI_DAC_DATA_INTERNAL_RAMP_16BIT = 11,
+};
+
+struct axi_dac_info {
+ unsigned int version;
+ const struct iio_backend_info *backend_info;
+ bool has_dac_clk;
+ bool has_child_nodes;
};
struct axi_dac_state {
@@ -77,9 +110,11 @@ struct axi_dac_state {
* data/variables.
*/
struct mutex lock;
+ const struct axi_dac_info *info;
u64 dac_clk;
u32 reg_config;
bool int_tone;
+ int dac_clk_rate;
};
static int axi_dac_enable(struct iio_backend *back)
@@ -89,7 +124,7 @@ static int axi_dac_enable(struct iio_backend *back)
int ret;
guard(mutex)(&st->lock);
- ret = regmap_set_bits(st->regmap, AXI_DAC_REG_RSTN,
+ ret = regmap_set_bits(st->regmap, AXI_DAC_RSTN_REG,
AXI_DAC_RSTN_MMCM_RSTN);
if (ret)
return ret;
@@ -98,12 +133,14 @@ static int axi_dac_enable(struct iio_backend *back)
* designs really use it but if they don't we still get the lock bit
* set. So let's do it all the time so the code is generic.
*/
- ret = regmap_read_poll_timeout(st->regmap, AXI_DAC_DRP_STATUS, __val,
- __val & AXI_DAC_DRP_LOCKED, 100, 1000);
+ ret = regmap_read_poll_timeout(st->regmap, AXI_DAC_DRP_STATUS_REG,
+ __val,
+ __val & AXI_DAC_DRP_STATUS_DRP_LOCKED,
+ 100, 1000);
if (ret)
return ret;
- return regmap_set_bits(st->regmap, AXI_DAC_REG_RSTN,
+ return regmap_set_bits(st->regmap, AXI_DAC_RSTN_REG,
AXI_DAC_RSTN_RSTN | AXI_DAC_RSTN_MMCM_RSTN);
}
@@ -112,7 +149,7 @@ static void axi_dac_disable(struct iio_backend *back)
struct axi_dac_state *st = iio_backend_get_priv(back);
guard(mutex)(&st->lock);
- regmap_write(st->regmap, AXI_DAC_REG_RSTN, 0);
+ regmap_write(st->regmap, AXI_DAC_RSTN_REG, 0);
}
static struct iio_buffer *axi_dac_request_buffer(struct iio_backend *back,
@@ -155,15 +192,15 @@ static int __axi_dac_frequency_get(struct axi_dac_state *st, unsigned int chan,
}
if (tone_2)
- reg = AXI_DAC_REG_CHAN_CNTRL_4(chan);
+ reg = AXI_DAC_CHAN_CNTRL_4_REG(chan);
else
- reg = AXI_DAC_REG_CHAN_CNTRL_2(chan);
+ reg = AXI_DAC_CHAN_CNTRL_2_REG(chan);
ret = regmap_read(st->regmap, reg, &raw);
if (ret)
return ret;
- raw = FIELD_GET(AXI_DAC_FREQUENCY, raw);
+ raw = FIELD_GET(AXI_DAC_CHAN_CNTRL_2_FREQUENCY, raw);
*freq = DIV_ROUND_CLOSEST_ULL(raw * st->dac_clk, BIT(16));
return 0;
@@ -194,17 +231,18 @@ static int axi_dac_scale_get(struct axi_dac_state *st,
u32 reg, raw;
if (tone_2)
- reg = AXI_DAC_REG_CHAN_CNTRL_3(chan->channel);
+ reg = AXI_DAC_CHAN_CNTRL_3_REG(chan->channel);
else
- reg = AXI_DAC_REG_CHAN_CNTRL_1(chan->channel);
+ reg = AXI_DAC_CHAN_CNTRL_1_REG(chan->channel);
ret = regmap_read(st->regmap, reg, &raw);
if (ret)
return ret;
- sign = FIELD_GET(AXI_DAC_SCALE_SIGN, raw);
- raw = FIELD_GET(AXI_DAC_SCALE, raw);
- scale = DIV_ROUND_CLOSEST_ULL((u64)raw * MEGA, AXI_DAC_SCALE_INT);
+ sign = FIELD_GET(AXI_DAC_CHAN_CNTRL_3_SCALE_SIGN, raw);
+ raw = FIELD_GET(AXI_DAC_CHAN_CNTRL_3_SCALE, raw);
+ scale = DIV_ROUND_CLOSEST_ULL((u64)raw * MEGA,
+ AXI_DAC_CHAN_CNTRL_3_SCALE_INT);
vals[0] = scale / MEGA;
vals[1] = scale % MEGA;
@@ -227,15 +265,15 @@ static int axi_dac_phase_get(struct axi_dac_state *st,
int ret, vals[2];
if (tone_2)
- reg = AXI_DAC_REG_CHAN_CNTRL_4(chan->channel);
+ reg = AXI_DAC_CHAN_CNTRL_4_REG(chan->channel);
else
- reg = AXI_DAC_REG_CHAN_CNTRL_2(chan->channel);
+ reg = AXI_DAC_CHAN_CNTRL_2_REG(chan->channel);
ret = regmap_read(st->regmap, reg, &raw);
if (ret)
return ret;
- raw = FIELD_GET(AXI_DAC_PHASE, raw);
+ raw = FIELD_GET(AXI_DAC_CHAN_CNTRL_2_PHASE, raw);
phase = DIV_ROUND_CLOSEST_ULL((u64)raw * AXI_DAC_2_PI_MEGA, U16_MAX);
vals[0] = phase / MEGA;
@@ -260,18 +298,20 @@ static int __axi_dac_frequency_set(struct axi_dac_state *st, unsigned int chan,
}
if (tone_2)
- reg = AXI_DAC_REG_CHAN_CNTRL_4(chan);
+ reg = AXI_DAC_CHAN_CNTRL_4_REG(chan);
else
- reg = AXI_DAC_REG_CHAN_CNTRL_2(chan);
+ reg = AXI_DAC_CHAN_CNTRL_2_REG(chan);
raw = DIV64_U64_ROUND_CLOSEST((u64)freq * BIT(16), sample_rate);
- ret = regmap_update_bits(st->regmap, reg, AXI_DAC_FREQUENCY, raw);
+ ret = regmap_update_bits(st->regmap, reg,
+ AXI_DAC_CHAN_CNTRL_2_FREQUENCY, raw);
if (ret)
return ret;
/* synchronize channels */
- return regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC);
+ return regmap_set_bits(st->regmap, AXI_DAC_CNTRL_1_REG,
+ AXI_DAC_CNTRL_1_SYNC);
}
static int axi_dac_frequency_set(struct axi_dac_state *st,
@@ -312,16 +352,16 @@ static int axi_dac_scale_set(struct axi_dac_state *st,
/* format is 1.1.14 (sign, integer and fractional bits) */
if (scale < 0) {
- raw = FIELD_PREP(AXI_DAC_SCALE_SIGN, 1);
+ raw = FIELD_PREP(AXI_DAC_CHAN_CNTRL_3_SCALE_SIGN, 1);
scale *= -1;
}
- raw |= div_u64((u64)scale * AXI_DAC_SCALE_INT, MEGA);
+ raw |= div_u64((u64)scale * AXI_DAC_CHAN_CNTRL_3_SCALE_INT, MEGA);
if (tone_2)
- reg = AXI_DAC_REG_CHAN_CNTRL_3(chan->channel);
+ reg = AXI_DAC_CHAN_CNTRL_3_REG(chan->channel);
else
- reg = AXI_DAC_REG_CHAN_CNTRL_1(chan->channel);
+ reg = AXI_DAC_CHAN_CNTRL_1_REG(chan->channel);
guard(mutex)(&st->lock);
ret = regmap_write(st->regmap, reg, raw);
@@ -329,7 +369,8 @@ static int axi_dac_scale_set(struct axi_dac_state *st,
return ret;
/* synchronize channels */
- ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC);
+ ret = regmap_set_bits(st->regmap, AXI_DAC_CNTRL_1_REG,
+ AXI_DAC_CNTRL_1_SYNC);
if (ret)
return ret;
@@ -355,18 +396,19 @@ static int axi_dac_phase_set(struct axi_dac_state *st,
raw = DIV_ROUND_CLOSEST_ULL((u64)phase * U16_MAX, AXI_DAC_2_PI_MEGA);
if (tone_2)
- reg = AXI_DAC_REG_CHAN_CNTRL_4(chan->channel);
+ reg = AXI_DAC_CHAN_CNTRL_4_REG(chan->channel);
else
- reg = AXI_DAC_REG_CHAN_CNTRL_2(chan->channel);
+ reg = AXI_DAC_CHAN_CNTRL_2_REG(chan->channel);
guard(mutex)(&st->lock);
- ret = regmap_update_bits(st->regmap, reg, AXI_DAC_PHASE,
- FIELD_PREP(AXI_DAC_PHASE, raw));
+ ret = regmap_update_bits(st->regmap, reg, AXI_DAC_CHAN_CNTRL_2_PHASE,
+ FIELD_PREP(AXI_DAC_CHAN_CNTRL_2_PHASE, raw));
if (ret)
return ret;
/* synchronize channels */
- ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC);
+ ret = regmap_set_bits(st->regmap, AXI_DAC_CNTRL_1_REG,
+ AXI_DAC_CNTRL_1_SYNC);
if (ret)
return ret;
@@ -437,7 +479,7 @@ static int axi_dac_extend_chan(struct iio_backend *back,
if (chan->type != IIO_ALTVOLTAGE)
return -EINVAL;
- if (st->reg_config & AXI_DDS_DISABLE)
+ if (st->reg_config & AXI_DAC_CONFIG_DDS_DISABLE)
/* nothing to extend */
return 0;
@@ -454,13 +496,19 @@ static int axi_dac_data_source_set(struct iio_backend *back, unsigned int chan,
switch (data) {
case IIO_BACKEND_INTERNAL_CONTINUOUS_WAVE:
return regmap_update_bits(st->regmap,
- AXI_DAC_REG_CHAN_CNTRL_7(chan),
- AXI_DAC_DATA_SEL,
+ AXI_DAC_CHAN_CNTRL_7_REG(chan),
+ AXI_DAC_CHAN_CNTRL_7_DATA_SEL,
AXI_DAC_DATA_INTERNAL_TONE);
case IIO_BACKEND_EXTERNAL:
return regmap_update_bits(st->regmap,
- AXI_DAC_REG_CHAN_CNTRL_7(chan),
- AXI_DAC_DATA_SEL, AXI_DAC_DATA_DMA);
+ AXI_DAC_CHAN_CNTRL_7_REG(chan),
+ AXI_DAC_CHAN_CNTRL_7_DATA_SEL,
+ AXI_DAC_DATA_DMA);
+ case IIO_BACKEND_INTERNAL_RAMP_16BIT:
+ return regmap_update_bits(st->regmap,
+ AXI_DAC_CHAN_CNTRL_7_REG(chan),
+ AXI_DAC_CHAN_CNTRL_7_DATA_SEL,
+ AXI_DAC_DATA_INTERNAL_RAMP_16BIT);
default:
return -EINVAL;
}
@@ -475,7 +523,7 @@ static int axi_dac_set_sample_rate(struct iio_backend *back, unsigned int chan,
if (!sample_rate)
return -EINVAL;
- if (st->reg_config & AXI_DDS_DISABLE)
+ if (st->reg_config & AXI_DAC_CONFIG_DDS_DISABLE)
/* sample_rate has no meaning if DDS is disabled */
return 0;
@@ -518,6 +566,184 @@ static int axi_dac_reg_access(struct iio_backend *back, unsigned int reg,
return regmap_write(st->regmap, reg, writeval);
}
+static int axi_dac_ddr_enable(struct iio_backend *back)
+{
+ struct axi_dac_state *st = iio_backend_get_priv(back);
+
+ return regmap_clear_bits(st->regmap, AXI_DAC_CNTRL_2_REG,
+ AXI_DAC_CNTRL_2_SDR_DDR_N);
+}
+
+static int axi_dac_ddr_disable(struct iio_backend *back)
+{
+ struct axi_dac_state *st = iio_backend_get_priv(back);
+
+ return regmap_set_bits(st->regmap, AXI_DAC_CNTRL_2_REG,
+ AXI_DAC_CNTRL_2_SDR_DDR_N);
+}
+
+static int axi_dac_data_stream_enable(struct iio_backend *back)
+{
+ struct axi_dac_state *st = iio_backend_get_priv(back);
+
+ return regmap_set_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG,
+ AXI_DAC_CUSTOM_CTRL_STREAM_ENABLE);
+}
+
+static int axi_dac_data_stream_disable(struct iio_backend *back)
+{
+ struct axi_dac_state *st = iio_backend_get_priv(back);
+
+ return regmap_clear_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG,
+ AXI_DAC_CUSTOM_CTRL_STREAM_ENABLE);
+}
+
+static int axi_dac_data_transfer_addr(struct iio_backend *back, u32 address)
+{
+ struct axi_dac_state *st = iio_backend_get_priv(back);
+
+ if (address > FIELD_MAX(AXI_DAC_CUSTOM_CTRL_ADDRESS))
+ return -EINVAL;
+
+ /*
+ * Sample register address, when the DAC is configured, or stream
+ * start address when the FSM is in stream state.
+ */
+ return regmap_update_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG,
+ AXI_DAC_CUSTOM_CTRL_ADDRESS,
+ FIELD_PREP(AXI_DAC_CUSTOM_CTRL_ADDRESS,
+ address));
+}
+
+static int axi_dac_data_format_set(struct iio_backend *back, unsigned int ch,
+ const struct iio_backend_data_fmt *data)
+{
+ struct axi_dac_state *st = iio_backend_get_priv(back);
+
+ switch (data->type) {
+ case IIO_BACKEND_DATA_UNSIGNED:
+ return regmap_clear_bits(st->regmap, AXI_DAC_CNTRL_2_REG,
+ AXI_DAC_CNTRL_2_UNSIGNED_DATA);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int __axi_dac_bus_reg_write(struct iio_backend *back, u32 reg,
+ u32 val, size_t data_size)
+{
+ struct axi_dac_state *st = iio_backend_get_priv(back);
+ int ret;
+ u32 ival;
+
+ /*
+ * Both AXI_DAC_CNTRL_2_REG and AXI_DAC_CUSTOM_WR_REG need to know
+ * the data size. So keeping data size control here only,
+ * since data size is mandatory for the current transfer.
+ * DDR state handled separately by specific backend calls,
+ * generally all raw register writes are SDR.
+ */
+ if (data_size == sizeof(u16))
+ ival = FIELD_PREP(AXI_DAC_CUSTOM_WR_DATA_16, val);
+ else
+ ival = FIELD_PREP(AXI_DAC_CUSTOM_WR_DATA_8, val);
+
+ ret = regmap_write(st->regmap, AXI_DAC_CUSTOM_WR_REG, ival);
+ if (ret)
+ return ret;
+
+ if (data_size == sizeof(u8))
+ ret = regmap_set_bits(st->regmap, AXI_DAC_CNTRL_2_REG,
+ AXI_DAC_CNTRL_2_SYMB_8B);
+ else
+ ret = regmap_clear_bits(st->regmap, AXI_DAC_CNTRL_2_REG,
+ AXI_DAC_CNTRL_2_SYMB_8B);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG,
+ AXI_DAC_CUSTOM_CTRL_ADDRESS,
+ FIELD_PREP(AXI_DAC_CUSTOM_CTRL_ADDRESS, reg));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG,
+ AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA,
+ AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA);
+ if (ret)
+ return ret;
+
+ ret = regmap_read_poll_timeout(st->regmap,
+ AXI_DAC_UI_STATUS_REG, ival,
+ FIELD_GET(AXI_DAC_UI_STATUS_IF_BUSY, ival) == 0,
+ 10, 100 * KILO);
+ if (ret == -ETIMEDOUT)
+ dev_err(st->dev, "AXI read timeout\n");
+
+ /* Cleaning always AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA */
+ return regmap_clear_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG,
+ AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA);
+}
+
+static int axi_dac_bus_reg_write(struct iio_backend *back, u32 reg,
+ u32 val, size_t data_size)
+{
+ struct axi_dac_state *st = iio_backend_get_priv(back);
+
+ guard(mutex)(&st->lock);
+ return __axi_dac_bus_reg_write(back, reg, val, data_size);
+}
+
+static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg, u32 *val,
+ size_t data_size)
+{
+ struct axi_dac_state *st = iio_backend_get_priv(back);
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ /*
+ * SPI, we write with read flag, then we read just at the AXI
+ * io address space to get data read.
+ */
+ ret = __axi_dac_bus_reg_write(back, AXI_DAC_RD_ADDR(reg), 0,
+ data_size);
+ if (ret)
+ return ret;
+
+ return regmap_read(st->regmap, AXI_DAC_CUSTOM_RD_REG, val);
+}
+
+static void axi_dac_child_remove(void *data)
+{
+ platform_device_unregister(data);
+}
+
+static int axi_dac_create_platform_device(struct axi_dac_state *st,
+ struct fwnode_handle *child)
+{
+ struct ad3552r_hs_platform_data pdata = {
+ .bus_reg_read = axi_dac_bus_reg_read,
+ .bus_reg_write = axi_dac_bus_reg_write,
+ .bus_sample_data_clock_hz = st->dac_clk_rate,
+ };
+ struct platform_device_info pi = {
+ .parent = st->dev,
+ .name = fwnode_get_name(child),
+ .id = PLATFORM_DEVID_AUTO,
+ .fwnode = child,
+ .data = &pdata,
+ .size_data = sizeof(pdata),
+ };
+ struct platform_device *pdev;
+
+ pdev = platform_device_register_full(&pi);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ return devm_add_action_or_reset(st->dev, axi_dac_child_remove, pdev);
+}
+
static const struct iio_backend_ops axi_dac_generic_ops = {
.enable = axi_dac_enable,
.disable = axi_dac_disable,
@@ -531,11 +757,30 @@ static const struct iio_backend_ops axi_dac_generic_ops = {
.debugfs_reg_access = iio_backend_debugfs_ptr(axi_dac_reg_access),
};
+static const struct iio_backend_ops axi_ad3552r_ops = {
+ .enable = axi_dac_enable,
+ .disable = axi_dac_disable,
+ .request_buffer = axi_dac_request_buffer,
+ .free_buffer = axi_dac_free_buffer,
+ .data_source_set = axi_dac_data_source_set,
+ .ddr_enable = axi_dac_ddr_enable,
+ .ddr_disable = axi_dac_ddr_disable,
+ .data_stream_enable = axi_dac_data_stream_enable,
+ .data_stream_disable = axi_dac_data_stream_disable,
+ .data_format_set = axi_dac_data_format_set,
+ .data_transfer_addr = axi_dac_data_transfer_addr,
+};
+
static const struct iio_backend_info axi_dac_generic = {
.name = "axi-dac",
.ops = &axi_dac_generic_ops,
};
+static const struct iio_backend_info axi_ad3552r = {
+ .name = "axi-ad3552r",
+ .ops = &axi_ad3552r_ops,
+};
+
static const struct regmap_config axi_dac_regmap_config = {
.val_bits = 32,
.reg_bits = 32,
@@ -545,7 +790,6 @@ static const struct regmap_config axi_dac_regmap_config = {
static int axi_dac_probe(struct platform_device *pdev)
{
- const unsigned int *expected_ver;
struct axi_dac_state *st;
void __iomem *base;
unsigned int ver;
@@ -556,14 +800,29 @@ static int axi_dac_probe(struct platform_device *pdev)
if (!st)
return -ENOMEM;
- expected_ver = device_get_match_data(&pdev->dev);
- if (!expected_ver)
+ st->info = device_get_match_data(&pdev->dev);
+ if (!st->info)
return -ENODEV;
+ clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk");
+ if (IS_ERR(clk)) {
+ /* Backward compat., old fdt versions without clock-names. */
+ clk = devm_clk_get_enabled(&pdev->dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(clk),
+ "failed to get clock\n");
+ }
- clk = devm_clk_get_enabled(&pdev->dev, NULL);
- if (IS_ERR(clk))
- return dev_err_probe(&pdev->dev, PTR_ERR(clk),
- "failed to get clock\n");
+ if (st->info->has_dac_clk) {
+ struct clk *dac_clk;
+
+ dac_clk = devm_clk_get_enabled(&pdev->dev, "dac_clk");
+ if (IS_ERR(dac_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(dac_clk),
+ "failed to get dac_clk clock\n");
+
+ /* We only care about the streaming mode rate */
+ st->dac_clk_rate = clk_get_rate(dac_clk) / 2;
+ }
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
@@ -580,7 +839,7 @@ static int axi_dac_probe(struct platform_device *pdev)
* Force disable the core. Up to the frontend to enable us. And we can
* still read/write registers...
*/
- ret = regmap_write(st->regmap, AXI_DAC_REG_RSTN, 0);
+ ret = regmap_write(st->regmap, AXI_DAC_RSTN_REG, 0);
if (ret)
return ret;
@@ -588,12 +847,13 @@ static int axi_dac_probe(struct platform_device *pdev)
if (ret)
return ret;
- if (ADI_AXI_PCORE_VER_MAJOR(ver) != ADI_AXI_PCORE_VER_MAJOR(*expected_ver)) {
+ if (ADI_AXI_PCORE_VER_MAJOR(ver) !=
+ ADI_AXI_PCORE_VER_MAJOR(st->info->version)) {
dev_err(&pdev->dev,
"Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n",
- ADI_AXI_PCORE_VER_MAJOR(*expected_ver),
- ADI_AXI_PCORE_VER_MINOR(*expected_ver),
- ADI_AXI_PCORE_VER_PATCH(*expected_ver),
+ ADI_AXI_PCORE_VER_MAJOR(st->info->version),
+ ADI_AXI_PCORE_VER_MINOR(st->info->version),
+ ADI_AXI_PCORE_VER_PATCH(st->info->version),
ADI_AXI_PCORE_VER_MAJOR(ver),
ADI_AXI_PCORE_VER_MINOR(ver),
ADI_AXI_PCORE_VER_PATCH(ver));
@@ -601,7 +861,7 @@ static int axi_dac_probe(struct platform_device *pdev)
}
/* Let's get the core read only configuration */
- ret = regmap_read(st->regmap, AXI_DAC_REG_CONFIG, &st->reg_config);
+ ret = regmap_read(st->regmap, AXI_DAC_CONFIG_REG, &st->reg_config);
if (ret)
return ret;
@@ -613,16 +873,40 @@ static int axi_dac_probe(struct platform_device *pdev)
* want independent channels let's override the core's default value and
* set the R1_MODE bit.
*/
- ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_2, ADI_DAC_R1_MODE);
+ ret = regmap_set_bits(st->regmap, AXI_DAC_CNTRL_2_REG,
+ ADI_DAC_CNTRL_2_R1_MODE);
if (ret)
return ret;
mutex_init(&st->lock);
- ret = devm_iio_backend_register(&pdev->dev, &axi_dac_generic, st);
+
+ ret = devm_iio_backend_register(&pdev->dev, st->info->backend_info, st);
if (ret)
return dev_err_probe(&pdev->dev, ret,
"failed to register iio backend\n");
+ device_for_each_child_node_scoped(&pdev->dev, child) {
+ int val;
+
+ if (!st->info->has_child_nodes)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "invalid fdt axi-dac compatible.");
+
+ /* Processing only reg 0 node */
+ ret = fwnode_property_read_u32(child, "reg", &val);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "invalid reg property.");
+ if (val != 0)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "invalid node address.");
+
+ ret = axi_dac_create_platform_device(st, child);
+ if (ret)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "cannot create device.");
+ }
+
dev_info(&pdev->dev, "AXI DAC IP core (%d.%.2d.%c) probed\n",
ADI_AXI_PCORE_VER_MAJOR(ver),
ADI_AXI_PCORE_VER_MINOR(ver),
@@ -631,10 +915,21 @@ static int axi_dac_probe(struct platform_device *pdev)
return 0;
}
-static unsigned int axi_dac_9_1_b_info = ADI_AXI_PCORE_VER(9, 1, 'b');
+static const struct axi_dac_info dac_generic = {
+ .version = ADI_AXI_PCORE_VER(9, 1, 'b'),
+ .backend_info = &axi_dac_generic,
+};
+
+static const struct axi_dac_info dac_ad3552r = {
+ .version = ADI_AXI_PCORE_VER(9, 1, 'b'),
+ .backend_info = &axi_ad3552r,
+ .has_dac_clk = true,
+ .has_child_nodes = true,
+};
static const struct of_device_id axi_dac_of_match[] = {
- { .compatible = "adi,axi-dac-9.1.b", .data = &axi_dac_9_1_b_info },
+ { .compatible = "adi,axi-dac-9.1.b", .data = &dac_generic },
+ { .compatible = "adi,axi-ad3552r", .data = &dac_ad3552r },
{}
};
MODULE_DEVICE_TABLE(of, axi_dac_of_match);
@@ -651,5 +946,5 @@ module_platform_driver(axi_dac_driver);
MODULE_AUTHOR("Nuno Sa <[email protected]>");
MODULE_DESCRIPTION("Analog Devices Generic AXI DAC IP core driver");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(IIO_DMAENGINE_BUFFER);
-MODULE_IMPORT_NS(IIO_BACKEND);
+MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");
+MODULE_IMPORT_NS("IIO_BACKEND");
diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c
index 7332064d0852..f36f10bfb6be 100644
--- a/drivers/iio/dac/dpot-dac.c
+++ b/drivers/iio/dac/dpot-dac.c
@@ -243,7 +243,7 @@ MODULE_DEVICE_TABLE(of, dpot_dac_match);
static struct platform_driver dpot_dac_driver = {
.probe = dpot_dac_probe,
- .remove_new = dpot_dac_remove,
+ .remove = dpot_dac_remove,
.driver = {
.name = "iio-dpot-dac",
.of_match_table = dpot_dac_match,
diff --git a/drivers/iio/dac/lpc18xx_dac.c b/drivers/iio/dac/lpc18xx_dac.c
index b3aa4443a6a4..2332b0c22691 100644
--- a/drivers/iio/dac/lpc18xx_dac.c
+++ b/drivers/iio/dac/lpc18xx_dac.c
@@ -184,9 +184,9 @@ static const struct of_device_id lpc18xx_dac_match[] = {
MODULE_DEVICE_TABLE(of, lpc18xx_dac_match);
static struct platform_driver lpc18xx_dac_driver = {
- .probe = lpc18xx_dac_probe,
- .remove_new = lpc18xx_dac_remove,
- .driver = {
+ .probe = lpc18xx_dac_probe,
+ .remove = lpc18xx_dac_remove,
+ .driver = {
.name = "lpc18xx-dac",
.of_match_table = lpc18xx_dac_match,
},
diff --git a/drivers/iio/dac/m62332.c b/drivers/iio/dac/m62332.c
index ae53baccec91..3497513854d7 100644
--- a/drivers/iio/dac/m62332.c
+++ b/drivers/iio/dac/m62332.c
@@ -201,7 +201,7 @@ static int m62332_probe(struct i2c_client *client)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &m62332_info;
- ret = iio_map_array_register(indio_dev, client->dev.platform_data);
+ ret = iio_map_array_register(indio_dev, dev_get_platdata(&client->dev));
if (ret < 0)
return ret;
diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c
index 685980184d3c..84336736a47b 100644
--- a/drivers/iio/dac/max517.c
+++ b/drivers/iio/dac/max517.c
@@ -143,10 +143,10 @@ static const struct iio_chan_spec max517_channels[] = {
static int max517_probe(struct i2c_client *client)
{
+ const struct max517_platform_data *platform_data = dev_get_platdata(&client->dev);
const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct max517_data *data;
struct iio_dev *indio_dev;
- struct max517_platform_data *platform_data = client->dev.platform_data;
int chan;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c
index 2d567073996b..95ed5197d16f 100644
--- a/drivers/iio/dac/stm32-dac-core.c
+++ b/drivers/iio/dac/stm32-dac-core.c
@@ -245,7 +245,7 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
static struct platform_driver stm32_dac_driver = {
.probe = stm32_dac_probe,
- .remove_new = stm32_dac_remove,
+ .remove = stm32_dac_remove,
.driver = {
.name = "stm32-dac-core",
.of_match_table = stm32_dac_of_match,
diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c
index 5a722f307e7e..3bfb368b3a23 100644
--- a/drivers/iio/dac/stm32-dac.c
+++ b/drivers/iio/dac/stm32-dac.c
@@ -398,7 +398,7 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
static struct platform_driver stm32_dac_driver = {
.probe = stm32_dac_probe,
- .remove_new = stm32_dac_remove,
+ .remove = stm32_dac_remove,
.driver = {
.name = "stm32-dac",
.of_match_table = stm32_dac_of_match,
diff --git a/drivers/iio/dac/vf610_dac.c b/drivers/iio/dac/vf610_dac.c
index de73bc5a1c93..82a078fa98ad 100644
--- a/drivers/iio/dac/vf610_dac.c
+++ b/drivers/iio/dac/vf610_dac.c
@@ -272,7 +272,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_dac_pm_ops, vf610_dac_suspend,
static struct platform_driver vf610_dac_driver = {
.probe = vf610_dac_probe,
- .remove_new = vf610_dac_remove,
+ .remove = vf610_dac_remove,
.driver = {
.name = "vf610-dac",
.of_match_table = vf610_dac_match,