Files
linux/drivers/iio/dac/ad3552r.c
Greg Kroah-Hartman a425990fa9 Merge tag 'iio-for-6.15a' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next
Jonathan writes:

IIO: New device support, features and cleanup for the 6.15 cycle.

The usual mixture of new drivers, support in existing drivers for new
devices, a range of features and general subsystem cleanup.

Two merges of immutable branches in here:
* SPI offload support. Culmination of a long effort to bring the ability
  to offload triggered sequences of SPI operations to specific hardware,
  allow high datarate acquisition over an SPI bus (if you have the right
  hardware / FPGA firmware)
* GPIO set-array-helper - enables code simplification.

New device support
==================

adi,ad3552r-hs:
- Add support for AD3541r and AD3542r via newly supported FPGA HDL.
adi,ad4030
- New driver supporting the AD4030, AD4630 AD4630-16, AD4640-24, AD4632-16,
  AD4632-24 1 and 2 channel high precision SPI ADCs.
adi,ad4851
- New driver and backend support for the AD4851, AD4852, AD4853, AD4854,
  AD4855, AD4846, AD4857, AD4858 and AD4858I high speed multichannel
  simultaneous sampling ADCs.
adi,ad7191
- New driver for this 24-bit ADC for precision bridge applications,
adi,ad7380
- Add support for the adaq4381-4 which is a 14-bit version of the
  already supported adaq4380-1
adi,adis16550
- New driver using the ADIS library (which needed extensions) for this
  IMU.
brcm,apds9160
- New driver for this proximity and ambient light sensor.
dynaimage,al3000a
- New driver for this illuminance sensor.
mcube,mc3230
- Add support for the mc3510c accelerometer with a different scale to existing
  supported parts (some rework preceded this)
nxp,imx93
- Add compatibles for imx94 and imx95 which are fully compatible with imx93.
rockchip,saradc
- Add support for the RK3528 ADC
- Add support for the RK3562 ADC
silab,si7210
- New driver to support this I2C Hall effect magnetic position sensor.
ti,ads7138
- New driver supporting the ADS7128 and AD7138 I2C ADCs.

Staging driver drop
===================

adi,adis16240
- Drop this impact sensor. Interesting part but complex hence never left
  staging due to ABI challenges. No longer readily available so drop driver.

New features
============

Documentation
- A really nice overview document introduce ADC terminology and how
  it maps to IIO.
core
- New description for FAULT events, used in the ad7173.
- filter_type ABI used in ad4130.
buffer-dmaengine
- Split DMA channel request from buffer allocation (for SPI offload)
- Add a new _with_handle setup variant. (for SPI offload)
adi,adf4371
- Add control of reference clock type and support for frequency doubling
  where appropriate.
adi,ad4695
- Support SPI offload.
- Support oversampling control.
adi,ad5791
- Support SPI offload.
adi,ad7124
- Add channel calibration support.
adi,ad7380:
- Alert support (threshold interrupts)
- SPI offload support.
adi,ad7606
- Support writing registers when using backend enabling software control
  of modes.
adi,ad7944
- Support SPI offload.
adi,ad9832
- Use devm_regulator_get_enable() to simplify code.
adi,ad9834
- Use devm_regulator_get_enable() to simplify code.
adi,adxl345
- Improve IRQ handling code.
- Add debug access to registers.
bosch,bmi270
- Add temperature channel support.
- Add data ready trigger.
google,cross_ec
- Add trace events.
mcube,mc3230
- Add mount matrix support
- Add an OF match table.

Cleanup and minor bug fixes
===========================

Tree wide:
- Stop using iio_device_claim_direct_scoped() and introduce sparse friendly
  iio_device_claim/release_direct()

  The conditional scoped cleanup has proved hard to deal with, requiring
  workarounds for various compiler issues and in is rather non-intuitive
  so abandon that experiment. One of the attractions of that approach was
  that it made it much harder to have unbalanced   claim/release bugs so
  instead introduce a conditional-lock style boolean returning new pair
  of functions. These are inline in the header and have __acquire and
  __release calls allowing sparse to detect lack of balance.  There are
  occasional false positives but so far those have reflected complex code
  paths that benefited from cleanup anyway.
  The first set of driver conversions are in this pull request, more to
  follow next cycle. Various related cleanup in drivers.
  Removal of the _scoped code is completed and the definition removed.
