2019-05-30 02:57:44 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2016-02-11 16:49:54 +03:00
/*
* ADS1015 - Texas Instruments Analog - to - Digital Converter
*
* Copyright ( c ) 2016 , Intel Corporation .
*
* IIO driver for ADS1015 ADC 7 - bit I2C slave address :
* * 0x48 - ADDR connected to Ground
* * 0x49 - ADDR connected to Vdd
* * 0x4A - ADDR connected to SDA
* * 0x4B - ADDR connected to SCL
*/
# include <linux/module.h>
# include <linux/init.h>
2017-07-20 18:24:27 +03:00
# include <linux/irq.h>
2016-02-11 16:49:54 +03:00
# include <linux/i2c.h>
2019-12-05 20:46:37 +03:00
# include <linux/property.h>
2016-02-11 16:49:54 +03:00
# include <linux/regmap.h>
# include <linux/pm_runtime.h>
# include <linux/mutex.h>
# include <linux/delay.h>
# include <linux/iio/iio.h>
# include <linux/iio/types.h>
# include <linux/iio/sysfs.h>
2017-07-20 18:24:27 +03:00
# include <linux/iio/events.h>
2016-02-11 16:49:54 +03:00
# include <linux/iio/buffer.h>
# include <linux/iio/triggered_buffer.h>
# include <linux/iio/trigger_consumer.h>
# define ADS1015_DRV_NAME "ads1015"
2019-12-05 20:46:36 +03:00
# define ADS1015_CHANNELS 8
2016-02-11 16:49:54 +03:00
# define ADS1015_CONV_REG 0x00
# define ADS1015_CFG_REG 0x01
2017-07-20 18:24:27 +03:00
# define ADS1015_LO_THRESH_REG 0x02
# define ADS1015_HI_THRESH_REG 0x03
2016-02-11 16:49:54 +03:00
2017-07-20 18:24:27 +03:00
# define ADS1015_CFG_COMP_QUE_SHIFT 0
# define ADS1015_CFG_COMP_LAT_SHIFT 2
# define ADS1015_CFG_COMP_POL_SHIFT 3
# define ADS1015_CFG_COMP_MODE_SHIFT 4
2016-02-11 16:49:54 +03:00
# define ADS1015_CFG_DR_SHIFT 5
# define ADS1015_CFG_MOD_SHIFT 8
# define ADS1015_CFG_PGA_SHIFT 9
# define ADS1015_CFG_MUX_SHIFT 12
2017-07-20 18:24:27 +03:00
# define ADS1015_CFG_COMP_QUE_MASK GENMASK(1, 0)
# define ADS1015_CFG_COMP_LAT_MASK BIT(2)
2017-08-24 03:22:57 +03:00
# define ADS1015_CFG_COMP_POL_MASK BIT(3)
2017-07-20 18:24:27 +03:00
# define ADS1015_CFG_COMP_MODE_MASK BIT(4)
2016-02-11 16:49:54 +03:00
# define ADS1015_CFG_DR_MASK GENMASK(7, 5)
# define ADS1015_CFG_MOD_MASK BIT(8)
# define ADS1015_CFG_PGA_MASK GENMASK(11, 9)
# define ADS1015_CFG_MUX_MASK GENMASK(14, 12)
2017-07-20 18:24:27 +03:00
/* Comparator queue and disable field */
# define ADS1015_CFG_COMP_DISABLE 3
/* Comparator polarity field */
# define ADS1015_CFG_COMP_POL_LOW 0
# define ADS1015_CFG_COMP_POL_HIGH 1
/* Comparator mode field */
# define ADS1015_CFG_COMP_MODE_TRAD 0
# define ADS1015_CFG_COMP_MODE_WINDOW 1
2016-02-11 16:49:54 +03:00
/* device operating modes */
# define ADS1015_CONTINUOUS 0
# define ADS1015_SINGLESHOT 1
# define ADS1015_SLEEP_DELAY_MS 2000
# define ADS1015_DEFAULT_PGA 2
# define ADS1015_DEFAULT_DATA_RATE 4
# define ADS1015_DEFAULT_CHAN 0
2017-03-15 07:45:00 +03:00
enum chip_ids {
2019-12-05 20:46:37 +03:00
ADSXXXX = 0 ,
2016-05-16 08:18:46 +03:00
ADS1015 ,
ADS1115 ,
} ;
2016-02-11 16:49:54 +03:00
enum ads1015_channels {
ADS1015_AIN0_AIN1 = 0 ,
ADS1015_AIN0_AIN3 ,
ADS1015_AIN1_AIN3 ,
ADS1015_AIN2_AIN3 ,
ADS1015_AIN0 ,
ADS1015_AIN1 ,
ADS1015_AIN2 ,
ADS1015_AIN3 ,
ADS1015_TIMESTAMP ,
} ;
static const unsigned int ads1015_data_rate [ ] = {
128 , 250 , 490 , 920 , 1600 , 2400 , 3300 , 3300
} ;
2016-05-16 08:18:46 +03:00
static const unsigned int ads1115_data_rate [ ] = {
8 , 16 , 32 , 64 , 128 , 250 , 475 , 860
} ;
2017-07-20 18:24:18 +03:00
/*
* Translation from PGA bits to full - scale positive and negative input voltage
* range in mV
*/
static int ads1015_fullscale_range [ ] = {
6144 , 4096 , 2048 , 1024 , 512 , 256 , 256 , 256
2016-02-11 16:49:54 +03:00
} ;
2017-07-20 18:24:27 +03:00
/*
* Translation from COMP_QUE field value to the number of successive readings
* exceed the threshold values before an interrupt is generated
*/
static const int ads1015_comp_queue [ ] = { 1 , 2 , 4 } ;
static const struct iio_event_spec ads1015_events [ ] = {
{
. type = IIO_EV_TYPE_THRESH ,
. dir = IIO_EV_DIR_RISING ,
. mask_separate = BIT ( IIO_EV_INFO_VALUE ) |
BIT ( IIO_EV_INFO_ENABLE ) ,
} , {
. type = IIO_EV_TYPE_THRESH ,
. dir = IIO_EV_DIR_FALLING ,
. mask_separate = BIT ( IIO_EV_INFO_VALUE ) ,
} , {
. type = IIO_EV_TYPE_THRESH ,
. dir = IIO_EV_DIR_EITHER ,
. mask_separate = BIT ( IIO_EV_INFO_ENABLE ) |
BIT ( IIO_EV_INFO_PERIOD ) ,
} ,
} ;
2016-02-11 16:49:54 +03:00
# define ADS1015_V_CHAN(_chan, _addr) { \
. type = IIO_VOLTAGE , \
. indexed = 1 , \
. address = _addr , \
. channel = _chan , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) | \
BIT ( IIO_CHAN_INFO_SCALE ) | \
BIT ( IIO_CHAN_INFO_SAMP_FREQ ) , \
. scan_index = _addr , \
. scan_type = { \
. sign = ' s ' , \
. realbits = 12 , \
. storagebits = 16 , \
. shift = 4 , \
. endianness = IIO_CPU , \
} , \
2017-07-20 18:24:27 +03:00
. event_spec = ads1015_events , \
. num_event_specs = ARRAY_SIZE ( ads1015_events ) , \
2016-05-18 01:02:03 +03:00
. datasheet_name = " AIN " # _chan , \
2016-02-11 16:49:54 +03:00
}
# define ADS1015_V_DIFF_CHAN(_chan, _chan2, _addr) { \
. type = IIO_VOLTAGE , \
. differential = 1 , \
. indexed = 1 , \
. address = _addr , \
. channel = _chan , \
. channel2 = _chan2 , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) | \
BIT ( IIO_CHAN_INFO_SCALE ) | \
BIT ( IIO_CHAN_INFO_SAMP_FREQ ) , \
. scan_index = _addr , \
. scan_type = { \
. sign = ' s ' , \
. realbits = 12 , \
. storagebits = 16 , \
. shift = 4 , \
. endianness = IIO_CPU , \
} , \
2017-07-20 18:24:27 +03:00
. event_spec = ads1015_events , \
. num_event_specs = ARRAY_SIZE ( ads1015_events ) , \
2016-05-18 01:02:03 +03:00
. datasheet_name = " AIN " # _chan " -AIN " # _chan2 , \
2016-02-11 16:49:54 +03:00
}
2016-05-16 08:18:46 +03:00
# define ADS1115_V_CHAN(_chan, _addr) { \
. type = IIO_VOLTAGE , \
. indexed = 1 , \
. address = _addr , \
. channel = _chan , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) | \
BIT ( IIO_CHAN_INFO_SCALE ) | \
BIT ( IIO_CHAN_INFO_SAMP_FREQ ) , \
. scan_index = _addr , \
. scan_type = { \
. sign = ' s ' , \
. realbits = 16 , \
. storagebits = 16 , \
. endianness = IIO_CPU , \
} , \
2017-07-20 18:24:27 +03:00
. event_spec = ads1015_events , \
. num_event_specs = ARRAY_SIZE ( ads1015_events ) , \
2016-05-18 01:02:03 +03:00
. datasheet_name = " AIN " # _chan , \
2016-05-16 08:18:46 +03:00
}
# define ADS1115_V_DIFF_CHAN(_chan, _chan2, _addr) { \
. type = IIO_VOLTAGE , \
. differential = 1 , \
. indexed = 1 , \
. address = _addr , \
. channel = _chan , \
. channel2 = _chan2 , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) | \
BIT ( IIO_CHAN_INFO_SCALE ) | \
BIT ( IIO_CHAN_INFO_SAMP_FREQ ) , \
. scan_index = _addr , \
. scan_type = { \
. sign = ' s ' , \
. realbits = 16 , \
. storagebits = 16 , \
. endianness = IIO_CPU , \
} , \
2017-07-20 18:24:27 +03:00
. event_spec = ads1015_events , \
. num_event_specs = ARRAY_SIZE ( ads1015_events ) , \
2016-05-18 01:02:03 +03:00
. datasheet_name = " AIN " # _chan " -AIN " # _chan2 , \
2016-05-16 08:18:46 +03:00
}
2019-12-05 20:46:36 +03:00
struct ads1015_channel_data {
bool enabled ;
unsigned int pga ;
unsigned int data_rate ;
} ;
2017-07-20 18:24:27 +03:00
struct ads1015_thresh_data {
unsigned int comp_queue ;
int high_thresh ;
int low_thresh ;
} ;
2016-02-11 16:49:54 +03:00
struct ads1015_data {
struct regmap * regmap ;
/*
* Protects ADC ops , e . g : concurrent sysfs / buffered
* data reads , configuration updates
*/
struct mutex lock ;
struct ads1015_channel_data channel_data [ ADS1015_CHANNELS ] ;
2016-05-16 08:18:46 +03:00
2017-07-20 18:24:27 +03:00
unsigned int event_channel ;
unsigned int comp_mode ;
struct ads1015_thresh_data thresh_data [ ADS1015_CHANNELS ] ;
2016-05-16 08:18:46 +03:00
unsigned int * data_rate ;
2017-07-20 18:24:20 +03:00
/*
* Set to true when the ADC is switched to the continuous - conversion
* mode and exits from a power - down state . This flag is used to avoid
* getting the stale result from the conversion register .
*/
bool conv_invalid ;
2016-02-11 16:49:54 +03:00
} ;
2017-07-20 18:24:27 +03:00
static bool ads1015_event_channel_enabled ( struct ads1015_data * data )
{
return ( data - > event_channel ! = ADS1015_CHANNELS ) ;
}
static void ads1015_event_channel_enable ( struct ads1015_data * data , int chan ,
int comp_mode )
{
WARN_ON ( ads1015_event_channel_enabled ( data ) ) ;
data - > event_channel = chan ;
data - > comp_mode = comp_mode ;
}
static void ads1015_event_channel_disable ( struct ads1015_data * data , int chan )
{
data - > event_channel = ADS1015_CHANNELS ;
}
2016-02-11 16:49:54 +03:00
static bool ads1015_is_writeable_reg ( struct device * dev , unsigned int reg )
{
2017-07-20 18:24:27 +03:00
switch ( reg ) {
case ADS1015_CFG_REG :
case ADS1015_LO_THRESH_REG :
case ADS1015_HI_THRESH_REG :
return true ;
default :
return false ;
}
2016-02-11 16:49:54 +03:00
}
static const struct regmap_config ads1015_regmap_config = {
. reg_bits = 8 ,
. val_bits = 16 ,
2017-07-20 18:24:27 +03:00
. max_register = ADS1015_HI_THRESH_REG ,
2016-02-11 16:49:54 +03:00
. writeable_reg = ads1015_is_writeable_reg ,
} ;
static const struct iio_chan_spec ads1015_channels [ ] = {
ADS1015_V_DIFF_CHAN ( 0 , 1 , ADS1015_AIN0_AIN1 ) ,
ADS1015_V_DIFF_CHAN ( 0 , 3 , ADS1015_AIN0_AIN3 ) ,
ADS1015_V_DIFF_CHAN ( 1 , 3 , ADS1015_AIN1_AIN3 ) ,
ADS1015_V_DIFF_CHAN ( 2 , 3 , ADS1015_AIN2_AIN3 ) ,
ADS1015_V_CHAN ( 0 , ADS1015_AIN0 ) ,
ADS1015_V_CHAN ( 1 , ADS1015_AIN1 ) ,
ADS1015_V_CHAN ( 2 , ADS1015_AIN2 ) ,
ADS1015_V_CHAN ( 3 , ADS1015_AIN3 ) ,
IIO_CHAN_SOFT_TIMESTAMP ( ADS1015_TIMESTAMP ) ,
} ;
2016-05-16 08:18:46 +03:00
static const struct iio_chan_spec ads1115_channels [ ] = {
ADS1115_V_DIFF_CHAN ( 0 , 1 , ADS1015_AIN0_AIN1 ) ,
ADS1115_V_DIFF_CHAN ( 0 , 3 , ADS1015_AIN0_AIN3 ) ,
ADS1115_V_DIFF_CHAN ( 1 , 3 , ADS1015_AIN1_AIN3 ) ,
ADS1115_V_DIFF_CHAN ( 2 , 3 , ADS1015_AIN2_AIN3 ) ,
ADS1115_V_CHAN ( 0 , ADS1015_AIN0 ) ,
ADS1115_V_CHAN ( 1 , ADS1015_AIN1 ) ,
ADS1115_V_CHAN ( 2 , ADS1015_AIN2 ) ,
ADS1115_V_CHAN ( 3 , ADS1015_AIN3 ) ,
IIO_CHAN_SOFT_TIMESTAMP ( ADS1015_TIMESTAMP ) ,
} ;
2020-08-03 08:04:05 +03:00
# ifdef CONFIG_PM
2016-02-11 16:49:54 +03:00
static int ads1015_set_power_state ( struct ads1015_data * data , bool on )
{
int ret ;
struct device * dev = regmap_get_device ( data - > regmap ) ;
if ( on ) {
2021-05-16 19:20:59 +03:00
ret = pm_runtime_resume_and_get ( dev ) ;
2016-02-11 16:49:54 +03:00
} else {
pm_runtime_mark_last_busy ( dev ) ;
ret = pm_runtime_put_autosuspend ( dev ) ;
}
2017-07-20 18:24:21 +03:00
return ret < 0 ? ret : 0 ;
2016-02-11 16:49:54 +03:00
}
2020-08-03 08:04:05 +03:00
# else /* !CONFIG_PM */
static int ads1015_set_power_state ( struct ads1015_data * data , bool on )
{
return 0 ;
}
# endif /* !CONFIG_PM */
2016-02-11 16:49:54 +03:00
static
int ads1015_get_adc_result ( struct ads1015_data * data , int chan , int * val )
{
2017-08-24 11:25:51 +03:00
int ret , pga , dr , dr_old , conv_time ;
2017-07-20 18:24:22 +03:00
unsigned int old , mask , cfg ;
2016-02-11 16:49:54 +03:00
if ( chan < 0 | | chan > = ADS1015_CHANNELS )
return - EINVAL ;
2017-07-20 18:24:22 +03:00
ret = regmap_read ( data - > regmap , ADS1015_CFG_REG , & old ) ;
if ( ret )
return ret ;
2016-02-11 16:49:54 +03:00
pga = data - > channel_data [ chan ] . pga ;
dr = data - > channel_data [ chan ] . data_rate ;
2017-07-20 18:24:22 +03:00
mask = ADS1015_CFG_MUX_MASK | ADS1015_CFG_PGA_MASK |
ADS1015_CFG_DR_MASK ;
cfg = chan < < ADS1015_CFG_MUX_SHIFT | pga < < ADS1015_CFG_PGA_SHIFT |
dr < < ADS1015_CFG_DR_SHIFT ;
2016-02-11 16:49:54 +03:00
2017-07-20 18:24:27 +03:00
if ( ads1015_event_channel_enabled ( data ) ) {
mask | = ADS1015_CFG_COMP_QUE_MASK | ADS1015_CFG_COMP_MODE_MASK ;
cfg | = data - > thresh_data [ chan ] . comp_queue < <
ADS1015_CFG_COMP_QUE_SHIFT |
data - > comp_mode < <
ADS1015_CFG_COMP_MODE_SHIFT ;
}
2017-07-20 18:24:22 +03:00
cfg = ( old & ~ mask ) | ( cfg & mask ) ;
2017-08-24 11:25:51 +03:00
if ( old ! = cfg ) {
ret = regmap_write ( data - > regmap , ADS1015_CFG_REG , cfg ) ;
if ( ret )
return ret ;
data - > conv_invalid = true ;
}
if ( data - > conv_invalid ) {
dr_old = ( old & ADS1015_CFG_DR_MASK ) > > ADS1015_CFG_DR_SHIFT ;
2017-07-20 18:24:22 +03:00
conv_time = DIV_ROUND_UP ( USEC_PER_SEC , data - > data_rate [ dr_old ] ) ;
conv_time + = DIV_ROUND_UP ( USEC_PER_SEC , data - > data_rate [ dr ] ) ;
2017-08-25 08:39:16 +03:00
conv_time + = conv_time / 10 ; /* 10% internal clock inaccuracy */
2016-02-11 16:49:54 +03:00
usleep_range ( conv_time , conv_time + 1 ) ;
2017-07-20 18:24:20 +03:00
data - > conv_invalid = false ;
2016-02-11 16:49:54 +03:00
}
return regmap_read ( data - > regmap , ADS1015_CONV_REG , val ) ;
}
static irqreturn_t ads1015_trigger_handler ( int irq , void * p )
{
struct iio_poll_func * pf = p ;
struct iio_dev * indio_dev = pf - > indio_dev ;
struct ads1015_data * data = iio_priv ( indio_dev ) ;
2021-05-01 20:01:10 +03:00
/* Ensure natural alignment of timestamp */
struct {
s16 chan ;
s64 timestamp __aligned ( 8 ) ;
} scan ;
2016-02-11 16:49:54 +03:00
int chan , ret , res ;
2021-05-01 20:01:10 +03:00
memset ( & scan , 0 , sizeof ( scan ) ) ;
2016-02-11 16:49:54 +03:00
mutex_lock ( & data - > lock ) ;
chan = find_first_bit ( indio_dev - > active_scan_mask ,
indio_dev - > masklength ) ;
ret = ads1015_get_adc_result ( data , chan , & res ) ;
if ( ret < 0 ) {
mutex_unlock ( & data - > lock ) ;
goto err ;
}
2021-05-01 20:01:10 +03:00
scan . chan = res ;
2016-02-11 16:49:54 +03:00
mutex_unlock ( & data - > lock ) ;
2021-05-01 20:01:10 +03:00
iio_push_to_buffers_with_timestamp ( indio_dev , & scan ,
2016-03-09 21:05:49 +03:00
iio_get_time_ns ( indio_dev ) ) ;
2016-02-11 16:49:54 +03:00
err :
iio_trigger_notify_done ( indio_dev - > trig ) ;
return IRQ_HANDLED ;
}
2017-07-20 18:24:18 +03:00
static int ads1015_set_scale ( struct ads1015_data * data ,
struct iio_chan_spec const * chan ,
2016-02-11 16:49:54 +03:00
int scale , int uscale )
{
2017-07-20 18:24:23 +03:00
int i ;
2017-07-20 18:24:18 +03:00
int fullscale = div_s64 ( ( scale * 1000000LL + uscale ) < <
( chan - > scan_type . realbits - 1 ) , 1000000 ) ;
2016-02-11 16:49:54 +03:00
2017-07-20 18:24:18 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( ads1015_fullscale_range ) ; i + + ) {
if ( ads1015_fullscale_range [ i ] = = fullscale ) {
2017-07-20 18:24:23 +03:00
data - > channel_data [ chan - > address ] . pga = i ;
return 0 ;
2016-02-11 16:49:54 +03:00
}
2017-07-20 18:24:18 +03:00
}
2016-02-11 16:49:54 +03:00
2017-07-20 18:24:23 +03:00
return - EINVAL ;
2016-02-11 16:49:54 +03:00
}
static int ads1015_set_data_rate ( struct ads1015_data * data , int chan , int rate )
{
2017-07-20 18:24:17 +03:00
int i ;
2016-02-11 16:49:54 +03:00
2017-07-20 18:24:17 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( ads1015_data_rate ) ; i + + ) {
2016-05-16 08:18:46 +03:00
if ( data - > data_rate [ i ] = = rate ) {
2017-07-20 18:24:17 +03:00
data - > channel_data [ chan ] . data_rate = i ;
return 0 ;
2016-02-11 16:49:54 +03:00
}
2017-07-20 18:24:17 +03:00
}
2016-02-11 16:49:54 +03:00
2017-07-20 18:24:17 +03:00
return - EINVAL ;
2016-02-11 16:49:54 +03:00
}
static int ads1015_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan , int * val ,
int * val2 , long mask )
{
int ret , idx ;
struct ads1015_data * data = iio_priv ( indio_dev ) ;
mutex_lock ( & data - > lock ) ;
switch ( mask ) {
2016-05-16 08:18:46 +03:00
case IIO_CHAN_INFO_RAW : {
int shift = chan - > scan_type . shift ;
2017-07-20 18:24:26 +03:00
ret = iio_device_claim_direct_mode ( indio_dev ) ;
if ( ret )
2016-02-11 16:49:54 +03:00
break ;
2017-07-20 18:24:27 +03:00
if ( ads1015_event_channel_enabled ( data ) & &
data - > event_channel ! = chan - > address ) {
ret = - EBUSY ;
goto release_direct ;
}
2016-02-11 16:49:54 +03:00
ret = ads1015_set_power_state ( data , true ) ;
if ( ret < 0 )
2017-07-20 18:24:26 +03:00
goto release_direct ;
2016-02-11 16:49:54 +03:00
ret = ads1015_get_adc_result ( data , chan - > address , val ) ;
if ( ret < 0 ) {
ads1015_set_power_state ( data , false ) ;
2017-07-20 18:24:26 +03:00
goto release_direct ;
2016-02-11 16:49:54 +03:00
}
2016-05-16 08:18:46 +03:00
* val = sign_extend32 ( * val > > shift , 15 - shift ) ;
2016-02-11 16:49:54 +03:00
ret = ads1015_set_power_state ( data , false ) ;
if ( ret < 0 )
2017-07-20 18:24:26 +03:00
goto release_direct ;
2016-02-11 16:49:54 +03:00
ret = IIO_VAL_INT ;
2017-07-20 18:24:26 +03:00
release_direct :
iio_device_release_direct_mode ( indio_dev ) ;
2016-02-11 16:49:54 +03:00
break ;
2016-05-16 08:18:46 +03:00
}
2016-02-11 16:49:54 +03:00
case IIO_CHAN_INFO_SCALE :
idx = data - > channel_data [ chan - > address ] . pga ;
2017-07-20 18:24:18 +03:00
* val = ads1015_fullscale_range [ idx ] ;
* val2 = chan - > scan_type . realbits - 1 ;
ret = IIO_VAL_FRACTIONAL_LOG2 ;
2016-02-11 16:49:54 +03:00
break ;
case IIO_CHAN_INFO_SAMP_FREQ :
idx = data - > channel_data [ chan - > address ] . data_rate ;
2016-05-16 08:18:46 +03:00
* val = data - > data_rate [ idx ] ;
2016-02-11 16:49:54 +03:00
ret = IIO_VAL_INT ;
break ;
default :
ret = - EINVAL ;
break ;
}
mutex_unlock ( & data - > lock ) ;
return ret ;
}
static int ads1015_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan , int val ,
int val2 , long mask )
{
struct ads1015_data * data = iio_priv ( indio_dev ) ;
int ret ;
mutex_lock ( & data - > lock ) ;
switch ( mask ) {
case IIO_CHAN_INFO_SCALE :
2017-07-20 18:24:18 +03:00
ret = ads1015_set_scale ( data , chan , val , val2 ) ;
2016-02-11 16:49:54 +03:00
break ;
case IIO_CHAN_INFO_SAMP_FREQ :
ret = ads1015_set_data_rate ( data , chan - > address , val ) ;
break ;
default :
ret = - EINVAL ;
break ;
}
mutex_unlock ( & data - > lock ) ;
return ret ;
}
2017-07-20 18:24:27 +03:00
static int ads1015_read_event ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan , enum iio_event_type type ,
enum iio_event_direction dir , enum iio_event_info info , int * val ,
int * val2 )
{
struct ads1015_data * data = iio_priv ( indio_dev ) ;
int ret ;
unsigned int comp_queue ;
int period ;
int dr ;
mutex_lock ( & data - > lock ) ;
switch ( info ) {
case IIO_EV_INFO_VALUE :
* val = ( dir = = IIO_EV_DIR_RISING ) ?
data - > thresh_data [ chan - > address ] . high_thresh :
data - > thresh_data [ chan - > address ] . low_thresh ;
ret = IIO_VAL_INT ;
break ;
case IIO_EV_INFO_PERIOD :
dr = data - > channel_data [ chan - > address ] . data_rate ;
comp_queue = data - > thresh_data [ chan - > address ] . comp_queue ;
period = ads1015_comp_queue [ comp_queue ] *
USEC_PER_SEC / data - > data_rate [ dr ] ;
* val = period / USEC_PER_SEC ;
* val2 = period % USEC_PER_SEC ;
ret = IIO_VAL_INT_PLUS_MICRO ;
break ;
default :
ret = - EINVAL ;
break ;
}
mutex_unlock ( & data - > lock ) ;
return ret ;
}
static int ads1015_write_event ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan , enum iio_event_type type ,
enum iio_event_direction dir , enum iio_event_info info , int val ,
int val2 )
{
struct ads1015_data * data = iio_priv ( indio_dev ) ;
int realbits = chan - > scan_type . realbits ;
int ret = 0 ;
long long period ;
int i ;
int dr ;
mutex_lock ( & data - > lock ) ;
switch ( info ) {
case IIO_EV_INFO_VALUE :
if ( val > = 1 < < ( realbits - 1 ) | | val < - 1 < < ( realbits - 1 ) ) {
ret = - EINVAL ;
break ;
}
if ( dir = = IIO_EV_DIR_RISING )
data - > thresh_data [ chan - > address ] . high_thresh = val ;
else
data - > thresh_data [ chan - > address ] . low_thresh = val ;
break ;
case IIO_EV_INFO_PERIOD :
dr = data - > channel_data [ chan - > address ] . data_rate ;
period = val * USEC_PER_SEC + val2 ;
for ( i = 0 ; i < ARRAY_SIZE ( ads1015_comp_queue ) - 1 ; i + + ) {
if ( period < = ads1015_comp_queue [ i ] *
USEC_PER_SEC / data - > data_rate [ dr ] )
break ;
}
data - > thresh_data [ chan - > address ] . comp_queue = i ;
break ;
default :
ret = - EINVAL ;
break ;
}
mutex_unlock ( & data - > lock ) ;
return ret ;
}
static int ads1015_read_event_config ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan , enum iio_event_type type ,
enum iio_event_direction dir )
{
struct ads1015_data * data = iio_priv ( indio_dev ) ;
int ret = 0 ;
mutex_lock ( & data - > lock ) ;
if ( data - > event_channel = = chan - > address ) {
switch ( dir ) {
case IIO_EV_DIR_RISING :
ret = 1 ;
break ;
case IIO_EV_DIR_EITHER :
ret = ( data - > comp_mode = = ADS1015_CFG_COMP_MODE_WINDOW ) ;
break ;
default :
ret = - EINVAL ;
break ;
}
}
mutex_unlock ( & data - > lock ) ;
return ret ;
}
static int ads1015_enable_event_config ( struct ads1015_data * data ,
const struct iio_chan_spec * chan , int comp_mode )
{
int low_thresh = data - > thresh_data [ chan - > address ] . low_thresh ;
int high_thresh = data - > thresh_data [ chan - > address ] . high_thresh ;
int ret ;
unsigned int val ;
if ( ads1015_event_channel_enabled ( data ) ) {
if ( data - > event_channel ! = chan - > address | |
( data - > comp_mode = = ADS1015_CFG_COMP_MODE_TRAD & &
comp_mode = = ADS1015_CFG_COMP_MODE_WINDOW ) )
return - EBUSY ;
return 0 ;
}
if ( comp_mode = = ADS1015_CFG_COMP_MODE_TRAD ) {
low_thresh = max ( - 1 < < ( chan - > scan_type . realbits - 1 ) ,
high_thresh - 1 ) ;
}
ret = regmap_write ( data - > regmap , ADS1015_LO_THRESH_REG ,
low_thresh < < chan - > scan_type . shift ) ;
if ( ret )
return ret ;
ret = regmap_write ( data - > regmap , ADS1015_HI_THRESH_REG ,
high_thresh < < chan - > scan_type . shift ) ;
if ( ret )
return ret ;
ret = ads1015_set_power_state ( data , true ) ;
if ( ret < 0 )
return ret ;
ads1015_event_channel_enable ( data , chan - > address , comp_mode ) ;
ret = ads1015_get_adc_result ( data , chan - > address , & val ) ;
if ( ret ) {
ads1015_event_channel_disable ( data , chan - > address ) ;
ads1015_set_power_state ( data , false ) ;
}
return ret ;
}
static int ads1015_disable_event_config ( struct ads1015_data * data ,
const struct iio_chan_spec * chan , int comp_mode )
{
int ret ;
if ( ! ads1015_event_channel_enabled ( data ) )
return 0 ;
if ( data - > event_channel ! = chan - > address )
return 0 ;
if ( data - > comp_mode = = ADS1015_CFG_COMP_MODE_TRAD & &
comp_mode = = ADS1015_CFG_COMP_MODE_WINDOW )
return 0 ;
ret = regmap_update_bits ( data - > regmap , ADS1015_CFG_REG ,
ADS1015_CFG_COMP_QUE_MASK ,
ADS1015_CFG_COMP_DISABLE < <
ADS1015_CFG_COMP_QUE_SHIFT ) ;
if ( ret )
return ret ;
ads1015_event_channel_disable ( data , chan - > address ) ;
return ads1015_set_power_state ( data , false ) ;
}
static int ads1015_write_event_config ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan , enum iio_event_type type ,
enum iio_event_direction dir , int state )
{
struct ads1015_data * data = iio_priv ( indio_dev ) ;
int ret ;
int comp_mode = ( dir = = IIO_EV_DIR_EITHER ) ?
ADS1015_CFG_COMP_MODE_WINDOW : ADS1015_CFG_COMP_MODE_TRAD ;
mutex_lock ( & data - > lock ) ;
/* Prevent from enabling both buffer and event at a time */
ret = iio_device_claim_direct_mode ( indio_dev ) ;
if ( ret ) {
mutex_unlock ( & data - > lock ) ;
return ret ;
}
if ( state )
ret = ads1015_enable_event_config ( data , chan , comp_mode ) ;
else
ret = ads1015_disable_event_config ( data , chan , comp_mode ) ;
iio_device_release_direct_mode ( indio_dev ) ;
mutex_unlock ( & data - > lock ) ;
return ret ;
}
static irqreturn_t ads1015_event_handler ( int irq , void * priv )
{
struct iio_dev * indio_dev = priv ;
struct ads1015_data * data = iio_priv ( indio_dev ) ;
int val ;
int ret ;
/* Clear the latched ALERT/RDY pin */
ret = regmap_read ( data - > regmap , ADS1015_CONV_REG , & val ) ;
if ( ret )
return IRQ_HANDLED ;
if ( ads1015_event_channel_enabled ( data ) ) {
enum iio_event_direction dir ;
u64 code ;
dir = data - > comp_mode = = ADS1015_CFG_COMP_MODE_TRAD ?
IIO_EV_DIR_RISING : IIO_EV_DIR_EITHER ;
code = IIO_UNMOD_EVENT_CODE ( IIO_VOLTAGE , data - > event_channel ,
IIO_EV_TYPE_THRESH , dir ) ;
iio_push_event ( indio_dev , code , iio_get_time_ns ( indio_dev ) ) ;
}
return IRQ_HANDLED ;
}
2016-02-11 16:49:54 +03:00
static int ads1015_buffer_preenable ( struct iio_dev * indio_dev )
{
2017-07-20 18:24:27 +03:00
struct ads1015_data * data = iio_priv ( indio_dev ) ;
/* Prevent from enabling both buffer and event at a time */
if ( ads1015_event_channel_enabled ( data ) )
return - EBUSY ;
2016-02-11 16:49:54 +03:00
return ads1015_set_power_state ( iio_priv ( indio_dev ) , true ) ;
}
static int ads1015_buffer_postdisable ( struct iio_dev * indio_dev )
{
return ads1015_set_power_state ( iio_priv ( indio_dev ) , false ) ;
}
static const struct iio_buffer_setup_ops ads1015_buffer_setup_ops = {
. preenable = ads1015_buffer_preenable ,
. postdisable = ads1015_buffer_postdisable ,
. validate_scan_mask = & iio_validate_scan_mask_onehot ,
} ;
2017-07-20 18:24:18 +03:00
static IIO_CONST_ATTR_NAMED ( ads1015_scale_available , scale_available ,
" 3 2 1 0.5 0.25 0.125 " ) ;
static IIO_CONST_ATTR_NAMED ( ads1115_scale_available , scale_available ,
" 0.1875 0.125 0.0625 0.03125 0.015625 0.007813 " ) ;
2016-05-16 08:18:46 +03:00
static IIO_CONST_ATTR_NAMED ( ads1015_sampling_frequency_available ,
sampling_frequency_available , " 128 250 490 920 1600 2400 3300 " ) ;
static IIO_CONST_ATTR_NAMED ( ads1115_sampling_frequency_available ,
sampling_frequency_available , " 8 16 32 64 128 250 475 860 " ) ;
2016-02-11 16:49:54 +03:00
static struct attribute * ads1015_attributes [ ] = {
2017-07-20 18:24:18 +03:00
& iio_const_attr_ads1015_scale_available . dev_attr . attr ,
2016-05-16 08:18:46 +03:00
& iio_const_attr_ads1015_sampling_frequency_available . dev_attr . attr ,
2016-02-11 16:49:54 +03:00
NULL ,
} ;
static const struct attribute_group ads1015_attribute_group = {
. attrs = ads1015_attributes ,
} ;
2016-05-16 08:18:46 +03:00
static struct attribute * ads1115_attributes [ ] = {
2017-07-20 18:24:18 +03:00
& iio_const_attr_ads1115_scale_available . dev_attr . attr ,
2016-05-16 08:18:46 +03:00
& iio_const_attr_ads1115_sampling_frequency_available . dev_attr . attr ,
NULL ,
} ;
static const struct attribute_group ads1115_attribute_group = {
. attrs = ads1115_attributes ,
} ;
2017-01-21 20:03:00 +03:00
static const struct iio_info ads1015_info = {
2016-05-16 08:18:46 +03:00
. read_raw = ads1015_read_raw ,
. write_raw = ads1015_write_raw ,
2017-07-20 18:24:27 +03:00
. read_event_value = ads1015_read_event ,
. write_event_value = ads1015_write_event ,
. read_event_config = ads1015_read_event_config ,
. write_event_config = ads1015_write_event_config ,
2016-05-16 08:18:46 +03:00
. attrs = & ads1015_attribute_group ,
} ;
2017-01-21 20:03:00 +03:00
static const struct iio_info ads1115_info = {
2016-02-11 16:49:54 +03:00
. read_raw = ads1015_read_raw ,
. write_raw = ads1015_write_raw ,
2017-07-20 18:24:27 +03:00
. read_event_value = ads1015_read_event ,
. write_event_value = ads1015_write_event ,
. read_event_config = ads1015_read_event_config ,
. write_event_config = ads1015_write_event_config ,
2016-05-16 08:18:46 +03:00
. attrs = & ads1115_attribute_group ,
2016-02-11 16:49:54 +03:00
} ;
2019-12-05 20:46:37 +03:00
static int ads1015_client_get_channels_config ( struct i2c_client * client )
2016-02-11 16:49:54 +03:00
{
2016-08-16 21:43:37 +03:00
struct iio_dev * indio_dev = i2c_get_clientdata ( client ) ;
struct ads1015_data * data = iio_priv ( indio_dev ) ;
2019-12-05 20:46:37 +03:00
struct device * dev = & client - > dev ;
struct fwnode_handle * node ;
int i = - 1 ;
2016-02-11 16:49:54 +03:00
2019-12-05 20:46:37 +03:00
device_for_each_child_node ( dev , node ) {
2016-02-11 16:49:54 +03:00
u32 pval ;
unsigned int channel ;
unsigned int pga = ADS1015_DEFAULT_PGA ;
unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE ;
2019-12-05 20:46:37 +03:00
if ( fwnode_property_read_u32 ( node , " reg " , & pval ) ) {
dev_err ( dev , " invalid reg on %pfw \n " , node ) ;
2016-02-11 16:49:54 +03:00
continue ;
}
channel = pval ;
if ( channel > = ADS1015_CHANNELS ) {
2019-12-05 20:46:37 +03:00
dev_err ( dev , " invalid channel index %d on %pfw \n " ,
2017-07-19 00:43:08 +03:00
channel , node ) ;
2016-02-11 16:49:54 +03:00
continue ;
}
2019-12-05 20:46:37 +03:00
if ( ! fwnode_property_read_u32 ( node , " ti,gain " , & pval ) ) {
2016-02-11 16:49:54 +03:00
pga = pval ;
if ( pga > 6 ) {
2019-12-05 20:46:37 +03:00
dev_err ( dev , " invalid gain on %pfw \n " , node ) ;
fwnode_handle_put ( node ) ;
2016-02-11 16:49:54 +03:00
return - EINVAL ;
}
}
2019-12-05 20:46:37 +03:00
if ( ! fwnode_property_read_u32 ( node , " ti,datarate " , & pval ) ) {
2016-02-11 16:49:54 +03:00
data_rate = pval ;
if ( data_rate > 7 ) {
2019-12-05 20:46:37 +03:00
dev_err ( dev , " invalid data_rate on %pfw \n " , node ) ;
fwnode_handle_put ( node ) ;
2016-02-11 16:49:54 +03:00
return - EINVAL ;
}
}
data - > channel_data [ channel ] . pga = pga ;
data - > channel_data [ channel ] . data_rate = data_rate ;
2019-12-05 20:46:37 +03:00
i + + ;
2016-02-11 16:49:54 +03:00
}
2019-12-05 20:46:37 +03:00
return i < 0 ? - EINVAL : 0 ;
2016-02-11 16:49:54 +03:00
}
static void ads1015_get_channels_config ( struct i2c_client * client )
{
unsigned int k ;
struct iio_dev * indio_dev = i2c_get_clientdata ( client ) ;
struct ads1015_data * data = iio_priv ( indio_dev ) ;
2019-12-05 20:46:37 +03:00
if ( ! ads1015_client_get_channels_config ( client ) )
2016-02-11 16:49:54 +03:00
return ;
2019-12-05 20:46:37 +03:00
2016-02-11 16:49:54 +03:00
/* fallback on default configuration */
for ( k = 0 ; k < ADS1015_CHANNELS ; + + k ) {
data - > channel_data [ k ] . pga = ADS1015_DEFAULT_PGA ;
data - > channel_data [ k ] . data_rate = ADS1015_DEFAULT_DATA_RATE ;
}
}
2017-07-20 18:24:24 +03:00
static int ads1015_set_conv_mode ( struct ads1015_data * data , int mode )
{
return regmap_update_bits ( data - > regmap , ADS1015_CFG_REG ,
ADS1015_CFG_MOD_MASK ,
mode < < ADS1015_CFG_MOD_SHIFT ) ;
}
2016-02-11 16:49:54 +03:00
static int ads1015_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
struct iio_dev * indio_dev ;
struct ads1015_data * data ;
int ret ;
2017-03-15 07:45:00 +03:00
enum chip_ids chip ;
2017-07-20 18:24:27 +03:00
int i ;
2016-02-11 16:49:54 +03:00
indio_dev = devm_iio_device_alloc ( & client - > dev , sizeof ( * data ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
data = iio_priv ( indio_dev ) ;
i2c_set_clientdata ( client , indio_dev ) ;
mutex_init ( & data - > lock ) ;
indio_dev - > name = ADS1015_DRV_NAME ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
2019-12-05 20:46:37 +03:00
chip = ( enum chip_ids ) device_get_match_data ( & client - > dev ) ;
if ( chip = = ADSXXXX )
2017-03-15 07:45:00 +03:00
chip = id - > driver_data ;
switch ( chip ) {
2016-05-16 08:18:46 +03:00
case ADS1015 :
indio_dev - > channels = ads1015_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( ads1015_channels ) ;
indio_dev - > info = & ads1015_info ;
data - > data_rate = ( unsigned int * ) & ads1015_data_rate ;
break ;
case ADS1115 :
indio_dev - > channels = ads1115_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( ads1115_channels ) ;
indio_dev - > info = & ads1115_info ;
data - > data_rate = ( unsigned int * ) & ads1115_data_rate ;
break ;
2019-12-05 20:46:37 +03:00
default :
dev_err ( & client - > dev , " Unknown chip %d \n " , chip ) ;
return - EINVAL ;
2016-05-16 08:18:46 +03:00
}
2017-07-20 18:24:27 +03:00
data - > event_channel = ADS1015_CHANNELS ;
/*
* Set default lower and upper threshold to min and max value
* respectively .
*/
for ( i = 0 ; i < ADS1015_CHANNELS ; i + + ) {
int realbits = indio_dev - > channels [ i ] . scan_type . realbits ;
data - > thresh_data [ i ] . low_thresh = - 1 < < ( realbits - 1 ) ;
data - > thresh_data [ i ] . high_thresh = ( 1 < < ( realbits - 1 ) ) - 1 ;
}
2016-02-11 16:49:54 +03:00
/* we need to keep this ABI the same as used by hwmon ADS1015 driver */
ads1015_get_channels_config ( client ) ;
data - > regmap = devm_regmap_init_i2c ( client , & ads1015_regmap_config ) ;
if ( IS_ERR ( data - > regmap ) ) {
dev_err ( & client - > dev , " Failed to allocate register map \n " ) ;
return PTR_ERR ( data - > regmap ) ;
}
2017-07-20 18:24:25 +03:00
ret = devm_iio_triggered_buffer_setup ( & client - > dev , indio_dev , NULL ,
ads1015_trigger_handler ,
& ads1015_buffer_setup_ops ) ;
2016-02-11 16:49:54 +03:00
if ( ret < 0 ) {
dev_err ( & client - > dev , " iio triggered buffer setup failed \n " ) ;
return ret ;
}
2017-07-20 18:24:19 +03:00
2017-07-20 18:24:27 +03:00
if ( client - > irq ) {
unsigned long irq_trig =
irqd_get_trigger_type ( irq_get_irq_data ( client - > irq ) ) ;
unsigned int cfg_comp_mask = ADS1015_CFG_COMP_QUE_MASK |
ADS1015_CFG_COMP_LAT_MASK | ADS1015_CFG_COMP_POL_MASK ;
unsigned int cfg_comp =
ADS1015_CFG_COMP_DISABLE < < ADS1015_CFG_COMP_QUE_SHIFT |
1 < < ADS1015_CFG_COMP_LAT_SHIFT ;
switch ( irq_trig ) {
case IRQF_TRIGGER_LOW :
2017-08-24 03:22:57 +03:00
cfg_comp | = ADS1015_CFG_COMP_POL_LOW < <
ADS1015_CFG_COMP_POL_SHIFT ;
2017-07-20 18:24:27 +03:00
break ;
case IRQF_TRIGGER_HIGH :
2017-08-24 03:22:57 +03:00
cfg_comp | = ADS1015_CFG_COMP_POL_HIGH < <
ADS1015_CFG_COMP_POL_SHIFT ;
2017-07-20 18:24:27 +03:00
break ;
default :
return - EINVAL ;
}
ret = regmap_update_bits ( data - > regmap , ADS1015_CFG_REG ,
cfg_comp_mask , cfg_comp ) ;
if ( ret )
return ret ;
ret = devm_request_threaded_irq ( & client - > dev , client - > irq ,
NULL , ads1015_event_handler ,
irq_trig | IRQF_ONESHOT ,
client - > name , indio_dev ) ;
if ( ret )
return ret ;
}
2017-07-20 18:24:24 +03:00
ret = ads1015_set_conv_mode ( data , ADS1015_CONTINUOUS ) ;
2017-07-20 18:24:19 +03:00
if ( ret )
return ret ;
2017-07-20 18:24:20 +03:00
data - > conv_invalid = true ;
2016-02-11 16:49:54 +03:00
ret = pm_runtime_set_active ( & client - > dev ) ;
if ( ret )
2017-07-20 18:24:25 +03:00
return ret ;
2016-02-11 16:49:54 +03:00
pm_runtime_set_autosuspend_delay ( & client - > dev , ADS1015_SLEEP_DELAY_MS ) ;
pm_runtime_use_autosuspend ( & client - > dev ) ;
pm_runtime_enable ( & client - > dev ) ;
ret = iio_device_register ( indio_dev ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " Failed to register IIO device \n " ) ;
2017-07-20 18:24:25 +03:00
return ret ;
2016-02-11 16:49:54 +03:00
}
return 0 ;
}
static int ads1015_remove ( struct i2c_client * client )
{
struct iio_dev * indio_dev = i2c_get_clientdata ( client ) ;
struct ads1015_data * data = iio_priv ( indio_dev ) ;
iio_device_unregister ( indio_dev ) ;
pm_runtime_disable ( & client - > dev ) ;
pm_runtime_set_suspended ( & client - > dev ) ;
/* power down single shot mode */
2017-07-20 18:24:24 +03:00
return ads1015_set_conv_mode ( data , ADS1015_SINGLESHOT ) ;
2016-02-11 16:49:54 +03:00
}
# ifdef CONFIG_PM
static int ads1015_runtime_suspend ( struct device * dev )
{
struct iio_dev * indio_dev = i2c_get_clientdata ( to_i2c_client ( dev ) ) ;
struct ads1015_data * data = iio_priv ( indio_dev ) ;
2017-07-20 18:24:24 +03:00
return ads1015_set_conv_mode ( data , ADS1015_SINGLESHOT ) ;
2016-02-11 16:49:54 +03:00
}
static int ads1015_runtime_resume ( struct device * dev )
{
struct iio_dev * indio_dev = i2c_get_clientdata ( to_i2c_client ( dev ) ) ;
struct ads1015_data * data = iio_priv ( indio_dev ) ;
2017-07-20 18:24:20 +03:00
int ret ;
2016-02-11 16:49:54 +03:00
2017-07-20 18:24:24 +03:00
ret = ads1015_set_conv_mode ( data , ADS1015_CONTINUOUS ) ;
2017-07-20 18:24:20 +03:00
if ( ! ret )
data - > conv_invalid = true ;
return ret ;
2016-02-11 16:49:54 +03:00
}
# endif
static const struct dev_pm_ops ads1015_pm_ops = {
SET_RUNTIME_PM_OPS ( ads1015_runtime_suspend ,
ads1015_runtime_resume , NULL )
} ;
static const struct i2c_device_id ads1015_id [ ] = {
2016-05-16 08:18:46 +03:00
{ " ads1015 " , ADS1015 } ,
{ " ads1115 " , ADS1115 } ,
2016-02-11 16:49:54 +03:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , ads1015_id ) ;
2017-03-15 07:45:00 +03:00
static const struct of_device_id ads1015_of_match [ ] = {
{
. compatible = " ti,ads1015 " ,
. data = ( void * ) ADS1015
} ,
{
. compatible = " ti,ads1115 " ,
. data = ( void * ) ADS1115
} ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , ads1015_of_match ) ;
2016-02-11 16:49:54 +03:00
static struct i2c_driver ads1015_driver = {
. driver = {
. name = ADS1015_DRV_NAME ,
2017-03-15 07:45:00 +03:00
. of_match_table = ads1015_of_match ,
2016-02-11 16:49:54 +03:00
. pm = & ads1015_pm_ops ,
} ,
. probe = ads1015_probe ,
. remove = ads1015_remove ,
. id_table = ads1015_id ,
} ;
module_i2c_driver ( ads1015_driver ) ;
MODULE_AUTHOR ( " Daniel Baluta <daniel.baluta@intel.com> " ) ;
MODULE_DESCRIPTION ( " Texas Instruments ADS1015 ADC driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;