2019-03-16 05:15:13 +03:00
// SPDX-License-Identifier: GPL-2.0
2011-03-24 21:37:00 +03:00
/*
2012-09-21 17:29:00 +04:00
* AD7170 / AD7171 and AD7780 / AD7781 SPI ADC driver
2011-03-24 21:37:00 +03:00
*
* Copyright 2011 Analog Devices Inc .
2019-03-16 05:15:26 +03:00
* Copyright 2019 Renato Lui Geh
2011-03-24 21:37:00 +03: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 13:35:34 +03:00
# include <linux/gpio/consumer.h>
2011-07-03 23:49:50 +04:00
# include <linux/module.h>
2019-03-16 05:14:14 +03:00
# include <linux/bits.h>
2011-03-24 21:37:00 +03:00
2012-04-25 18:54:58 +04:00
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
2012-08-10 20:36:00 +04:00
# include <linux/iio/adc/ad_sigma_delta.h>
2011-03-24 21:37:00 +03:00
2018-11-08 16:03:40 +03: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-16 05: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 16:03:40 +03:00
2019-03-16 05:14:14 +03:00
# define AD7780_PATTERN_GOOD 1
# define AD7780_PATTERN_MASK GENMASK(1, 0)
2018-11-08 16:03:40 +03:00
2019-03-16 05:14:14 +03:00
# define AD7170_PATTERN_GOOD 5
# define AD7170_PATTERN_MASK GENMASK(2, 0)
2011-03-24 21:37:00 +03:00
2019-03-16 05:12:27 +03:00
# define AD7780_GAIN_MIDPOINT 64
# define AD7780_FILTER_MIDPOINT 13350
2019-03-16 05: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-16 05:13:13 +03:00
2011-03-24 21:37:00 +03:00
struct ad7780_chip_info {
2012-09-21 17:29:00 +04:00
struct iio_chan_spec channel ;
unsigned int pattern_mask ;
unsigned int pattern ;
2018-11-08 16:03:20 +03:00
bool is_ad778x ;
2011-03-24 21:37:00 +03:00
} ;
struct ad7780_state {
const struct ad7780_chip_info * chip_info ;
struct regulator * reg ;
2015-11-18 13:35:34 +03:00
struct gpio_desc * powerdown_gpio ;
2019-03-16 05:12:27 +03:00
struct gpio_desc * gain_gpio ;
struct gpio_desc * filter_gpio ;
unsigned int gain ;
2019-03-16 05:13:42 +03:00
unsigned int odr ;
2019-03-16 05:12:27 +03:00
unsigned int int_vref_mv ;
2012-08-10 20:36:00 +04:00
struct ad_sigma_delta sd ;
2011-03-24 21:37:00 +03:00
} ;
enum ad7780_supported_device_ids {
2012-09-21 17:29:00 +04:00
ID_AD7170 ,
ID_AD7171 ,
2011-03-24 21:37:00 +03:00
ID_AD7780 ,
ID_AD7781 ,
} ;
2012-08-10 20:36:00 +04:00
static struct ad7780_state * ad_sigma_delta_to_ad7780 ( struct ad_sigma_delta * sd )
2011-03-24 21:37:00 +03:00
{
2012-08-10 20:36:00 +04:00
return container_of ( sd , struct ad7780_state , sd ) ;
}
2011-03-24 21:37:00 +03:00
2012-08-10 20:36:00 +04: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 20:36:00 +04:00
{
struct ad7780_state * st = ad_sigma_delta_to_ad7780 ( sigma_delta ) ;
2016-03-26 22:50:24 +03:00
unsigned int val ;
2012-08-10 20:36:00 +04:00
switch ( mode ) {
case AD_SD_MODE_SINGLE :
case AD_SD_MODE_CONTINUOUS :
val = 1 ;
break ;
default :
val = 0 ;
break ;
}
2011-03-24 21:37:00 +03:00
2015-11-18 13:35:34 +03:00
gpiod_set_value ( st - > powerdown_gpio , val ) ;
2011-03-24 21:37:00 +03:00
2012-08-10 20:36:00 +04:00
return 0 ;
2011-03-24 21:37:00 +03:00
}
2011-05-18 17:42:29 +04: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 21:37:00 +03:00
{
2011-05-18 17:42:30 +04:00
struct ad7780_state * st = iio_priv ( indio_dev ) ;
2018-11-05 22:14:58 +03:00
int voltage_uv ;
2011-05-18 17:42:29 +04:00
switch ( m ) {
2012-04-15 20:41:18 +04:00
case IIO_CHAN_INFO_RAW :
2012-08-10 20:36:00 +04:00
return ad_sigma_delta_single_conversion ( indio_dev , chan , val ) ;
2011-10-26 20:41:36 +04:00
case IIO_CHAN_INFO_SCALE :
2018-11-05 22:14:58 +03:00
voltage_uv = regulator_get_voltage ( st - > reg ) ;
if ( voltage_uv < 0 )
return voltage_uv ;
2019-03-16 05:12:27 +03:00
voltage_uv / = 1000 ;
* val = voltage_uv * st - > gain ;
2013-09-28 13:31:00 +04:00
* val2 = chan - > scan_type . realbits - 1 ;
2019-03-16 05:12:27 +03:00
st - > int_vref_mv = voltage_uv ;
2013-09-28 13:31:00 +04:00
return IIO_VAL_FRACTIONAL_LOG2 ;
2012-08-10 20:36:00 +04:00
case IIO_CHAN_INFO_OFFSET :
2018-11-01 17:43:02 +03:00
* val = - ( 1 < < ( chan - > scan_type . realbits - 1 ) ) ;
2012-08-10 20:36:00 +04:00
return IIO_VAL_INT ;
2019-03-16 05:13:42 +03:00
case IIO_CHAN_INFO_SAMP_FREQ :
* val = st - > odr ;
return IIO_VAL_INT ;
2019-03-16 05:12:53 +03:00
default :
break ;
2011-05-18 17:42:29 +04:00
}
2012-08-10 20:36:00 +04:00
2011-05-18 17:42:29 +04:00
return - EINVAL ;
2011-03-24 21:37:00 +03:00
}
2019-03-16 05: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-16 05:13:42 +03:00
st - > odr = ad778x_odr_avail [ val ] ;
2019-03-16 05:12:27 +03:00
gpiod_set_value ( st - > filter_gpio , val ) ;
break ;
default :
break ;
}
return 0 ;
}
2012-08-10 20:36:00 +04: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 20:36:00 +04:00
{
struct ad7780_state * st = ad_sigma_delta_to_ad7780 ( sigma_delta ) ;
2012-09-21 17:29:00 +04:00
const struct ad7780_chip_info * chip_info = st - > chip_info ;
2012-08-10 20:36:00 +04: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 20:36:00 +04:00
return - EIO ;
2019-03-16 05:13:42 +03:00
if ( chip_info - > is_ad778x ) {
2019-03-16 05:13:13 +03:00
st - > gain = ad778x_gain [ raw_sample & AD7780_GAIN ] ;
2019-03-16 05:13:42 +03:00
st - > odr = ad778x_odr_avail [ raw_sample & AD7780_FILTER ] ;
}
2019-03-16 05:13:13 +03:00
2012-08-10 20:36:00 +04: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 ,
} ;
2012-09-21 17:29:00 +04:00
# define AD7780_CHANNEL(bits, wordsize) \
2019-03-22 00:15:28 +03:00
AD_SD_CHANNEL ( 1 , 0 , 0 , bits , 32 , ( wordsize ) - ( bits ) )
2019-03-16 05:13:42 +03:00
# define AD7170_CHANNEL(bits, wordsize) \
2019-03-22 00:15:28 +03:00
AD_SD_CHANNEL_NO_SAMP_FREQ ( 1 , 0 , 0 , bits , 32 , ( wordsize ) - ( bits ) )
2012-09-21 17:29:00 +04:00
2011-03-24 21:37:00 +03:00
static const struct ad7780_chip_info ad7780_chip_info_tbl [ ] = {
2012-09-21 17:29:00 +04:00
[ ID_AD7170 ] = {
2019-03-16 05:13:42 +03:00
. channel = AD7170_CHANNEL ( 12 , 24 ) ,
2019-03-16 05:14:14 +03:00
. pattern = AD7170_PATTERN_GOOD ,
2018-11-08 16:03:40 +03:00
. pattern_mask = AD7170_PATTERN_MASK ,
2018-11-08 16:03:20 +03:00
. is_ad778x = false ,
2012-09-21 17:29:00 +04:00
} ,
[ ID_AD7171 ] = {
2019-03-16 05:13:42 +03:00
. channel = AD7170_CHANNEL ( 16 , 24 ) ,
2019-03-16 05:14:14 +03:00
. pattern = AD7170_PATTERN_GOOD ,
2018-11-08 16:03:40 +03:00
. pattern_mask = AD7170_PATTERN_MASK ,
2018-11-08 16:03:20 +03:00
. is_ad778x = false ,
2012-09-21 17:29:00 +04:00
} ,
2011-03-24 21:37:00 +03:00
[ ID_AD7780 ] = {
2012-09-21 17:29:00 +04:00
. channel = AD7780_CHANNEL ( 24 , 32 ) ,
2019-03-16 05:14:14 +03:00
. pattern = AD7780_PATTERN_GOOD ,
2018-11-08 16:03:40 +03:00
. pattern_mask = AD7780_PATTERN_MASK ,
2018-11-08 16:03:20 +03:00
. is_ad778x = true ,
2011-03-24 21:37:00 +03:00
} ,
[ ID_AD7781 ] = {
2012-09-21 17:29:00 +04:00
. channel = AD7780_CHANNEL ( 20 , 32 ) ,
2019-03-16 05:14:14 +03:00
. pattern = AD7780_PATTERN_GOOD ,
2018-11-08 16:03:40 +03:00
. pattern_mask = AD7780_PATTERN_MASK ,
2018-11-08 16:03:20 +03:00
. is_ad778x = true ,
2011-03-24 21:37:00 +03:00
} ,
} ;
2011-05-18 17:42:37 +04:00
static const struct iio_info ad7780_info = {
2017-03-11 17:26:36 +03:00
. read_raw = ad7780_read_raw ,
2019-03-16 05:12:27 +03:00
. write_raw = ad7780_write_raw ,
2011-05-18 17:42:37 +04:00
} ;
2019-03-16 05: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 22:21:57 +04:00
static int ad7780_probe ( struct spi_device * spi )
2011-03-24 21:37:00 +03:00
{
struct ad7780_state * st ;
2011-05-18 17:42:30 +04:00
struct iio_dev * indio_dev ;
2018-11-05 22:16:14 +03:00
int ret ;
2011-03-24 21:37:00 +03:00
2013-08-31 21:12:00 +04: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 17:42:30 +04:00
return - ENOMEM ;
st = iio_priv ( indio_dev ) ;
2012-08-10 20:36:00 +04:00
st - > gain = 1 ;
ad_sd_init ( & st - > sd , indio_dev , spi , & ad7780_sigma_delta_info ) ;
2011-03-24 21:37:00 +03:00
st - > chip_info =
& ad7780_chip_info_tbl [ spi_get_device_id ( spi ) - > driver_data ] ;
2011-05-18 17:42:30 +04:00
spi_set_drvdata ( spi , indio_dev ) ;
2011-03-24 21:37:00 +03:00
2011-05-18 17:42:30 +04:00
indio_dev - > dev . parent = & spi - > dev ;
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 17:42:37 +04:00
indio_dev - > info = & ad7780_info ;
2011-03-24 21:37:00 +03:00
2019-03-16 05:12:27 +03:00
ret = ad7780_init_gpios ( & spi - > dev , st ) ;
if ( ret )
goto error_cleanup_buffer_and_trigger ;
2011-03-24 21:37:00 +03:00
2019-03-16 05: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 20:36:00 +04:00
ret = ad_sd_setup_buffer_and_trigger ( indio_dev ) ;
2011-03-24 21:37:00 +03:00
if ( ret )
2013-08-31 21:12:00 +04:00
goto error_disable_reg ;
2011-03-24 21:37:00 +03:00
2011-05-18 17:42:30 +04:00
ret = iio_device_register ( indio_dev ) ;
2011-03-24 21:37:00 +03:00
if ( ret )
2012-08-10 20:36:00 +04:00
goto error_cleanup_buffer_and_trigger ;
2011-03-24 21:37:00 +03:00
return 0 ;
2012-08-10 20:36:00 +04:00
error_cleanup_buffer_and_trigger :
ad_sd_cleanup_buffer_and_trigger ( indio_dev ) ;
2011-03-24 21:37:00 +03:00
error_disable_reg :
2016-10-31 20:04:31 +03:00
regulator_disable ( st - > reg ) ;
2011-05-18 17:42:30 +04:00
2011-03-24 21:37:00 +03:00
return ret ;
}
2012-11-19 22:26:37 +04:00
static int ad7780_remove ( struct spi_device * spi )
2011-03-24 21:37:00 +03:00
{
2011-05-18 17:42:30 +04:00
struct iio_dev * indio_dev = spi_get_drvdata ( spi ) ;
struct ad7780_state * st = iio_priv ( indio_dev ) ;
2011-10-14 17:46:58 +04:00
iio_device_unregister ( indio_dev ) ;
2012-08-10 20:36:00 +04:00
ad_sd_cleanup_buffer_and_trigger ( indio_dev ) ;
2016-10-31 20:04:31 +03:00
regulator_disable ( st - > reg ) ;
2011-05-18 17:42:30 +04:00
2011-03-24 21:37:00 +03:00
return 0 ;
}
static const struct spi_device_id ad7780_id [ ] = {
2012-09-21 17:29:00 +04:00
{ " ad7170 " , ID_AD7170 } ,
{ " ad7171 " , ID_AD7171 } ,
2011-03-24 21:37:00 +03:00
{ " ad7780 " , ID_AD7780 } ,
{ " ad7781 " , ID_AD7781 } ,
{ }
} ;
2011-11-16 11:53:31 +04:00
MODULE_DEVICE_TABLE ( spi , ad7780_id ) ;
2011-03-24 21:37:00 +03:00
static struct spi_driver ad7780_driver = {
. driver = {
. name = " ad7780 " ,
} ,
. probe = ad7780_probe ,
2012-11-19 22:21:38 +04:00
. remove = ad7780_remove ,
2011-03-24 21:37:00 +03:00
. id_table = ad7780_id ,
} ;
2011-11-16 13:13:39 +04:00
module_spi_driver ( ad7780_driver ) ;
2011-03-24 21:37:00 +03:00
2018-08-14 14:23:17 +03:00
MODULE_AUTHOR ( " Michael Hennerich <michael.hennerich@analog.com> " ) ;
2012-09-21 17:29:00 +04:00
MODULE_DESCRIPTION ( " Analog Devices AD7780 and similar ADCs " ) ;
2011-03-24 21:37:00 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;