2019-05-28 19:57:06 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2011-12-05 20:05:41 +04:00
/*
* Analog devices AD5764 , AD5764R , AD5744 , AD5744R quad - channel
* Digital to Analog Converters driver
*
* Copyright 2011 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/regulator/consumer.h>
2012-04-25 18:54:58 +04:00
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
2011-12-05 20:05:41 +04:00
# define AD5764_REG_SF_NOP 0x0
# define AD5764_REG_SF_CONFIG 0x1
# define AD5764_REG_SF_CLEAR 0x4
# define AD5764_REG_SF_LOAD 0x5
# define AD5764_REG_DATA(x) ((2 << 3) | (x))
# define AD5764_REG_COARSE_GAIN(x) ((3 << 3) | (x))
# define AD5764_REG_FINE_GAIN(x) ((4 << 3) | (x))
# define AD5764_REG_OFFSET(x) ((5 << 3) | (x))
# define AD5764_NUM_CHANNELS 4
/**
* struct ad5764_chip_info - chip specific information
* @ int_vref : Value of the internal reference voltage in uV - 0 if external
* reference voltage is used
* @ channel channel specification
*/
struct ad5764_chip_info {
unsigned long int_vref ;
const struct iio_chan_spec * channels ;
} ;
/**
* struct ad5764_state - driver instance specific data
* @ spi : spi_device
* @ chip_info : chip info
* @ vref_reg : vref supply regulators
* @ data : spi transfer buffers
*/
struct ad5764_state {
struct spi_device * spi ;
const struct ad5764_chip_info * chip_info ;
struct regulator_bulk_data vref_reg [ 2 ] ;
/*
* DMA ( thus cache coherency maintenance ) requires the
* transfer buffers to live in their own cache lines .
*/
union {
__be32 d32 ;
u8 d8 [ 4 ] ;
} data [ 2 ] ____cacheline_aligned ;
} ;
enum ad5764_type {
ID_AD5744 ,
ID_AD5744R ,
ID_AD5764 ,
ID_AD5764R ,
} ;
# define AD5764_CHANNEL(_chan, _bits) { \
. type = IIO_VOLTAGE , \
. indexed = 1 , \
. output = 1 , \
. channel = ( _chan ) , \
. address = ( _chan ) , \
2013-02-27 23:28:00 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) | \
BIT ( IIO_CHAN_INFO_SCALE ) | \
BIT ( IIO_CHAN_INFO_CALIBSCALE ) | \
BIT ( IIO_CHAN_INFO_CALIBBIAS ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_OFFSET ) , \
2013-12-11 22:45:00 +04:00
. scan_type = { \
. sign = ' u ' , \
. realbits = ( _bits ) , \
. storagebits = 16 , \
. shift = 16 - ( _bits ) , \
} , \
2011-12-05 20:05:41 +04:00
}
# define DECLARE_AD5764_CHANNELS(_name, _bits) \
const struct iio_chan_spec _name # # _channels [ ] = { \
AD5764_CHANNEL ( 0 , ( _bits ) ) , \
AD5764_CHANNEL ( 1 , ( _bits ) ) , \
AD5764_CHANNEL ( 2 , ( _bits ) ) , \
AD5764_CHANNEL ( 3 , ( _bits ) ) , \
} ;
static DECLARE_AD5764_CHANNELS ( ad5764 , 16 ) ;
static DECLARE_AD5764_CHANNELS ( ad5744 , 14 ) ;
static const struct ad5764_chip_info ad5764_chip_infos [ ] = {
[ ID_AD5744 ] = {
. int_vref = 0 ,
. channels = ad5744_channels ,
} ,
[ ID_AD5744R ] = {
. int_vref = 5000000 ,
. channels = ad5744_channels ,
} ,
[ ID_AD5764 ] = {
. int_vref = 0 ,
. channels = ad5764_channels ,
} ,
[ ID_AD5764R ] = {
. int_vref = 5000000 ,
. channels = ad5764_channels ,
} ,
} ;
static int ad5764_write ( struct iio_dev * indio_dev , unsigned int reg ,
unsigned int val )
{
struct ad5764_state * st = iio_priv ( indio_dev ) ;
int ret ;
mutex_lock ( & indio_dev - > mlock ) ;
st - > data [ 0 ] . d32 = cpu_to_be32 ( ( reg < < 16 ) | val ) ;
ret = spi_write ( st - > spi , & st - > data [ 0 ] . d8 [ 1 ] , 3 ) ;
mutex_unlock ( & indio_dev - > mlock ) ;
return ret ;
}
static int ad5764_read ( struct iio_dev * indio_dev , unsigned int reg ,
unsigned int * val )
{
struct ad5764_state * st = iio_priv ( indio_dev ) ;
int ret ;
struct spi_transfer t [ ] = {
{
. tx_buf = & st - > data [ 0 ] . d8 [ 1 ] ,
. len = 3 ,
. cs_change = 1 ,
} , {
. rx_buf = & st - > data [ 1 ] . d8 [ 1 ] ,
. len = 3 ,
} ,
} ;
mutex_lock ( & indio_dev - > mlock ) ;
st - > data [ 0 ] . d32 = cpu_to_be32 ( ( 1 < < 23 ) | ( reg < < 16 ) ) ;
2013-01-09 21:31:00 +04:00
ret = spi_sync_transfer ( st - > spi , t , ARRAY_SIZE ( t ) ) ;
2011-12-05 20:05:41 +04:00
if ( ret > = 0 )
* val = be32_to_cpu ( st - > data [ 1 ] . d32 ) & 0xffff ;
mutex_unlock ( & indio_dev - > mlock ) ;
return ret ;
}
static int ad5764_chan_info_to_reg ( struct iio_chan_spec const * chan , long info )
{
switch ( info ) {
2018-03-06 15:02:57 +03:00
case IIO_CHAN_INFO_RAW :
2011-12-05 20:05:41 +04:00
return AD5764_REG_DATA ( chan - > address ) ;
case IIO_CHAN_INFO_CALIBBIAS :
return AD5764_REG_OFFSET ( chan - > address ) ;
case IIO_CHAN_INFO_CALIBSCALE :
return AD5764_REG_FINE_GAIN ( chan - > address ) ;
default :
break ;
}
return 0 ;
}
static int ad5764_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan , int val , int val2 , long info )
{
const int max_val = ( 1 < < chan - > scan_type . realbits ) ;
unsigned int reg ;
switch ( info ) {
2012-04-15 20:41:19 +04:00
case IIO_CHAN_INFO_RAW :
2011-12-05 20:05:41 +04:00
if ( val > = max_val | | val < 0 )
return - EINVAL ;
val < < = chan - > scan_type . shift ;
break ;
case IIO_CHAN_INFO_CALIBBIAS :
if ( val > = 128 | | val < - 128 )
return - EINVAL ;
break ;
case IIO_CHAN_INFO_CALIBSCALE :
if ( val > = 32 | | val < - 32 )
return - EINVAL ;
break ;
default :
return - EINVAL ;
}
reg = ad5764_chan_info_to_reg ( chan , info ) ;
return ad5764_write ( indio_dev , reg , ( u16 ) val ) ;
}
static int ad5764_get_channel_vref ( struct ad5764_state * st ,
unsigned int channel )
{
if ( st - > chip_info - > int_vref )
return st - > chip_info - > int_vref ;
else
return regulator_get_voltage ( st - > vref_reg [ channel / 2 ] . consumer ) ;
}
static int ad5764_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan , int * val , int * val2 , long info )
{
struct ad5764_state * st = iio_priv ( indio_dev ) ;
unsigned int reg ;
int vref ;
int ret ;
switch ( info ) {
2012-04-15 20:41:19 +04:00
case IIO_CHAN_INFO_RAW :
2011-12-05 20:05:41 +04:00
reg = AD5764_REG_DATA ( chan - > address ) ;
ret = ad5764_read ( indio_dev , reg , val ) ;
if ( ret < 0 )
return ret ;
* val > > = chan - > scan_type . shift ;
return IIO_VAL_INT ;
case IIO_CHAN_INFO_CALIBBIAS :
reg = AD5764_REG_OFFSET ( chan - > address ) ;
ret = ad5764_read ( indio_dev , reg , val ) ;
if ( ret < 0 )
return ret ;
* val = sign_extend32 ( * val , 7 ) ;
return IIO_VAL_INT ;
case IIO_CHAN_INFO_CALIBSCALE :
reg = AD5764_REG_FINE_GAIN ( chan - > address ) ;
ret = ad5764_read ( indio_dev , reg , val ) ;
if ( ret < 0 )
return ret ;
* val = sign_extend32 ( * val , 5 ) ;
return IIO_VAL_INT ;
case IIO_CHAN_INFO_SCALE :
2013-09-28 13:31:00 +04:00
/* vout = 4 * vref + ((dac_code / 65536) - 0.5) */
2011-12-05 20:05:41 +04:00
vref = ad5764_get_channel_vref ( st , chan - > channel ) ;
if ( vref < 0 )
return vref ;
2013-09-28 13:31:00 +04:00
* val = vref * 4 / 1000 ;
* val2 = chan - > scan_type . realbits ;
return IIO_VAL_FRACTIONAL_LOG2 ;
2011-12-05 20:05:41 +04:00
case IIO_CHAN_INFO_OFFSET :
* val = - ( 1 < < chan - > scan_type . realbits ) / 2 ;
return IIO_VAL_INT ;
}
return - EINVAL ;
}
static const struct iio_info ad5764_info = {
. read_raw = ad5764_read_raw ,
. write_raw = ad5764_write_raw ,
} ;
2012-12-22 01:21:43 +04:00
static int ad5764_probe ( struct spi_device * spi )
2011-12-05 20:05:41 +04:00
{
enum ad5764_type type = spi_get_device_id ( spi ) - > driver_data ;
struct iio_dev * indio_dev ;
struct ad5764_state * st ;
int ret ;
2013-08-19 15:38:00 +04:00
indio_dev = devm_iio_device_alloc ( & spi - > dev , sizeof ( * st ) ) ;
2011-12-05 20:05:41 +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 - > spi = spi ;
st - > chip_info = & ad5764_chip_infos [ type ] ;
indio_dev - > dev . parent = & spi - > dev ;
indio_dev - > name = spi_get_device_id ( spi ) - > name ;
indio_dev - > info = & ad5764_info ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > num_channels = AD5764_NUM_CHANNELS ;
indio_dev - > channels = st - > chip_info - > channels ;
if ( st - > chip_info - > int_vref = = 0 ) {
st - > vref_reg [ 0 ] . supply = " vrefAB " ;
st - > vref_reg [ 1 ] . supply = " vrefCD " ;
2013-08-19 15:38:00 +04:00
ret = devm_regulator_bulk_get ( & st - > spi - > dev ,
2011-12-05 20:05:41 +04:00
ARRAY_SIZE ( st - > vref_reg ) , st - > vref_reg ) ;
if ( ret ) {
dev_err ( & spi - > dev , " Failed to request vref regulators: %d \n " ,
ret ) ;
2013-08-19 15:38:00 +04:00
return ret ;
2011-12-05 20:05:41 +04:00
}
ret = regulator_bulk_enable ( ARRAY_SIZE ( st - > vref_reg ) ,
st - > vref_reg ) ;
if ( ret ) {
dev_err ( & spi - > dev , " Failed to enable vref regulators: %d \n " ,
ret ) ;
2013-08-19 15:38:00 +04:00
return ret ;
2011-12-05 20:05:41 +04:00
}
}
ret = iio_device_register ( indio_dev ) ;
if ( ret ) {
dev_err ( & spi - > dev , " Failed to register iio device: %d \n " , ret ) ;
goto error_disable_reg ;
}
return 0 ;
error_disable_reg :
if ( st - > chip_info - > int_vref = = 0 )
regulator_bulk_disable ( ARRAY_SIZE ( st - > vref_reg ) , st - > vref_reg ) ;
return ret ;
}
2012-12-22 01:21:43 +04:00
static int ad5764_remove ( struct spi_device * spi )
2011-12-05 20:05:41 +04:00
{
struct iio_dev * indio_dev = spi_get_drvdata ( spi ) ;
struct ad5764_state * st = iio_priv ( indio_dev ) ;
iio_device_unregister ( indio_dev ) ;
2013-08-19 15:38:00 +04:00
if ( st - > chip_info - > int_vref = = 0 )
2011-12-05 20:05:41 +04:00
regulator_bulk_disable ( ARRAY_SIZE ( st - > vref_reg ) , st - > vref_reg ) ;
return 0 ;
}
static const struct spi_device_id ad5764_ids [ ] = {
{ " ad5744 " , ID_AD5744 } ,
{ " ad5744r " , ID_AD5744R } ,
{ " ad5764 " , ID_AD5764 } ,
{ " ad5764r " , ID_AD5764R } ,
{ }
} ;
MODULE_DEVICE_TABLE ( spi , ad5764_ids ) ;
static struct spi_driver ad5764_driver = {
. driver = {
. name = " ad5764 " ,
} ,
. probe = ad5764_probe ,
2012-12-22 01:21:43 +04:00
. remove = ad5764_remove ,
2011-12-05 20:05:41 +04:00
. id_table = ad5764_ids ,
} ;
2012-02-20 22:42:38 +04:00
module_spi_driver ( ad5764_driver ) ;
2011-12-05 20:05:41 +04:00
MODULE_AUTHOR ( " Lars-Peter Clausen <lars@metafoo.de> " ) ;
MODULE_DESCRIPTION ( " Analog Devices AD5744/AD5744R/AD5764/AD5764R DAC " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;