- Use of str_enable_disable() and similar helpers.
- Don't set regmap cache to REGCACHE_NONE as that's the default anyway.
- Change some caches from RBTREE to MAPLE reflecting best practice.
- Use the new gpiod_multi_set_value_cansleep()
- Make sure to grab direct mode for some calibrations paths.
- Avoid using memcmp on structures when checking for matching channel configs.
  Instead just match field by field.
dt-bindings:
- Fix up indentation inconsistencies.
gts-helper:
- Simplify building of available scale table.
adi,ad-sigma-delta
- Make sure to disable channel after calibration done.
- Add error handling in configuring channel during calibration.
adi,ad2s1201
- use a bitmap_write() rather than directly accessing underlying storage.
adi,ad3552r-hs
- Fix a wrong error message.
- Make sure to use instruction mode for configuration.
adi,ad4695
- Add a conversion to ensure exit from conversion mode.
- Use custom regmap to handle required sclk rate change.
- Fix an out of bounds array access
- Simplify oversampling ratio handling.
adi,ad4851
- Fix a sign bug.
adi,ad5791
- Fix wrong exported number of storage bits.
adi,ad7124
- Disable all channels at probe to avoid strange initial configurations.
adi,ad7173
- Rework to allow static const struct ad_sigma_delta without need
  to make a copy.
adi,ad7623
- Drop a BSD license tag that the authors consider unnecessary.
adi,ad7768-1
- Fix channels sign description exposed to user space.
- Set MOSI idle state to avoid accidental device reset.
- Avoid some overkill locking.
adi,axi-dac
- Check if device interface is busy when enabling data stream.
- Add control of bus mode.
bosch,bmi270
- Move a struct definition to a c file as only used there.
vishay,veml6030
- Enable regmap cache to reduce bus traffic.
- Fix ABI bug around scale reporting.
vishay,vem6075
- Check array bounds to harden against broken hardware.

Various other minor tweaks and fixes not called out.

*

* tag 'iio-for-6.15a' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (223 commits)
  doc: iio: ad7380: describe offload support
  iio: ad7380: add support for SPI offload
  iio: light: Add check for array bounds in veml6075_read_int_time_ms
  iio: adc: ti-ads7924 Drop unnecessary function parameters
  staging: iio: ad9834: Use devm_regulator_get_enable()
  staging: iio: ad9832: Use devm_regulator_get_enable()
  iio: gyro: bmg160_spi: add of_match_table
  dt-bindings: iio: adc: Add i.MX94 and i.MX95 support
  iio: adc: ad7768-1: remove unnecessary locking
  Documentation: ABI: add wideband filter type to sysfs-bus-iio
  iio: adc: ad7768-1: set MOSI idle state to prevent accidental reset
  iio: adc: ad7768-1: Fix conversion result sign
  iio: adc: ad7124: Benefit of dev = indio_dev->dev.parent in ad7124_parse_channel_config()
  iio: adc: ad7124: Implement system calibration
  iio: adc: ad7124: Implement internal calibration at probe time
  iio: adc: ad_sigma_delta: Add error checking for ad_sigma_delta_set_channel()
  iio: adc: ad4130: Adapt internal names to match official filter_type ABI
  iio: adc: ad7173: Fix comparison of channel configs
  iio: adc: ad7124: Fix comparison of channel configs
  iio: adc: ad4130: Fix comparison of channel setups
  ...
2025-03-14 07:15:12 +01:00

