2023-03-07 07:55:34 +01:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* ADS1100 - Texas Instruments Analog - to - Digital Converter
*
* Copyright ( c ) 2023 , Topic Embedded Products
*
* Datasheet : https : //www.ti.com/lit/gpn/ads1100
* IIO driver for ADS1100 and ADS1000 ADC 16 - bit I2C
*/
# include <linux/bitfield.h>
# include <linux/bits.h>
# include <linux/delay.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/i2c.h>
# include <linux/mutex.h>
# include <linux/property.h>
# include <linux/pm_runtime.h>
# include <linux/regulator/consumer.h>
# include <linux/units.h>
# include <linux/iio/iio.h>
# include <linux/iio/types.h>
/* The ADS1100 has a single byte config register */
/* Conversion in progress bit */
# define ADS1100_CFG_ST_BSY BIT(7)
/* Single conversion bit */
# define ADS1100_CFG_SC BIT(4)
/* Data rate */
# define ADS1100_DR_MASK GENMASK(3, 2)
/* Gain */
# define ADS1100_PGA_MASK GENMASK(1, 0)
# define ADS1100_CONTINUOUS 0
# define ADS1100_SINGLESHOT ADS1100_CFG_SC
# define ADS1100_SLEEP_DELAY_MS 2000
static const int ads1100_data_rate [ ] = { 128 , 32 , 16 , 8 } ;
static const int ads1100_data_rate_bits [ ] = { 12 , 14 , 15 , 16 } ;
struct ads1100_data {
struct i2c_client * client ;
struct regulator * reg_vdd ;
struct mutex lock ;
int scale_avail [ 2 * 4 ] ; /* 4 gain settings */
u8 config ;
bool supports_data_rate ; /* Only the ADS1100 can select the rate */
} ;
static const struct iio_chan_spec ads1100_channel = {
. type = IIO_VOLTAGE ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
. info_mask_shared_by_all =
BIT ( IIO_CHAN_INFO_SCALE ) | BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
. info_mask_shared_by_all_available =
BIT ( IIO_CHAN_INFO_SCALE ) | BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
. scan_type = {
. sign = ' s ' ,
. realbits = 16 ,
. storagebits = 16 ,
. endianness = IIO_CPU ,
} ,
. datasheet_name = " AIN " ,
} ;
static int ads1100_set_config_bits ( struct ads1100_data * data , u8 mask , u8 value )
{
int ret ;
u8 config = ( data - > config & ~ mask ) | ( value & mask ) ;
if ( data - > config = = config )
return 0 ; /* Already done */
ret = i2c_master_send ( data - > client , & config , 1 ) ;
if ( ret < 0 )
return ret ;
data - > config = config ;
return 0 ;
} ;
static int ads1100_data_bits ( struct ads1100_data * data )
{
return ads1100_data_rate_bits [ FIELD_GET ( ADS1100_DR_MASK , data - > config ) ] ;
}
static int ads1100_get_adc_result ( struct ads1100_data * data , int chan , int * val )
{
int ret ;
__be16 buffer ;
s16 value ;
if ( chan ! = 0 )
return - EINVAL ;
ret = pm_runtime_resume_and_get ( & data - > client - > dev ) ;
if ( ret < 0 )
return ret ;
ret = i2c_master_recv ( data - > client , ( char * ) & buffer , sizeof ( buffer ) ) ;
pm_runtime_mark_last_busy ( & data - > client - > dev ) ;
pm_runtime_put_autosuspend ( & data - > client - > dev ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " I2C read fail: %d \n " , ret ) ;
return ret ;
}
/* Value is always 16-bit 2's complement */
value = be16_to_cpu ( buffer ) ;
/* Shift result to compensate for bit resolution vs. sample rate */
value < < = 16 - ads1100_data_bits ( data ) ;
* val = sign_extend32 ( value , 15 ) ;
return 0 ;
}
static int ads1100_set_scale ( struct ads1100_data * data , int val , int val2 )
{
int microvolts ;
int gain ;
/* With Vdd between 2.7 and 5V, the scale is always below 1 */
if ( val )
return - EINVAL ;
if ( ! val2 )
return - EINVAL ;
microvolts = regulator_get_voltage ( data - > reg_vdd ) ;
/*
* val2 is in ' micro ' units , n = val2 / 1000000
* result must be millivolts , d = microvolts / 1000
* the full - scale value is d / n , corresponds to 2 ^ 15 ,
* hence the gain = ( d / n ) > > 15 , factoring out the 1000 and moving the
* bitshift so everything fits in 32 - bits yields this formula .
*/
gain = DIV_ROUND_CLOSEST ( microvolts , BIT ( 15 ) ) * MILLI / val2 ;
if ( gain < BIT ( 0 ) | | gain > BIT ( 3 ) )
return - EINVAL ;
ads1100_set_config_bits ( data , ADS1100_PGA_MASK , ffs ( gain ) - 1 ) ;
return 0 ;
}
static int ads1100_set_data_rate ( struct ads1100_data * data , int chan , int rate )
{
unsigned int i ;
unsigned int size ;
size = data - > supports_data_rate ? ARRAY_SIZE ( ads1100_data_rate ) : 1 ;
for ( i = 0 ; i < size ; i + + ) {
if ( ads1100_data_rate [ i ] = = rate )
return ads1100_set_config_bits ( data , ADS1100_DR_MASK ,
FIELD_PREP ( ADS1100_DR_MASK , i ) ) ;
}
return - EINVAL ;
}
static int ads1100_get_vdd_millivolts ( struct ads1100_data * data )
{
return regulator_get_voltage ( data - > reg_vdd ) / ( MICRO / MILLI ) ;
}
static void ads1100_calc_scale_avail ( struct ads1100_data * data )
{
int millivolts = ads1100_get_vdd_millivolts ( data ) ;
unsigned int i ;
for ( i = 0 ; i < ARRAY_SIZE ( data - > scale_avail ) / 2 ; i + + ) {
data - > scale_avail [ i * 2 + 0 ] = millivolts ;
data - > scale_avail [ i * 2 + 1 ] = 15 + i ;
}
}
static int ads1100_read_avail ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
const int * * vals , int * type , int * length ,
long mask )
{
struct ads1100_data * data = iio_priv ( indio_dev ) ;
if ( chan - > type ! = IIO_VOLTAGE )
return - EINVAL ;
switch ( mask ) {
case IIO_CHAN_INFO_SAMP_FREQ :
* type = IIO_VAL_INT ;
* vals = ads1100_data_rate ;
if ( data - > supports_data_rate )
* length = ARRAY_SIZE ( ads1100_data_rate ) ;
else
* length = 1 ;
return IIO_AVAIL_LIST ;
case IIO_CHAN_INFO_SCALE :
* type = IIO_VAL_FRACTIONAL_LOG2 ;
* vals = data - > scale_avail ;
* length = ARRAY_SIZE ( data - > scale_avail ) ;
return IIO_AVAIL_LIST ;
default :
return - EINVAL ;
}
}
static int ads1100_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan , int * val ,
int * val2 , long mask )
{
int ret ;
struct ads1100_data * data = iio_priv ( indio_dev ) ;
mutex_lock ( & data - > lock ) ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
ret = iio_device_claim_direct_mode ( indio_dev ) ;
if ( ret )
break ;
ret = ads1100_get_adc_result ( data , chan - > address , val ) ;
if ( ret > = 0 )
ret = IIO_VAL_INT ;
iio_device_release_direct_mode ( indio_dev ) ;
break ;
case IIO_CHAN_INFO_SCALE :
/* full-scale is the supply voltage in millivolts */
* val = ads1100_get_vdd_millivolts ( data ) ;
* val2 = 15 + FIELD_GET ( ADS1100_PGA_MASK , data - > config ) ;
ret = IIO_VAL_FRACTIONAL_LOG2 ;
break ;
case IIO_CHAN_INFO_SAMP_FREQ :
* val = ads1100_data_rate [ FIELD_GET ( ADS1100_DR_MASK ,
data - > config ) ] ;
ret = IIO_VAL_INT ;
break ;
default :
ret = - EINVAL ;
break ;
}
mutex_unlock ( & data - > lock ) ;
return ret ;
}
static int ads1100_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan , int val ,
int val2 , long mask )
{
struct ads1100_data * data = iio_priv ( indio_dev ) ;
int ret ;
mutex_lock ( & data - > lock ) ;
switch ( mask ) {
case IIO_CHAN_INFO_SCALE :
ret = ads1100_set_scale ( data , val , val2 ) ;
break ;
case IIO_CHAN_INFO_SAMP_FREQ :
ret = ads1100_set_data_rate ( data , chan - > address , val ) ;
break ;
default :
ret = - EINVAL ;
break ;
}
mutex_unlock ( & data - > lock ) ;
return ret ;
}
static const struct iio_info ads1100_info = {
. read_avail = ads1100_read_avail ,
. read_raw = ads1100_read_raw ,
. write_raw = ads1100_write_raw ,
} ;
static int ads1100_setup ( struct ads1100_data * data )
{
int ret ;
u8 buffer [ 3 ] ;
/* Setup continuous sampling mode at 8sps */
buffer [ 0 ] = ADS1100_DR_MASK | ADS1100_CONTINUOUS ;
ret = i2c_master_send ( data - > client , buffer , 1 ) ;
if ( ret < 0 )
return ret ;
ret = i2c_master_recv ( data - > client , buffer , sizeof ( buffer ) ) ;
if ( ret < 0 )
return ret ;
/* Config register returned in third byte, strip away the busy status */
data - > config = buffer [ 2 ] & ~ ADS1100_CFG_ST_BSY ;
/* Detect the sample rate capability by checking the DR bits */
data - > supports_data_rate = FIELD_GET ( ADS1100_DR_MASK , buffer [ 2 ] ) ! = 0 ;
return 0 ;
}
static void ads1100_reg_disable ( void * reg )
{
regulator_disable ( reg ) ;
}
static void ads1100_disable_continuous ( void * data )
{
ads1100_set_config_bits ( data , ADS1100_CFG_SC , ADS1100_SINGLESHOT ) ;
}
static int ads1100_probe ( struct i2c_client * client )
{
struct iio_dev * indio_dev ;
struct ads1100_data * data ;
struct device * dev = & client - > dev ;
int ret ;
indio_dev = devm_iio_device_alloc ( dev , sizeof ( * data ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
data = iio_priv ( indio_dev ) ;
dev_set_drvdata ( dev , data ) ;
data - > client = client ;
mutex_init ( & data - > lock ) ;
indio_dev - > name = " ads1100 " ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > channels = & ads1100_channel ;
indio_dev - > num_channels = 1 ;
indio_dev - > info = & ads1100_info ;
data - > reg_vdd = devm_regulator_get ( dev , " vdd " ) ;
if ( IS_ERR ( data - > reg_vdd ) )
return dev_err_probe ( dev , PTR_ERR ( data - > reg_vdd ) ,
" Failed to get vdd regulator \n " ) ;
ret = regulator_enable ( data - > reg_vdd ) ;
if ( ret < 0 )
2023-03-23 18:23:56 +03:00
return dev_err_probe ( dev , ret ,
2023-03-07 07:55:34 +01:00
" Failed to enable vdd regulator \n " ) ;
ret = devm_add_action_or_reset ( dev , ads1100_reg_disable , data - > reg_vdd ) ;
if ( ret )
return ret ;
ret = ads1100_setup ( data ) ;
if ( ret )
return dev_err_probe ( dev , ret ,
" Failed to communicate with device \n " ) ;
ret = devm_add_action_or_reset ( dev , ads1100_disable_continuous , data ) ;
if ( ret )
return ret ;
ads1100_calc_scale_avail ( data ) ;
pm_runtime_set_autosuspend_delay ( dev , ADS1100_SLEEP_DELAY_MS ) ;
pm_runtime_use_autosuspend ( dev ) ;
pm_runtime_set_active ( dev ) ;
ret = devm_pm_runtime_enable ( dev ) ;
if ( ret )
return dev_err_probe ( dev , ret , " Failed to enable pm_runtime \n " ) ;
ret = devm_iio_device_register ( dev , indio_dev ) ;
if ( ret )
return dev_err_probe ( dev , ret ,
" Failed to register IIO device \n " ) ;
return 0 ;
}
static int ads1100_runtime_suspend ( struct device * dev )
{
struct ads1100_data * data = dev_get_drvdata ( dev ) ;
ads1100_set_config_bits ( data , ADS1100_CFG_SC , ADS1100_SINGLESHOT ) ;
regulator_disable ( data - > reg_vdd ) ;
return 0 ;
}
static int ads1100_runtime_resume ( struct device * dev )
{
struct ads1100_data * data = dev_get_drvdata ( dev ) ;
int ret ;
ret = regulator_enable ( data - > reg_vdd ) ;
if ( ret ) {
dev_err ( & data - > client - > dev , " Failed to enable Vdd \n " ) ;
return ret ;
}
/*
* We ' ll always change the mode bit in the config register , so there is
* no need here to " force " a write to the config register . If the device
* has been power - cycled , we ' ll re - write its config register now .
*/
return ads1100_set_config_bits ( data , ADS1100_CFG_SC ,
ADS1100_CONTINUOUS ) ;
}
static DEFINE_RUNTIME_DEV_PM_OPS ( ads1100_pm_ops ,
ads1100_runtime_suspend ,
ads1100_runtime_resume ,
NULL ) ;
static const struct i2c_device_id ads1100_id [ ] = {
{ " ads1100 " } ,
{ " ads1000 " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , ads1100_id ) ;
static const struct of_device_id ads1100_of_match [ ] = {
{ . compatible = " ti,ads1100 " } ,
{ . compatible = " ti,ads1000 " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , ads1100_of_match ) ;
static struct i2c_driver ads1100_driver = {
. driver = {
. name = " ads1100 " ,
. of_match_table = ads1100_of_match ,
. pm = pm_ptr ( & ads1100_pm_ops ) ,
} ,
2023-05-15 22:50:48 +02:00
. probe = ads1100_probe ,
2023-03-07 07:55:34 +01:00
. id_table = ads1100_id ,
} ;
module_i2c_driver ( ads1100_driver ) ;
MODULE_AUTHOR ( " Mike Looijmans <mike.looijmans@topic.nl> " ) ;
MODULE_DESCRIPTION ( " Texas Instruments ADS1100 ADC driver " ) ;
MODULE_LICENSE ( " GPL " ) ;