2019-03-15 23:15:13 -03:00
// SPDX-License-Identifier: GPL-2.0
2011-03-24 19:37:00 +01:00
/*
2012-09-21 14:29:00 +01:00
* AD7170 / AD7171 and AD7780 / AD7781 SPI ADC driver
2011-03-24 19:37:00 +01:00
*
* Copyright 2011 Analog Devices Inc .
2019-03-15 23:15:26 -03:00
* Copyright 2019 Renato Lui Geh
2011-03-24 19:37:00 +01:00
*/
# include <linux/interrupt.h>
# include <linux/device.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/sysfs.h>
# include <linux/spi/spi.h>
# include <linux/regulator/consumer.h>
# include <linux/err.h>
# include <linux/sched.h>
2015-11-18 12:35:34 +02:00
# include <linux/gpio/consumer.h>
2011-07-03 15:49:50 -04:00
# include <linux/module.h>
2019-03-15 23:14:14 -03:00
# include <linux/bits.h>
2011-03-24 19:37:00 +01:00
2012-04-25 15:54:58 +01:00
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
2012-08-10 17:36:00 +01:00
# include <linux/iio/adc/ad_sigma_delta.h>
2011-03-24 19:37:00 +01:00
2018-11-08 11:03:40 -02:00
# define AD7780_RDY BIT(7)
# define AD7780_FILTER BIT(6)
# define AD7780_ERR BIT(5)
# define AD7780_ID1 BIT(4)
# define AD7780_ID0 BIT(3)
# define AD7780_GAIN BIT(2)
2019-03-15 23:14:27 -03:00
# define AD7170_ID 0
# define AD7171_ID 1
# define AD7780_ID 1
# define AD7781_ID 0
# define AD7780_ID_MASK (AD7780_ID0 | AD7780_ID1)
2018-11-08 11:03:40 -02:00
2019-03-15 23:14:14 -03:00
# define AD7780_PATTERN_GOOD 1
# define AD7780_PATTERN_MASK GENMASK(1, 0)
2018-11-08 11:03:40 -02:00
2019-03-15 23:14:14 -03:00
# define AD7170_PATTERN_GOOD 5
# define AD7170_PATTERN_MASK GENMASK(2, 0)
2011-03-24 19:37:00 +01:00
2019-03-15 23:12:27 -03:00
# define AD7780_GAIN_MIDPOINT 64
# define AD7780_FILTER_MIDPOINT 13350
2019-03-15 23:13:42 -03:00
static const unsigned int ad778x_gain [ 2 ] = { 1 , 128 } ;
static const unsigned int ad778x_odr_avail [ 2 ] = { 10000 , 16700 } ;
2019-03-15 23:13:13 -03:00
2011-03-24 19:37:00 +01:00
struct ad7780_chip_info {
2012-09-21 14:29:00 +01:00
struct iio_chan_spec channel ;
unsigned int pattern_mask ;
unsigned int pattern ;
2018-11-08 11:03:20 -02:00
bool is_ad778x ;
2011-03-24 19:37:00 +01:00
} ;
struct ad7780_state {
const struct ad7780_chip_info * chip_info ;
struct regulator * reg ;
2015-11-18 12:35:34 +02:00
struct gpio_desc * powerdown_gpio ;
2019-03-15 23:12:27 -03:00
struct gpio_desc * gain_gpio ;
struct gpio_desc * filter_gpio ;
unsigned int gain ;
2019-03-15 23:13:42 -03:00
unsigned int odr ;
2019-03-15 23:12:27 -03:00
unsigned int int_vref_mv ;
2012-08-10 17:36:00 +01:00
struct ad_sigma_delta sd ;
2011-03-24 19:37:00 +01:00
} ;
enum ad7780_supported_device_ids {
2012-09-21 14:29:00 +01:00
ID_AD7170 ,
ID_AD7171 ,
2011-03-24 19:37:00 +01:00
ID_AD7780 ,
ID_AD7781 ,
} ;
2012-08-10 17:36:00 +01:00
static struct ad7780_state * ad_sigma_delta_to_ad7780 ( struct ad_sigma_delta * sd )
2011-03-24 19:37:00 +01:00
{
2012-08-10 17:36:00 +01:00
return container_of ( sd , struct ad7780_state , sd ) ;
}
2011-03-24 19:37:00 +01:00
2012-08-10 17:36:00 +01:00
static int ad7780_set_mode ( struct ad_sigma_delta * sigma_delta ,
2015-10-14 21:14:13 +03:00
enum ad_sigma_delta_mode mode )
2012-08-10 17:36:00 +01:00
{
struct ad7780_state * st = ad_sigma_delta_to_ad7780 ( sigma_delta ) ;
2016-03-26 12:50:24 -07:00
unsigned int val ;
2012-08-10 17:36:00 +01:00
switch ( mode ) {
case AD_SD_MODE_SINGLE :
case AD_SD_MODE_CONTINUOUS :
val = 1 ;
break ;
default :
val = 0 ;
break ;
}
2011-03-24 19:37:00 +01:00
2015-11-18 12:35:34 +02:00
gpiod_set_value ( st - > powerdown_gpio , val ) ;
2011-03-24 19:37:00 +01:00
2012-08-10 17:36:00 +01:00
return 0 ;
2011-03-24 19:37:00 +01:00
}
2011-05-18 14:42:29 +01:00
static int ad7780_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val ,
int * val2 ,
long m )
2011-03-24 19:37:00 +01:00
{
2011-05-18 14:42:30 +01:00
struct ad7780_state * st = iio_priv ( indio_dev ) ;
2018-11-05 17:14:58 -02:00
int voltage_uv ;
2011-05-18 14:42:29 +01:00
switch ( m ) {
2012-04-15 17:41:18 +01:00
case IIO_CHAN_INFO_RAW :
2012-08-10 17:36:00 +01:00
return ad_sigma_delta_single_conversion ( indio_dev , chan , val ) ;
2011-10-26 17:41:36 +01:00
case IIO_CHAN_INFO_SCALE :
2018-11-05 17:14:58 -02:00
voltage_uv = regulator_get_voltage ( st - > reg ) ;
if ( voltage_uv < 0 )
return voltage_uv ;
2019-03-15 23:12:27 -03:00
voltage_uv / = 1000 ;
* val = voltage_uv * st - > gain ;
2013-09-28 10:31:00 +01:00
* val2 = chan - > scan_type . realbits - 1 ;
2019-03-15 23:12:27 -03:00
st - > int_vref_mv = voltage_uv ;
2013-09-28 10:31:00 +01:00
return IIO_VAL_FRACTIONAL_LOG2 ;
2012-08-10 17:36:00 +01:00
case IIO_CHAN_INFO_OFFSET :
2018-11-01 11:43:02 -03:00
* val = - ( 1 < < ( chan - > scan_type . realbits - 1 ) ) ;
2012-08-10 17:36:00 +01:00
return IIO_VAL_INT ;
2019-03-15 23:13:42 -03:00
case IIO_CHAN_INFO_SAMP_FREQ :
* val = st - > odr ;
return IIO_VAL_INT ;
2019-03-15 23:12:53 -03:00
default :
break ;
2011-05-18 14:42:29 +01:00
}
2012-08-10 17:36:00 +01:00
2011-05-18 14:42:29 +01:00
return - EINVAL ;
2011-03-24 19:37:00 +01:00
}
2019-03-15 23:12:27 -03:00
static int ad7780_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int val ,
int val2 ,
long m )
{
struct ad7780_state * st = iio_priv ( indio_dev ) ;
const struct ad7780_chip_info * chip_info = st - > chip_info ;
unsigned long long vref ;
unsigned int full_scale , gain ;
if ( ! chip_info - > is_ad778x )
return - EINVAL ;
switch ( m ) {
case IIO_CHAN_INFO_SCALE :
if ( val ! = 0 )
return - EINVAL ;
vref = st - > int_vref_mv * 1000000LL ;
full_scale = 1 < < ( chip_info - > channel . scan_type . realbits - 1 ) ;
gain = DIV_ROUND_CLOSEST_ULL ( vref , full_scale ) ;
gain = DIV_ROUND_CLOSEST ( gain , val2 ) ;
st - > gain = gain ;
if ( gain < AD7780_GAIN_MIDPOINT )
gain = 0 ;
else
gain = 1 ;
gpiod_set_value ( st - > gain_gpio , gain ) ;
break ;
case IIO_CHAN_INFO_SAMP_FREQ :
if ( 1000 * val + val2 / 1000 < AD7780_FILTER_MIDPOINT )
val = 0 ;
else
val = 1 ;
2019-03-15 23:13:42 -03:00
st - > odr = ad778x_odr_avail [ val ] ;
2019-03-15 23:12:27 -03:00
gpiod_set_value ( st - > filter_gpio , val ) ;
break ;
default :
break ;
}
return 0 ;
}
2012-08-10 17:36:00 +01:00
static int ad7780_postprocess_sample ( struct ad_sigma_delta * sigma_delta ,
2015-10-14 21:14:13 +03:00
unsigned int raw_sample )
2012-08-10 17:36:00 +01:00
{
struct ad7780_state * st = ad_sigma_delta_to_ad7780 ( sigma_delta ) ;
2012-09-21 14:29:00 +01:00
const struct ad7780_chip_info * chip_info = st - > chip_info ;
2012-08-10 17:36:00 +01:00
if ( ( raw_sample & AD7780_ERR ) | |
2015-10-14 21:14:13 +03:00
( ( raw_sample & chip_info - > pattern_mask ) ! = chip_info - > pattern ) )
2012-08-10 17:36:00 +01:00
return - EIO ;
2019-03-15 23:13:42 -03:00
if ( chip_info - > is_ad778x ) {
2019-03-15 23:13:13 -03:00
st - > gain = ad778x_gain [ raw_sample & AD7780_GAIN ] ;
2019-03-15 23:13:42 -03:00
st - > odr = ad778x_odr_avail [ raw_sample & AD7780_FILTER ] ;
}
2019-03-15 23:13:13 -03:00
2012-08-10 17:36:00 +01:00
return 0 ;
}
static const struct ad_sigma_delta_info ad7780_sigma_delta_info = {
. set_mode = ad7780_set_mode ,
. postprocess_sample = ad7780_postprocess_sample ,
. has_registers = false ,
2020-01-13 12:26:52 +02:00
. irq_flags = IRQF_TRIGGER_LOW ,
2012-08-10 17:36:00 +01:00
} ;
2020-03-21 11:07:58 +02:00
# define _AD7780_CHANNEL(_bits, _wordsize, _mask_all) \
{ \
. type = IIO_VOLTAGE , \
. indexed = 1 , \
. channel = 0 , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) | \
BIT ( IIO_CHAN_INFO_OFFSET ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) , \
. info_mask_shared_by_all = _mask_all , \
. scan_index = 1 , \
. scan_type = { \
. sign = ' u ' , \
. realbits = ( _bits ) , \
. storagebits = 32 , \
. shift = ( _wordsize ) - ( _bits ) , \
. endianness = IIO_BE , \
} , \
}
# define AD7780_CHANNEL(_bits, _wordsize) \
_AD7780_CHANNEL ( _bits , _wordsize , BIT ( IIO_CHAN_INFO_SAMP_FREQ ) )
# define AD7170_CHANNEL(_bits, _wordsize) \
_AD7780_CHANNEL ( _bits , _wordsize , 0 )
2012-09-21 14:29:00 +01:00
2011-03-24 19:37:00 +01:00
static const struct ad7780_chip_info ad7780_chip_info_tbl [ ] = {
2012-09-21 14:29:00 +01:00
[ ID_AD7170 ] = {
2019-03-15 23:13:42 -03:00
. channel = AD7170_CHANNEL ( 12 , 24 ) ,
2019-03-15 23:14:14 -03:00
. pattern = AD7170_PATTERN_GOOD ,
2018-11-08 11:03:40 -02:00
. pattern_mask = AD7170_PATTERN_MASK ,
2018-11-08 11:03:20 -02:00
. is_ad778x = false ,
2012-09-21 14:29:00 +01:00
} ,
[ ID_AD7171 ] = {
2019-03-15 23:13:42 -03:00
. channel = AD7170_CHANNEL ( 16 , 24 ) ,
2019-03-15 23:14:14 -03:00
. pattern = AD7170_PATTERN_GOOD ,
2018-11-08 11:03:40 -02:00
. pattern_mask = AD7170_PATTERN_MASK ,
2018-11-08 11:03:20 -02:00
. is_ad778x = false ,
2012-09-21 14:29:00 +01:00
} ,
2011-03-24 19:37:00 +01:00
[ ID_AD7780 ] = {
2012-09-21 14:29:00 +01:00
. channel = AD7780_CHANNEL ( 24 , 32 ) ,
2019-03-15 23:14:14 -03:00
. pattern = AD7780_PATTERN_GOOD ,
2018-11-08 11:03:40 -02:00
. pattern_mask = AD7780_PATTERN_MASK ,
2018-11-08 11:03:20 -02:00
. is_ad778x = true ,
2011-03-24 19:37:00 +01:00
} ,
[ ID_AD7781 ] = {
2012-09-21 14:29:00 +01:00
. channel = AD7780_CHANNEL ( 20 , 32 ) ,
2019-03-15 23:14:14 -03:00
. pattern = AD7780_PATTERN_GOOD ,
2018-11-08 11:03:40 -02:00
. pattern_mask = AD7780_PATTERN_MASK ,
2018-11-08 11:03:20 -02:00
. is_ad778x = true ,
2011-03-24 19:37:00 +01:00
} ,
} ;
2011-05-18 14:42:37 +01:00
static const struct iio_info ad7780_info = {
2017-03-11 19:56:36 +05:30
. read_raw = ad7780_read_raw ,
2019-03-15 23:12:27 -03:00
. write_raw = ad7780_write_raw ,
2011-05-18 14:42:37 +01:00
} ;
2019-03-15 23:12:27 -03:00
static int ad7780_init_gpios ( struct device * dev , struct ad7780_state * st )
{
int ret ;
st - > powerdown_gpio = devm_gpiod_get_optional ( dev ,
" powerdown " ,
GPIOD_OUT_LOW ) ;
if ( IS_ERR ( st - > powerdown_gpio ) ) {
ret = PTR_ERR ( st - > powerdown_gpio ) ;
dev_err ( dev , " Failed to request powerdown GPIO: %d \n " , ret ) ;
return ret ;
}
if ( ! st - > chip_info - > is_ad778x )
return 0 ;
st - > gain_gpio = devm_gpiod_get_optional ( dev ,
" adi,gain " ,
GPIOD_OUT_HIGH ) ;
if ( IS_ERR ( st - > gain_gpio ) ) {
ret = PTR_ERR ( st - > gain_gpio ) ;
dev_err ( dev , " Failed to request gain GPIO: %d \n " , ret ) ;
return ret ;
}
st - > filter_gpio = devm_gpiod_get_optional ( dev ,
" adi,filter " ,
GPIOD_OUT_HIGH ) ;
if ( IS_ERR ( st - > filter_gpio ) ) {
ret = PTR_ERR ( st - > filter_gpio ) ;
dev_err ( dev , " Failed to request filter GPIO: %d \n " , ret ) ;
return ret ;
}
return 0 ;
}
2012-11-19 13:21:57 -05:00
static int ad7780_probe ( struct spi_device * spi )
2011-03-24 19:37:00 +01:00
{
struct ad7780_state * st ;
2011-05-18 14:42:30 +01:00
struct iio_dev * indio_dev ;
2018-11-05 17:16:14 -02:00
int ret ;
2011-03-24 19:37:00 +01:00
2013-08-31 18:12:00 +01:00
indio_dev = devm_iio_device_alloc ( & spi - > dev , sizeof ( * st ) ) ;
2015-03-31 13:04:07 +03:00
if ( ! indio_dev )
2011-05-18 14:42:30 +01:00
return - ENOMEM ;
st = iio_priv ( indio_dev ) ;
2012-08-10 17:36:00 +01:00
st - > gain = 1 ;
ad_sd_init ( & st - > sd , indio_dev , spi , & ad7780_sigma_delta_info ) ;
2011-03-24 19:37:00 +01:00
st - > chip_info =
& ad7780_chip_info_tbl [ spi_get_device_id ( spi ) - > driver_data ] ;
2011-05-18 14:42:30 +01:00
spi_set_drvdata ( spi , indio_dev ) ;
2011-03-24 19:37:00 +01:00
2011-05-18 14:42:30 +01:00
indio_dev - > name = spi_get_device_id ( spi ) - > name ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > channels = & st - > chip_info - > channel ;
indio_dev - > num_channels = 1 ;
2011-05-18 14:42:37 +01:00
indio_dev - > info = & ad7780_info ;
2011-03-24 19:37:00 +01:00
2019-03-15 23:12:27 -03:00
ret = ad7780_init_gpios ( & spi - > dev , st ) ;
if ( ret )
2020-05-17 11:59:53 +02:00
return ret ;
2011-03-24 19:37:00 +01:00
2019-03-15 23:14:59 -03:00
st - > reg = devm_regulator_get ( & spi - > dev , " avdd " ) ;
if ( IS_ERR ( st - > reg ) )
return PTR_ERR ( st - > reg ) ;
ret = regulator_enable ( st - > reg ) ;
if ( ret ) {
dev_err ( & spi - > dev , " Failed to enable specified AVdd supply \n " ) ;
return ret ;
}
2012-08-10 17:36:00 +01:00
ret = ad_sd_setup_buffer_and_trigger ( indio_dev ) ;
2011-03-24 19:37:00 +01:00
if ( ret )
2013-08-31 18:12:00 +01:00
goto error_disable_reg ;
2011-03-24 19:37:00 +01:00
2011-05-18 14:42:30 +01:00
ret = iio_device_register ( indio_dev ) ;
2011-03-24 19:37:00 +01:00
if ( ret )
2012-08-10 17:36:00 +01:00
goto error_cleanup_buffer_and_trigger ;
2011-03-24 19:37:00 +01:00
return 0 ;
2012-08-10 17:36:00 +01:00
error_cleanup_buffer_and_trigger :
ad_sd_cleanup_buffer_and_trigger ( indio_dev ) ;
2011-03-24 19:37:00 +01:00
error_disable_reg :
2016-11-01 01:04:31 +08:00
regulator_disable ( st - > reg ) ;
2011-05-18 14:42:30 +01:00
2011-03-24 19:37:00 +01:00
return ret ;
}
2012-11-19 13:26:37 -05:00
static int ad7780_remove ( struct spi_device * spi )
2011-03-24 19:37:00 +01:00
{
2011-05-18 14:42:30 +01:00
struct iio_dev * indio_dev = spi_get_drvdata ( spi ) ;
struct ad7780_state * st = iio_priv ( indio_dev ) ;
2011-10-14 14:46:58 +01:00
iio_device_unregister ( indio_dev ) ;
2012-08-10 17:36:00 +01:00
ad_sd_cleanup_buffer_and_trigger ( indio_dev ) ;
2016-11-01 01:04:31 +08:00
regulator_disable ( st - > reg ) ;
2011-05-18 14:42:30 +01:00
2011-03-24 19:37:00 +01:00
return 0 ;
}
static const struct spi_device_id ad7780_id [ ] = {
2012-09-21 14:29:00 +01:00
{ " ad7170 " , ID_AD7170 } ,
{ " ad7171 " , ID_AD7171 } ,
2011-03-24 19:37:00 +01:00
{ " ad7780 " , ID_AD7780 } ,
{ " ad7781 " , ID_AD7781 } ,
{ }
} ;
2011-11-16 08:53:31 +01:00
MODULE_DEVICE_TABLE ( spi , ad7780_id ) ;
2011-03-24 19:37:00 +01:00
static struct spi_driver ad7780_driver = {
. driver = {
. name = " ad7780 " ,
} ,
. probe = ad7780_probe ,
2012-11-19 13:21:38 -05:00
. remove = ad7780_remove ,
2011-03-24 19:37:00 +01:00
. id_table = ad7780_id ,
} ;
2011-11-16 10:13:39 +01:00
module_spi_driver ( ad7780_driver ) ;
2011-03-24 19:37:00 +01:00
2018-08-14 13:23:17 +02:00
MODULE_AUTHOR ( " Michael Hennerich <michael.hennerich@analog.com> " ) ;
2012-09-21 14:29:00 +01:00
MODULE_DESCRIPTION ( " Analog Devices AD7780 and similar ADCs " ) ;
2011-03-24 19:37:00 +01:00
MODULE_LICENSE ( " GPL v2 " ) ;