702 lines
17 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Analog Devices AD3552R
* Digital to Analog converter driver
*
* 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/spi/spi.h>
#include "ad3552r.h"
struct ad3552r_desc {
const struct ad3552r_model_data *model_data;
/* Used to look the spi bus for atomic operations where needed */
struct mutex lock;
struct gpio_desc *gpio_reset;
struct gpio_desc *gpio_ldac;
struct spi_device *spi;
struct ad3552r_ch_data ch_data[AD3552R_MAX_CH];
struct iio_chan_spec channels[AD3552R_MAX_CH + 1];
unsigned long enabled_ch;
unsigned int num_ch;
};
static u8 _ad3552r_reg_len(u8 addr)
{
switch (addr) {
case AD3552R_REG_ADDR_HW_LDAC_16B:
case AD3552R_REG_ADDR_CH_SELECT_16B:
case AD3552R_REG_ADDR_SW_LDAC_16B:
case AD3552R_REG_ADDR_HW_LDAC_24B:
case AD3552R_REG_ADDR_CH_SELECT_24B:
case AD3552R_REG_ADDR_SW_LDAC_24B:
return 1;
default:
break;
}
if (addr > AD3552R_REG_ADDR_HW_LDAC_24B)
return 3;
if (addr > AD3552R_REG_ADDR_HW_LDAC_16B)
return 2;
return 1;
}
/* SPI transfer to device */
static int ad3552r_transfer(struct ad3552r_desc *dac, u8 addr, u32 len,
u8 *data, bool is_read)
{
/* Maximum transfer: Addr (1B) + 2 * (Data Reg (3B)) + SW LDAC(1B) */
u8 buf[8];
buf[0] = addr & AD3552R_ADDR_MASK;
buf[0] |= is_read ? AD3552R_READ_BIT : 0;
if (is_read)
return spi_write_then_read(dac->spi, buf, 1, data, len);
memcpy(buf + 1, data, len);
return spi_write_then_read(dac->spi, buf, len + 1, NULL, 0);
}
static int ad3552r_write_reg(struct ad3552r_desc *dac, u8 addr, u16 val)
{
u8 reg_len;
u8 buf[AD3552R_MAX_REG_SIZE] = { 0 };
reg_len = _ad3552r_reg_len(addr);
if (reg_len == 2)
/* Only DAC register are 2 bytes wide */
val &= AD3552R_MASK_DAC_12B;
if (reg_len == 1)
buf[0] = val & 0xFF;
else
/* reg_len can be 2 or 3, but 3rd bytes needs to be set to 0 */
put_unaligned_be16(val, buf);
return ad3552r_transfer(dac, addr, reg_len, buf, false);
}
static int ad3552r_read_reg(struct ad3552r_desc *dac, u8 addr, u16 *val)
{
int err;
u8 reg_len, buf[AD3552R_MAX_REG_SIZE] = { 0 };
reg_len = _ad3552r_reg_len(addr);
err = ad3552r_transfer(dac, addr, reg_len, buf, true);
if (err)
return err;
if (reg_len == 1)
*val = buf[0];
else
/* reg_len can be 2 or 3, but only first 2 bytes are relevant */
*val = get_unaligned_be16(buf);
return 0;
}
/* 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)
{
int ret;
u16 reg;
ret = ad3552r_read_reg(dac, addr, &reg);
if (ret < 0)
return ret;
reg &= ~mask;
reg |= val;
return ad3552r_write_reg(dac, addr, reg);
}
#define AD3552R_CH_DAC(_idx) ((struct iio_chan_spec) { \
.type = IIO_VOLTAGE, \
.output = true, \
.indexed = true, \
.channel = _idx, \
.scan_index = _idx, \
.scan_type = { \
.sign = 'u', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_BE, \
}, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_ENABLE) | \
BIT(IIO_CHAN_INFO_OFFSET), \
})
static int ad3552r_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long mask)
{
struct ad3552r_desc *dac = iio_priv(indio_dev);
u16 tmp_val;
int err;
u8 ch = chan->channel;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&dac->lock);
err = ad3552r_read_reg(dac, AD3552R_REG_ADDR_CH_DAC_24B(ch),
&tmp_val);
mutex_unlock(&dac->lock);
if (err < 0)
return err;
*val = tmp_val;
return IIO_VAL_INT;
case IIO_CHAN_INFO_ENABLE:
mutex_lock(&dac->lock);
err = ad3552r_read_reg(dac, AD3552R_REG_ADDR_POWERDOWN_CONFIG,
&tmp_val);
mutex_unlock(&dac->lock);
if (err < 0)
return err;
*val = !((tmp_val & AD3552R_MASK_CH_DAC_POWERDOWN(ch)) >>
__ffs(AD3552R_MASK_CH_DAC_POWERDOWN(ch)));
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = dac->ch_data[ch].scale_int;
*val2 = dac->ch_data[ch].scale_dec;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OFFSET:
*val = dac->ch_data[ch].offset_int;
*val2 = dac->ch_data[ch].offset_dec;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static int ad3552r_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct ad3552r_desc *dac = iio_priv(indio_dev);
int err;
mutex_lock(&dac->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
err = ad3552r_write_reg(dac,
AD3552R_REG_ADDR_CH_DAC_24B(chan->channel),
val);
break;
case IIO_CHAN_INFO_ENABLE:
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;
break;
}
mutex_unlock(&dac->lock);
return err;
}
static const struct iio_info ad3552r_iio_info = {
.read_raw = ad3552r_read_raw,
.write_raw = ad3552r_write_raw
};
static int32_t ad3552r_trigger_hw_ldac(struct gpio_desc *ldac)
{
gpiod_set_value_cansleep(ldac, 0);
usleep_range(AD3552R_LDAC_PULSE_US, AD3552R_LDAC_PULSE_US + 10);
gpiod_set_value_cansleep(ldac, 1);
return 0;
}
static int ad3552r_write_all_channels(struct ad3552r_desc *dac, u8 *data)
{
int err, len;
u8 addr, buff[AD3552R_MAX_CH * AD3552R_MAX_REG_SIZE + 1];
addr = AD3552R_REG_ADDR_CH_INPUT_24B(1);
/* CH1 */
memcpy(buff, data + 2, 2);
buff[2] = 0;
/* CH0 */
memcpy(buff + 3, data, 2);
buff[5] = 0;
len = 6;
if (!dac->gpio_ldac) {
/* Software LDAC */
buff[6] = AD3552R_MASK_ALL_CH;
++len;
}
err = ad3552r_transfer(dac, addr, len, buff, false);
if (err)
return err;
if (dac->gpio_ldac)
return ad3552r_trigger_hw_ldac(dac->gpio_ldac);
return 0;
}
static int ad3552r_write_codes(struct ad3552r_desc *dac, u32 mask, u8 *data)
{
int err;
u8 addr, buff[AD3552R_MAX_REG_SIZE];
if (mask == AD3552R_MASK_ALL_CH) {
if (memcmp(data, data + 2, 2) != 0)
return ad3552r_write_all_channels(dac, data);
addr = AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B;
} else {
addr = AD3552R_REG_ADDR_CH_INPUT_24B(__ffs(mask));
}
memcpy(buff, data, 2);
buff[2] = 0;
err = ad3552r_transfer(dac, addr, 3, data, false);
if (err)
return err;
if (dac->gpio_ldac)
return ad3552r_trigger_hw_ldac(dac->gpio_ldac);
return ad3552r_write_reg(dac, AD3552R_REG_ADDR_SW_LDAC_24B, mask);
}
static irqreturn_t ad3552r_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct iio_buffer *buf = indio_dev->buffer;
struct ad3552r_desc *dac = iio_priv(indio_dev);
/* Maximum size of a scan */
u8 buff[AD3552R_MAX_CH * AD3552R_MAX_REG_SIZE];
int err;
memset(buff, 0, sizeof(buff));
err = iio_pop_from_buffer(buf, buff);
if (err)
goto end;
mutex_lock(&dac->lock);
ad3552r_write_codes(dac, *indio_dev->active_scan_mask, buff);
mutex_unlock(&dac->lock);
end:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ad3552r_check_scratch_pad(struct ad3552r_desc *dac)
{
const u16 val1 = AD3552R_SCRATCH_PAD_TEST_VAL1;
const u16 val2 = AD3552R_SCRATCH_PAD_TEST_VAL2;
u16 val;
int err;
err = ad3552r_write_reg(dac, AD3552R_REG_ADDR_SCRATCH_PAD, val1);
if (err < 0)
return err;
err = ad3552r_read_reg(dac, AD3552R_REG_ADDR_SCRATCH_PAD, &val);
if (err < 0)
return err;
if (val1 != val)
return -ENODEV;
err = ad3552r_write_reg(dac, AD3552R_REG_ADDR_SCRATCH_PAD, val2);
if (err < 0)
return err;
err = ad3552r_read_reg(dac, AD3552R_REG_ADDR_SCRATCH_PAD, &val);
if (err < 0)
return err;
if (val2 != val)
return -ENODEV;
return 0;
}
struct reg_addr_pool {
struct ad3552r_desc *dac;
u8 addr;
};
static int ad3552r_read_reg_wrapper(struct reg_addr_pool *addr)
{
int err;
u16 val;
err = ad3552r_read_reg(addr->dac, addr->addr, &val);
if (err)
return err;
return val;
}
static int ad3552r_reset(struct ad3552r_desc *dac)
{
struct reg_addr_pool addr;
int ret;
int val;
dac->gpio_reset = devm_gpiod_get_optional(&dac->spi->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(dac->gpio_reset))
return dev_err_probe(&dac->spi->dev, PTR_ERR(dac->gpio_reset),
"Error while getting gpio reset");
if (dac->gpio_reset) {
/* Perform hardware reset */
usleep_range(10, 20);
gpiod_set_value_cansleep(dac->gpio_reset, 1);
} else {
/* Perform software reset if no GPIO provided */
ret = ad3552r_update_reg_field(dac,
AD3552R_REG_ADDR_INTERFACE_CONFIG_A,
AD3552R_MASK_SOFTWARE_RESET,
AD3552R_MASK_SOFTWARE_RESET);
if (ret < 0)
return ret;
}
addr.dac = dac;
addr.addr = AD3552R_REG_ADDR_INTERFACE_CONFIG_B;
ret = readx_poll_timeout(ad3552r_read_reg_wrapper, &addr, val,
val == AD3552R_DEFAULT_CONFIG_B_VALUE ||
val < 0,
5000, 50000);
if (val < 0)
ret = val;
if (ret) {
dev_err(&dac->spi->dev, "Error while resetting");
return ret;
}
ret = readx_poll_timeout(ad3552r_read_reg_wrapper, &addr, val,
!(val & AD3552R_MASK_INTERFACE_NOT_READY) ||
val < 0,
5000, 50000);
if (val < 0)
ret = val;
if (ret) {
dev_err(&dac->spi->dev, "Error while resetting");
return ret;
}
/* Clear reset error flag, see ad3552r manual, rev B table 38. */
ret = ad3552r_write_reg(dac, AD3552R_REG_ADDR_ERR_STATUS,
AD3552R_MASK_RESET_STATUS);
if (ret)
return ret;
return ad3552r_update_reg_field(dac,
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,
struct fwnode_handle *child,
u32 ch)
{
struct device *dev = &dac->spi->dev;
int err;
u8 addr;
u16 reg;
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 err;
dac->ch_data[ch].range_override = 1;
addr = AD3552R_REG_ADDR_CH_GAIN(ch);
err = ad3552r_write_reg(dac, addr,
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");
return 0;
}
static int ad3552r_configure_device(struct ad3552r_desc *dac)
{
struct device *dev = &dac->spi->dev;
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");
err = ad3552r_get_ref_voltage(dev, &val);
if (err < 0)
return err;
err = ad3552r_update_reg_field(dac,
AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
AD3552R_MASK_REFERENCE_VOLTAGE_SEL,
FIELD_PREP(AD3552R_MASK_REFERENCE_VOLTAGE_SEL, val));
if (err)
return err;
err = ad3552r_get_drive_strength(dev, &val);
if (!err) {
err = ad3552r_update_reg_field(dac,
AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
AD3552R_MASK_SDO_DRIVE_STRENGTH,
FIELD_PREP(AD3552R_MASK_SDO_DRIVE_STRENGTH, val));
if (err)
return err;
}
dac->num_ch = device_get_child_node_count(dev);
if (!dac->num_ch) {
dev_err(dev, "No channels defined\n");
return -ENODEV;
}
device_for_each_child_node_scoped(dev, child) {
err = fwnode_property_read_u32(child, "reg", &ch);
if (err)
return dev_err_probe(dev, err,
"mandatory reg property missing\n");
if (ch >= dac->model_data->num_hw_channels)
return dev_err_probe(dev, -EINVAL,
"reg must be less than %d\n",
dac->model_data->num_hw_channels);
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;
dac->ch_data[ch].range = val;
} else if (dac->model_data->requires_output_range) {
return dev_err_probe(dev, -EINVAL,
"adi,output-range-microvolt is required for %s\n",
dac->model_data->model_name);
} else {
err = ad3552r_configure_custom_gain(dac, child, ch);
if (err)
return err;
}
ad3552r_calc_gain_and_offset(&dac->ch_data[ch], dac->model_data);
dac->enabled_ch |= BIT(ch);
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;
dac->channels[cnt] = AD3552R_CH_DAC(ch);
++cnt;
}
/* Disable unused channels */
for_each_clear_bit(ch, &dac->enabled_ch,
dac->model_data->num_hw_channels) {
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;
}
dac->num_ch = cnt;
return 0;
}
static int ad3552r_init(struct ad3552r_desc *dac)
{
int err;
u16 val, id;
err = ad3552r_reset(dac);
if (err) {
dev_err(&dac->spi->dev, "Reset failed\n");
return err;
}
err = ad3552r_check_scratch_pad(dac);
if (err) {
dev_err(&dac->spi->dev, "Scratch pad test failed\n");
return err;
}
err = ad3552r_read_reg(dac, AD3552R_REG_ADDR_PRODUCT_ID_L, &val);
if (err) {
dev_err(&dac->spi->dev, "Fail read PRODUCT_ID_L\n");
return err;
}
id = val;
err = ad3552r_read_reg(dac, AD3552R_REG_ADDR_PRODUCT_ID_H, &val);
if (err) {
dev_err(&dac->spi->dev, "Fail read PRODUCT_ID_H\n");
return err;
}
id |= val << 8;
if (id != dac->model_data->chip_id) {
dev_err(&dac->spi->dev, "Product id not matching\n");
return -ENODEV;
}
return ad3552r_configure_device(dac);
}
static int ad3552r_probe(struct spi_device *spi)
{
struct ad3552r_desc *dac;
struct iio_dev *indio_dev;
int err;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*dac));
if (!indio_dev)
return -ENOMEM;
dac = iio_priv(indio_dev);
dac->spi = spi;
dac->model_data = spi_get_device_match_data(spi);
if (!dac->model_data)
return -EINVAL;
mutex_init(&dac->lock);
err = ad3552r_init(dac);
if (err)
return err;
/* Config triggered buffer device */
indio_dev->name = dac->model_data->model_name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &ad3552r_iio_info;
indio_dev->num_channels = dac->num_ch;
indio_dev->channels = dac->channels;
indio_dev->modes = INDIO_DIRECT_MODE;
err = devm_iio_triggered_buffer_setup_ext(&indio_dev->dev, indio_dev, NULL,
&ad3552r_trigger_handler,
IIO_BUFFER_DIRECTION_OUT,
NULL,
NULL);
if (err)
return err;
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad3552r_id[] = {
{
.name = "ad3541r",
.driver_data = (kernel_ulong_t)&ad3541r_model_data
},
{
.name = "ad3542r",
.driver_data = (kernel_ulong_t)&ad3542r_model_data
},
{
.name = "ad3551r",
.driver_data = (kernel_ulong_t)&ad3551r_model_data
},
{
.name = "ad3552r",
.driver_data = (kernel_ulong_t)&ad3552r_model_data
},
{ }
};
MODULE_DEVICE_TABLE(spi, ad3552r_id);
static const struct of_device_id ad3552r_of_match[] = {
{ .compatible = "adi,ad3541r", .data = &ad3541r_model_data },
{ .compatible = "adi,ad3542r", .data = &ad3542r_model_data },
{ .compatible = "adi,ad3551r", .data = &ad3551r_model_data },
{ .compatible = "adi,ad3552r", .data = &ad3552r_model_data },
{ }
};
MODULE_DEVICE_TABLE(of, ad3552r_of_match);
static struct spi_driver ad3552r_driver = {
.driver = {
.name = "ad3552r",
.of_match_table = ad3552r_of_match,
},
.probe = ad3552r_probe,
.id_table = ad3552r_id
};
module_spi_driver(ad3552r_driver);
MODULE_AUTHOR("Mihail Chindris <mihail.chindris@analog.com>");
MODULE_DESCRIPTION("Analog Device AD3552R DAC");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS("IIO_AD3552R");