2019-05-28 19:57:06 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2012-09-17 13:24:00 +04:00
/*
* AD5755 , AD5755 - 1 , AD5757 , AD5735 , AD5737 Digital to analog converters driver
*
* Copyright 2012 Analog Devices Inc .
*/
# include <linux/device.h>
# include <linux/err.h>
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/spi/spi.h>
# include <linux/slab.h>
# include <linux/sysfs.h>
# include <linux/delay.h>
2021-12-05 20:01:29 +03:00
# include <linux/property.h>
2012-09-17 13:24:00 +04:00
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
# define AD5755_NUM_CHANNELS 4
# define AD5755_ADDR(x) ((x) << 16)
# define AD5755_WRITE_REG_DATA(chan) (chan)
# define AD5755_WRITE_REG_GAIN(chan) (0x08 | (chan))
# define AD5755_WRITE_REG_OFFSET(chan) (0x10 | (chan))
# define AD5755_WRITE_REG_CTRL(chan) (0x1c | (chan))
# define AD5755_READ_REG_DATA(chan) (chan)
# define AD5755_READ_REG_CTRL(chan) (0x4 | (chan))
# define AD5755_READ_REG_GAIN(chan) (0x8 | (chan))
# define AD5755_READ_REG_OFFSET(chan) (0xc | (chan))
# define AD5755_READ_REG_CLEAR(chan) (0x10 | (chan))
# define AD5755_READ_REG_SLEW(chan) (0x14 | (chan))
# define AD5755_READ_REG_STATUS 0x18
# define AD5755_READ_REG_MAIN 0x19
# define AD5755_READ_REG_DC_DC 0x1a
# define AD5755_CTRL_REG_SLEW 0x0
# define AD5755_CTRL_REG_MAIN 0x1
# define AD5755_CTRL_REG_DAC 0x2
# define AD5755_CTRL_REG_DC_DC 0x3
# define AD5755_CTRL_REG_SW 0x4
# define AD5755_READ_FLAG 0x800000
# define AD5755_NOOP 0x1CE000
# define AD5755_DAC_INT_EN BIT(8)
# define AD5755_DAC_CLR_EN BIT(7)
# define AD5755_DAC_OUT_EN BIT(6)
# define AD5755_DAC_INT_CURRENT_SENSE_RESISTOR BIT(5)
# define AD5755_DAC_DC_DC_EN BIT(4)
# define AD5755_DAC_VOLTAGE_OVERRANGE_EN BIT(3)
# define AD5755_DC_DC_MAXV 0
# define AD5755_DC_DC_FREQ_SHIFT 2
# define AD5755_DC_DC_PHASE_SHIFT 4
# define AD5755_EXT_DC_DC_COMP_RES BIT(6)
# define AD5755_SLEW_STEP_SIZE_SHIFT 0
# define AD5755_SLEW_RATE_SHIFT 3
# define AD5755_SLEW_ENABLE BIT(12)
2021-12-05 20:01:29 +03:00
enum ad5755_mode {
AD5755_MODE_VOLTAGE_0V_5V = 0 ,
AD5755_MODE_VOLTAGE_0V_10V = 1 ,
AD5755_MODE_VOLTAGE_PLUSMINUS_5V = 2 ,
AD5755_MODE_VOLTAGE_PLUSMINUS_10V = 3 ,
AD5755_MODE_CURRENT_4mA_20mA = 4 ,
AD5755_MODE_CURRENT_0mA_20mA = 5 ,
AD5755_MODE_CURRENT_0mA_24mA = 6 ,
} ;
enum ad5755_dc_dc_phase {
AD5755_DC_DC_PHASE_ALL_SAME_EDGE = 0 ,
AD5755_DC_DC_PHASE_A_B_SAME_EDGE_C_D_OPP_EDGE = 1 ,
AD5755_DC_DC_PHASE_A_C_SAME_EDGE_B_D_OPP_EDGE = 2 ,
AD5755_DC_DC_PHASE_90_DEGREE = 3 ,
} ;
enum ad5755_dc_dc_freq {
AD5755_DC_DC_FREQ_250kHZ = 0 ,
AD5755_DC_DC_FREQ_410kHZ = 1 ,
AD5755_DC_DC_FREQ_650kHZ = 2 ,
} ;
enum ad5755_dc_dc_maxv {
AD5755_DC_DC_MAXV_23V = 0 ,
AD5755_DC_DC_MAXV_24V5 = 1 ,
AD5755_DC_DC_MAXV_27V = 2 ,
AD5755_DC_DC_MAXV_29V5 = 3 ,
} ;
enum ad5755_slew_rate {
AD5755_SLEW_RATE_64k = 0 ,
AD5755_SLEW_RATE_32k = 1 ,
AD5755_SLEW_RATE_16k = 2 ,
AD5755_SLEW_RATE_8k = 3 ,
AD5755_SLEW_RATE_4k = 4 ,
AD5755_SLEW_RATE_2k = 5 ,
AD5755_SLEW_RATE_1k = 6 ,
AD5755_SLEW_RATE_500 = 7 ,
AD5755_SLEW_RATE_250 = 8 ,
AD5755_SLEW_RATE_125 = 9 ,
AD5755_SLEW_RATE_64 = 10 ,
AD5755_SLEW_RATE_32 = 11 ,
AD5755_SLEW_RATE_16 = 12 ,
AD5755_SLEW_RATE_8 = 13 ,
AD5755_SLEW_RATE_4 = 14 ,
AD5755_SLEW_RATE_0_5 = 15 ,
} ;
enum ad5755_slew_step_size {
AD5755_SLEW_STEP_SIZE_1 = 0 ,
AD5755_SLEW_STEP_SIZE_2 = 1 ,
AD5755_SLEW_STEP_SIZE_4 = 2 ,
AD5755_SLEW_STEP_SIZE_8 = 3 ,
AD5755_SLEW_STEP_SIZE_16 = 4 ,
AD5755_SLEW_STEP_SIZE_32 = 5 ,
AD5755_SLEW_STEP_SIZE_64 = 6 ,
AD5755_SLEW_STEP_SIZE_128 = 7 ,
AD5755_SLEW_STEP_SIZE_256 = 8 ,
} ;
/**
* struct ad5755_platform_data - AD5755 DAC driver platform data
* @ ext_dc_dc_compenstation_resistor : Whether an external DC - DC converter
* compensation register is used .
* @ dc_dc_phase : DC - DC converter phase .
* @ dc_dc_freq : DC - DC converter frequency .
* @ dc_dc_maxv : DC - DC maximum allowed boost voltage .
* @ dac : Per DAC instance parameters .
* @ dac . mode : The mode to be used for the DAC output .
* @ dac . ext_current_sense_resistor : Whether an external current sense resistor
* is used .
* @ dac . enable_voltage_overrange : Whether to enable 20 % voltage output overrange .
* @ dac . slew . enable : Whether to enable digital slew .
* @ dac . slew . rate : Slew rate of the digital slew .
* @ dac . slew . step_size : Slew step size of the digital slew .
* */
struct ad5755_platform_data {
bool ext_dc_dc_compenstation_resistor ;
enum ad5755_dc_dc_phase dc_dc_phase ;
enum ad5755_dc_dc_freq dc_dc_freq ;
enum ad5755_dc_dc_maxv dc_dc_maxv ;
struct {
enum ad5755_mode mode ;
bool ext_current_sense_resistor ;
bool enable_voltage_overrange ;
struct {
bool enable ;
enum ad5755_slew_rate rate ;
enum ad5755_slew_step_size step_size ;
} slew ;
} dac [ 4 ] ;
} ;
2012-09-17 13:24:00 +04:00
/**
* struct ad5755_chip_info - chip specific information
* @ channel_template : channel specification
* @ calib_shift : shift for the calibration data registers
* @ has_voltage_out : whether the chip has voltage outputs
*/
struct ad5755_chip_info {
const struct iio_chan_spec channel_template ;
unsigned int calib_shift ;
bool has_voltage_out ;
} ;
/**
* struct ad5755_state - driver instance specific data
* @ spi : spi device the driver is attached to
* @ chip_info : chip model specific constants , available modes etc
* @ pwr_down : bitmask which contains hether a channel is powered down or not
* @ ctrl : software shadow of the channel ctrl registers
* @ channels : iio channel spec for the device
2020-07-16 16:59:20 +03:00
* @ lock : lock to protect the data buffer during SPI ops
2012-09-17 13:24:00 +04:00
* @ data : spi transfer buffers
*/
struct ad5755_state {
struct spi_device * spi ;
const struct ad5755_chip_info * chip_info ;
unsigned int pwr_down ;
unsigned int ctrl [ AD5755_NUM_CHANNELS ] ;
struct iio_chan_spec channels [ AD5755_NUM_CHANNELS ] ;
2020-05-14 12:06:05 +03:00
struct mutex lock ;
2012-09-17 13:24:00 +04:00
/*
2022-05-08 20:56:30 +03:00
* DMA ( thus cache coherency maintenance ) may require the
2012-09-17 13:24:00 +04:00
* transfer buffers to live in their own cache lines .
*/
union {
2013-11-25 16:41:00 +04:00
__be32 d32 ;
2012-09-17 13:24:00 +04:00
u8 d8 [ 4 ] ;
2022-05-08 20:56:30 +03:00
} data [ 2 ] __aligned ( IIO_DMA_MINALIGN ) ;
2012-09-17 13:24:00 +04:00
} ;
enum ad5755_type {
ID_AD5755 ,
ID_AD5757 ,
ID_AD5735 ,
ID_AD5737 ,
} ;
2016-06-27 11:27:17 +03:00
static const int ad5755_dcdc_freq_table [ ] [ 2 ] = {
{ 250000 , AD5755_DC_DC_FREQ_250kHZ } ,
{ 410000 , AD5755_DC_DC_FREQ_410kHZ } ,
{ 650000 , AD5755_DC_DC_FREQ_650kHZ }
} ;
static const int ad5755_dcdc_maxv_table [ ] [ 2 ] = {
{ 23000000 , AD5755_DC_DC_MAXV_23V } ,
{ 24500000 , AD5755_DC_DC_MAXV_24V5 } ,
{ 27000000 , AD5755_DC_DC_MAXV_27V } ,
{ 29500000 , AD5755_DC_DC_MAXV_29V5 } ,
} ;
static const int ad5755_slew_rate_table [ ] [ 2 ] = {
{ 64000 , AD5755_SLEW_RATE_64k } ,
{ 32000 , AD5755_SLEW_RATE_32k } ,
{ 16000 , AD5755_SLEW_RATE_16k } ,
{ 8000 , AD5755_SLEW_RATE_8k } ,
{ 4000 , AD5755_SLEW_RATE_4k } ,
{ 2000 , AD5755_SLEW_RATE_2k } ,
{ 1000 , AD5755_SLEW_RATE_1k } ,
{ 500 , AD5755_SLEW_RATE_500 } ,
{ 250 , AD5755_SLEW_RATE_250 } ,
{ 125 , AD5755_SLEW_RATE_125 } ,
{ 64 , AD5755_SLEW_RATE_64 } ,
{ 32 , AD5755_SLEW_RATE_32 } ,
{ 16 , AD5755_SLEW_RATE_16 } ,
{ 8 , AD5755_SLEW_RATE_8 } ,
{ 4 , AD5755_SLEW_RATE_4 } ,
{ 0 , AD5755_SLEW_RATE_0_5 } ,
} ;
static const int ad5755_slew_step_table [ ] [ 2 ] = {
{ 256 , AD5755_SLEW_STEP_SIZE_256 } ,
{ 128 , AD5755_SLEW_STEP_SIZE_128 } ,
{ 64 , AD5755_SLEW_STEP_SIZE_64 } ,
{ 32 , AD5755_SLEW_STEP_SIZE_32 } ,
{ 16 , AD5755_SLEW_STEP_SIZE_16 } ,
{ 4 , AD5755_SLEW_STEP_SIZE_4 } ,
{ 2 , AD5755_SLEW_STEP_SIZE_2 } ,
{ 1 , AD5755_SLEW_STEP_SIZE_1 } ,
} ;
2012-09-17 13:24:00 +04:00
static int ad5755_write_unlocked ( struct iio_dev * indio_dev ,
unsigned int reg , unsigned int val )
{
struct ad5755_state * st = iio_priv ( indio_dev ) ;
st - > data [ 0 ] . d32 = cpu_to_be32 ( ( reg < < 16 ) | val ) ;
return spi_write ( st - > spi , & st - > data [ 0 ] . d8 [ 1 ] , 3 ) ;
}
static int ad5755_write_ctrl_unlocked ( struct iio_dev * indio_dev ,
unsigned int channel , unsigned int reg , unsigned int val )
{
return ad5755_write_unlocked ( indio_dev ,
AD5755_WRITE_REG_CTRL ( channel ) , ( reg < < 13 ) | val ) ;
}
static int ad5755_write ( struct iio_dev * indio_dev , unsigned int reg ,
unsigned int val )
{
2020-05-14 12:06:05 +03:00
struct ad5755_state * st = iio_priv ( indio_dev ) ;
2012-09-17 13:24:00 +04:00
int ret ;
2020-05-14 12:06:05 +03:00
mutex_lock ( & st - > lock ) ;
2012-09-17 13:24:00 +04:00
ret = ad5755_write_unlocked ( indio_dev , reg , val ) ;
2020-05-14 12:06:05 +03:00
mutex_unlock ( & st - > lock ) ;
2012-09-17 13:24:00 +04:00
return ret ;
}
static int ad5755_write_ctrl ( struct iio_dev * indio_dev , unsigned int channel ,
unsigned int reg , unsigned int val )
{
2020-05-14 12:06:05 +03:00
struct ad5755_state * st = iio_priv ( indio_dev ) ;
2012-09-17 13:24:00 +04:00
int ret ;
2020-05-14 12:06:05 +03:00
mutex_lock ( & st - > lock ) ;
2012-09-17 13:24:00 +04:00
ret = ad5755_write_ctrl_unlocked ( indio_dev , channel , reg , val ) ;
2020-05-14 12:06:05 +03:00
mutex_unlock ( & st - > lock ) ;
2012-09-17 13:24:00 +04:00
return ret ;
}
static int ad5755_read ( struct iio_dev * indio_dev , unsigned int addr )
{
struct ad5755_state * st = iio_priv ( indio_dev ) ;
int ret ;
struct spi_transfer t [ ] = {
{
. tx_buf = & st - > data [ 0 ] . d8 [ 1 ] ,
. len = 3 ,
. cs_change = 1 ,
} , {
. tx_buf = & st - > data [ 1 ] . d8 [ 1 ] ,
. rx_buf = & st - > data [ 1 ] . d8 [ 1 ] ,
. len = 3 ,
} ,
} ;
2020-05-14 12:06:05 +03:00
mutex_lock ( & st - > lock ) ;
2012-09-17 13:24:00 +04:00
st - > data [ 0 ] . d32 = cpu_to_be32 ( AD5755_READ_FLAG | ( addr < < 16 ) ) ;
st - > data [ 1 ] . d32 = cpu_to_be32 ( AD5755_NOOP ) ;
2013-01-09 21:31:00 +04:00
ret = spi_sync_transfer ( st - > spi , t , ARRAY_SIZE ( t ) ) ;
2012-09-17 13:24:00 +04:00
if ( ret > = 0 )
ret = be32_to_cpu ( st - > data [ 1 ] . d32 ) & 0xffff ;
2020-05-14 12:06:05 +03:00
mutex_unlock ( & st - > lock ) ;
2012-09-17 13:24:00 +04:00
return ret ;
}
static int ad5755_update_dac_ctrl ( struct iio_dev * indio_dev ,
unsigned int channel , unsigned int set , unsigned int clr )
{
struct ad5755_state * st = iio_priv ( indio_dev ) ;
int ret ;
st - > ctrl [ channel ] | = set ;
st - > ctrl [ channel ] & = ~ clr ;
ret = ad5755_write_ctrl_unlocked ( indio_dev , channel ,
AD5755_CTRL_REG_DAC , st - > ctrl [ channel ] ) ;
return ret ;
}
static int ad5755_set_channel_pwr_down ( struct iio_dev * indio_dev ,
unsigned int channel , bool pwr_down )
{
struct ad5755_state * st = iio_priv ( indio_dev ) ;
unsigned int mask = BIT ( channel ) ;
2020-05-14 12:06:05 +03:00
mutex_lock ( & st - > lock ) ;
2012-09-17 13:24:00 +04:00
if ( ( bool ) ( st - > pwr_down & mask ) = = pwr_down )
goto out_unlock ;
if ( ! pwr_down ) {
st - > pwr_down & = ~ mask ;
ad5755_update_dac_ctrl ( indio_dev , channel ,
AD5755_DAC_INT_EN | AD5755_DAC_DC_DC_EN , 0 ) ;
udelay ( 200 ) ;
ad5755_update_dac_ctrl ( indio_dev , channel ,
AD5755_DAC_OUT_EN , 0 ) ;
} else {
st - > pwr_down | = mask ;
ad5755_update_dac_ctrl ( indio_dev , channel ,
0 , AD5755_DAC_INT_EN | AD5755_DAC_OUT_EN |
AD5755_DAC_DC_DC_EN ) ;
}
out_unlock :
2020-05-14 12:06:05 +03:00
mutex_unlock ( & st - > lock ) ;
2012-09-17 13:24:00 +04:00
return 0 ;
}
static const int ad5755_min_max_table [ ] [ 2 ] = {
[ AD5755_MODE_VOLTAGE_0V_5V ] = { 0 , 5000 } ,
[ AD5755_MODE_VOLTAGE_0V_10V ] = { 0 , 10000 } ,
[ AD5755_MODE_VOLTAGE_PLUSMINUS_5V ] = { - 5000 , 5000 } ,
[ AD5755_MODE_VOLTAGE_PLUSMINUS_10V ] = { - 10000 , 10000 } ,
[ AD5755_MODE_CURRENT_4mA_20mA ] = { 4 , 20 } ,
[ AD5755_MODE_CURRENT_0mA_20mA ] = { 0 , 20 } ,
[ AD5755_MODE_CURRENT_0mA_24mA ] = { 0 , 24 } ,
} ;
static void ad5755_get_min_max ( struct ad5755_state * st ,
struct iio_chan_spec const * chan , int * min , int * max )
{
enum ad5755_mode mode = st - > ctrl [ chan - > channel ] & 7 ;
* min = ad5755_min_max_table [ mode ] [ 0 ] ;
* max = ad5755_min_max_table [ mode ] [ 1 ] ;
}
static inline int ad5755_get_offset ( struct ad5755_state * st ,
struct iio_chan_spec const * chan )
{
int min , max ;
ad5755_get_min_max ( st , chan , & min , & max ) ;
return ( min * ( 1 < < chan - > scan_type . realbits ) ) / ( max - min ) ;
}
static int ad5755_chan_reg_info ( struct ad5755_state * st ,
struct iio_chan_spec const * chan , long info , bool write ,
unsigned int * reg , unsigned int * shift , unsigned int * offset )
{
switch ( info ) {
case IIO_CHAN_INFO_RAW :
if ( write )
* reg = AD5755_WRITE_REG_DATA ( chan - > address ) ;
else
* reg = AD5755_READ_REG_DATA ( chan - > address ) ;
* shift = chan - > scan_type . shift ;
* offset = 0 ;
break ;
case IIO_CHAN_INFO_CALIBBIAS :
if ( write )
* reg = AD5755_WRITE_REG_OFFSET ( chan - > address ) ;
else
* reg = AD5755_READ_REG_OFFSET ( chan - > address ) ;
* shift = st - > chip_info - > calib_shift ;
* offset = 32768 ;
break ;
case IIO_CHAN_INFO_CALIBSCALE :
if ( write )
* reg = AD5755_WRITE_REG_GAIN ( chan - > address ) ;
else
* reg = AD5755_READ_REG_GAIN ( chan - > address ) ;
* shift = st - > chip_info - > calib_shift ;
* offset = 0 ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
static int ad5755_read_raw ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan , int * val , int * val2 , long info )
{
struct ad5755_state * st = iio_priv ( indio_dev ) ;
unsigned int reg , shift , offset ;
2013-09-28 13:31:00 +04:00
int min , max ;
2012-09-17 13:24:00 +04:00
int ret ;
switch ( info ) {
case IIO_CHAN_INFO_SCALE :
2013-09-28 13:31:00 +04:00
ad5755_get_min_max ( st , chan , & min , & max ) ;
* val = max - min ;
* val2 = chan - > scan_type . realbits ;
return IIO_VAL_FRACTIONAL_LOG2 ;
2012-09-17 13:24:00 +04:00
case IIO_CHAN_INFO_OFFSET :
* val = ad5755_get_offset ( st , chan ) ;
return IIO_VAL_INT ;
default :
ret = ad5755_chan_reg_info ( st , chan , info , false ,
& reg , & shift , & offset ) ;
if ( ret )
return ret ;
ret = ad5755_read ( indio_dev , reg ) ;
if ( ret < 0 )
return ret ;
* val = ( ret - offset ) > > shift ;
return IIO_VAL_INT ;
}
return - EINVAL ;
}
static int ad5755_write_raw ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan , int val , int val2 , long info )
{
struct ad5755_state * st = iio_priv ( indio_dev ) ;
unsigned int shift , reg , offset ;
int ret ;
ret = ad5755_chan_reg_info ( st , chan , info , true ,
& reg , & shift , & offset ) ;
if ( ret )
return ret ;
val < < = shift ;
val + = offset ;
if ( val < 0 | | val > 0xffff )
return - EINVAL ;
return ad5755_write ( indio_dev , reg , val ) ;
}
static ssize_t ad5755_read_powerdown ( struct iio_dev * indio_dev , uintptr_t priv ,
const struct iio_chan_spec * chan , char * buf )
{
struct ad5755_state * st = iio_priv ( indio_dev ) ;
2021-03-20 10:14:05 +03:00
return sysfs_emit ( buf , " %d \n " ,
( bool ) ( st - > pwr_down & ( 1 < < chan - > channel ) ) ) ;
2012-09-17 13:24:00 +04:00
}
static ssize_t ad5755_write_powerdown ( struct iio_dev * indio_dev , uintptr_t priv ,
struct iio_chan_spec const * chan , const char * buf , size_t len )
{
bool pwr_down ;
int ret ;
2022-04-09 13:58:12 +03:00
ret = kstrtobool ( buf , & pwr_down ) ;
2012-09-17 13:24:00 +04:00
if ( ret )
return ret ;
ret = ad5755_set_channel_pwr_down ( indio_dev , chan - > channel , pwr_down ) ;
return ret ? ret : len ;
}
static const struct iio_info ad5755_info = {
. read_raw = ad5755_read_raw ,
. write_raw = ad5755_write_raw ,
} ;
static const struct iio_chan_spec_ext_info ad5755_ext_info [ ] = {
{
. name = " powerdown " ,
. read = ad5755_read_powerdown ,
. write = ad5755_write_powerdown ,
2013-09-08 17:57:00 +04:00
. shared = IIO_SEPARATE ,
2012-09-17 13:24:00 +04:00
} ,
{ } ,
} ;
# define AD5755_CHANNEL(_bits) { \
. indexed = 1 , \
. output = 1 , \
2013-02-27 23:27:50 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) | \
BIT ( IIO_CHAN_INFO_SCALE ) | \
BIT ( IIO_CHAN_INFO_OFFSET ) | \
BIT ( IIO_CHAN_INFO_CALIBSCALE ) | \
BIT ( IIO_CHAN_INFO_CALIBBIAS ) , \
2013-12-11 22:45:00 +04:00
. scan_type = { \
. sign = ' u ' , \
. realbits = ( _bits ) , \
. storagebits = 16 , \
. shift = 16 - ( _bits ) , \
} , \
2012-09-17 13:24:00 +04:00
. ext_info = ad5755_ext_info , \
}
static const struct ad5755_chip_info ad5755_chip_info_tbl [ ] = {
[ ID_AD5735 ] = {
. channel_template = AD5755_CHANNEL ( 14 ) ,
. has_voltage_out = true ,
. calib_shift = 4 ,
} ,
[ ID_AD5737 ] = {
. channel_template = AD5755_CHANNEL ( 14 ) ,
. has_voltage_out = false ,
. calib_shift = 4 ,
} ,
[ ID_AD5755 ] = {
. channel_template = AD5755_CHANNEL ( 16 ) ,
. has_voltage_out = true ,
. calib_shift = 0 ,
} ,
[ ID_AD5757 ] = {
. channel_template = AD5755_CHANNEL ( 16 ) ,
. has_voltage_out = false ,
. calib_shift = 0 ,
} ,
} ;
static bool ad5755_is_valid_mode ( struct ad5755_state * st , enum ad5755_mode mode )
{
switch ( mode ) {
case AD5755_MODE_VOLTAGE_0V_5V :
case AD5755_MODE_VOLTAGE_0V_10V :
case AD5755_MODE_VOLTAGE_PLUSMINUS_5V :
case AD5755_MODE_VOLTAGE_PLUSMINUS_10V :
return st - > chip_info - > has_voltage_out ;
case AD5755_MODE_CURRENT_4mA_20mA :
case AD5755_MODE_CURRENT_0mA_20mA :
case AD5755_MODE_CURRENT_0mA_24mA :
return true ;
default :
return false ;
}
}
2012-12-22 01:21:43 +04:00
static int ad5755_setup_pdata ( struct iio_dev * indio_dev ,
const struct ad5755_platform_data * pdata )
2012-09-17 13:24:00 +04:00
{
struct ad5755_state * st = iio_priv ( indio_dev ) ;
unsigned int val ;
unsigned int i ;
2012-09-19 10:27:00 +04:00
int ret ;
2012-09-17 13:24:00 +04:00
if ( pdata - > dc_dc_phase > AD5755_DC_DC_PHASE_90_DEGREE | |
pdata - > dc_dc_freq > AD5755_DC_DC_FREQ_650kHZ | |
pdata - > dc_dc_maxv > AD5755_DC_DC_MAXV_29V5 )
return - EINVAL ;
val = pdata - > dc_dc_maxv < < AD5755_DC_DC_MAXV ;
val | = pdata - > dc_dc_freq < < AD5755_DC_DC_FREQ_SHIFT ;
val | = pdata - > dc_dc_phase < < AD5755_DC_DC_PHASE_SHIFT ;
if ( pdata - > ext_dc_dc_compenstation_resistor )
val | = AD5755_EXT_DC_DC_COMP_RES ;
ret = ad5755_write_ctrl ( indio_dev , 0 , AD5755_CTRL_REG_DC_DC , val ) ;
if ( ret < 0 )
return ret ;
for ( i = 0 ; i < ARRAY_SIZE ( pdata - > dac ) ; + + i ) {
val = pdata - > dac [ i ] . slew . step_size < <
AD5755_SLEW_STEP_SIZE_SHIFT ;
val | = pdata - > dac [ i ] . slew . rate < <
AD5755_SLEW_RATE_SHIFT ;
if ( pdata - > dac [ i ] . slew . enable )
val | = AD5755_SLEW_ENABLE ;
ret = ad5755_write_ctrl ( indio_dev , i ,
AD5755_CTRL_REG_SLEW , val ) ;
if ( ret < 0 )
return ret ;
}
for ( i = 0 ; i < ARRAY_SIZE ( pdata - > dac ) ; + + i ) {
if ( ! ad5755_is_valid_mode ( st , pdata - > dac [ i ] . mode ) )
return - EINVAL ;
val = 0 ;
if ( ! pdata - > dac [ i ] . ext_current_sense_resistor )
val | = AD5755_DAC_INT_CURRENT_SENSE_RESISTOR ;
if ( pdata - > dac [ i ] . enable_voltage_overrange )
val | = AD5755_DAC_VOLTAGE_OVERRANGE_EN ;
val | = pdata - > dac [ i ] . mode ;
ret = ad5755_update_dac_ctrl ( indio_dev , i , val , 0 ) ;
if ( ret < 0 )
return ret ;
}
return 0 ;
}
2012-12-22 01:21:43 +04:00
static bool ad5755_is_voltage_mode ( enum ad5755_mode mode )
2012-09-17 13:24:00 +04:00
{
switch ( mode ) {
case AD5755_MODE_VOLTAGE_0V_5V :
case AD5755_MODE_VOLTAGE_0V_10V :
case AD5755_MODE_VOLTAGE_PLUSMINUS_5V :
case AD5755_MODE_VOLTAGE_PLUSMINUS_10V :
return true ;
default :
return false ;
}
}
2012-12-22 01:21:43 +04:00
static int ad5755_init_channels ( struct iio_dev * indio_dev ,
const struct ad5755_platform_data * pdata )
2012-09-17 13:24:00 +04:00
{
struct ad5755_state * st = iio_priv ( indio_dev ) ;
struct iio_chan_spec * channels = st - > channels ;
unsigned int i ;
for ( i = 0 ; i < AD5755_NUM_CHANNELS ; + + i ) {
channels [ i ] = st - > chip_info - > channel_template ;
channels [ i ] . channel = i ;
channels [ i ] . address = i ;
if ( pdata & & ad5755_is_voltage_mode ( pdata - > dac [ i ] . mode ) )
channels [ i ] . type = IIO_VOLTAGE ;
else
channels [ i ] . type = IIO_CURRENT ;
}
indio_dev - > channels = channels ;
return 0 ;
}
# define AD5755_DEFAULT_DAC_PDATA { \
. mode = AD5755_MODE_CURRENT_4mA_20mA , \
. ext_current_sense_resistor = true , \
. enable_voltage_overrange = false , \
. slew = { \
. enable = false , \
. rate = AD5755_SLEW_RATE_64k , \
. step_size = AD5755_SLEW_STEP_SIZE_1 , \
} , \
}
static const struct ad5755_platform_data ad5755_default_pdata = {
. ext_dc_dc_compenstation_resistor = false ,
. dc_dc_phase = AD5755_DC_DC_PHASE_ALL_SAME_EDGE ,
. dc_dc_freq = AD5755_DC_DC_FREQ_410kHZ ,
. dc_dc_maxv = AD5755_DC_DC_MAXV_23V ,
. dac = {
[ 0 ] = AD5755_DEFAULT_DAC_PDATA ,
[ 1 ] = AD5755_DEFAULT_DAC_PDATA ,
[ 2 ] = AD5755_DEFAULT_DAC_PDATA ,
[ 3 ] = AD5755_DEFAULT_DAC_PDATA ,
} ,
} ;
2021-12-05 20:01:29 +03:00
static struct ad5755_platform_data * ad5755_parse_fw ( struct device * dev )
2016-06-27 11:27:17 +03:00
{
2021-12-05 20:01:29 +03:00
struct fwnode_handle * pp ;
2016-06-27 11:27:17 +03:00
struct ad5755_platform_data * pdata ;
unsigned int tmp ;
unsigned int tmparray [ 3 ] ;
int devnr , i ;
2021-12-05 20:01:29 +03:00
if ( ! dev_fwnode ( dev ) )
return NULL ;
2016-06-27 11:27:17 +03:00
pdata = devm_kzalloc ( dev , sizeof ( * pdata ) , GFP_KERNEL ) ;
if ( ! pdata )
return NULL ;
pdata - > ext_dc_dc_compenstation_resistor =
2021-12-05 20:01:29 +03:00
device_property_read_bool ( dev , " adi,ext-dc-dc-compenstation-resistor " ) ;
2016-06-27 11:27:17 +03:00
2021-12-05 20:01:29 +03:00
pdata - > dc_dc_phase = AD5755_DC_DC_PHASE_ALL_SAME_EDGE ;
device_property_read_u32 ( dev , " adi,dc-dc-phase " , & pdata - > dc_dc_phase ) ;
2016-06-27 11:27:17 +03:00
pdata - > dc_dc_freq = AD5755_DC_DC_FREQ_410kHZ ;
2021-12-05 20:01:29 +03:00
if ( ! device_property_read_u32 ( dev , " adi,dc-dc-freq-hz " , & tmp ) ) {
2016-06-27 11:27:17 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( ad5755_dcdc_freq_table ) ; i + + ) {
if ( tmp = = ad5755_dcdc_freq_table [ i ] [ 0 ] ) {
pdata - > dc_dc_freq = ad5755_dcdc_freq_table [ i ] [ 1 ] ;
break ;
}
}
2020-01-23 12:19:54 +03:00
if ( i = = ARRAY_SIZE ( ad5755_dcdc_freq_table ) )
2016-06-27 11:27:17 +03:00
dev_err ( dev ,
2020-01-23 12:19:54 +03:00
" adi,dc-dc-freq out of range selecting 410kHz \n " ) ;
2016-06-27 11:27:17 +03:00
}
pdata - > dc_dc_maxv = AD5755_DC_DC_MAXV_23V ;
2021-12-05 20:01:29 +03:00
if ( ! device_property_read_u32 ( dev , " adi,dc-dc-max-microvolt " , & tmp ) ) {
2016-06-27 11:27:17 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( ad5755_dcdc_maxv_table ) ; i + + ) {
if ( tmp = = ad5755_dcdc_maxv_table [ i ] [ 0 ] ) {
pdata - > dc_dc_maxv = ad5755_dcdc_maxv_table [ i ] [ 1 ] ;
break ;
}
}
2020-01-23 12:19:54 +03:00
if ( i = = ARRAY_SIZE ( ad5755_dcdc_maxv_table ) )
2016-06-27 11:27:17 +03:00
dev_err ( dev ,
2020-01-23 12:19:54 +03:00
" adi,dc-dc-maxv out of range selecting 23V \n " ) ;
2016-06-27 11:27:17 +03:00
}
devnr = 0 ;
2021-12-05 20:01:29 +03:00
device_for_each_child_node ( dev , pp ) {
2016-07-26 01:40:01 +03:00
if ( devnr > = AD5755_NUM_CHANNELS ) {
2016-06-27 11:27:17 +03:00
dev_err ( dev ,
2020-01-23 12:19:54 +03:00
" There are too many channels defined in DT \n " ) ;
2016-06-27 11:27:17 +03:00
goto error_out ;
}
2021-12-05 20:01:29 +03:00
pdata - > dac [ devnr ] . mode = AD5755_MODE_CURRENT_4mA_20mA ;
fwnode_property_read_u32 ( pp , " adi,mode " , & pdata - > dac [ devnr ] . mode ) ;
2016-06-27 11:27:17 +03:00
pdata - > dac [ devnr ] . ext_current_sense_resistor =
2021-12-05 20:01:29 +03:00
fwnode_property_read_bool ( pp , " adi,ext-current-sense-resistor " ) ;
2016-06-27 11:27:17 +03:00
pdata - > dac [ devnr ] . enable_voltage_overrange =
2021-12-05 20:01:29 +03:00
fwnode_property_read_bool ( pp , " adi,enable-voltage-overrange " ) ;
2016-06-27 11:27:17 +03:00
2021-12-05 20:01:29 +03:00
if ( ! fwnode_property_read_u32_array ( pp , " adi,slew " , tmparray , 3 ) ) {
2016-06-27 11:27:17 +03:00
pdata - > dac [ devnr ] . slew . enable = tmparray [ 0 ] ;
pdata - > dac [ devnr ] . slew . rate = AD5755_SLEW_RATE_64k ;
for ( i = 0 ; i < ARRAY_SIZE ( ad5755_slew_rate_table ) ; i + + ) {
if ( tmparray [ 1 ] = = ad5755_slew_rate_table [ i ] [ 0 ] ) {
pdata - > dac [ devnr ] . slew . rate =
ad5755_slew_rate_table [ i ] [ 1 ] ;
break ;
}
}
2020-01-23 12:19:54 +03:00
if ( i = = ARRAY_SIZE ( ad5755_slew_rate_table ) )
2016-06-27 11:27:17 +03:00
dev_err ( dev ,
2020-01-23 12:19:54 +03:00
" channel %d slew rate out of range selecting 64kHz \n " ,
2016-06-27 11:27:17 +03:00
devnr ) ;
pdata - > dac [ devnr ] . slew . step_size = AD5755_SLEW_STEP_SIZE_1 ;
for ( i = 0 ; i < ARRAY_SIZE ( ad5755_slew_step_table ) ; i + + ) {
if ( tmparray [ 2 ] = = ad5755_slew_step_table [ i ] [ 0 ] ) {
pdata - > dac [ devnr ] . slew . step_size =
ad5755_slew_step_table [ i ] [ 1 ] ;
break ;
}
}
2020-01-23 12:19:54 +03:00
if ( i = = ARRAY_SIZE ( ad5755_slew_step_table ) )
2016-06-27 11:27:17 +03:00
dev_err ( dev ,
2020-01-23 12:19:54 +03:00
" channel %d slew step size out of range selecting 1 LSB \n " ,
2016-06-27 11:27:17 +03:00
devnr ) ;
} else {
pdata - > dac [ devnr ] . slew . enable = false ;
pdata - > dac [ devnr ] . slew . rate = AD5755_SLEW_RATE_64k ;
pdata - > dac [ devnr ] . slew . step_size =
AD5755_SLEW_STEP_SIZE_1 ;
}
devnr + + ;
}
return pdata ;
error_out :
devm_kfree ( dev , pdata ) ;
return NULL ;
}
2012-12-22 01:21:43 +04:00
static int ad5755_probe ( struct spi_device * spi )
2012-09-17 13:24:00 +04:00
{
enum ad5755_type type = spi_get_device_id ( spi ) - > driver_data ;
2021-12-05 20:01:29 +03:00
const struct ad5755_platform_data * pdata ;
2012-09-17 13:24:00 +04:00
struct iio_dev * indio_dev ;
struct ad5755_state * st ;
int ret ;
2013-08-19 15:38:00 +04:00
indio_dev = devm_iio_device_alloc ( & spi - > dev , sizeof ( * st ) ) ;
2012-09-17 13:24:00 +04:00
if ( indio_dev = = NULL ) {
dev_err ( & spi - > dev , " Failed to allocate iio device \n " ) ;
return - ENOMEM ;
}
st = iio_priv ( indio_dev ) ;
spi_set_drvdata ( spi , indio_dev ) ;
st - > chip_info = & ad5755_chip_info_tbl [ type ] ;
st - > spi = spi ;
st - > pwr_down = 0xf ;
indio_dev - > name = spi_get_device_id ( spi ) - > name ;
indio_dev - > info = & ad5755_info ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > num_channels = AD5755_NUM_CHANNELS ;
2020-05-14 12:06:05 +03:00
mutex_init ( & st - > lock ) ;
2016-06-27 11:27:17 +03:00
2021-12-05 20:01:29 +03:00
pdata = ad5755_parse_fw ( & spi - > dev ) ;
2016-06-27 11:27:17 +03:00
if ( ! pdata ) {
2021-12-05 20:01:29 +03:00
dev_warn ( & spi - > dev , " no firmware provided parameters? using default \n " ) ;
2012-09-17 13:24:00 +04:00
pdata = & ad5755_default_pdata ;
2016-06-27 11:27:17 +03:00
}
2012-09-17 13:24:00 +04:00
ret = ad5755_init_channels ( indio_dev , pdata ) ;
if ( ret )
2013-08-19 15:38:00 +04:00
return ret ;
2012-09-17 13:24:00 +04:00
ret = ad5755_setup_pdata ( indio_dev , pdata ) ;
if ( ret )
2013-08-19 15:38:00 +04:00
return ret ;
2012-09-17 13:24:00 +04:00
2013-10-29 15:39:00 +04:00
return devm_iio_device_register ( & spi - > dev , indio_dev ) ;
2012-09-17 13:24:00 +04:00
}
static const struct spi_device_id ad5755_id [ ] = {
{ " ad5755 " , ID_AD5755 } ,
{ " ad5755-1 " , ID_AD5755 } ,
{ " ad5757 " , ID_AD5757 } ,
{ " ad5735 " , ID_AD5735 } ,
{ " ad5737 " , ID_AD5737 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( spi , ad5755_id ) ;
2016-06-27 11:27:17 +03:00
static const struct of_device_id ad5755_of_match [ ] = {
{ . compatible = " adi,ad5755 " } ,
{ . compatible = " adi,ad5755-1 " } ,
{ . compatible = " adi,ad5757 " } ,
{ . compatible = " adi,ad5735 " } ,
{ . compatible = " adi,ad5737 " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , ad5755_of_match ) ;
2012-09-17 13:24:00 +04:00
static struct spi_driver ad5755_driver = {
. driver = {
. name = " ad5755 " ,
} ,
. probe = ad5755_probe ,
. id_table = ad5755_id ,
} ;
module_spi_driver ( ad5755_driver ) ;
MODULE_AUTHOR ( " Lars-Peter Clausen <lars@metafoo.de> " ) ;
MODULE_DESCRIPTION ( " Analog Devices AD5755/55-1/57/35/37 DAC " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;