2011-03-21 19:59:36 +03:00
/*
* ads1015 . c - lm_sensors driver for ads1015 12 - bit 4 - input ADC
* ( C ) Copyright 2010
* Dirk Eibach , Guntermann & Drunck GmbH < eibach @ gdsys . de >
*
* Based on the ads7828 driver by Steve Hardy .
*
* Datasheet available at : http : //focus.ti.com/lit/ds/symlink/ads1015.pdf
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/delay.h>
# include <linux/i2c.h>
# include <linux/hwmon.h>
# include <linux/hwmon-sysfs.h>
# include <linux/err.h>
# include <linux/mutex.h>
2017-02-24 16:12:56 +03:00
# include <linux/of_device.h>
2011-03-21 19:59:36 +03:00
# include <linux/of.h>
2017-05-21 23:34:39 +03:00
# include <linux/platform_data/ads1015.h>
2011-03-21 19:59:36 +03:00
/* ADS1015 registers */
enum {
ADS1015_CONVERSION = 0 ,
ADS1015_CONFIG = 1 ,
} ;
/* PGA fullscale voltages in mV */
static const unsigned int fullscale_table [ 8 ] = {
6144 , 4096 , 2048 , 1024 , 512 , 256 , 256 , 256 } ;
2011-03-21 19:59:37 +03:00
/* Data rates in samples per second */
2013-08-01 23:23:48 +04:00
static const unsigned int data_rate_table_1015 [ 8 ] = {
128 , 250 , 490 , 920 , 1600 , 2400 , 3300 , 3300
} ;
static const unsigned int data_rate_table_1115 [ 8 ] = {
8 , 16 , 32 , 64 , 128 , 250 , 475 , 860
} ;
2011-03-21 19:59:37 +03:00
2011-03-21 19:59:36 +03:00
# define ADS1015_DEFAULT_CHANNELS 0xff
2011-03-21 19:59:37 +03:00
# define ADS1015_DEFAULT_PGA 2
# define ADS1015_DEFAULT_DATA_RATE 4
2011-03-21 19:59:36 +03:00
2013-08-01 23:23:48 +04:00
enum ads1015_chips {
ads1015 ,
ads1115 ,
} ;
2011-03-21 19:59:36 +03:00
struct ads1015_data {
struct device * hwmon_dev ;
struct mutex update_lock ; /* mutex protect updates */
2011-03-21 19:59:37 +03:00
struct ads1015_channel_data channel_data [ ADS1015_CHANNELS ] ;
2013-08-01 23:23:48 +04:00
enum ads1015_chips id ;
2011-03-21 19:59:36 +03:00
} ;
2012-04-09 21:53:00 +04:00
static int ads1015_read_adc ( struct i2c_client * client , unsigned int channel )
2011-03-21 19:59:36 +03:00
{
u16 config ;
struct ads1015_data * data = i2c_get_clientdata ( client ) ;
2011-03-21 19:59:37 +03:00
unsigned int pga = data - > channel_data [ channel ] . pga ;
unsigned int data_rate = data - > channel_data [ channel ] . data_rate ;
unsigned int conversion_time_ms ;
2013-08-01 23:23:48 +04:00
const unsigned int * const rate_table = data - > id = = ads1115 ?
data_rate_table_1115 : data_rate_table_1015 ;
2011-03-21 19:59:36 +03:00
int res ;
mutex_lock ( & data - > update_lock ) ;
2011-03-21 19:59:37 +03:00
/* get channel parameters */
2011-11-04 15:00:47 +04:00
res = i2c_smbus_read_word_swapped ( client , ADS1015_CONFIG ) ;
2011-03-21 19:59:36 +03:00
if ( res < 0 )
goto err_unlock ;
config = res ;
2013-08-01 23:23:48 +04:00
conversion_time_ms = DIV_ROUND_UP ( 1000 , rate_table [ data_rate ] ) ;
2011-03-21 19:59:36 +03:00
2011-03-21 19:59:37 +03:00
/* setup and start single conversion */
config & = 0x001f ;
config | = ( 1 < < 15 ) | ( 1 < < 8 ) ;
config | = ( channel & 0x0007 ) < < 12 ;
config | = ( pga & 0x0007 ) < < 9 ;
config | = ( data_rate & 0x0007 ) < < 5 ;
2011-03-21 19:59:36 +03:00
2011-11-04 15:00:47 +04:00
res = i2c_smbus_write_word_swapped ( client , ADS1015_CONFIG , config ) ;
2011-03-21 19:59:36 +03:00
if ( res < 0 )
goto err_unlock ;
2011-03-21 19:59:37 +03:00
/* wait until conversion finished */
msleep ( conversion_time_ms ) ;
2011-11-04 15:00:47 +04:00
res = i2c_smbus_read_word_swapped ( client , ADS1015_CONFIG ) ;
2011-03-21 19:59:37 +03:00
if ( res < 0 )
goto err_unlock ;
config = res ;
if ( ! ( config & ( 1 < < 15 ) ) ) {
/* conversion not finished in time */
2011-03-21 19:59:36 +03:00
res = - EIO ;
goto err_unlock ;
}
2011-11-04 15:00:47 +04:00
res = i2c_smbus_read_word_swapped ( client , ADS1015_CONVERSION ) ;
2011-03-21 19:59:36 +03:00
err_unlock :
mutex_unlock ( & data - > update_lock ) ;
return res ;
}
2012-04-09 21:53:00 +04:00
static int ads1015_reg_to_mv ( struct i2c_client * client , unsigned int channel ,
s16 reg )
{
struct ads1015_data * data = i2c_get_clientdata ( client ) ;
unsigned int pga = data - > channel_data [ channel ] . pga ;
int fullscale = fullscale_table [ pga ] ;
2016-02-18 16:07:52 +03:00
const int mask = data - > id = = ads1115 ? 0x7fff : 0x7ff0 ;
2012-04-09 21:53:00 +04:00
2013-08-01 23:23:48 +04:00
return DIV_ROUND_CLOSEST ( reg * fullscale , mask ) ;
2012-04-09 21:53:00 +04:00
}
2011-03-21 19:59:36 +03:00
/* sysfs callback function */
static ssize_t show_in ( struct device * dev , struct device_attribute * da ,
char * buf )
{
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
struct i2c_client * client = to_i2c_client ( dev ) ;
int res ;
2012-04-09 21:53:00 +04:00
int index = attr - > index ;
2011-03-21 19:59:36 +03:00
2012-04-09 21:53:00 +04:00
res = ads1015_read_adc ( client , index ) ;
if ( res < 0 )
return res ;
2011-03-21 19:59:36 +03:00
2012-04-09 21:53:00 +04:00
return sprintf ( buf , " %d \n " , ads1015_reg_to_mv ( client , index , res ) ) ;
2011-03-21 19:59:36 +03:00
}
2011-03-21 19:59:37 +03:00
static const struct sensor_device_attribute ads1015_in [ ] = {
SENSOR_ATTR ( in0_input , S_IRUGO , show_in , NULL , 0 ) ,
SENSOR_ATTR ( in1_input , S_IRUGO , show_in , NULL , 1 ) ,
SENSOR_ATTR ( in2_input , S_IRUGO , show_in , NULL , 2 ) ,
SENSOR_ATTR ( in3_input , S_IRUGO , show_in , NULL , 3 ) ,
SENSOR_ATTR ( in4_input , S_IRUGO , show_in , NULL , 4 ) ,
SENSOR_ATTR ( in5_input , S_IRUGO , show_in , NULL , 5 ) ,
SENSOR_ATTR ( in6_input , S_IRUGO , show_in , NULL , 6 ) ,
SENSOR_ATTR ( in7_input , S_IRUGO , show_in , NULL , 7 ) ,
2011-03-21 19:59:36 +03:00
} ;
/*
* Driver interface
*/
static int ads1015_remove ( struct i2c_client * client )
{
struct ads1015_data * data = i2c_get_clientdata ( client ) ;
2011-03-21 19:59:37 +03:00
int k ;
2011-03-21 19:59:36 +03:00
hwmon_device_unregister ( data - > hwmon_dev ) ;
2011-03-21 19:59:37 +03:00
for ( k = 0 ; k < ADS1015_CHANNELS ; + + k )
2011-03-21 19:59:37 +03:00
device_remove_file ( & client - > dev , & ads1015_in [ k ] . dev_attr ) ;
2011-03-21 19:59:36 +03:00
return 0 ;
}
# ifdef CONFIG_OF
2011-03-21 19:59:37 +03:00
static int ads1015_get_channels_config_of ( struct i2c_client * client )
{
struct ads1015_data * data = i2c_get_clientdata ( client ) ;
struct device_node * node ;
if ( ! client - > dev . of_node
| | ! of_get_next_child ( client - > dev . of_node , NULL ) )
return - EINVAL ;
for_each_child_of_node ( client - > dev . of_node , node ) {
2014-08-05 06:56:47 +04:00
u32 pval ;
2011-03-21 19:59:37 +03:00
unsigned int channel ;
unsigned int pga = ADS1015_DEFAULT_PGA ;
unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE ;
2014-08-05 06:56:47 +04:00
if ( of_property_read_u32 ( node , " reg " , & pval ) ) {
2011-03-21 19:59:37 +03:00
dev_err ( & client - > dev , " invalid reg on %s \n " ,
node - > full_name ) ;
continue ;
}
2014-08-05 06:56:47 +04:00
channel = pval ;
2014-07-30 07:13:52 +04:00
if ( channel > = ADS1015_CHANNELS ) {
2011-03-21 19:59:37 +03:00
dev_err ( & client - > dev ,
" invalid channel index %d on %s \n " ,
channel , node - > full_name ) ;
continue ;
}
2014-08-05 06:56:47 +04:00
if ( ! of_property_read_u32 ( node , " ti,gain " , & pval ) ) {
pga = pval ;
2011-03-21 19:59:37 +03:00
if ( pga > 6 ) {
2014-08-05 06:56:47 +04:00
dev_err ( & client - > dev , " invalid gain on %s \n " ,
2011-03-21 19:59:37 +03:00
node - > full_name ) ;
2014-08-05 05:59:49 +04:00
return - EINVAL ;
2011-03-21 19:59:37 +03:00
}
}
2014-08-05 06:56:47 +04:00
if ( ! of_property_read_u32 ( node , " ti,datarate " , & pval ) ) {
data_rate = pval ;
2011-03-21 19:59:37 +03:00
if ( data_rate > 7 ) {
dev_err ( & client - > dev ,
" invalid data_rate on %s \n " ,
node - > full_name ) ;
2014-08-05 05:59:49 +04:00
return - EINVAL ;
2011-03-21 19:59:37 +03:00
}
}
data - > channel_data [ channel ] . enabled = true ;
data - > channel_data [ channel ] . pga = pga ;
data - > channel_data [ channel ] . data_rate = data_rate ;
}
return 0 ;
}
2011-03-21 19:59:36 +03:00
# endif
2011-03-21 19:59:37 +03:00
static void ads1015_get_channels_config ( struct i2c_client * client )
{
unsigned int k ;
struct ads1015_data * data = i2c_get_clientdata ( client ) ;
struct ads1015_platform_data * pdata = dev_get_platdata ( & client - > dev ) ;
2011-03-21 19:59:36 +03:00
/* prefer platform data */
2011-03-21 19:59:37 +03:00
if ( pdata ) {
memcpy ( data - > channel_data , pdata - > channel_data ,
sizeof ( data - > channel_data ) ) ;
return ;
}
2011-03-21 19:59:36 +03:00
# ifdef CONFIG_OF
2011-03-21 19:59:37 +03:00
if ( ! ads1015_get_channels_config_of ( client ) )
return ;
2011-03-21 19:59:36 +03:00
# endif
/* fallback on default configuration */
2011-03-21 19:59:37 +03:00
for ( k = 0 ; k < ADS1015_CHANNELS ; + + k ) {
data - > channel_data [ k ] . enabled = true ;
data - > channel_data [ k ] . pga = ADS1015_DEFAULT_PGA ;
data - > channel_data [ k ] . data_rate = ADS1015_DEFAULT_DATA_RATE ;
}
2011-03-21 19:59:36 +03:00
}
static int ads1015_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
struct ads1015_data * data ;
int err ;
unsigned int k ;
2012-06-02 20:58:00 +04:00
data = devm_kzalloc ( & client - > dev , sizeof ( struct ads1015_data ) ,
GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
2017-02-24 16:12:56 +03:00
if ( client - > dev . of_node )
data - > id = ( enum ads1015_chips )
of_device_get_match_data ( & client - > dev ) ;
else
data - > id = id - > driver_data ;
2011-03-21 19:59:36 +03:00
i2c_set_clientdata ( client , data ) ;
mutex_init ( & data - > update_lock ) ;
/* build sysfs attribute group */
2011-03-21 19:59:37 +03:00
ads1015_get_channels_config ( client ) ;
for ( k = 0 ; k < ADS1015_CHANNELS ; + + k ) {
if ( ! data - > channel_data [ k ] . enabled )
2011-03-21 19:59:36 +03:00
continue ;
2011-03-21 19:59:37 +03:00
err = device_create_file ( & client - > dev , & ads1015_in [ k ] . dev_attr ) ;
if ( err )
2012-02-22 20:13:52 +04:00
goto exit_remove ;
2011-03-21 19:59:36 +03:00
}
data - > hwmon_dev = hwmon_device_register ( & client - > dev ) ;
if ( IS_ERR ( data - > hwmon_dev ) ) {
err = PTR_ERR ( data - > hwmon_dev ) ;
goto exit_remove ;
}
return 0 ;
exit_remove :
2011-03-21 19:59:37 +03:00
for ( k = 0 ; k < ADS1015_CHANNELS ; + + k )
2011-03-21 19:59:37 +03:00
device_remove_file ( & client - > dev , & ads1015_in [ k ] . dev_attr ) ;
2011-03-21 19:59:36 +03:00
return err ;
}
static const struct i2c_device_id ads1015_id [ ] = {
2013-08-01 23:23:48 +04:00
{ " ads1015 " , ads1015 } ,
{ " ads1115 " , ads1115 } ,
2011-03-21 19:59:36 +03:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , ads1015_id ) ;
2017-02-24 16:12:56 +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 ) ;
2011-03-21 19:59:36 +03:00
static struct i2c_driver ads1015_driver = {
. driver = {
. name = " ads1015 " ,
2017-02-24 16:12:56 +03:00
. of_match_table = of_match_ptr ( ads1015_of_match ) ,
2011-03-21 19:59:36 +03:00
} ,
. probe = ads1015_probe ,
. remove = ads1015_remove ,
. id_table = ads1015_id ,
} ;
2012-01-20 11:38:18 +04:00
module_i2c_driver ( ads1015_driver ) ;
2011-03-21 19:59:36 +03:00
MODULE_AUTHOR ( " Dirk Eibach <eibach@gdsys.de> " ) ;
MODULE_DESCRIPTION ( " ADS1015 driver " ) ;
MODULE_LICENSE ( " GPL " ) ;