2012-05-12 12:36:38 +04:00
/*
* Driver for Texas Instruments INA219 , INA226 power monitor chips
*
* INA219 :
* Zero Drift Bi - Directional Current / Power Monitor with I2C Interface
* Datasheet : http : //www.ti.com/product/ina219
*
2012-05-12 22:33:11 +04:00
* INA220 :
* Bi - Directional Current / Power Monitor with I2C Interface
* Datasheet : http : //www.ti.com/product/ina220
*
2012-05-12 12:36:38 +04:00
* INA226 :
* Bi - Directional Current / Power Monitor with I2C Interface
* Datasheet : http : //www.ti.com/product/ina226
*
2012-05-12 22:33:11 +04:00
* INA230 :
* Bi - directional Current / Power Monitor with I2C Interface
* Datasheet : http : //www.ti.com/product/ina230
*
2012-05-12 12:36:38 +04:00
* Copyright ( C ) 2012 Lothar Felten < l - felten @ ti . com >
* Thanks to Jan Volkering
*
* 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 ; version 2 of the License .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/err.h>
# include <linux/slab.h>
# include <linux/i2c.h>
# include <linux/hwmon.h>
# include <linux/hwmon-sysfs.h>
2012-10-10 17:25:56 +04:00
# include <linux/jiffies.h>
2013-06-19 10:50:20 +04:00
# include <linux/of.h>
2015-01-05 17:20:52 +03:00
# include <linux/delay.h>
2012-05-12 12:36:38 +04:00
# include <linux/platform_data/ina2xx.h>
/* common register definitions */
# define INA2XX_CONFIG 0x00
# define INA2XX_SHUNT_VOLTAGE 0x01 /* readonly */
# define INA2XX_BUS_VOLTAGE 0x02 /* readonly */
# define INA2XX_POWER 0x03 /* readonly */
# define INA2XX_CURRENT 0x04 /* readonly */
# define INA2XX_CALIBRATION 0x05
/* INA226 register definitions */
# define INA226_MASK_ENABLE 0x06
# define INA226_ALERT_LIMIT 0x07
# define INA226_DIE_ID 0xFF
/* register count */
# define INA219_REGISTERS 6
# define INA226_REGISTERS 8
# define INA2XX_MAX_REGISTERS 8
/* settings - depend on use case */
# define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */
# define INA226_CONFIG_DEFAULT 0x4527 /* averages=16 */
/* worst case is 68.10 ms (~14.6Hz, ina219) */
# define INA2XX_CONVERSION_RATE 15
2015-01-05 17:20:52 +03:00
# define INA2XX_MAX_DELAY 69 /* worst case delay in ms */
# define INA2XX_RSHUNT_DEFAULT 10000
2012-05-12 12:36:38 +04:00
enum ina2xx_ids { ina219 , ina226 } ;
2012-05-12 22:21:01 +04:00
struct ina2xx_config {
u16 config_default ;
int calibration_factor ;
int registers ;
int shunt_div ;
int bus_voltage_shift ;
int bus_voltage_lsb ; /* uV */
int power_lsb ; /* uW */
} ;
2012-05-12 12:36:38 +04:00
struct ina2xx_data {
2013-09-03 00:16:19 +04:00
struct i2c_client * client ;
2012-05-12 22:21:01 +04:00
const struct ina2xx_config * config ;
2012-05-12 12:36:38 +04:00
2015-01-05 17:20:52 +03:00
long rshunt ;
2012-05-12 12:36:38 +04:00
struct mutex update_lock ;
bool valid ;
unsigned long last_updated ;
int kind ;
u16 regs [ INA2XX_MAX_REGISTERS ] ;
} ;
2012-05-12 22:21:01 +04:00
static const struct ina2xx_config ina2xx_config [ ] = {
[ ina219 ] = {
. config_default = INA219_CONFIG_DEFAULT ,
. calibration_factor = 40960000 ,
. registers = INA219_REGISTERS ,
. shunt_div = 100 ,
. bus_voltage_shift = 3 ,
. bus_voltage_lsb = 4000 ,
. power_lsb = 20000 ,
} ,
[ ina226 ] = {
. config_default = INA226_CONFIG_DEFAULT ,
. calibration_factor = 5120000 ,
. registers = INA226_REGISTERS ,
. shunt_div = 400 ,
. bus_voltage_shift = 0 ,
. bus_voltage_lsb = 1250 ,
. power_lsb = 25000 ,
} ,
} ;
2015-01-05 17:20:55 +03:00
static int ina2xx_calibrate ( struct ina2xx_data * data )
{
return i2c_smbus_write_word_swapped ( data - > client , INA2XX_CALIBRATION ,
data - > config - > calibration_factor / data - > rshunt ) ;
}
2015-01-05 17:20:52 +03:00
/*
* Initialize the configuration and calibration registers .
*/
static int ina2xx_init ( struct ina2xx_data * data )
2012-05-12 12:36:38 +04:00
{
2013-09-03 00:16:19 +04:00
struct i2c_client * client = data - > client ;
2015-01-05 17:20:52 +03:00
int ret ;
2012-05-12 12:36:38 +04:00
2015-01-05 17:20:52 +03:00
/* device configuration */
ret = i2c_smbus_write_word_swapped ( client , INA2XX_CONFIG ,
data - > config - > config_default ) ;
if ( ret < 0 )
return ret ;
2012-05-12 12:36:38 +04:00
2015-01-05 17:20:52 +03:00
/*
* Set current LSB to 1 mA , shunt is in uOhms
* ( equation 13 in datasheet ) .
*/
2015-01-05 17:20:55 +03:00
return ina2xx_calibrate ( data ) ;
2015-01-05 17:20:52 +03:00
}
2012-05-12 12:36:38 +04:00
2015-01-05 17:20:52 +03:00
static int ina2xx_do_update ( struct device * dev )
{
struct ina2xx_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
int i , rv , retry ;
2012-05-12 12:36:38 +04:00
2015-01-05 17:20:52 +03:00
dev_dbg ( & client - > dev , " Starting ina2xx update \n " ) ;
2012-05-12 12:36:38 +04:00
2015-01-05 17:20:52 +03:00
for ( retry = 5 ; retry ; retry - - ) {
2012-05-12 12:36:38 +04:00
/* Read all registers */
2012-05-12 22:21:01 +04:00
for ( i = 0 ; i < data - > config - > registers ; i + + ) {
2015-01-05 17:20:52 +03:00
rv = i2c_smbus_read_word_swapped ( client , i ) ;
if ( rv < 0 )
return rv ;
2012-05-12 12:36:38 +04:00
data - > regs [ i ] = rv ;
}
2015-01-05 17:20:52 +03:00
/*
* If the current value in the calibration register is 0 , the
* power and current registers will also remain at 0. In case
* the chip has been reset let ' s check the calibration
* register and reinitialize if needed .
*/
if ( data - > regs [ INA2XX_CALIBRATION ] = = 0 ) {
dev_warn ( dev , " chip not calibrated, reinitializing \n " ) ;
rv = ina2xx_init ( data ) ;
if ( rv < 0 )
return rv ;
/*
* Let ' s make sure the power and current registers
* have been updated before trying again .
*/
msleep ( INA2XX_MAX_DELAY ) ;
continue ;
}
2012-05-12 12:36:38 +04:00
data - > last_updated = jiffies ;
data - > valid = 1 ;
2015-01-05 17:20:52 +03:00
return 0 ;
2012-05-12 12:36:38 +04:00
}
2015-01-05 17:20:52 +03:00
/*
* If we ' re here then although all write operations succeeded , the
* chip still returns 0 in the calibration register . Nothing more we
* can do here .
*/
dev_err ( dev , " unable to reinitialize the chip \n " ) ;
return - ENODEV ;
}
static struct ina2xx_data * ina2xx_update_device ( struct device * dev )
{
struct ina2xx_data * data = dev_get_drvdata ( dev ) ;
struct ina2xx_data * ret = data ;
int rv ;
mutex_lock ( & data - > update_lock ) ;
if ( time_after ( jiffies , data - > last_updated +
HZ / INA2XX_CONVERSION_RATE ) | | ! data - > valid ) {
rv = ina2xx_do_update ( dev ) ;
if ( rv < 0 )
ret = ERR_PTR ( rv ) ;
}
2012-05-12 12:36:38 +04:00
mutex_unlock ( & data - > update_lock ) ;
return ret ;
}
2012-05-12 22:21:01 +04:00
static int ina2xx_get_value ( struct ina2xx_data * data , u8 reg )
2012-05-12 12:36:38 +04:00
{
2012-05-12 22:21:01 +04:00
int val ;
2012-05-12 12:36:38 +04:00
switch ( reg ) {
case INA2XX_SHUNT_VOLTAGE :
2014-06-09 01:06:24 +04:00
/* signed register */
val = DIV_ROUND_CLOSEST ( ( s16 ) data - > regs [ reg ] ,
2012-05-12 22:21:01 +04:00
data - > config - > shunt_div ) ;
2012-05-12 12:36:38 +04:00
break ;
case INA2XX_BUS_VOLTAGE :
2012-05-12 22:21:01 +04:00
val = ( data - > regs [ reg ] > > data - > config - > bus_voltage_shift )
* data - > config - > bus_voltage_lsb ;
val = DIV_ROUND_CLOSEST ( val , 1000 ) ;
2012-05-12 12:36:38 +04:00
break ;
case INA2XX_POWER :
2012-05-12 22:21:01 +04:00
val = data - > regs [ reg ] * data - > config - > power_lsb ;
2012-05-12 12:36:38 +04:00
break ;
case INA2XX_CURRENT :
2014-06-09 01:06:24 +04:00
/* signed register, LSB=1mA (selected), in mA */
val = ( s16 ) data - > regs [ reg ] ;
2012-05-12 12:36:38 +04:00
break ;
2015-01-05 17:20:55 +03:00
case INA2XX_CALIBRATION :
val = data - > config - > calibration_factor / data - > regs [ reg ] ;
break ;
2012-05-12 12:36:38 +04:00
default :
/* programmer goofed */
WARN_ON_ONCE ( 1 ) ;
val = 0 ;
break ;
}
return val ;
}
static ssize_t ina2xx_show_value ( struct device * dev ,
struct device_attribute * da , char * buf )
{
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
struct ina2xx_data * data = ina2xx_update_device ( dev ) ;
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
2012-05-12 22:21:01 +04:00
return snprintf ( buf , PAGE_SIZE , " %d \n " ,
ina2xx_get_value ( data , attr - > index ) ) ;
2012-05-12 12:36:38 +04:00
}
2015-01-05 17:20:55 +03:00
static ssize_t ina2xx_set_shunt ( struct device * dev ,
struct device_attribute * da ,
const char * buf , size_t count )
{
struct ina2xx_data * data = ina2xx_update_device ( dev ) ;
unsigned long val ;
int status ;
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
status = kstrtoul ( buf , 10 , & val ) ;
if ( status < 0 )
return status ;
if ( val = = 0 | |
/* Values greater than the calibration factor make no sense. */
val > data - > config - > calibration_factor )
return - EINVAL ;
mutex_lock ( & data - > update_lock ) ;
data - > rshunt = val ;
status = ina2xx_calibrate ( data ) ;
mutex_unlock ( & data - > update_lock ) ;
if ( status < 0 )
return status ;
return count ;
}
2012-05-12 12:36:38 +04:00
/* shunt voltage */
2013-01-10 22:04:06 +04:00
static SENSOR_DEVICE_ATTR ( in0_input , S_IRUGO , ina2xx_show_value , NULL ,
INA2XX_SHUNT_VOLTAGE ) ;
2012-05-12 12:36:38 +04:00
/* bus voltage */
2013-01-10 22:04:06 +04:00
static SENSOR_DEVICE_ATTR ( in1_input , S_IRUGO , ina2xx_show_value , NULL ,
INA2XX_BUS_VOLTAGE ) ;
2012-05-12 12:36:38 +04:00
/* calculated current */
2013-01-10 22:04:06 +04:00
static SENSOR_DEVICE_ATTR ( curr1_input , S_IRUGO , ina2xx_show_value , NULL ,
INA2XX_CURRENT ) ;
2012-05-12 12:36:38 +04:00
/* calculated power */
2013-01-10 22:04:06 +04:00
static SENSOR_DEVICE_ATTR ( power1_input , S_IRUGO , ina2xx_show_value , NULL ,
INA2XX_POWER ) ;
2012-05-12 12:36:38 +04:00
2015-01-05 17:20:55 +03:00
/* shunt resistance */
static SENSOR_DEVICE_ATTR ( shunt_resistor , S_IRUGO | S_IWUSR ,
ina2xx_show_value , ina2xx_set_shunt ,
INA2XX_CALIBRATION ) ;
2012-05-12 12:36:38 +04:00
/* pointers to created device attributes */
2013-09-03 00:16:19 +04:00
static struct attribute * ina2xx_attrs [ ] = {
2012-05-12 12:36:38 +04:00
& sensor_dev_attr_in0_input . dev_attr . attr ,
& sensor_dev_attr_in1_input . dev_attr . attr ,
& sensor_dev_attr_curr1_input . dev_attr . attr ,
& sensor_dev_attr_power1_input . dev_attr . attr ,
2015-01-05 17:20:55 +03:00
& sensor_dev_attr_shunt_resistor . dev_attr . attr ,
2012-05-12 12:36:38 +04:00
NULL ,
} ;
2013-09-03 00:16:19 +04:00
ATTRIBUTE_GROUPS ( ina2xx ) ;
2012-05-12 12:36:38 +04:00
static int ina2xx_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
struct i2c_adapter * adapter = client - > adapter ;
struct ina2xx_platform_data * pdata ;
2013-09-03 00:16:19 +04:00
struct device * dev = & client - > dev ;
struct ina2xx_data * data ;
struct device * hwmon_dev ;
u32 val ;
2014-11-27 12:59:06 +03:00
int ret ;
2012-05-12 12:36:38 +04:00
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_WORD_DATA ) )
return - ENODEV ;
2013-09-03 00:16:19 +04:00
data = devm_kzalloc ( dev , sizeof ( * data ) , GFP_KERNEL ) ;
2012-05-12 12:36:38 +04:00
if ( ! data )
return - ENOMEM ;
2013-09-03 00:16:19 +04:00
if ( dev_get_platdata ( dev ) ) {
pdata = dev_get_platdata ( dev ) ;
2015-01-05 17:20:52 +03:00
data - > rshunt = pdata - > shunt_uohms ;
2013-09-03 00:16:19 +04:00
} else if ( ! of_property_read_u32 ( dev - > of_node ,
" shunt-resistor " , & val ) ) {
2015-01-05 17:20:52 +03:00
data - > rshunt = val ;
} else {
data - > rshunt = INA2XX_RSHUNT_DEFAULT ;
2012-05-12 12:36:38 +04:00
}
/* set the device type */
data - > kind = id - > driver_data ;
2012-05-12 22:21:01 +04:00
data - > config = & ina2xx_config [ data - > kind ] ;
2015-01-05 17:20:52 +03:00
data - > client = client ;
2012-05-12 12:36:38 +04:00
2015-01-05 17:20:54 +03:00
if ( data - > rshunt < = 0 | |
data - > rshunt > data - > config - > calibration_factor )
2014-11-27 12:59:06 +03:00
return - ENODEV ;
2015-01-05 17:20:52 +03:00
ret = ina2xx_init ( data ) ;
2014-11-27 12:59:06 +03:00
if ( ret < 0 ) {
2015-01-05 17:20:52 +03:00
dev_err ( dev , " error configuring the device: %d \n " , ret ) ;
2014-11-27 12:59:06 +03:00
return - ENODEV ;
}
2012-05-12 12:36:38 +04:00
mutex_init ( & data - > update_lock ) ;
2013-09-03 00:16:19 +04:00
hwmon_dev = devm_hwmon_device_register_with_groups ( dev , client - > name ,
data , ina2xx_groups ) ;
if ( IS_ERR ( hwmon_dev ) )
return PTR_ERR ( hwmon_dev ) ;
2012-05-12 12:36:38 +04:00
2013-09-03 00:16:19 +04:00
dev_info ( dev , " power monitor %s (Rshunt = %li uOhm) \n " ,
2015-01-05 17:20:52 +03:00
id - > name , data - > rshunt ) ;
2012-05-12 22:21:01 +04:00
2012-05-12 12:36:38 +04:00
return 0 ;
}
static const struct i2c_device_id ina2xx_id [ ] = {
{ " ina219 " , ina219 } ,
2012-05-12 22:33:11 +04:00
{ " ina220 " , ina219 } ,
2012-05-12 12:36:38 +04:00
{ " ina226 " , ina226 } ,
2012-05-12 22:33:11 +04:00
{ " ina230 " , ina226 } ,
2012-05-12 12:36:38 +04:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , ina2xx_id ) ;
static struct i2c_driver ina2xx_driver = {
. driver = {
. name = " ina2xx " ,
} ,
. probe = ina2xx_probe ,
. id_table = ina2xx_id ,
} ;
2012-10-08 16:40:35 +04:00
module_i2c_driver ( ina2xx_driver ) ;
2012-05-12 12:36:38 +04:00
MODULE_AUTHOR ( " Lothar Felten <l-felten@ti.com> " ) ;
MODULE_DESCRIPTION ( " ina2xx driver " ) ;
MODULE_LICENSE ( " GPL " ) ;