2010-10-28 05:44:07 +04:00
/*
* AD5624R , AD5644R , AD5664R Digital to analog convertors spi driver
*
2011-03-09 18:01:45 +03:00
* Copyright 2010 - 2011 Analog Devices Inc .
2010-10-28 05:44:07 +04:00
*
2011-03-09 18:01:45 +03:00
* Licensed under the GPL - 2.
2010-10-28 05:44:07 +04:00
*/
# include <linux/interrupt.h>
# include <linux/fs.h>
# include <linux/device.h>
# include <linux/kernel.h>
# include <linux/spi/spi.h>
# include <linux/slab.h>
# include <linux/sysfs.h>
2011-03-09 18:01:45 +03:00
# include <linux/regulator/consumer.h>
2011-07-03 23:49:50 +04:00
# include <linux/module.h>
2010-10-28 05:44:07 +04:00
2012-04-25 18:54:58 +04:00
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
2012-06-04 13:36:19 +04:00
2010-10-28 05:44:07 +04:00
# include "ad5624r.h"
2010-11-19 17:16:44 +03:00
static int ad5624r_spi_write ( struct spi_device * spi ,
2015-06-19 15:48:06 +03:00
u8 cmd , u8 addr , u16 val , u8 shift )
2010-10-28 05:44:07 +04:00
{
u32 data ;
u8 msg [ 3 ] ;
/*
2011-03-09 18:01:45 +03:00
* The input shift register is 24 bits wide . The first two bits are
* don ' t care bits . The next three are the command bits , C2 to C0 ,
* followed by the 3 - bit DAC address , A2 to A0 , and then the
* 16 - , 14 - , 12 - bit data - word . The data - word comprises the 16 - ,
* 14 - , 12 - bit input code followed by 0 , 2 , or 4 don ' t care bits ,
* for the AD5664R , AD5644R , and AD5624R , respectively .
2010-10-28 05:44:07 +04:00
*/
2015-06-19 15:48:06 +03:00
data = ( 0 < < 22 ) | ( cmd < < 19 ) | ( addr < < 16 ) | ( val < < shift ) ;
2010-10-28 05:44:07 +04:00
msg [ 0 ] = data > > 16 ;
msg [ 1 ] = data > > 8 ;
msg [ 2 ] = data ;
2010-11-19 17:16:44 +03:00
return spi_write ( spi , msg , 3 ) ;
2010-10-28 05:44:07 +04:00
}
2011-11-15 19:31:24 +04:00
static int ad5624r_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val ,
int * val2 ,
long m )
2010-10-28 05:44:07 +04:00
{
2011-06-27 16:07:31 +04:00
struct ad5624r_state * st = iio_priv ( indio_dev ) ;
2010-10-28 05:44:07 +04:00
2011-11-15 19:31:24 +04:00
switch ( m ) {
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-11-15 19:31:24 +04:00
}
return - EINVAL ;
}
static int ad5624r_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int val ,
int val2 ,
long mask )
{
struct ad5624r_state * st = iio_priv ( indio_dev ) ;
switch ( mask ) {
2012-04-15 20:41:19 +04:00
case IIO_CHAN_INFO_RAW :
2011-11-15 19:31:24 +04:00
if ( val > = ( 1 < < chan - > scan_type . realbits ) | | val < 0 )
return - EINVAL ;
return ad5624r_spi_write ( st - > us ,
AD5624R_CMD_WRITE_INPUT_N_UPDATE_N ,
chan - > address , val ,
chan - > scan_type . shift ) ;
default :
2014-03-07 11:38:00 +04:00
return - EINVAL ;
2011-11-15 19:31:24 +04:00
}
2010-10-28 05:44:07 +04:00
}
2012-06-04 13:36:16 +04:00
static const char * const ad5624r_powerdown_modes [ ] = {
" 1kohm_to_gnd " ,
" 100kohm_to_gnd " ,
" three_state "
} ;
static int ad5624r_get_powerdown_mode ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan )
2010-10-28 05:44:07 +04:00
{
2011-06-27 16:07:31 +04:00
struct ad5624r_state * st = iio_priv ( indio_dev ) ;
2010-10-28 05:44:07 +04:00
2012-06-04 13:36:16 +04:00
return st - > pwr_down_mode ;
2010-10-28 05:44:07 +04:00
}
2012-06-04 13:36:16 +04:00
static int ad5624r_set_powerdown_mode ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan , unsigned int mode )
2010-10-28 05:44:07 +04:00
{
2011-06-27 16:07:31 +04:00
struct ad5624r_state * st = iio_priv ( indio_dev ) ;
2010-10-28 05:44:07 +04:00
2012-06-04 13:36:16 +04:00
st - > pwr_down_mode = mode ;
2010-10-28 05:44:07 +04:00
2012-06-04 13:36:16 +04:00
return 0 ;
2010-10-28 05:44:07 +04:00
}
2012-06-04 13:36:16 +04:00
static const struct iio_enum ad5624r_powerdown_mode_enum = {
. items = ad5624r_powerdown_modes ,
. num_items = ARRAY_SIZE ( ad5624r_powerdown_modes ) ,
. get = ad5624r_get_powerdown_mode ,
. set = ad5624r_set_powerdown_mode ,
} ;
static ssize_t ad5624r_read_dac_powerdown ( struct iio_dev * indio_dev ,
uintptr_t private , const struct iio_chan_spec * chan , char * buf )
2010-10-28 05:44:07 +04:00
{
2011-06-27 16:07:31 +04:00
struct ad5624r_state * st = iio_priv ( indio_dev ) ;
2010-10-28 05:44:07 +04:00
2011-03-09 18:01:45 +03:00
return sprintf ( buf , " %d \n " ,
2012-06-04 13:36:16 +04:00
! ! ( st - > pwr_down_mask & ( 1 < < chan - > channel ) ) ) ;
2010-10-28 05:44:07 +04:00
}
2012-06-04 13:36:16 +04:00
static ssize_t ad5624r_write_dac_powerdown ( struct iio_dev * indio_dev ,
uintptr_t private , const struct iio_chan_spec * chan , const char * buf ,
size_t len )
2010-10-28 05:44:07 +04:00
{
2012-06-04 13:36:23 +04:00
bool pwr_down ;
2010-10-28 05:44:07 +04:00
int ret ;
2011-06-27 16:07:31 +04:00
struct ad5624r_state * st = iio_priv ( indio_dev ) ;
2010-10-28 05:44:07 +04:00
2012-06-04 13:36:23 +04:00
ret = strtobool ( buf , & pwr_down ) ;
2010-10-28 05:44:07 +04:00
if ( ret )
return ret ;
2012-06-04 13:36:23 +04:00
if ( pwr_down )
2012-06-04 13:36:16 +04:00
st - > pwr_down_mask | = ( 1 < < chan - > channel ) ;
2011-03-09 18:01:45 +03:00
else
2012-06-04 13:36:23 +04:00
st - > pwr_down_mask & = ~ ( 1 < < chan - > channel ) ;
2010-10-28 05:44:07 +04:00
2011-03-09 18:01:45 +03:00
ret = ad5624r_spi_write ( st - > us , AD5624R_CMD_POWERDOWN_DAC , 0 ,
( st - > pwr_down_mode < < 4 ) |
st - > pwr_down_mask , 16 ) ;
2010-10-28 05:44:07 +04:00
return ret ? ret : len ;
}
2011-05-18 17:42:37 +04:00
static const struct iio_info ad5624r_info = {
2011-11-15 19:31:24 +04:00
. write_raw = ad5624r_write_raw ,
. read_raw = ad5624r_read_raw ,
2011-05-18 17:42:37 +04:00
. driver_module = THIS_MODULE ,
} ;
2012-06-04 13:36:16 +04:00
static const struct iio_chan_spec_ext_info ad5624r_ext_info [ ] = {
{
. name = " powerdown " ,
. read = ad5624r_read_dac_powerdown ,
. write = ad5624r_write_dac_powerdown ,
2013-09-08 17:57:00 +04:00
. shared = IIO_SEPARATE ,
2012-06-04 13:36:16 +04:00
} ,
2013-09-08 17:57:00 +04:00
IIO_ENUM ( " powerdown_mode " , IIO_SHARED_BY_TYPE ,
& ad5624r_powerdown_mode_enum ) ,
2012-06-04 13:36:16 +04:00
IIO_ENUM_AVAILABLE ( " powerdown_mode " , & ad5624r_powerdown_mode_enum ) ,
{ } ,
} ;
# define AD5624R_CHANNEL(_chan, _bits) { \
. type = IIO_VOLTAGE , \
. indexed = 1 , \
. output = 1 , \
. channel = ( _chan ) , \
2013-02-27 23:11:22 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) , \
2012-06-04 13:36:16 +04:00
. address = ( _chan ) , \
2013-12-11 22:45:00 +04:00
. scan_type = { \
. sign = ' u ' , \
. realbits = ( _bits ) , \
. storagebits = 16 , \
. shift = 16 - ( _bits ) , \
} , \
2012-06-04 13:36:16 +04:00
. ext_info = ad5624r_ext_info , \
}
# define DECLARE_AD5624R_CHANNELS(_name, _bits) \
const struct iio_chan_spec _name # # _channels [ ] = { \
AD5624R_CHANNEL ( 0 , _bits ) , \
AD5624R_CHANNEL ( 1 , _bits ) , \
AD5624R_CHANNEL ( 2 , _bits ) , \
AD5624R_CHANNEL ( 3 , _bits ) , \
}
static DECLARE_AD5624R_CHANNELS ( ad5624r , 12 ) ;
static DECLARE_AD5624R_CHANNELS ( ad5644r , 14 ) ;
static DECLARE_AD5624R_CHANNELS ( ad5664r , 16 ) ;
static const struct ad5624r_chip_info ad5624r_chip_info_tbl [ ] = {
[ ID_AD5624R3 ] = {
. channels = ad5624r_channels ,
. int_vref_mv = 1250 ,
} ,
[ ID_AD5624R5 ] = {
. channels = ad5624r_channels ,
. int_vref_mv = 2500 ,
} ,
[ ID_AD5644R3 ] = {
. channels = ad5644r_channels ,
. int_vref_mv = 1250 ,
} ,
[ ID_AD5644R5 ] = {
. channels = ad5644r_channels ,
. int_vref_mv = 2500 ,
} ,
[ ID_AD5664R3 ] = {
. channels = ad5664r_channels ,
. int_vref_mv = 1250 ,
} ,
[ ID_AD5664R5 ] = {
. channels = ad5664r_channels ,
. int_vref_mv = 2500 ,
} ,
} ;
2012-12-22 01:21:43 +04:00
static int ad5624r_probe ( struct spi_device * spi )
2010-10-28 05:44:07 +04:00
{
struct ad5624r_state * st ;
2011-06-27 16:07:31 +04:00
struct iio_dev * indio_dev ;
2011-03-09 18:01:45 +03:00
int ret , voltage_uv = 0 ;
2010-10-28 05:44:07 +04:00
2013-08-19 15:38:00 +04:00
indio_dev = devm_iio_device_alloc ( & spi - > dev , sizeof ( * st ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
2011-06-27 16:07:31 +04:00
st = iio_priv ( indio_dev ) ;
2013-08-19 15:38:00 +04:00
st - > reg = devm_regulator_get ( & spi - > dev , " vcc " ) ;
2011-08-30 15:41:19 +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-08-30 15:41:19 +04:00
2012-12-14 16:07:00 +04:00
ret = regulator_get_voltage ( st - > reg ) ;
if ( ret < 0 )
goto error_disable_reg ;
voltage_uv = ret ;
2011-08-30 15:41:19 +04:00
}
2011-06-27 16:07:31 +04:00
spi_set_drvdata ( spi , indio_dev ) ;
2011-03-09 18:01:45 +03:00
st - > chip_info =
& ad5624r_chip_info_tbl [ spi_get_device_id ( spi ) - > driver_data ] ;
if ( voltage_uv )
st - > vref_mv = voltage_uv / 1000 ;
else
st - > vref_mv = st - > chip_info - > int_vref_mv ;
2010-10-28 05:44:07 +04:00
st - > us = spi ;
2011-06-27 16:07:31 +04:00
indio_dev - > dev . parent = & spi - > dev ;
indio_dev - > name = spi_get_device_id ( spi ) - > name ;
indio_dev - > info = & ad5624r_info ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
2011-11-15 19:31:24 +04:00
indio_dev - > channels = st - > chip_info - > channels ;
indio_dev - > num_channels = AD5624R_DAC_CHANNELS ;
2011-06-27 16:07:31 +04:00
2011-08-30 15:41:18 +04:00
ret = ad5624r_spi_write ( spi , AD5624R_CMD_INTERNAL_REFER_SETUP , 0 ,
! ! voltage_uv , 16 ) ;
2010-10-28 05:44:07 +04:00
if ( ret )
2011-08-30 15:41:19 +04:00
goto error_disable_reg ;
2010-10-28 05:44:07 +04:00
2011-08-30 15:41:18 +04:00
ret = iio_device_register ( indio_dev ) ;
2011-03-09 18:01:45 +03:00
if ( ret )
2011-08-30 15:41:19 +04:00
goto error_disable_reg ;
2010-10-28 05:44:07 +04:00
return 0 ;
2011-03-09 18:01:45 +03:00
error_disable_reg :
2011-08-30 15:41:19 +04:00
if ( ! IS_ERR ( st - > reg ) )
regulator_disable ( st - > reg ) ;
2011-03-09 18:01:45 +03:00
2010-10-28 05:44:07 +04:00
return ret ;
}
2012-12-22 01:21:43 +04:00
static int ad5624r_remove ( struct spi_device * spi )
2010-10-28 05:44:07 +04:00
{
2011-06-27 16:07:31 +04:00
struct iio_dev * indio_dev = spi_get_drvdata ( spi ) ;
struct ad5624r_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-03-09 18:01:45 +03:00
2010-10-28 05:44:07 +04:00
return 0 ;
}
2010-11-19 17:16:45 +03:00
static const struct spi_device_id ad5624r_id [ ] = {
2011-03-09 18:01:45 +03:00
{ " ad5624r3 " , ID_AD5624R3 } ,
{ " ad5644r3 " , ID_AD5644R3 } ,
{ " ad5664r3 " , ID_AD5664R3 } ,
{ " ad5624r5 " , ID_AD5624R5 } ,
{ " ad5644r5 " , ID_AD5644R5 } ,
{ " ad5664r5 " , ID_AD5664R5 } ,
2010-11-19 17:16:45 +03:00
{ }
} ;
2011-11-16 11:53:31 +04:00
MODULE_DEVICE_TABLE ( spi , ad5624r_id ) ;
2010-11-19 17:16:45 +03:00
2010-10-28 05:44:07 +04:00
static struct spi_driver ad5624r_driver = {
. driver = {
2010-11-19 17:16:46 +03:00
. name = " ad5624r " ,
} ,
2010-10-28 05:44:07 +04:00
. probe = ad5624r_probe ,
2012-12-22 01:21:43 +04:00
. remove = ad5624r_remove ,
2010-11-19 17:16:45 +03:00
. id_table = ad5624r_id ,
2010-10-28 05:44:07 +04:00
} ;
2011-11-16 13:13:39 +04:00
module_spi_driver ( ad5624r_driver ) ;
2010-10-28 05:44:07 +04:00
MODULE_AUTHOR ( " Barry Song <21cnbao@gmail.com> " ) ;
MODULE_DESCRIPTION ( " Analog Devices AD5624/44/64R DAC spi driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;