2021-12-13 14:08:25 +03:00
// 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 {
2023-08-03 22:56:23 +03:00
AD3542R_ID = 0x4009 ,
AD3552R_ID = 0x4008 ,
2021-12-13 14:08:25 +03:00
} ;
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 , & reg ) ;
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 ;
2022-03-16 15:23:54 +03:00
int val ;
2021-12-13 14:08:25 +03:00
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 ;
u32 val ;
int err ;
u8 addr ;
u16 reg = 0 , offset ;
2024-03-30 22:08:48 +03:00
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 " ) ;
2021-12-13 14:08:25 +03:00
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 ) ;
2024-03-30 22:08:48 +03:00
if ( err )
return dev_err_probe ( dev , err ,
" mandatory adi,gain-scaling-p property missing \n " ) ;
2021-12-13 14:08:25 +03:00
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 ) ;
2024-03-30 22:08:48 +03:00
if ( err )
return dev_err_probe ( dev , err ,
" mandatory adi,gain-scaling-n property missing \n " ) ;
2021-12-13 14:08:25 +03:00
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 ) ;
2024-03-30 22:08:48 +03:00
if ( err )
return dev_err_probe ( dev , err ,
" mandatory adi,rfb-ohms property missing \n " ) ;
2021-12-13 14:08:25 +03:00
dac - > ch_data [ ch ] . rfb = val ;
err = fwnode_property_read_u32 ( gain_child , " adi,gain-offset " , & val ) ;
2024-03-30 22:08:48 +03:00
if ( err )
return dev_err_probe ( dev , err ,
" mandatory adi,gain-offset property missing \n " ) ;
2021-12-13 14:08:25 +03:00
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 ) ;
2024-03-30 22:08:48 +03:00
if ( err )
return dev_err_probe ( dev , err , " Error writing register \n " ) ;
2021-12-13 14:08:25 +03:00
err = ad3552r_write_reg ( dac , addr , reg ) ;
2024-03-30 22:08:48 +03:00
if ( err )
return dev_err_probe ( dev , err , " Error writing register \n " ) ;
2021-12-13 14:08:25 +03:00
2024-03-30 22:08:48 +03:00
return 0 ;
2021-12-13 14:08:25 +03:00
}
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 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 ;
}
2024-03-30 21:53:04 +03:00
device_for_each_child_node_scoped ( dev , child ) {
2021-12-13 14:08:25 +03:00
err = fwnode_property_read_u32 ( child , " reg " , & ch ) ;
2024-03-30 21:53:04 +03:00
if ( err )
return dev_err_probe ( dev , err ,
" mandatory reg property missing \n " ) ;
if ( ch > = AD3552R_NUM_CH )
return dev_err_probe ( dev , - EINVAL ,
" reg must be less than %d \n " ,
AD3552R_NUM_CH ) ;
2021-12-13 14:08:25 +03:00
if ( fwnode_property_present ( child , " adi,output-range-microvolt " ) ) {
err = fwnode_property_read_u32_array ( child ,
" adi,output-range-microvolt " ,
vals ,
2 ) ;
2024-03-30 21:53:04 +03:00
if ( err )
return dev_err_probe ( dev , err ,
2021-12-13 14:08:25 +03:00
" adi,output-range-microvolt property could not be parsed \n " ) ;
err = ad3552r_find_range ( dac - > chip_id , vals ) ;
2024-03-30 21:53:04 +03:00
if ( err < 0 )
return dev_err_probe ( dev , err ,
" Invalid adi,output-range-microvolt value \n " ) ;
2021-12-13 14:08:25 +03:00
val = err ;
err = ad3552r_set_ch_value ( dac ,
AD3552R_CH_OUTPUT_RANGE_SEL ,
ch , val ) ;
if ( err )
2024-03-30 21:53:04 +03:00
return err ;
2021-12-13 14:08:25 +03:00
dac - > ch_data [ ch ] . range = val ;
} else if ( dac - > chip_id = = AD3542R_ID ) {
2024-03-30 21:53:04 +03:00
return dev_err_probe ( dev , - EINVAL ,
" adi,output-range-microvolt is required for ad3542r \n " ) ;
2021-12-13 14:08:25 +03:00
} else {
err = ad3552r_configure_custom_gain ( dac , child , ch ) ;
if ( err )
2024-03-30 21:53:04 +03:00
return err ;
2021-12-13 14:08:25 +03:00
}
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 )
2024-03-30 21:53:04 +03:00
return err ;
2021-12-13 14:08:25 +03:00
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 ;
}
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 " ) ;