2018-04-11 14:52:12 +03:00
// SPDX-License-Identifier: GPL-2.0+
2011-06-10 17:40:49 +04:00
/*
* AD5686R , AD5685R , AD5684R Digital to analog converters driver
*
* Copyright 2011 Analog Devices Inc .
*/
# include <linux/interrupt.h>
# include <linux/fs.h>
# include <linux/device.h>
2011-07-03 23:49:50 +04:00
# include <linux/module.h>
2011-06-10 17:40:49 +04:00
# include <linux/kernel.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-06-10 17:40:49 +04:00
2018-04-11 14:53:17 +03:00
# include "ad5686.h"
2011-06-10 17:40:49 +04:00
2012-06-04 13:36:17 +04:00
static const char * const ad5686_powerdown_modes [ ] = {
" 1kohm_to_gnd " ,
" 100kohm_to_gnd " ,
" three_state "
} ;
static int ad5686_get_powerdown_mode ( struct iio_dev * indio_dev ,
2018-04-11 14:51:51 +03:00
const struct iio_chan_spec * chan )
2011-06-10 17:40:49 +04:00
{
struct ad5686_state * st = iio_priv ( indio_dev ) ;
2012-06-04 13:36:17 +04:00
return ( ( st - > pwr_down_mode > > ( chan - > channel * 2 ) ) & 0x3 ) - 1 ;
2011-06-10 17:40:49 +04:00
}
2012-06-04 13:36:17 +04:00
static int ad5686_set_powerdown_mode ( struct iio_dev * indio_dev ,
2018-04-11 14:51:51 +03:00
const struct iio_chan_spec * chan ,
unsigned int mode )
2011-06-10 17:40:49 +04:00
{
struct ad5686_state * st = iio_priv ( indio_dev ) ;
2012-06-04 13:36:17 +04:00
st - > pwr_down_mode & = ~ ( 0x3 < < ( chan - > channel * 2 ) ) ;
st - > pwr_down_mode | = ( ( mode + 1 ) < < ( chan - > channel * 2 ) ) ;
2011-06-10 17:40:49 +04:00
2012-06-04 13:36:17 +04:00
return 0 ;
2011-06-10 17:40:49 +04:00
}
2012-06-04 13:36:17 +04:00
static const struct iio_enum ad5686_powerdown_mode_enum = {
. items = ad5686_powerdown_modes ,
. num_items = ARRAY_SIZE ( ad5686_powerdown_modes ) ,
. get = ad5686_get_powerdown_mode ,
. set = ad5686_set_powerdown_mode ,
} ;
static ssize_t ad5686_read_dac_powerdown ( struct iio_dev * indio_dev ,
2018-04-11 14:51:51 +03:00
uintptr_t private , const struct iio_chan_spec * chan , char * buf )
2011-06-10 17:40:49 +04:00
{
struct ad5686_state * st = iio_priv ( indio_dev ) ;
return sprintf ( buf , " %d \n " , ! ! ( st - > pwr_down_mask &
2018-04-11 14:51:51 +03:00
( 0x3 < < ( chan - > channel * 2 ) ) ) ) ;
2011-06-10 17:40:49 +04:00
}
2012-06-04 13:36:17 +04:00
static ssize_t ad5686_write_dac_powerdown ( struct iio_dev * indio_dev ,
2018-04-11 14:51:51 +03:00
uintptr_t private ,
const struct iio_chan_spec * chan ,
const char * buf ,
size_t len )
2011-06-10 17:40:49 +04:00
{
bool readin ;
int ret ;
struct ad5686_state * st = iio_priv ( indio_dev ) ;
ret = strtobool ( buf , & readin ) ;
if ( ret )
return ret ;
2012-10-18 18:43:00 +04:00
if ( readin )
2012-06-04 13:36:17 +04:00
st - > pwr_down_mask | = ( 0x3 < < ( chan - > channel * 2 ) ) ;
2011-06-10 17:40:49 +04:00
else
2012-06-04 13:36:17 +04:00
st - > pwr_down_mask & = ~ ( 0x3 < < ( chan - > channel * 2 ) ) ;
2011-06-10 17:40:49 +04:00
2018-04-11 14:53:17 +03:00
ret = st - > write ( st , AD5686_CMD_POWERDOWN_DAC , 0 ,
st - > pwr_down_mask & st - > pwr_down_mode ) ;
2011-06-10 17:40:49 +04:00
return ret ? ret : len ;
}
static int ad5686_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val ,
int * val2 ,
long m )
{
struct ad5686_state * st = iio_priv ( indio_dev ) ;
int ret ;
switch ( m ) {
2012-04-15 20:41:19 +04:00
case IIO_CHAN_INFO_RAW :
2011-06-10 17:40:49 +04:00
mutex_lock ( & indio_dev - > mlock ) ;
2018-04-11 14:53:17 +03:00
ret = st - > read ( st , chan - > address ) ;
2011-06-10 17:40:49 +04:00
mutex_unlock ( & indio_dev - > mlock ) ;
if ( ret < 0 )
return ret ;
* val = ret ;
return IIO_VAL_INT ;
2011-10-26 20:41:36 +04:00
case IIO_CHAN_INFO_SCALE :
2013-09-28 13:31:00 +04:00
* val = st - > vref_mv ;
* val2 = chan - > scan_type . realbits ;
return IIO_VAL_FRACTIONAL_LOG2 ;
2011-06-10 17:40:49 +04:00
}
return - EINVAL ;
}
static int ad5686_write_raw ( struct iio_dev * indio_dev ,
2018-04-11 14:51:51 +03:00
struct iio_chan_spec const * chan ,
int val ,
int val2 ,
long mask )
2011-06-10 17:40:49 +04:00
{
struct ad5686_state * st = iio_priv ( indio_dev ) ;
int ret ;
switch ( mask ) {
2012-04-15 20:41:19 +04:00
case IIO_CHAN_INFO_RAW :
2011-10-19 19:51:28 +04:00
if ( val > ( 1 < < chan - > scan_type . realbits ) | | val < 0 )
2011-06-10 17:40:49 +04:00
return - EINVAL ;
mutex_lock ( & indio_dev - > mlock ) ;
2018-04-11 14:53:17 +03:00
ret = st - > write ( st ,
AD5686_CMD_WRITE_INPUT_N_UPDATE_N ,
chan - > address ,
val < < chan - > scan_type . shift ) ;
2011-06-10 17:40:49 +04:00
mutex_unlock ( & indio_dev - > mlock ) ;
break ;
default :
ret = - EINVAL ;
}
return ret ;
}
static const struct iio_info ad5686_info = {
. read_raw = ad5686_read_raw ,
. write_raw = ad5686_write_raw ,
} ;
2012-06-04 13:36:17 +04:00
static const struct iio_chan_spec_ext_info ad5686_ext_info [ ] = {
{
. name = " powerdown " ,
. read = ad5686_read_dac_powerdown ,
. write = ad5686_write_dac_powerdown ,
2013-09-08 17:57:00 +04:00
. shared = IIO_SEPARATE ,
2012-06-04 13:36:17 +04:00
} ,
2013-09-08 17:57:00 +04:00
IIO_ENUM ( " powerdown_mode " , IIO_SEPARATE , & ad5686_powerdown_mode_enum ) ,
2012-06-04 13:36:17 +04:00
IIO_ENUM_AVAILABLE ( " powerdown_mode " , & ad5686_powerdown_mode_enum ) ,
{ } ,
} ;
2018-04-11 14:52:31 +03:00
# define AD5868_CHANNEL(chan, addr, bits, _shift) { \
2012-06-04 13:36:17 +04:00
. type = IIO_VOLTAGE , \
. indexed = 1 , \
. output = 1 , \
. channel = chan , \
2013-02-27 23:27:41 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) , \
2018-04-11 14:52:31 +03:00
. address = addr , \
2013-12-11 22:45:00 +04:00
. scan_type = { \
. sign = ' u ' , \
. realbits = ( bits ) , \
. storagebits = 16 , \
. shift = ( _shift ) , \
} , \
2012-06-04 13:36:17 +04:00
. ext_info = ad5686_ext_info , \
}
2018-04-11 14:52:31 +03:00
# define DECLARE_AD5686_CHANNELS(name, bits, _shift) \
static struct iio_chan_spec name [ ] = { \
AD5868_CHANNEL ( 0 , 1 , bits , _shift ) , \
AD5868_CHANNEL ( 1 , 2 , bits , _shift ) , \
AD5868_CHANNEL ( 2 , 4 , bits , _shift ) , \
AD5868_CHANNEL ( 3 , 8 , bits , _shift ) , \
}
2018-04-11 14:53:01 +03:00
# define DECLARE_AD5676_CHANNELS(name, bits, _shift) \
static struct iio_chan_spec name [ ] = { \
AD5868_CHANNEL ( 0 , 0 , bits , _shift ) , \
AD5868_CHANNEL ( 1 , 1 , bits , _shift ) , \
AD5868_CHANNEL ( 2 , 2 , bits , _shift ) , \
AD5868_CHANNEL ( 3 , 3 , bits , _shift ) , \
AD5868_CHANNEL ( 4 , 4 , bits , _shift ) , \
AD5868_CHANNEL ( 5 , 5 , bits , _shift ) , \
AD5868_CHANNEL ( 6 , 6 , bits , _shift ) , \
AD5868_CHANNEL ( 7 , 7 , bits , _shift ) , \
}
DECLARE_AD5676_CHANNELS ( ad5672_channels , 12 , 4 ) ;
DECLARE_AD5676_CHANNELS ( ad5676_channels , 16 , 0 ) ;
2018-04-11 14:52:31 +03:00
DECLARE_AD5686_CHANNELS ( ad5684_channels , 12 , 4 ) ;
DECLARE_AD5686_CHANNELS ( ad5685r_channels , 14 , 2 ) ;
DECLARE_AD5686_CHANNELS ( ad5686_channels , 16 , 0 ) ;
2012-06-04 13:36:17 +04:00
static const struct ad5686_chip_info ad5686_chip_info_tbl [ ] = {
2018-04-11 14:53:01 +03:00
[ ID_AD5672R ] = {
. channels = ad5672_channels ,
. int_vref_mv = 2500 ,
. num_channels = 8 ,
} ,
[ ID_AD5676 ] = {
. channels = ad5676_channels ,
. num_channels = 8 ,
} ,
[ ID_AD5676R ] = {
. channels = ad5676_channels ,
. int_vref_mv = 2500 ,
. num_channels = 8 ,
} ,
2012-06-04 13:36:17 +04:00
[ ID_AD5684 ] = {
2018-04-11 14:52:31 +03:00
. channels = ad5684_channels ,
. num_channels = 4 ,
2018-04-11 14:53:01 +03:00
} ,
[ ID_AD5684R ] = {
. channels = ad5684_channels ,
2012-06-04 13:36:17 +04:00
. int_vref_mv = 2500 ,
2018-04-11 14:53:01 +03:00
. num_channels = 4 ,
2012-06-04 13:36:17 +04:00
} ,
2018-04-11 14:52:48 +03:00
[ ID_AD5685R ] = {
2018-04-11 14:52:31 +03:00
. channels = ad5685r_channels ,
2012-06-04 13:36:17 +04:00
. int_vref_mv = 2500 ,
2018-04-11 14:52:31 +03:00
. num_channels = 4 ,
2012-06-04 13:36:17 +04:00
} ,
[ ID_AD5686 ] = {
2018-04-11 14:52:31 +03:00
. channels = ad5686_channels ,
. num_channels = 4 ,
2018-04-11 14:53:01 +03:00
} ,
[ ID_AD5686R ] = {
. channels = ad5686_channels ,
2012-06-04 13:36:17 +04:00
. int_vref_mv = 2500 ,
2018-04-11 14:53:01 +03:00
. num_channels = 4 ,
2012-06-04 13:36:17 +04:00
} ,
} ;
2018-04-11 14:53:17 +03:00
int ad5686_probe ( struct device * dev ,
enum ad5686_supported_device_ids chip_type ,
const char * name , ad5686_write_func write ,
ad5686_read_func read )
2011-06-10 17:40:49 +04:00
{
struct ad5686_state * st ;
struct iio_dev * indio_dev ;
2014-03-07 11:38:00 +04:00
int ret , voltage_uv = 0 ;
2011-06-10 17:40:49 +04:00
2018-04-11 14:53:17 +03:00
indio_dev = devm_iio_device_alloc ( dev , sizeof ( * st ) ) ;
2011-06-10 17:40:49 +04:00
if ( indio_dev = = NULL )
return - ENOMEM ;
st = iio_priv ( indio_dev ) ;
2018-04-11 14:53:17 +03:00
dev_set_drvdata ( dev , indio_dev ) ;
st - > dev = dev ;
st - > write = write ;
st - > read = read ;
2011-06-10 17:40:49 +04:00
2018-04-11 14:53:17 +03:00
st - > reg = devm_regulator_get_optional ( dev , " vcc " ) ;
2011-06-10 17:40:49 +04:00
if ( ! IS_ERR ( st - > reg ) ) {
ret = regulator_enable ( st - > reg ) ;
if ( ret )
2013-08-19 15:38:00 +04:00
return ret ;
2011-06-10 17:40:49 +04:00
2012-12-14 16:08:00 +04:00
ret = regulator_get_voltage ( st - > reg ) ;
if ( ret < 0 )
goto error_disable_reg ;
voltage_uv = ret ;
2011-06-10 17:40:49 +04:00
}
2018-04-11 14:53:17 +03:00
st - > chip_info = & ad5686_chip_info_tbl [ chip_type ] ;
2011-06-10 17:40:49 +04:00
if ( voltage_uv )
st - > vref_mv = voltage_uv / 1000 ;
else
st - > vref_mv = st - > chip_info - > int_vref_mv ;
2012-06-04 13:36:17 +04:00
/* Set all the power down mode for all channels to 1K pulldown */
st - > pwr_down_mode = 0x55 ;
2018-04-11 14:53:17 +03:00
indio_dev - > dev . parent = dev ;
indio_dev - > name = name ;
2011-06-10 17:40:49 +04:00
indio_dev - > info = & ad5686_info ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
2018-04-11 14:52:31 +03:00
indio_dev - > channels = st - > chip_info - > channels ;
indio_dev - > num_channels = st - > chip_info - > num_channels ;
2011-06-10 17:40:49 +04:00
2018-04-11 14:53:17 +03:00
ret = st - > write ( st , AD5686_CMD_INTERNAL_REFER_SETUP ,
0 , ! ! voltage_uv ) ;
2011-06-10 17:40:49 +04:00
if ( ret )
goto error_disable_reg ;
2011-09-02 20:14:40 +04:00
ret = iio_device_register ( indio_dev ) ;
if ( ret )
goto error_disable_reg ;
2011-06-10 17:40:49 +04:00
return 0 ;
error_disable_reg :
if ( ! IS_ERR ( st - > reg ) )
regulator_disable ( st - > reg ) ;
return ret ;
}
2018-04-11 14:53:17 +03:00
EXPORT_SYMBOL_GPL ( ad5686_probe ) ;
2011-06-10 17:40:49 +04:00
2018-04-11 14:53:17 +03:00
int ad5686_remove ( struct device * dev )
2011-06-10 17:40:49 +04:00
{
2018-04-11 14:53:17 +03:00
struct iio_dev * indio_dev = dev_get_drvdata ( dev ) ;
2011-06-10 17:40:49 +04:00
struct ad5686_state * st = iio_priv ( indio_dev ) ;
2011-10-14 17:46:58 +04:00
iio_device_unregister ( indio_dev ) ;
2013-08-19 15:38:00 +04:00
if ( ! IS_ERR ( st - > reg ) )
2011-08-30 15:41:19 +04:00
regulator_disable ( st - > reg ) ;
2011-06-10 17:40:49 +04:00
return 0 ;
}
2018-04-11 14:53:17 +03:00
EXPORT_SYMBOL_GPL ( ad5686_remove ) ;
2011-06-10 17:40:49 +04:00
MODULE_AUTHOR ( " Michael Hennerich <hennerich@blackfin.uclinux.org> " ) ;
MODULE_DESCRIPTION ( " Analog Devices AD5686/85/84 DAC " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;