Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Mihail Chindris | 4813 | 99.92% | 1 | 33.33% |
Dan Carpenter | 4 | 0.08% | 2 | 66.67% |
Total | 4817 | 3 |
// SPDX-License-Identifier: GPL-2.0-only /* * Analog Devices AD3552R * Digital to Analog converter driver * * Copyright 2021 Analog Devices Inc. */ #include <asm/unaligned.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_NUM_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 ad3542r_id { AD3542R_ID = 0x4008, AD3552R_ID = 0x4009, }; 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_desc { /* 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_NUM_CH]; struct iio_chan_spec channels[AD3552R_NUM_CH + 1]; unsigned long enabled_ch; unsigned int num_ch; enum ad3542r_id chip_id; }; 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) { 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; } 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) { int ret; u16 reg; ret = ad3552r_read_reg(dac, addr, ®); if (ret < 0) return ret; reg &= ~mask; reg |= ad3552r_field_prep(val, mask); 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, \ .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: err = ad3552r_set_ch_value(dac, AD3552R_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_NUM_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_NUM_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; } 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; if (dac->chip_id == AD3542R_ID) { v_min = ad3542r_ch_ranges[idx][0]; v_max = ad3542r_ch_ranges[idx][1]; } else { v_min = ad3552r_ch_ranges[idx][0]; v_max = ad3552r_ch_ranges[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(u16 id, s32 *vals) { int i, len; const s32 (*ranges)[2]; if (id == AD3542R_ID) { len = ARRAY_SIZE(ad3542r_ch_ranges); ranges = ad3542r_ch_ranges; } else { len = ARRAY_SIZE(ad3552r_ch_ranges); ranges = ad3552r_ch_ranges; } for (i = 0; i < len; i++) if (vals[0] == ranges[i][0] * 1000 && vals[1] == ranges[i][1] * 1000) return i; return -EINVAL; } static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac, struct fwnode_handle *child, u32 ch) { struct device *dev = &dac->spi->dev; struct fwnode_handle *gain_child; u32 val; int err; u8 addr; u16 reg = 0, offset; gain_child = fwnode_get_named_child_node(child, "custom-output-range-config"); if (!gain_child) { dev_err(dev, "mandatory custom-output-range-config property missing\n"); return -EINVAL; } 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) { dev_err(dev, "mandatory adi,gain-scaling-p property missing\n"); goto put_child; } 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) { dev_err(dev, "mandatory adi,gain-scaling-n property missing\n"); goto put_child; } 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) { dev_err(dev, "mandatory adi,rfb-ohms property missing\n"); goto put_child; } dac->ch_data[ch].rfb = val; err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val); if (err) { dev_err(dev, "mandatory adi,gain-offset property missing\n"); goto put_child; } dac->ch_data[ch].gain_offset = val; offset = abs((s32)val); reg |= ad3552r_field_prep((offset >> 8), AD3552R_MASK_CH_OFFSET_BIT_8); 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); if (err) { dev_err(dev, "Error writing register\n"); goto put_child; } err = ad3552r_write_reg(dac, addr, reg); if (err) { dev_err(dev, "Error writing register\n"); goto put_child; } put_child: fwnode_handle_put(gain_child); return err; } static void ad3552r_reg_disable(void *reg) { regulator_disable(reg); } static int ad3552r_configure_device(struct ad3552r_desc *dac) { struct device *dev = &dac->spi->dev; struct fwnode_handle *child; struct regulator *vref; int err, cnt = 0, voltage, delta = 100000; u32 vals[2], 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"); vref = devm_regulator_get_optional(dev, "vref"); if (IS_ERR(vref)) { if (PTR_ERR(vref) != -ENODEV) return dev_err_probe(dev, PTR_ERR(vref), "Error getting vref"); if (device_property_read_bool(dev, "adi,vref-out-en")) val = AD3552R_INTERNAL_VREF_PIN_2P5V; else val = AD3552R_INTERNAL_VREF_PIN_FLOATING; } else { err = regulator_enable(vref); if (err) { dev_err(dev, "Failed to enable external vref supply\n"); return err; } err = devm_add_action_or_reset(dev, ad3552r_reg_disable, vref); if (err) { regulator_disable(vref); return err; } voltage = regulator_get_voltage(vref); 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_update_reg_field(dac, addr_mask_map[AD3552R_VREF_SELECT][0], addr_mask_map[AD3552R_VREF_SELECT][1], val); if (err) return err; err = device_property_read_u32(dev, "adi,sdo-drive-strength", &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); 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(dev, child) { err = fwnode_property_read_u32(child, "reg", &ch); if (err) { dev_err(dev, "mandatory reg property missing\n"); goto put_child; } if (ch >= AD3552R_NUM_CH) { dev_err(dev, "reg must be less than %d\n", AD3552R_NUM_CH); err = -EINVAL; goto put_child; } if (fwnode_property_present(child, "adi,output-range-microvolt")) { err = fwnode_property_read_u32_array(child, "adi,output-range-microvolt", vals, 2); if (err) { dev_err(dev, "adi,output-range-microvolt property could not be parsed\n"); goto put_child; } err = ad3552r_find_range(dac->chip_id, vals); if (err < 0) { dev_err(dev, "Invalid adi,output-range-microvolt value\n"); goto put_child; } val = err; err = ad3552r_set_ch_value(dac, AD3552R_CH_OUTPUT_RANGE_SEL, ch, val); if (err) goto put_child; dac->ch_data[ch].range = val; } else if (dac->chip_id == AD3542R_ID) { dev_err(dev, "adi,output-range-microvolt is required for ad3542r\n"); err = -EINVAL; goto put_child; } else { err = ad3552r_configure_custom_gain(dac, child, ch); if (err) goto put_child; } ad3552r_calc_gain_and_offset(dac, ch); dac->enabled_ch |= BIT(ch); err = ad3552r_set_ch_value(dac, AD3552R_CH_SELECT, ch, 1); if (err < 0) goto put_child; dac->channels[cnt] = AD3552R_CH_DAC(ch); ++cnt; } /* Disable unused channels */ for_each_clear_bit(ch, &dac->enabled_ch, AD3552R_NUM_CH) { err = ad3552r_set_ch_value(dac, AD3552R_CH_AMPLIFIER_POWERDOWN, ch, 1); if (err) return err; } dac->num_ch = cnt; return 0; put_child: fwnode_handle_put(child); return err; } 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->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) { const struct spi_device_id *id = spi_get_device_id(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->chip_id = id->driver_data; mutex_init(&dac->lock); err = ad3552r_init(dac); if (err) return err; /* Config triggered buffer device */ if (dac->chip_id == AD3552R_ID) indio_dev->name = "ad3552r"; else indio_dev->name = "ad3542r"; 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[] = { { "ad3542r", AD3542R_ID }, { "ad3552r", AD3552R_ID }, { } }; MODULE_DEVICE_TABLE(spi, ad3552r_id); static const struct of_device_id ad3552r_of_match[] = { { .compatible = "adi,ad3542r"}, { .compatible = "adi,ad3552r"}, { } }; 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");
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1