2019-04-02 12:31:55 +02:00
// SPDX-License-Identifier: GPL-2.0
2011-09-21 11:15:49 +01:00
/*
* AD7746 capacitive sensor driver supporting AD7745 , AD7746 and AD7747
*
* Copyright 2011 Analog Devices Inc .
*/
2022-06-26 13:29:29 +01:00
# include <linux/bitfield.h>
2018-04-13 13:36:42 -03:00
# include <linux/delay.h>
2011-09-21 11:15:49 +01:00
# include <linux/device.h>
# include <linux/i2c.h>
2018-04-13 13:36:42 -03:00
# include <linux/interrupt.h>
# include <linux/kernel.h>
2011-10-04 18:21:11 +11:00
# include <linux/module.h>
2018-04-13 13:36:42 -03:00
# include <linux/slab.h>
2011-10-04 18:21:11 +11:00
# include <linux/stat.h>
2018-04-13 13:36:42 -03:00
# include <linux/sysfs.h>
2011-09-21 11:15:49 +01:00
2022-06-26 13:29:24 +01:00
# include <asm/unaligned.h>
2012-04-25 15:54:58 +01:00
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
2011-09-21 11:15:49 +01:00
2022-06-26 13:29:35 +01:00
/* AD7746 Register Definition */
2011-09-21 11:15:49 +01:00
# define AD7746_REG_STATUS 0
# define AD7746_REG_CAP_DATA_HIGH 1
# define AD7746_REG_VT_DATA_HIGH 4
# define AD7746_REG_CAP_SETUP 7
# define AD7746_REG_VT_SETUP 8
# define AD7746_REG_EXC_SETUP 9
# define AD7746_REG_CFG 10
# define AD7746_REG_CAPDACA 11
# define AD7746_REG_CAPDACB 12
# define AD7746_REG_CAP_OFFH 13
# define AD7746_REG_CAP_GAINH 15
# define AD7746_REG_VOLT_GAINH 17
/* Status Register Bit Designations (AD7746_REG_STATUS) */
2015-09-10 22:02:39 +05:30
# define AD7746_STATUS_EXCERR BIT(3)
# define AD7746_STATUS_RDY BIT(2)
# define AD7746_STATUS_RDYVT BIT(1)
# define AD7746_STATUS_RDYCAP BIT(0)
2011-09-21 11:15:49 +01:00
/* Capacitive Channel Setup Register Bit Designations (AD7746_REG_CAP_SETUP) */
2017-03-24 19:25:33 +05:30
# define AD7746_CAPSETUP_CAPEN BIT(7)
# define AD7746_CAPSETUP_CIN2 BIT(6) /* AD7746 only */
# define AD7746_CAPSETUP_CAPDIFF BIT(5)
# define AD7746_CAPSETUP_CACHOP BIT(0)
2011-09-21 11:15:49 +01:00
/* Voltage/Temperature Setup Register Bit Designations (AD7746_REG_VT_SETUP) */
2022-06-26 13:29:29 +01:00
# define AD7746_VTSETUP_VTEN BIT(7)
# define AD7746_VTSETUP_VTMD_MASK GENMASK(6, 5)
# define AD7746_VTSETUP_VTMD_INT_TEMP 0
# define AD7746_VTSETUP_VTMD_EXT_TEMP 1
# define AD7746_VTSETUP_VTMD_VDD_MON 2
# define AD7746_VTSETUP_VTMD_EXT_VIN 3
2017-03-24 19:25:33 +05:30
# define AD7746_VTSETUP_EXTREF BIT(4)
# define AD7746_VTSETUP_VTSHORT BIT(1)
# define AD7746_VTSETUP_VTCHOP BIT(0)
2011-09-21 11:15:49 +01:00
/* Excitation Setup Register Bit Designations (AD7746_REG_EXC_SETUP) */
2015-09-25 22:53:01 +05:30
# define AD7746_EXCSETUP_CLKCTRL BIT(7)
# define AD7746_EXCSETUP_EXCON BIT(6)
# define AD7746_EXCSETUP_EXCB BIT(5)
# define AD7746_EXCSETUP_NEXCB BIT(4)
# define AD7746_EXCSETUP_EXCA BIT(3)
# define AD7746_EXCSETUP_NEXCA BIT(2)
2022-06-26 13:29:29 +01:00
# define AD7746_EXCSETUP_EXCLVL_MASK GENMASK(1, 0)
2011-09-21 11:15:49 +01:00
/* Config Register Bit Designations (AD7746_REG_CFG) */
2016-10-28 16:26:52 +08:00
# define AD7746_CONF_VTFS_MASK GENMASK(7, 6)
# define AD7746_CONF_CAPFS_MASK GENMASK(5, 3)
2022-06-26 13:29:29 +01:00
# define AD7746_CONF_MODE_MASK GENMASK(2, 0)
# define AD7746_CONF_MODE_IDLE 0
# define AD7746_CONF_MODE_CONT_CONV 1
# define AD7746_CONF_MODE_SINGLE_CONV 2
# define AD7746_CONF_MODE_PWRDN 3
# define AD7746_CONF_MODE_OFFS_CAL 5
# define AD7746_CONF_MODE_GAIN_CAL 6
2011-09-21 11:15:49 +01:00
/* CAPDAC Register Bit Designations (AD7746_REG_CAPDACx) */
2017-03-24 19:25:33 +05:30
# define AD7746_CAPDAC_DACEN BIT(7)
2022-06-26 13:29:29 +01:00
# define AD7746_CAPDAC_DACP_MASK GENMASK(6, 0)
2011-09-21 11:15:49 +01:00
struct ad7746_chip_info {
struct i2c_client * client ;
2017-03-14 03:34:25 +05:30
struct mutex lock ; /* protect sensor state */
2011-09-21 11:15:49 +01:00
/*
* Capacitive channel digital filter setup ;
* conversion time / update rate setup per channel
*/
u8 config ;
u8 cap_setup ;
u8 vt_setup ;
u8 capdac [ 2 ] [ 2 ] ;
s8 capdac_set ;
} ;
enum ad7746_chan {
VIN ,
VIN_VDD ,
TEMP_INT ,
TEMP_EXT ,
CIN1 ,
CIN1_DIFF ,
CIN2 ,
CIN2_DIFF ,
} ;
2022-06-26 13:29:29 +01:00
struct ad7746_chan_info {
u8 addr ;
union {
u8 vtmd ;
struct { /* CAP SETUP fields */
unsigned int cin2 : 1 ;
unsigned int capdiff : 1 ;
} ;
} ;
} ;
static const struct ad7746_chan_info ad7746_chan_info [ ] = {
[ VIN ] = {
. addr = AD7746_REG_VT_DATA_HIGH ,
. vtmd = AD7746_VTSETUP_VTMD_EXT_VIN ,
} ,
[ VIN_VDD ] = {
. addr = AD7746_REG_VT_DATA_HIGH ,
. vtmd = AD7746_VTSETUP_VTMD_VDD_MON ,
} ,
[ TEMP_INT ] = {
. addr = AD7746_REG_VT_DATA_HIGH ,
. vtmd = AD7746_VTSETUP_VTMD_INT_TEMP ,
} ,
[ TEMP_EXT ] = {
. addr = AD7746_REG_VT_DATA_HIGH ,
. vtmd = AD7746_VTSETUP_VTMD_EXT_TEMP ,
} ,
[ CIN1 ] = {
. addr = AD7746_REG_CAP_DATA_HIGH ,
} ,
[ CIN1_DIFF ] = {
. addr = AD7746_REG_CAP_DATA_HIGH ,
. capdiff = 1 ,
} ,
[ CIN2 ] = {
. addr = AD7746_REG_CAP_DATA_HIGH ,
. cin2 = 1 ,
} ,
[ CIN2_DIFF ] = {
. addr = AD7746_REG_CAP_DATA_HIGH ,
. cin2 = 1 ,
. capdiff = 1 ,
} ,
} ;
2011-09-21 11:15:49 +01:00
static const struct iio_chan_spec ad7746_channels [ ] = {
[ VIN ] = {
. type = IIO_VOLTAGE ,
. indexed = 1 ,
. channel = 0 ,
2022-06-26 13:29:25 +01:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) | BIT ( IIO_CHAN_INFO_SCALE ) ,
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
2022-06-26 13:29:34 +01:00
. info_mask_shared_by_type_available = BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
2022-06-26 13:29:29 +01:00
. address = VIN ,
2011-09-21 11:15:49 +01:00
} ,
[ VIN_VDD ] = {
. type = IIO_VOLTAGE ,
. indexed = 1 ,
. channel = 1 ,
. extend_name = " supply " ,
2022-06-26 13:29:25 +01:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) | BIT ( IIO_CHAN_INFO_SCALE ) ,
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
2022-06-26 13:29:34 +01:00
. info_mask_shared_by_type_available = BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
2022-06-26 13:29:29 +01:00
. address = VIN_VDD ,
2011-09-21 11:15:49 +01:00
} ,
[ TEMP_INT ] = {
. type = IIO_TEMP ,
. indexed = 1 ,
. channel = 0 ,
2022-06-26 13:29:31 +01:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) ,
2022-06-26 13:29:29 +01:00
. address = TEMP_INT ,
2011-09-21 11:15:49 +01:00
} ,
[ TEMP_EXT ] = {
. type = IIO_TEMP ,
. indexed = 1 ,
. channel = 1 ,
2022-06-26 13:29:31 +01:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) ,
2022-06-26 13:29:29 +01:00
. address = TEMP_EXT ,
2011-09-21 11:15:49 +01:00
} ,
[ CIN1 ] = {
. type = IIO_CAPACITANCE ,
. indexed = 1 ,
. channel = 0 ,
2013-02-27 19:38:26 +00:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_CALIBSCALE ) | BIT ( IIO_CHAN_INFO_OFFSET ) ,
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_CALIBBIAS ) |
2016-10-10 18:01:31 +08:00
BIT ( IIO_CHAN_INFO_SCALE ) | BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
2022-06-26 13:29:34 +01:00
. info_mask_shared_by_type_available = BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
2022-06-26 13:29:29 +01:00
. address = CIN1 ,
2011-09-21 11:15:49 +01:00
} ,
[ CIN1_DIFF ] = {
. type = IIO_CAPACITANCE ,
. differential = 1 ,
. indexed = 1 ,
. channel = 0 ,
. channel2 = 2 ,
2013-02-27 19:38:26 +00:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
2022-06-26 13:29:33 +01:00
BIT ( IIO_CHAN_INFO_CALIBSCALE ) | BIT ( IIO_CHAN_INFO_ZEROPOINT ) ,
2013-02-27 19:38:26 +00:00
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_CALIBBIAS ) |
2016-10-10 18:01:31 +08:00
BIT ( IIO_CHAN_INFO_SCALE ) | BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
2022-06-26 13:29:34 +01:00
. info_mask_shared_by_type_available = BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
2022-06-26 13:29:29 +01:00
. address = CIN1_DIFF ,
2011-09-21 11:15:49 +01:00
} ,
[ CIN2 ] = {
. type = IIO_CAPACITANCE ,
. indexed = 1 ,
. channel = 1 ,
2013-02-27 19:38:26 +00:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_CALIBSCALE ) | BIT ( IIO_CHAN_INFO_OFFSET ) ,
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_CALIBBIAS ) |
2016-10-10 18:01:31 +08:00
BIT ( IIO_CHAN_INFO_SCALE ) | BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
2022-06-26 13:29:34 +01:00
. info_mask_shared_by_type_available = BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
2022-06-26 13:29:29 +01:00
. address = CIN2 ,
2011-09-21 11:15:49 +01:00
} ,
[ CIN2_DIFF ] = {
. type = IIO_CAPACITANCE ,
. differential = 1 ,
. indexed = 1 ,
. channel = 1 ,
. channel2 = 3 ,
2013-02-27 19:38:26 +00:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
2022-06-26 13:29:33 +01:00
BIT ( IIO_CHAN_INFO_CALIBSCALE ) | BIT ( IIO_CHAN_INFO_ZEROPOINT ) ,
2013-02-27 19:38:26 +00:00
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_CALIBBIAS ) |
2016-10-10 18:01:31 +08:00
BIT ( IIO_CHAN_INFO_SCALE ) | BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
2022-06-26 13:29:34 +01:00
. info_mask_shared_by_type_available = BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
2022-06-26 13:29:29 +01:00
. address = CIN2_DIFF ,
2011-09-21 11:15:49 +01:00
}
} ;
/* Values are Update Rate (Hz), Conversion Time (ms) + 1*/
static const unsigned char ad7746_vt_filter_rate_table [ ] [ 2 ] = {
2022-06-26 13:29:35 +01:00
{ 50 , 20 + 1 } , { 31 , 32 + 1 } , { 16 , 62 + 1 } , { 8 , 122 + 1 } ,
2011-09-21 11:15:49 +01:00
} ;
static const unsigned char ad7746_cap_filter_rate_table [ ] [ 2 ] = {
2022-06-26 13:29:35 +01:00
{ 91 , 11 + 1 } , { 84 , 12 + 1 } , { 50 , 20 + 1 } , { 26 , 38 + 1 } ,
{ 16 , 62 + 1 } , { 13 , 77 + 1 } , { 11 , 92 + 1 } , { 9 , 110 + 1 } ,
2011-09-21 11:15:49 +01:00
} ;
2021-05-23 14:12:37 -03:00
static int ad7746_set_capdac ( struct ad7746_chip_info * chip , int channel )
{
int ret = i2c_smbus_write_byte_data ( chip - > client ,
AD7746_REG_CAPDACA ,
chip - > capdac [ channel ] [ 0 ] ) ;
if ( ret < 0 )
return ret ;
return i2c_smbus_write_byte_data ( chip - > client ,
AD7746_REG_CAPDACB ,
chip - > capdac [ channel ] [ 1 ] ) ;
}
2011-09-21 11:15:49 +01:00
static int ad7746_select_channel ( struct iio_dev * indio_dev ,
2018-03-08 10:48:13 +01:00
struct iio_chan_spec const * chan )
2011-09-21 11:15:49 +01:00
{
struct ad7746_chip_info * chip = iio_priv ( indio_dev ) ;
u8 vt_setup , cap_setup ;
2018-04-13 13:36:43 -03:00
int ret , delay , idx ;
2011-09-21 11:15:49 +01:00
switch ( chan - > type ) {
case IIO_CAPACITANCE :
2022-06-26 13:29:29 +01:00
cap_setup = FIELD_PREP ( AD7746_CAPSETUP_CIN2 ,
ad7746_chan_info [ chan - > address ] . cin2 ) |
FIELD_PREP ( AD7746_CAPSETUP_CAPDIFF ,
ad7746_chan_info [ chan - > address ] . capdiff ) |
FIELD_PREP ( AD7746_CAPSETUP_CAPEN , 1 ) ;
2011-09-21 11:15:49 +01:00
vt_setup = chip - > vt_setup & ~ AD7746_VTSETUP_VTEN ;
2022-06-26 13:29:29 +01:00
idx = FIELD_GET ( AD7746_CONF_CAPFS_MASK , chip - > config ) ;
2016-10-28 16:26:52 +08:00
delay = ad7746_cap_filter_rate_table [ idx ] [ 1 ] ;
2011-09-21 11:15:49 +01:00
2021-05-23 14:12:37 -03:00
ret = ad7746_set_capdac ( chip , chan - > channel ) ;
if ( ret < 0 )
return ret ;
2023-01-05 03:53:51 +01:00
chip - > capdac_set = chan - > channel ;
2011-09-21 11:15:49 +01:00
break ;
case IIO_VOLTAGE :
case IIO_TEMP :
2022-06-26 13:29:29 +01:00
vt_setup = FIELD_PREP ( AD7746_VTSETUP_VTMD_MASK ,
ad7746_chan_info [ chan - > address ] . vtmd ) |
FIELD_PREP ( AD7746_VTSETUP_VTEN , 1 ) ;
2011-09-21 11:15:49 +01:00
cap_setup = chip - > cap_setup & ~ AD7746_CAPSETUP_CAPEN ;
2022-06-26 13:29:29 +01:00
idx = FIELD_GET ( AD7746_CONF_VTFS_MASK , chip - > config ) ;
2016-10-28 16:26:52 +08:00
delay = ad7746_cap_filter_rate_table [ idx ] [ 1 ] ;
2011-09-21 11:15:49 +01:00
break ;
default :
return - EINVAL ;
}
if ( chip - > cap_setup ! = cap_setup ) {
ret = i2c_smbus_write_byte_data ( chip - > client ,
AD7746_REG_CAP_SETUP ,
cap_setup ) ;
if ( ret < 0 )
return ret ;
chip - > cap_setup = cap_setup ;
}
if ( chip - > vt_setup ! = vt_setup ) {
ret = i2c_smbus_write_byte_data ( chip - > client ,
AD7746_REG_VT_SETUP ,
vt_setup ) ;
if ( ret < 0 )
return ret ;
chip - > vt_setup = vt_setup ;
}
return delay ;
}
static inline ssize_t ad7746_start_calib ( struct device * dev ,
struct device_attribute * attr ,
const char * buf ,
size_t len ,
u8 regval )
{
2012-05-12 15:39:45 +02:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2011-09-21 11:15:49 +01:00
struct ad7746_chip_info * chip = iio_priv ( indio_dev ) ;
int ret , timeout = 10 ;
2018-04-13 13:36:43 -03:00
bool doit ;
2011-09-21 11:15:49 +01:00
2022-04-09 12:58:12 +02:00
ret = kstrtobool ( buf , & doit ) ;
2011-09-21 11:15:49 +01:00
if ( ret < 0 )
return ret ;
if ( ! doit )
return 0 ;
2017-03-14 03:34:25 +05:30
mutex_lock ( & chip - > lock ) ;
2011-09-21 11:15:49 +01:00
regval | = chip - > config ;
ret = i2c_smbus_write_byte_data ( chip - > client , AD7746_REG_CFG , regval ) ;
2017-11-03 09:26:28 +01:00
if ( ret < 0 )
goto unlock ;
2011-09-21 11:15:49 +01:00
do {
msleep ( 20 ) ;
ret = i2c_smbus_read_byte_data ( chip - > client , AD7746_REG_CFG ) ;
2017-11-03 09:26:28 +01:00
if ( ret < 0 )
goto unlock ;
2011-09-21 11:15:49 +01:00
} while ( ( ret = = regval ) & & timeout - - ) ;
2017-03-14 03:34:25 +05:30
mutex_unlock ( & chip - > lock ) ;
2011-09-21 11:15:49 +01:00
return len ;
2017-11-03 09:26:28 +01:00
unlock :
mutex_unlock ( & chip - > lock ) ;
return ret ;
2011-09-21 11:15:49 +01:00
}
static ssize_t ad7746_start_offset_calib ( struct device * dev ,
struct device_attribute * attr ,
const char * buf ,
size_t len )
{
2012-05-12 15:39:45 +02:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2011-09-21 11:15:49 +01:00
int ret = ad7746_select_channel ( indio_dev ,
& ad7746_channels [ to_iio_dev_attr ( attr ) - > address ] ) ;
if ( ret < 0 )
return ret ;
return ad7746_start_calib ( dev , attr , buf , len ,
2022-06-26 13:29:29 +01:00
FIELD_PREP ( AD7746_CONF_MODE_MASK ,
AD7746_CONF_MODE_OFFS_CAL ) ) ;
2011-09-21 11:15:49 +01:00
}
static ssize_t ad7746_start_gain_calib ( struct device * dev ,
struct device_attribute * attr ,
const char * buf ,
size_t len )
{
2012-05-12 15:39:45 +02:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2011-09-21 11:15:49 +01:00
int ret = ad7746_select_channel ( indio_dev ,
& ad7746_channels [ to_iio_dev_attr ( attr ) - > address ] ) ;
if ( ret < 0 )
return ret ;
return ad7746_start_calib ( dev , attr , buf , len ,
2022-06-26 13:29:29 +01:00
FIELD_PREP ( AD7746_CONF_MODE_MASK ,
AD7746_CONF_MODE_GAIN_CAL ) ) ;
2011-09-21 11:15:49 +01:00
}
static IIO_DEVICE_ATTR ( in_capacitance0_calibbias_calibration ,
2017-03-16 14:02:19 +01:00
0200 , NULL , ad7746_start_offset_calib , CIN1 ) ;
2011-09-21 11:15:49 +01:00
static IIO_DEVICE_ATTR ( in_capacitance1_calibbias_calibration ,
2017-03-16 14:02:19 +01:00
0200 , NULL , ad7746_start_offset_calib , CIN2 ) ;
2011-09-21 11:15:49 +01:00
static IIO_DEVICE_ATTR ( in_capacitance0_calibscale_calibration ,
2017-03-16 14:02:19 +01:00
0200 , NULL , ad7746_start_gain_calib , CIN1 ) ;
2011-09-21 11:15:49 +01:00
static IIO_DEVICE_ATTR ( in_capacitance1_calibscale_calibration ,
2017-03-16 14:02:19 +01:00
0200 , NULL , ad7746_start_gain_calib , CIN2 ) ;
2011-09-21 11:15:49 +01:00
static IIO_DEVICE_ATTR ( in_voltage0_calibscale_calibration ,
2017-03-16 14:02:19 +01:00
0200 , NULL , ad7746_start_gain_calib , VIN ) ;
2011-09-21 11:15:49 +01:00
2016-10-10 18:01:31 +08:00
static int ad7746_store_cap_filter_rate_setup ( struct ad7746_chip_info * chip ,
int val )
2011-09-21 11:15:49 +01:00
{
2016-10-10 18:01:31 +08:00
int i ;
2011-09-21 11:15:49 +01:00
for ( i = 0 ; i < ARRAY_SIZE ( ad7746_cap_filter_rate_table ) ; i + + )
2016-10-10 18:01:31 +08:00
if ( val > = ad7746_cap_filter_rate_table [ i ] [ 0 ] )
2011-09-21 11:15:49 +01:00
break ;
if ( i > = ARRAY_SIZE ( ad7746_cap_filter_rate_table ) )
i = ARRAY_SIZE ( ad7746_cap_filter_rate_table ) - 1 ;
2016-10-28 16:26:52 +08:00
chip - > config & = ~ AD7746_CONF_CAPFS_MASK ;
2022-06-26 13:29:29 +01:00
chip - > config | = FIELD_PREP ( AD7746_CONF_CAPFS_MASK , i ) ;
2011-09-21 11:15:49 +01:00
2016-10-10 18:01:31 +08:00
return 0 ;
2011-09-21 11:15:49 +01:00
}
2016-10-10 18:01:31 +08:00
static int ad7746_store_vt_filter_rate_setup ( struct ad7746_chip_info * chip ,
int val )
2011-09-21 11:15:49 +01:00
{
2016-10-10 18:01:31 +08:00
int i ;
2011-09-21 11:15:49 +01:00
for ( i = 0 ; i < ARRAY_SIZE ( ad7746_vt_filter_rate_table ) ; i + + )
2016-10-10 18:01:31 +08:00
if ( val > = ad7746_vt_filter_rate_table [ i ] [ 0 ] )
2011-09-21 11:15:49 +01:00
break ;
if ( i > = ARRAY_SIZE ( ad7746_vt_filter_rate_table ) )
i = ARRAY_SIZE ( ad7746_vt_filter_rate_table ) - 1 ;
2016-10-28 16:26:52 +08:00
chip - > config & = ~ AD7746_CONF_VTFS_MASK ;
2022-06-26 13:29:29 +01:00
chip - > config | = FIELD_PREP ( AD7746_CONF_VTFS_MASK , i ) ;
2011-09-21 11:15:49 +01:00
2016-10-10 18:01:31 +08:00
return 0 ;
2011-09-21 11:15:49 +01:00
}
static struct attribute * ad7746_attributes [ ] = {
& iio_dev_attr_in_capacitance0_calibbias_calibration . dev_attr . attr ,
& iio_dev_attr_in_capacitance0_calibscale_calibration . dev_attr . attr ,
& iio_dev_attr_in_capacitance1_calibscale_calibration . dev_attr . attr ,
& iio_dev_attr_in_capacitance1_calibbias_calibration . dev_attr . attr ,
& iio_dev_attr_in_voltage0_calibscale_calibration . dev_attr . attr ,
NULL ,
} ;
static const struct attribute_group ad7746_attribute_group = {
. attrs = ad7746_attributes ,
} ;
static int ad7746_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int val ,
int val2 ,
long mask )
{
struct ad7746_chip_info * chip = iio_priv ( indio_dev ) ;
int ret , reg ;
switch ( mask ) {
2011-10-26 17:41:36 +01:00
case IIO_CHAN_INFO_CALIBSCALE :
2022-06-26 13:29:28 +01:00
if ( val ! = 1 )
return - EINVAL ;
2011-09-21 11:15:49 +01:00
val = ( val2 * 1024 ) / 15625 ;
switch ( chan - > type ) {
case IIO_CAPACITANCE :
reg = AD7746_REG_CAP_GAINH ;
break ;
case IIO_VOLTAGE :
reg = AD7746_REG_VOLT_GAINH ;
break ;
default :
2022-06-26 13:29:28 +01:00
return - EINVAL ;
2011-09-21 11:15:49 +01:00
}
2022-06-26 13:29:28 +01:00
mutex_lock ( & chip - > lock ) ;
2018-04-13 13:36:38 -03:00
ret = i2c_smbus_write_word_swapped ( chip - > client , reg , val ) ;
2022-06-26 13:29:28 +01:00
mutex_unlock ( & chip - > lock ) ;
2011-09-21 11:15:49 +01:00
if ( ret < 0 )
2022-06-26 13:29:28 +01:00
return ret ;
2011-09-21 11:15:49 +01:00
2022-06-26 13:29:28 +01:00
return 0 ;
2011-10-26 17:41:36 +01:00
case IIO_CHAN_INFO_CALIBBIAS :
2022-06-26 13:29:28 +01:00
if ( val < 0 | | val > 0xFFFF )
return - EINVAL ;
mutex_lock ( & chip - > lock ) ;
2018-04-13 13:36:38 -03:00
ret = i2c_smbus_write_word_swapped ( chip - > client ,
AD7746_REG_CAP_OFFH , val ) ;
2022-06-26 13:29:28 +01:00
mutex_unlock ( & chip - > lock ) ;
2011-09-21 11:15:49 +01:00
if ( ret < 0 )
2022-06-26 13:29:28 +01:00
return ret ;
2011-09-21 11:15:49 +01:00
2022-06-26 13:29:28 +01:00
return 0 ;
2011-10-26 17:41:36 +01:00
case IIO_CHAN_INFO_OFFSET :
2022-06-26 13:29:33 +01:00
case IIO_CHAN_INFO_ZEROPOINT :
2022-06-26 13:29:28 +01:00
if ( val < 0 | | val > 43008000 ) /* 21pF */
return - EINVAL ;
2011-09-21 11:15:49 +01:00
2015-10-04 16:30:45 +00:00
/*
* CAPDAC Scale = 21 pF_typ / 127
2011-09-21 11:15:49 +01:00
* CIN Scale = 8.192 pF / 2 ^ 24
* Offset Scale = CAPDAC Scale / CIN Scale = 338646
2015-10-03 18:32:48 +00:00
*/
2011-09-21 11:15:49 +01:00
val / = 338646 ;
2022-06-26 13:29:28 +01:00
mutex_lock ( & chip - > lock ) ;
2016-02-11 15:41:55 -05:00
chip - > capdac [ chan - > channel ] [ chan - > differential ] = val > 0 ?
2022-06-26 13:29:29 +01:00
FIELD_PREP ( AD7746_CAPDAC_DACP_MASK , val ) | AD7746_CAPDAC_DACEN : 0 ;
2011-09-21 11:15:49 +01:00
2021-05-23 14:12:37 -03:00
ret = ad7746_set_capdac ( chip , chan - > channel ) ;
2022-06-26 13:29:28 +01:00
if ( ret < 0 ) {
mutex_unlock ( & chip - > lock ) ;
return ret ;
}
2011-09-21 11:15:49 +01:00
chip - > capdac_set = chan - > channel ;
2022-06-26 13:29:28 +01:00
mutex_unlock ( & chip - > lock ) ;
2011-09-21 11:15:49 +01:00
2022-06-26 13:29:28 +01:00
return 0 ;
2016-10-10 18:01:31 +08:00
case IIO_CHAN_INFO_SAMP_FREQ :
2022-06-26 13:29:28 +01:00
if ( val2 )
return - EINVAL ;
2016-10-10 18:01:31 +08:00
switch ( chan - > type ) {
case IIO_CAPACITANCE :
2022-06-26 13:29:28 +01:00
mutex_lock ( & chip - > lock ) ;
2016-10-10 18:01:31 +08:00
ret = ad7746_store_cap_filter_rate_setup ( chip , val ) ;
2022-06-26 13:29:28 +01:00
mutex_unlock ( & chip - > lock ) ;
return ret ;
2016-10-10 18:01:31 +08:00
case IIO_VOLTAGE :
2022-06-26 13:29:28 +01:00
mutex_lock ( & chip - > lock ) ;
2016-10-10 18:01:31 +08:00
ret = ad7746_store_vt_filter_rate_setup ( chip , val ) ;
2022-06-26 13:29:28 +01:00
mutex_unlock ( & chip - > lock ) ;
return ret ;
2016-10-10 18:01:31 +08:00
default :
2022-06-26 13:29:28 +01:00
return - EINVAL ;
2016-10-10 18:01:31 +08:00
}
2011-09-21 11:15:49 +01:00
default :
2022-06-26 13:29:28 +01:00
return - EINVAL ;
2011-09-21 11:15:49 +01:00
}
}
2022-06-26 13:29:34 +01:00
static const int ad7746_v_samp_freq [ ] = { 50 , 31 , 16 , 8 , } ;
static const int ad7746_cap_samp_freq [ ] = { 91 , 84 , 50 , 26 , 16 , 13 , 11 , 9 , } ;
static int ad7746_read_avail ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan , const int * * vals ,
int * type , int * length , long mask )
{
if ( mask ! = IIO_CHAN_INFO_SAMP_FREQ )
return - EINVAL ;
switch ( chan - > type ) {
case IIO_VOLTAGE :
* vals = ad7746_v_samp_freq ;
* length = ARRAY_SIZE ( ad7746_v_samp_freq ) ;
break ;
case IIO_CAPACITANCE :
* vals = ad7746_cap_samp_freq ;
* length = ARRAY_SIZE ( ad7746_cap_samp_freq ) ;
break ;
default :
return - EINVAL ;
}
* type = IIO_VAL_INT ;
return IIO_AVAIL_LIST ;
}
2022-06-26 13:29:27 +01:00
static int ad7746_read_channel ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val )
{
struct ad7746_chip_info * chip = iio_priv ( indio_dev ) ;
int ret , delay ;
u8 data [ 3 ] ;
u8 regval ;
ret = ad7746_select_channel ( indio_dev , chan ) ;
if ( ret < 0 )
return ret ;
delay = ret ;
2022-06-26 13:29:29 +01:00
regval = chip - > config | FIELD_PREP ( AD7746_CONF_MODE_MASK ,
AD7746_CONF_MODE_SINGLE_CONV ) ;
2022-06-26 13:29:27 +01:00
ret = i2c_smbus_write_byte_data ( chip - > client , AD7746_REG_CFG , regval ) ;
if ( ret < 0 )
return ret ;
msleep ( delay ) ;
/* Now read the actual register */
2022-06-26 13:29:29 +01:00
ret = i2c_smbus_read_i2c_block_data ( chip - > client ,
ad7746_chan_info [ chan - > address ] . addr ,
2022-06-26 13:29:27 +01:00
sizeof ( data ) , data ) ;
if ( ret < 0 )
return ret ;
2022-06-26 13:29:33 +01:00
/*
* Offset applied internally becaue the _offset userspace interface is
* needed for the CAP DACs which apply a controllable offset .
*/
2022-06-26 13:29:27 +01:00
* val = get_unaligned_be24 ( data ) - 0x800000 ;
return 0 ;
}
2011-09-21 11:15:49 +01:00
static int ad7746_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val , int * val2 ,
long mask )
{
struct ad7746_chip_info * chip = iio_priv ( indio_dev ) ;
2022-06-26 13:29:27 +01:00
int ret , idx ;
u8 reg ;
2011-09-21 11:15:49 +01:00
switch ( mask ) {
2012-04-15 17:41:26 +01:00
case IIO_CHAN_INFO_RAW :
2022-06-26 13:29:28 +01:00
mutex_lock ( & chip - > lock ) ;
2022-06-26 13:29:27 +01:00
ret = ad7746_read_channel ( indio_dev , chan , val ) ;
2022-06-26 13:29:28 +01:00
mutex_unlock ( & chip - > lock ) ;
2011-09-21 11:15:49 +01:00
if ( ret < 0 )
2022-06-26 13:29:28 +01:00
return ret ;
2011-09-21 11:15:49 +01:00
2022-06-26 13:29:28 +01:00
return IIO_VAL_INT ;
2011-10-26 17:41:36 +01:00
case IIO_CHAN_INFO_CALIBSCALE :
2011-09-21 11:15:49 +01:00
switch ( chan - > type ) {
case IIO_CAPACITANCE :
reg = AD7746_REG_CAP_GAINH ;
break ;
case IIO_VOLTAGE :
reg = AD7746_REG_VOLT_GAINH ;
break ;
default :
2022-06-26 13:29:28 +01:00
return - EINVAL ;
2011-09-21 11:15:49 +01:00
}
2022-06-26 13:29:28 +01:00
mutex_lock ( & chip - > lock ) ;
2018-04-13 13:36:38 -03:00
ret = i2c_smbus_read_word_swapped ( chip - > client , reg ) ;
2022-06-26 13:29:28 +01:00
mutex_unlock ( & chip - > lock ) ;
2011-09-21 11:15:49 +01:00
if ( ret < 0 )
2022-06-26 13:29:28 +01:00
return ret ;
2011-09-21 11:15:49 +01:00
/* 1 + gain_val / 2^16 */
* val = 1 ;
2018-04-13 13:36:38 -03:00
* val2 = ( 15625 * ret ) / 1024 ;
2011-09-21 11:15:49 +01:00
2022-06-26 13:29:28 +01:00
return IIO_VAL_INT_PLUS_MICRO ;
2011-10-26 17:41:36 +01:00
case IIO_CHAN_INFO_CALIBBIAS :
2022-06-26 13:29:28 +01:00
mutex_lock ( & chip - > lock ) ;
2018-04-13 13:36:38 -03:00
ret = i2c_smbus_read_word_swapped ( chip - > client ,
AD7746_REG_CAP_OFFH ) ;
2022-06-26 13:29:28 +01:00
mutex_unlock ( & chip - > lock ) ;
2011-09-21 11:15:49 +01:00
if ( ret < 0 )
2022-06-26 13:29:28 +01:00
return ret ;
2018-04-13 13:36:38 -03:00
* val = ret ;
2011-09-21 11:15:49 +01:00
2022-06-26 13:29:28 +01:00
return IIO_VAL_INT ;
2011-10-26 17:41:36 +01:00
case IIO_CHAN_INFO_OFFSET :
2022-06-26 13:29:33 +01:00
case IIO_CHAN_INFO_ZEROPOINT :
2022-06-26 13:29:29 +01:00
* val = FIELD_GET ( AD7746_CAPDAC_DACP_MASK ,
chip - > capdac [ chan - > channel ] [ chan - > differential ] ) * 338646 ;
2011-09-21 11:15:49 +01:00
2022-06-26 13:29:28 +01:00
return IIO_VAL_INT ;
2011-10-26 17:41:36 +01:00
case IIO_CHAN_INFO_SCALE :
2011-09-21 11:15:49 +01:00
switch ( chan - > type ) {
case IIO_CAPACITANCE :
/* 8.192pf / 2^24 */
* val = 0 ;
2013-09-28 10:31:00 +01:00
* val2 = 488 ;
2022-06-26 13:29:28 +01:00
return IIO_VAL_INT_PLUS_NANO ;
2011-09-21 11:15:49 +01:00
case IIO_VOLTAGE :
/* 1170mV / 2^23 */
2013-09-28 10:31:00 +01:00
* val = 1170 ;
2022-06-26 13:29:25 +01:00
if ( chan - > channel = = 1 )
* val * = 6 ;
2013-09-28 10:31:00 +01:00
* val2 = 23 ;
2022-06-26 13:29:28 +01:00
return IIO_VAL_FRACTIONAL_LOG2 ;
2022-06-26 13:29:31 +01:00
case IIO_TEMP :
* val = 125 ;
* val2 = 8 ;
return IIO_VAL_FRACTIONAL_LOG2 ;
2011-09-21 11:15:49 +01:00
default :
2022-06-26 13:29:28 +01:00
return - EINVAL ;
2011-09-21 11:15:49 +01:00
}
2016-10-10 18:01:31 +08:00
case IIO_CHAN_INFO_SAMP_FREQ :
switch ( chan - > type ) {
case IIO_CAPACITANCE :
2022-06-26 13:29:29 +01:00
idx = FIELD_GET ( AD7746_CONF_CAPFS_MASK , chip - > config ) ;
2016-10-28 16:26:52 +08:00
* val = ad7746_cap_filter_rate_table [ idx ] [ 0 ] ;
2022-06-26 13:29:28 +01:00
return IIO_VAL_INT ;
2016-10-10 18:01:31 +08:00
case IIO_VOLTAGE :
2022-06-26 13:29:29 +01:00
idx = FIELD_GET ( AD7746_CONF_VTFS_MASK , chip - > config ) ;
2016-10-28 16:26:52 +08:00
* val = ad7746_vt_filter_rate_table [ idx ] [ 0 ] ;
2022-06-26 13:29:28 +01:00
return IIO_VAL_INT ;
2016-10-10 18:01:31 +08:00
default :
2022-06-26 13:29:28 +01:00
return - EINVAL ;
2016-10-10 18:01:31 +08:00
}
2011-09-21 11:15:49 +01:00
default :
2022-06-26 13:29:28 +01:00
return - EINVAL ;
2012-09-28 10:57:00 +01:00
}
2011-09-21 11:15:49 +01:00
}
static const struct iio_info ad7746_info = {
. attrs = & ad7746_attribute_group ,
2017-03-11 19:56:37 +05:30
. read_raw = ad7746_read_raw ,
2022-06-26 13:29:34 +01:00
. read_avail = ad7746_read_avail ,
2017-03-11 19:56:37 +05:30
. write_raw = ad7746_write_raw ,
2011-09-21 11:15:49 +01:00
} ;
2022-11-18 23:36:46 +01:00
static int ad7746_probe ( struct i2c_client * client )
2011-09-21 11:15:49 +01:00
{
2022-11-18 23:36:46 +01:00
const struct i2c_device_id * id = i2c_client_get_device_id ( client ) ;
2021-05-01 09:32:53 -03:00
struct device * dev = & client - > dev ;
2011-09-21 11:15:49 +01:00
struct ad7746_chip_info * chip ;
struct iio_dev * indio_dev ;
unsigned char regval = 0 ;
2021-05-01 09:32:53 -03:00
unsigned int vdd_permille ;
2021-05-18 17:56:47 +08:00
int ret ;
2011-09-21 11:15:49 +01:00
2013-08-24 20:24:00 +01:00
indio_dev = devm_iio_device_alloc ( & client - > dev , sizeof ( * chip ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
2022-06-26 13:29:35 +01:00
2011-09-21 11:15:49 +01:00
chip = iio_priv ( indio_dev ) ;
2017-03-14 03:34:25 +05:30
mutex_init ( & chip - > lock ) ;
2011-09-21 11:15:49 +01:00
chip - > client = client ;
chip - > capdac_set = - 1 ;
indio_dev - > name = id - > name ;
indio_dev - > info = & ad7746_info ;
indio_dev - > channels = ad7746_channels ;
if ( id - > driver_data = = 7746 )
indio_dev - > num_channels = ARRAY_SIZE ( ad7746_channels ) ;
else
indio_dev - > num_channels = ARRAY_SIZE ( ad7746_channels ) - 2 ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
2021-05-01 09:32:53 -03:00
if ( device_property_read_bool ( dev , " adi,exca-output-en " ) ) {
if ( device_property_read_bool ( dev , " adi,exca-output-invert " ) )
regval | = AD7746_EXCSETUP_NEXCA ;
else
regval | = AD7746_EXCSETUP_EXCA ;
}
2011-09-21 11:15:49 +01:00
2021-05-01 09:32:53 -03:00
if ( device_property_read_bool ( dev , " adi,excb-output-en " ) ) {
if ( device_property_read_bool ( dev , " adi,excb-output-invert " ) )
regval | = AD7746_EXCSETUP_NEXCB ;
else
regval | = AD7746_EXCSETUP_EXCB ;
}
2011-09-21 11:15:49 +01:00
2021-05-01 09:32:53 -03:00
ret = device_property_read_u32 ( dev , " adi,excitation-vdd-permille " ,
& vdd_permille ) ;
if ( ! ret ) {
switch ( vdd_permille ) {
case 125 :
2022-06-26 13:29:29 +01:00
regval | = FIELD_PREP ( AD7746_EXCSETUP_EXCLVL_MASK , 0 ) ;
2021-05-01 09:32:53 -03:00
break ;
case 250 :
2022-06-26 13:29:29 +01:00
regval | = FIELD_PREP ( AD7746_EXCSETUP_EXCLVL_MASK , 1 ) ;
2021-05-01 09:32:53 -03:00
break ;
case 375 :
2022-06-26 13:29:29 +01:00
regval | = FIELD_PREP ( AD7746_EXCSETUP_EXCLVL_MASK , 2 ) ;
2021-05-01 09:32:53 -03:00
break ;
case 500 :
2022-06-26 13:29:29 +01:00
regval | = FIELD_PREP ( AD7746_EXCSETUP_EXCLVL_MASK , 3 ) ;
2021-05-01 09:32:53 -03:00
break ;
default :
break ;
}
2011-09-21 11:15:49 +01:00
}
2022-06-26 13:29:35 +01:00
ret = i2c_smbus_write_byte_data ( chip - > client , AD7746_REG_EXC_SETUP ,
regval ) ;
2011-09-21 11:15:49 +01:00
if ( ret < 0 )
2013-08-24 20:24:00 +01:00
return ret ;
2011-09-21 11:15:49 +01:00
2021-05-23 14:12:16 -03:00
return devm_iio_device_register ( indio_dev - > dev . parent , indio_dev ) ;
2011-09-21 11:15:49 +01:00
}
static const struct i2c_device_id ad7746_id [ ] = {
{ " ad7745 " , 7745 } ,
{ " ad7746 " , 7746 } ,
{ " ad7747 " , 7747 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , ad7746_id ) ;
2019-05-18 19:27:33 -03:00
static const struct of_device_id ad7746_of_match [ ] = {
{ . compatible = " adi,ad7745 " } ,
{ . compatible = " adi,ad7746 " } ,
{ . compatible = " adi,ad7747 " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , ad7746_of_match ) ;
2011-09-21 11:15:49 +01:00
static struct i2c_driver ad7746_driver = {
. driver = {
. name = KBUILD_MODNAME ,
2019-05-18 19:27:33 -03:00
. of_match_table = ad7746_of_match ,
2011-09-21 11:15:49 +01:00
} ,
2023-05-15 22:50:48 +02:00
. probe = ad7746_probe ,
2011-09-21 11:15:49 +01:00
. id_table = ad7746_id ,
} ;
2011-11-16 10:13:38 +01:00
module_i2c_driver ( ad7746_driver ) ;
2011-09-21 11:15:49 +01:00
2018-08-14 13:23:17 +02:00
MODULE_AUTHOR ( " Michael Hennerich <michael.hennerich@analog.com> " ) ;
2011-09-21 11:15:49 +01:00
MODULE_DESCRIPTION ( " Analog Devices AD7746/5/7 capacitive sensor driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;