2011-01-14 08:46:11 +03:00
/*
* Fuel gauge driver for Maxim 17042 / 8966 / 8997
* Note that Maxim 8966 and 8997 are mfd and this is its subdevice .
*
* Copyright ( C ) 2011 Samsung Electronics
* MyungJoo Ham < myungjoo . ham @ samsung . com >
*
* 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 . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
* This driver is based on max17040_battery . c
*/
# include <linux/init.h>
2011-07-03 23:28:29 +04:00
# include <linux/module.h>
2011-01-14 08:46:11 +03:00
# include <linux/slab.h>
# include <linux/i2c.h>
2012-03-13 22:03:52 +04:00
# include <linux/delay.h>
2012-01-24 21:26:06 +04:00
# include <linux/interrupt.h>
2012-03-27 00:53:40 +04:00
# include <linux/pm.h>
2011-01-14 08:46:11 +03:00
# include <linux/mod_devicetable.h>
# include <linux/power_supply.h>
# include <linux/power/max17042_battery.h>
2012-02-22 22:06:22 +04:00
# include <linux/of.h>
2013-10-25 08:55:02 +04:00
# include <linux/regmap.h>
2011-01-14 08:46:11 +03:00
2012-03-13 22:03:52 +04:00
/* Status register bits */
# define STATUS_POR_BIT (1 << 1)
# define STATUS_BST_BIT (1 << 3)
# define STATUS_VMN_BIT (1 << 8)
# define STATUS_TMN_BIT (1 << 9)
# define STATUS_SMN_BIT (1 << 10)
# define STATUS_BI_BIT (1 << 11)
# define STATUS_VMX_BIT (1 << 12)
# define STATUS_TMX_BIT (1 << 13)
# define STATUS_SMX_BIT (1 << 14)
# define STATUS_BR_BIT (1 << 15)
2012-01-24 21:26:06 +04:00
/* Interrupt mask bits */
# define CONFIG_ALRT_BIT_ENBL (1 << 2)
2012-03-21 01:33:16 +04:00
# define STATUS_INTR_SOCMIN_BIT (1 << 10)
# define STATUS_INTR_SOCMAX_BIT (1 << 14)
2012-01-24 21:26:06 +04:00
2012-03-13 22:03:52 +04:00
# define VFSOC0_LOCK 0x0000
# define VFSOC0_UNLOCK 0x0080
# define MODEL_UNLOCK1 0X0059
# define MODEL_UNLOCK2 0X00C4
# define MODEL_LOCK1 0X0000
# define MODEL_LOCK2 0X0000
# define dQ_ACC_DIV 0x4
# define dP_ACC_100 0x1900
# define dP_ACC_200 0x3200
2012-05-05 13:04:26 +04:00
# define MAX17042_IC_VERSION 0x0092
# define MAX17047_IC_VERSION 0x00AC /* same for max17050 */
2011-01-14 08:46:11 +03:00
struct max17042_chip {
struct i2c_client * client ;
2013-10-25 08:55:02 +04:00
struct regmap * regmap ;
2011-01-14 08:46:11 +03:00
struct power_supply battery ;
2012-05-05 13:04:26 +04:00
enum max170xx_chip_type chip_type ;
2011-01-14 08:46:11 +03:00
struct max17042_platform_data * pdata ;
2012-03-13 22:03:52 +04:00
struct work_struct work ;
int init_complete ;
2011-01-14 08:46:11 +03:00
} ;
static enum power_supply_property max17042_battery_props [ ] = {
2011-06-30 13:07:41 +04:00
POWER_SUPPLY_PROP_PRESENT ,
POWER_SUPPLY_PROP_CYCLE_COUNT ,
POWER_SUPPLY_PROP_VOLTAGE_MAX ,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN ,
2011-01-14 08:46:11 +03:00
POWER_SUPPLY_PROP_VOLTAGE_NOW ,
POWER_SUPPLY_PROP_VOLTAGE_AVG ,
2012-04-10 14:51:20 +04:00
POWER_SUPPLY_PROP_VOLTAGE_OCV ,
2011-01-14 08:46:11 +03:00
POWER_SUPPLY_PROP_CAPACITY ,
2011-06-30 13:07:41 +04:00
POWER_SUPPLY_PROP_CHARGE_FULL ,
2012-05-07 08:55:58 +04:00
POWER_SUPPLY_PROP_CHARGE_COUNTER ,
2011-06-30 13:07:41 +04:00
POWER_SUPPLY_PROP_TEMP ,
POWER_SUPPLY_PROP_CURRENT_NOW ,
POWER_SUPPLY_PROP_CURRENT_AVG ,
2011-01-14 08:46:11 +03:00
} ;
static int max17042_get_property ( struct power_supply * psy ,
enum power_supply_property psp ,
union power_supply_propval * val )
{
struct max17042_chip * chip = container_of ( psy ,
struct max17042_chip , battery ) ;
2013-10-25 08:55:02 +04:00
struct regmap * map = chip - > regmap ;
2011-11-26 04:11:15 +04:00
int ret ;
2013-10-25 08:55:02 +04:00
u32 data ;
2011-01-14 08:46:11 +03:00
2012-03-13 22:03:52 +04:00
if ( ! chip - > init_complete )
return - EAGAIN ;
2011-01-14 08:46:11 +03:00
switch ( psp ) {
2011-06-30 13:07:41 +04:00
case POWER_SUPPLY_PROP_PRESENT :
2013-10-25 08:55:02 +04:00
ret = regmap_read ( map , MAX17042_STATUS , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 08:55:02 +04:00
if ( data & MAX17042_STATUS_BattAbsent )
2011-06-30 13:07:41 +04:00
val - > intval = 0 ;
else
val - > intval = 1 ;
break ;
case POWER_SUPPLY_PROP_CYCLE_COUNT :
2013-10-25 08:55:02 +04:00
ret = regmap_read ( map , MAX17042_Cycles , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 08:55:02 +04:00
val - > intval = data ;
2011-06-30 13:07:41 +04:00
break ;
case POWER_SUPPLY_PROP_VOLTAGE_MAX :
2013-10-25 08:55:02 +04:00
ret = regmap_read ( map , MAX17042_MinMaxVolt , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 08:55:02 +04:00
val - > intval = data > > 8 ;
2011-06-30 13:07:41 +04:00
val - > intval * = 20000 ; /* Units of LSB = 20mV */
break ;
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN :
2012-05-05 13:04:26 +04:00
if ( chip - > chip_type = = MAX17042 )
2013-10-25 08:55:02 +04:00
ret = regmap_read ( map , MAX17042_V_empty , & data ) ;
2012-05-05 13:04:26 +04:00
else
2013-10-25 08:55:02 +04:00
ret = regmap_read ( map , MAX17047_V_empty , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 08:55:02 +04:00
val - > intval = data > > 7 ;
2011-06-30 13:07:41 +04:00
val - > intval * = 10000 ; /* Units of LSB = 10mV */
break ;
2011-01-14 08:46:11 +03:00
case POWER_SUPPLY_PROP_VOLTAGE_NOW :
2013-10-25 08:55:02 +04:00
ret = regmap_read ( map , MAX17042_VCELL , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 08:55:02 +04:00
val - > intval = data * 625 / 8 ;
2011-01-14 08:46:11 +03:00
break ;
case POWER_SUPPLY_PROP_VOLTAGE_AVG :
2013-10-25 08:55:02 +04:00
ret = regmap_read ( map , MAX17042_AvgVCELL , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 08:55:02 +04:00
val - > intval = data * 625 / 8 ;
2012-04-10 14:51:20 +04:00
break ;
case POWER_SUPPLY_PROP_VOLTAGE_OCV :
2013-10-25 08:55:02 +04:00
ret = regmap_read ( map , MAX17042_OCVInternal , & data ) ;
2012-04-10 14:51:20 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 08:55:02 +04:00
val - > intval = data * 625 / 8 ;
2011-01-14 08:46:11 +03:00
break ;
case POWER_SUPPLY_PROP_CAPACITY :
2013-10-25 08:55:02 +04:00
ret = regmap_read ( map , MAX17042_RepSOC , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 08:55:02 +04:00
val - > intval = data > > 8 ;
2011-01-14 08:46:11 +03:00
break ;
2011-06-30 13:07:41 +04:00
case POWER_SUPPLY_PROP_CHARGE_FULL :
2013-10-25 08:55:02 +04:00
ret = regmap_read ( map , MAX17042_FullCAP , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 08:55:02 +04:00
val - > intval = data * 1000 / 2 ;
2012-05-07 08:55:58 +04:00
break ;
case POWER_SUPPLY_PROP_CHARGE_COUNTER :
2013-10-25 08:55:02 +04:00
ret = regmap_read ( map , MAX17042_QH , & data ) ;
2012-05-07 08:55:58 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 08:55:02 +04:00
val - > intval = data * 1000 / 2 ;
2011-06-30 13:07:41 +04:00
break ;
case POWER_SUPPLY_PROP_TEMP :
2013-10-25 08:55:02 +04:00
ret = regmap_read ( map , MAX17042_TEMP , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 08:55:02 +04:00
val - > intval = data ;
2011-06-30 13:07:41 +04:00
/* The value is signed. */
if ( val - > intval & 0x8000 ) {
val - > intval = ( 0x7fff & ~ val - > intval ) + 1 ;
val - > intval * = - 1 ;
}
/* The value is converted into deci-centigrade scale */
/* Units of LSB = 1 / 256 degree Celsius */
val - > intval = val - > intval * 10 / 256 ;
break ;
case POWER_SUPPLY_PROP_CURRENT_NOW :
if ( chip - > pdata - > enable_current_sense ) {
2013-10-25 08:55:02 +04:00
ret = regmap_read ( map , MAX17042_Current , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 08:55:02 +04:00
val - > intval = data ;
2011-06-30 13:07:41 +04:00
if ( val - > intval & 0x8000 ) {
/* Negative */
val - > intval = ~ val - > intval & 0x7fff ;
val - > intval + + ;
val - > intval * = - 1 ;
}
2011-08-13 08:19:57 +04:00
val - > intval * = 1562500 / chip - > pdata - > r_sns ;
2011-06-30 13:07:41 +04:00
} else {
return - EINVAL ;
}
break ;
case POWER_SUPPLY_PROP_CURRENT_AVG :
if ( chip - > pdata - > enable_current_sense ) {
2013-10-25 08:55:02 +04:00
ret = regmap_read ( map , MAX17042_AvgCurrent , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 08:55:02 +04:00
val - > intval = data ;
2011-06-30 13:07:41 +04:00
if ( val - > intval & 0x8000 ) {
/* Negative */
val - > intval = ~ val - > intval & 0x7fff ;
val - > intval + + ;
val - > intval * = - 1 ;
}
val - > intval * = 1562500 / chip - > pdata - > r_sns ;
} else {
return - EINVAL ;
}
break ;
2011-01-14 08:46:11 +03:00
default :
return - EINVAL ;
}
return 0 ;
}
2013-10-25 08:55:02 +04:00
static int max17042_write_verify_reg ( struct regmap * map , u8 reg , u32 value )
2012-03-13 22:03:52 +04:00
{
int retries = 8 ;
int ret ;
2013-10-25 08:55:02 +04:00
u32 read_value ;
2012-03-13 22:03:52 +04:00
do {
2013-10-25 08:55:02 +04:00
ret = regmap_write ( map , reg , value ) ;
regmap_read ( map , reg , & read_value ) ;
2012-03-13 22:03:52 +04:00
if ( read_value ! = value ) {
ret = - EIO ;
retries - - ;
}
} while ( retries & & read_value ! = value ) ;
if ( ret < 0 )
2013-10-25 08:55:02 +04:00
pr_err ( " %s: err %d \n " , __func__ , ret ) ;
2012-03-13 22:03:52 +04:00
return ret ;
}
2013-10-25 08:55:02 +04:00
static inline void max17042_override_por ( struct regmap * map ,
u8 reg , u16 value )
2012-03-13 22:03:52 +04:00
{
if ( value )
2013-10-25 08:55:02 +04:00
regmap_write ( map , reg , value ) ;
2012-03-13 22:03:52 +04:00
}
static inline void max10742_unlock_model ( struct max17042_chip * chip )
{
2013-10-25 08:55:02 +04:00
struct regmap * map = chip - > regmap ;
regmap_write ( map , MAX17042_MLOCKReg1 , MODEL_UNLOCK1 ) ;
regmap_write ( map , MAX17042_MLOCKReg2 , MODEL_UNLOCK2 ) ;
2012-03-13 22:03:52 +04:00
}
static inline void max10742_lock_model ( struct max17042_chip * chip )
{
2013-10-25 08:55:02 +04:00
struct regmap * map = chip - > regmap ;
regmap_write ( map , MAX17042_MLOCKReg1 , MODEL_LOCK1 ) ;
regmap_write ( map , MAX17042_MLOCKReg2 , MODEL_LOCK2 ) ;
2012-03-13 22:03:52 +04:00
}
static inline void max17042_write_model_data ( struct max17042_chip * chip ,
u8 addr , int size )
{
2013-10-25 08:55:02 +04:00
struct regmap * map = chip - > regmap ;
2012-03-13 22:03:52 +04:00
int i ;
for ( i = 0 ; i < size ; i + + )
2013-10-25 08:55:02 +04:00
regmap_write ( map , addr + i ,
chip - > pdata - > config_data - > cell_char_tbl [ i ] ) ;
2012-03-13 22:03:52 +04:00
}
static inline void max17042_read_model_data ( struct max17042_chip * chip ,
2013-10-25 08:55:02 +04:00
u8 addr , u32 * data , int size )
2012-03-13 22:03:52 +04:00
{
2013-10-25 08:55:02 +04:00
struct regmap * map = chip - > regmap ;
2012-03-13 22:03:52 +04:00
int i ;
for ( i = 0 ; i < size ; i + + )
2013-10-25 08:55:02 +04:00
regmap_read ( map , addr + i , & data [ i ] ) ;
2012-03-13 22:03:52 +04:00
}
static inline int max17042_model_data_compare ( struct max17042_chip * chip ,
u16 * data1 , u16 * data2 , int size )
{
int i ;
if ( memcmp ( data1 , data2 , size ) ) {
dev_err ( & chip - > client - > dev , " %s compare failed \n " , __func__ ) ;
for ( i = 0 ; i < size ; i + + )
dev_info ( & chip - > client - > dev , " 0x%x, 0x%x " ,
data1 [ i ] , data2 [ i ] ) ;
dev_info ( & chip - > client - > dev , " \n " ) ;
return - EINVAL ;
}
return 0 ;
}
static int max17042_init_model ( struct max17042_chip * chip )
{
int ret ;
2012-03-15 15:37:32 +04:00
int table_size = ARRAY_SIZE ( chip - > pdata - > config_data - > cell_char_tbl ) ;
2013-10-25 08:55:02 +04:00
u32 * temp_data ;
2012-03-13 22:03:52 +04:00
2012-03-15 15:37:32 +04:00
temp_data = kcalloc ( table_size , sizeof ( * temp_data ) , GFP_KERNEL ) ;
2012-03-13 22:03:52 +04:00
if ( ! temp_data )
return - ENOMEM ;
max10742_unlock_model ( chip ) ;
max17042_write_model_data ( chip , MAX17042_MODELChrTbl ,
table_size ) ;
max17042_read_model_data ( chip , MAX17042_MODELChrTbl , temp_data ,
table_size ) ;
ret = max17042_model_data_compare (
chip ,
chip - > pdata - > config_data - > cell_char_tbl ,
2013-10-25 08:55:02 +04:00
( u16 * ) temp_data ,
2012-03-13 22:03:52 +04:00
table_size ) ;
max10742_lock_model ( chip ) ;
kfree ( temp_data ) ;
return ret ;
}
static int max17042_verify_model_lock ( struct max17042_chip * chip )
{
int i ;
2012-03-15 15:37:32 +04:00
int table_size = ARRAY_SIZE ( chip - > pdata - > config_data - > cell_char_tbl ) ;
2013-10-25 08:55:02 +04:00
u32 * temp_data ;
2012-03-13 22:03:52 +04:00
int ret = 0 ;
2012-03-15 15:37:32 +04:00
temp_data = kcalloc ( table_size , sizeof ( * temp_data ) , GFP_KERNEL ) ;
2012-03-13 22:03:52 +04:00
if ( ! temp_data )
return - ENOMEM ;
max17042_read_model_data ( chip , MAX17042_MODELChrTbl , temp_data ,
table_size ) ;
for ( i = 0 ; i < table_size ; i + + )
if ( temp_data [ i ] )
ret = - EINVAL ;
kfree ( temp_data ) ;
return ret ;
}
static void max17042_write_config_regs ( struct max17042_chip * chip )
{
struct max17042_config_data * config = chip - > pdata - > config_data ;
2013-10-25 08:55:02 +04:00
struct regmap * map = chip - > regmap ;
2012-03-13 22:03:52 +04:00
2013-10-25 08:55:02 +04:00
regmap_write ( map , MAX17042_CONFIG , config - > config ) ;
regmap_write ( map , MAX17042_LearnCFG , config - > learn_cfg ) ;
regmap_write ( map , MAX17042_FilterCFG ,
2012-03-13 22:03:52 +04:00
config - > filter_cfg ) ;
2013-10-25 08:55:02 +04:00
regmap_write ( map , MAX17042_RelaxCFG , config - > relax_cfg ) ;
2012-05-05 13:04:26 +04:00
if ( chip - > chip_type = = MAX17047 )
2013-10-25 08:55:02 +04:00
regmap_write ( map , MAX17047_FullSOCThr ,
2012-05-05 13:04:26 +04:00
config - > full_soc_thresh ) ;
2012-03-13 22:03:52 +04:00
}
static void max17042_write_custom_regs ( struct max17042_chip * chip )
{
struct max17042_config_data * config = chip - > pdata - > config_data ;
2013-10-25 08:55:02 +04:00
struct regmap * map = chip - > regmap ;
2012-03-13 22:03:52 +04:00
2013-10-25 08:55:02 +04:00
max17042_write_verify_reg ( map , MAX17042_RCOMP0 , config - > rcomp0 ) ;
max17042_write_verify_reg ( map , MAX17042_TempCo , config - > tcompc0 ) ;
max17042_write_verify_reg ( map , MAX17042_ICHGTerm , config - > ichgt_term ) ;
2012-05-05 13:04:26 +04:00
if ( chip - > chip_type = = MAX17042 ) {
2013-10-25 08:55:02 +04:00
regmap_write ( map , MAX17042_EmptyTempCo , config - > empty_tempco ) ;
max17042_write_verify_reg ( map , MAX17042_K_empty0 ,
2012-05-05 13:04:26 +04:00
config - > kempty0 ) ;
} else {
2013-10-25 08:55:02 +04:00
max17042_write_verify_reg ( map , MAX17047_QRTbl00 ,
2012-05-05 13:04:26 +04:00
config - > qrtbl00 ) ;
2013-10-25 08:55:02 +04:00
max17042_write_verify_reg ( map , MAX17047_QRTbl10 ,
2012-05-05 13:04:26 +04:00
config - > qrtbl10 ) ;
2013-10-25 08:55:02 +04:00
max17042_write_verify_reg ( map , MAX17047_QRTbl20 ,
2012-05-05 13:04:26 +04:00
config - > qrtbl20 ) ;
2013-10-25 08:55:02 +04:00
max17042_write_verify_reg ( map , MAX17047_QRTbl30 ,
2012-05-05 13:04:26 +04:00
config - > qrtbl30 ) ;
}
2012-03-13 22:03:52 +04:00
}
static void max17042_update_capacity_regs ( struct max17042_chip * chip )
{
struct max17042_config_data * config = chip - > pdata - > config_data ;
2013-10-25 08:55:02 +04:00
struct regmap * map = chip - > regmap ;
2012-03-13 22:03:52 +04:00
2013-10-25 08:55:02 +04:00
max17042_write_verify_reg ( map , MAX17042_FullCAP ,
2012-03-13 22:03:52 +04:00
config - > fullcap ) ;
2013-10-25 08:55:02 +04:00
regmap_write ( map , MAX17042_DesignCap , config - > design_cap ) ;
max17042_write_verify_reg ( map , MAX17042_FullCAPNom ,
2012-03-13 22:03:52 +04:00
config - > fullcapnom ) ;
}
static void max17042_reset_vfsoc0_reg ( struct max17042_chip * chip )
{
2013-10-25 08:55:02 +04:00
unsigned int vfSoc ;
struct regmap * map = chip - > regmap ;
2012-03-13 22:03:52 +04:00
2013-10-25 08:55:02 +04:00
regmap_read ( map , MAX17042_VFSOC , & vfSoc ) ;
regmap_write ( map , MAX17042_VFSOC0Enable , VFSOC0_UNLOCK ) ;
max17042_write_verify_reg ( map , MAX17042_VFSOC0 , vfSoc ) ;
regmap_write ( map , MAX17042_VFSOC0Enable , VFSOC0_LOCK ) ;
2012-03-13 22:03:52 +04:00
}
static void max17042_load_new_capacity_params ( struct max17042_chip * chip )
{
2013-10-25 08:55:02 +04:00
u32 full_cap0 , rep_cap , dq_acc , vfSoc ;
2012-03-13 22:03:52 +04:00
u32 rem_cap ;
struct max17042_config_data * config = chip - > pdata - > config_data ;
2013-10-25 08:55:02 +04:00
struct regmap * map = chip - > regmap ;
2012-03-13 22:03:52 +04:00
2013-10-25 08:55:02 +04:00
regmap_read ( map , MAX17042_FullCAP0 , & full_cap0 ) ;
regmap_read ( map , MAX17042_VFSOC , & vfSoc ) ;
2012-03-13 22:03:52 +04:00
/* fg_vfSoc needs to shifted by 8 bits to get the
* perc in 1 % accuracy , to get the right rem_cap multiply
* full_cap0 , fg_vfSoc and devide by 100
*/
rem_cap = ( ( vfSoc > > 8 ) * full_cap0 ) / 100 ;
2013-10-25 08:55:02 +04:00
max17042_write_verify_reg ( map , MAX17042_RemCap , rem_cap ) ;
2012-03-13 22:03:52 +04:00
2013-10-25 08:55:02 +04:00
rep_cap = rem_cap ;
max17042_write_verify_reg ( map , MAX17042_RepCap , rep_cap ) ;
2012-03-13 22:03:52 +04:00
/* Write dQ_acc to 200% of Capacity and dP_acc to 200% */
dq_acc = config - > fullcap / dQ_ACC_DIV ;
2013-10-25 08:55:02 +04:00
max17042_write_verify_reg ( map , MAX17042_dQacc , dq_acc ) ;
max17042_write_verify_reg ( map , MAX17042_dPacc , dP_ACC_200 ) ;
2012-03-13 22:03:52 +04:00
2013-10-25 08:55:02 +04:00
max17042_write_verify_reg ( map , MAX17042_FullCAP ,
2012-03-13 22:03:52 +04:00
config - > fullcap ) ;
2013-10-25 08:55:02 +04:00
regmap_write ( map , MAX17042_DesignCap ,
2012-03-13 22:03:52 +04:00
config - > design_cap ) ;
2013-10-25 08:55:02 +04:00
max17042_write_verify_reg ( map , MAX17042_FullCAPNom ,
2012-03-13 22:03:52 +04:00
config - > fullcapnom ) ;
2012-05-05 13:04:26 +04:00
/* Update SOC register with new SOC */
2013-10-25 08:55:02 +04:00
regmap_write ( map , MAX17042_RepSOC , vfSoc ) ;
2012-03-13 22:03:52 +04:00
}
/*
* Block write all the override values coming from platform data .
* This function MUST be called before the POR initialization proceedure
* specified by maxim .
*/
static inline void max17042_override_por_values ( struct max17042_chip * chip )
{
2013-10-25 08:55:02 +04:00
struct regmap * map = chip - > regmap ;
2012-03-13 22:03:52 +04:00
struct max17042_config_data * config = chip - > pdata - > config_data ;
2013-10-25 08:55:02 +04:00
max17042_override_por ( map , MAX17042_TGAIN , config - > tgain ) ;
max17042_override_por ( map , MAx17042_TOFF , config - > toff ) ;
max17042_override_por ( map , MAX17042_CGAIN , config - > cgain ) ;
max17042_override_por ( map , MAX17042_COFF , config - > coff ) ;
max17042_override_por ( map , MAX17042_VALRT_Th , config - > valrt_thresh ) ;
max17042_override_por ( map , MAX17042_TALRT_Th , config - > talrt_thresh ) ;
max17042_override_por ( map , MAX17042_SALRT_Th ,
config - > soc_alrt_thresh ) ;
max17042_override_por ( map , MAX17042_CONFIG , config - > config ) ;
max17042_override_por ( map , MAX17042_SHDNTIMER , config - > shdntimer ) ;
max17042_override_por ( map , MAX17042_DesignCap , config - > design_cap ) ;
max17042_override_por ( map , MAX17042_ICHGTerm , config - > ichgt_term ) ;
max17042_override_por ( map , MAX17042_AtRate , config - > at_rate ) ;
max17042_override_por ( map , MAX17042_LearnCFG , config - > learn_cfg ) ;
max17042_override_por ( map , MAX17042_FilterCFG , config - > filter_cfg ) ;
max17042_override_por ( map , MAX17042_RelaxCFG , config - > relax_cfg ) ;
max17042_override_por ( map , MAX17042_MiscCFG , config - > misc_cfg ) ;
max17042_override_por ( map , MAX17042_MaskSOC , config - > masksoc ) ;
max17042_override_por ( map , MAX17042_FullCAP , config - > fullcap ) ;
max17042_override_por ( map , MAX17042_FullCAPNom , config - > fullcapnom ) ;
2012-05-05 13:04:26 +04:00
if ( chip - > chip_type = = MAX17042 )
2013-10-25 08:55:02 +04:00
max17042_override_por ( map , MAX17042_SOC_empty ,
2012-05-05 13:04:26 +04:00
config - > socempty ) ;
2013-10-25 08:55:02 +04:00
max17042_override_por ( map , MAX17042_LAvg_empty , config - > lavg_empty ) ;
max17042_override_por ( map , MAX17042_dQacc , config - > dqacc ) ;
max17042_override_por ( map , MAX17042_dPacc , config - > dpacc ) ;
2012-03-13 22:03:52 +04:00
2012-05-05 13:04:26 +04:00
if ( chip - > chip_type = = MAX17042 )
2013-10-25 08:55:02 +04:00
max17042_override_por ( map , MAX17042_V_empty , config - > vempty ) ;
2012-05-05 13:04:26 +04:00
else
2013-10-25 08:55:02 +04:00
max17042_override_por ( map , MAX17047_V_empty , config - > vempty ) ;
max17042_override_por ( map , MAX17042_TempNom , config - > temp_nom ) ;
max17042_override_por ( map , MAX17042_TempLim , config - > temp_lim ) ;
max17042_override_por ( map , MAX17042_FCTC , config - > fctc ) ;
max17042_override_por ( map , MAX17042_RCOMP0 , config - > rcomp0 ) ;
max17042_override_por ( map , MAX17042_TempCo , config - > tcompc0 ) ;
2012-05-05 13:04:26 +04:00
if ( chip - > chip_type ) {
2013-10-25 08:55:02 +04:00
max17042_override_por ( map , MAX17042_EmptyTempCo ,
config - > empty_tempco ) ;
max17042_override_por ( map , MAX17042_K_empty0 ,
config - > kempty0 ) ;
2012-05-05 13:04:26 +04:00
}
2012-03-13 22:03:52 +04:00
}
static int max17042_init_chip ( struct max17042_chip * chip )
{
2013-10-25 08:55:02 +04:00
struct regmap * map = chip - > regmap ;
2012-03-13 22:03:52 +04:00
int ret ;
max17042_override_por_values ( chip ) ;
/* After Power up, the MAX17042 requires 500mS in order
* to perform signal debouncing and initial SOC reporting
*/
msleep ( 500 ) ;
/* Initialize configaration */
max17042_write_config_regs ( chip ) ;
/* write cell characterization data */
ret = max17042_init_model ( chip ) ;
if ( ret ) {
dev_err ( & chip - > client - > dev , " %s init failed \n " ,
__func__ ) ;
return - EIO ;
}
2012-11-19 02:59:47 +04:00
ret = max17042_verify_model_lock ( chip ) ;
2012-03-13 22:03:52 +04:00
if ( ret ) {
dev_err ( & chip - > client - > dev , " %s lock verify failed \n " ,
__func__ ) ;
return - EIO ;
}
/* write custom parameters */
max17042_write_custom_regs ( chip ) ;
/* update capacity params */
max17042_update_capacity_regs ( chip ) ;
/* delay must be atleast 350mS to allow VFSOC
* to be calculated from the new configuration
*/
msleep ( 350 ) ;
/* reset vfsoc0 reg */
max17042_reset_vfsoc0_reg ( chip ) ;
/* load new capacity params */
max17042_load_new_capacity_params ( chip ) ;
/* Init complete, Clear the POR bit */
2015-02-24 12:54:47 +03:00
regmap_update_bits ( map , MAX17042_STATUS , STATUS_POR_BIT , 0x0 ) ;
2012-03-13 22:03:52 +04:00
return 0 ;
}
2012-01-24 21:26:06 +04:00
static void max17042_set_soc_threshold ( struct max17042_chip * chip , u16 off )
{
2013-10-25 08:55:02 +04:00
struct regmap * map = chip - > regmap ;
u32 soc , soc_tr ;
2012-01-24 21:26:06 +04:00
/* program interrupt thesholds such that we should
* get interrupt for every ' off ' perc change in the soc
*/
2013-10-25 08:55:02 +04:00
regmap_read ( map , MAX17042_RepSOC , & soc ) ;
soc > > = 8 ;
2012-01-24 21:26:06 +04:00
soc_tr = ( soc + off ) < < 8 ;
soc_tr | = ( soc - off ) ;
2013-10-25 08:55:02 +04:00
regmap_write ( map , MAX17042_SALRT_Th , soc_tr ) ;
2012-01-24 21:26:06 +04:00
}
static irqreturn_t max17042_thread_handler ( int id , void * dev )
{
struct max17042_chip * chip = dev ;
2013-10-25 08:55:02 +04:00
u32 val ;
2012-01-24 21:26:06 +04:00
2013-10-25 08:55:02 +04:00
regmap_read ( chip - > regmap , MAX17042_STATUS , & val ) ;
2012-03-21 01:33:16 +04:00
if ( ( val & STATUS_INTR_SOCMIN_BIT ) | |
( val & STATUS_INTR_SOCMAX_BIT ) ) {
2012-01-24 21:26:06 +04:00
dev_info ( & chip - > client - > dev , " SOC threshold INTR \n " ) ;
max17042_set_soc_threshold ( chip , 1 ) ;
}
power_supply_changed ( & chip - > battery ) ;
return IRQ_HANDLED ;
}
2012-03-13 22:03:52 +04:00
static void max17042_init_worker ( struct work_struct * work )
{
struct max17042_chip * chip = container_of ( work ,
struct max17042_chip , work ) ;
int ret ;
/* Initialize registers according to values from the platform data */
if ( chip - > pdata - > enable_por_init & & chip - > pdata - > config_data ) {
ret = max17042_init_chip ( chip ) ;
if ( ret )
return ;
}
chip - > init_complete = 1 ;
}
2012-02-22 22:06:22 +04:00
# ifdef CONFIG_OF
static struct max17042_platform_data *
max17042_get_pdata ( struct device * dev )
{
struct device_node * np = dev - > of_node ;
u32 prop ;
struct max17042_platform_data * pdata ;
if ( ! np )
return dev - > platform_data ;
pdata = devm_kzalloc ( dev , sizeof ( * pdata ) , GFP_KERNEL ) ;
if ( ! pdata )
return NULL ;
/*
* Require current sense resistor value to be specified for
* current - sense functionality to be enabled at all .
*/
if ( of_property_read_u32 ( np , " maxim,rsns-microohm " , & prop ) = = 0 ) {
pdata - > r_sns = prop ;
pdata - > enable_current_sense = true ;
}
return pdata ;
}
# else
static struct max17042_platform_data *
max17042_get_pdata ( struct device * dev )
{
return dev - > platform_data ;
}
# endif
2015-01-05 11:50:17 +03:00
static const struct regmap_config max17042_regmap_config = {
2013-10-25 08:55:02 +04:00
. reg_bits = 8 ,
. val_bits = 16 ,
. val_format_endian = REGMAP_ENDIAN_NATIVE ,
} ;
2012-11-19 22:22:23 +04:00
static int max17042_probe ( struct i2c_client * client ,
2011-01-14 08:46:11 +03:00
const struct i2c_device_id * id )
{
struct i2c_adapter * adapter = to_i2c_adapter ( client - > dev . parent ) ;
struct max17042_chip * chip ;
int ret ;
2013-10-25 08:55:02 +04:00
int i ;
u32 val ;
2011-01-14 08:46:11 +03:00
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_WORD_DATA ) )
return - EIO ;
2012-02-22 22:06:20 +04:00
chip = devm_kzalloc ( & client - > dev , sizeof ( * chip ) , GFP_KERNEL ) ;
2011-01-14 08:46:11 +03:00
if ( ! chip )
return - ENOMEM ;
chip - > client = client ;
2013-10-25 08:55:02 +04:00
chip - > regmap = devm_regmap_init_i2c ( client , & max17042_regmap_config ) ;
if ( IS_ERR ( chip - > regmap ) ) {
dev_err ( & client - > dev , " Failed to initialize regmap \n " ) ;
return - EINVAL ;
}
2012-02-22 22:06:22 +04:00
chip - > pdata = max17042_get_pdata ( & client - > dev ) ;
if ( ! chip - > pdata ) {
dev_err ( & client - > dev , " no platform data provided \n " ) ;
return - EINVAL ;
}
2011-01-14 08:46:11 +03:00
i2c_set_clientdata ( client , chip ) ;
2013-10-25 08:55:02 +04:00
regmap_read ( chip - > regmap , MAX17042_DevName , & val ) ;
if ( val = = MAX17042_IC_VERSION ) {
2012-05-05 13:04:26 +04:00
dev_dbg ( & client - > dev , " chip type max17042 detected \n " ) ;
chip - > chip_type = MAX17042 ;
2013-10-25 08:55:02 +04:00
} else if ( val = = MAX17047_IC_VERSION ) {
2012-05-05 13:04:26 +04:00
dev_dbg ( & client - > dev , " chip type max17047/50 detected \n " ) ;
chip - > chip_type = MAX17047 ;
} else {
2013-10-25 08:55:02 +04:00
dev_err ( & client - > dev , " device version mismatch: %x \n " , val ) ;
2012-05-05 13:04:26 +04:00
return - EIO ;
}
chip - > battery . name = " max170xx_battery " ;
2011-01-14 08:46:11 +03:00
chip - > battery . type = POWER_SUPPLY_TYPE_BATTERY ;
chip - > battery . get_property = max17042_get_property ;
chip - > battery . properties = max17042_battery_props ;
chip - > battery . num_properties = ARRAY_SIZE ( max17042_battery_props ) ;
2011-06-30 13:07:41 +04:00
/* When current is not measured,
* CURRENT_NOW and CURRENT_AVG properties should be invisible . */
if ( ! chip - > pdata - > enable_current_sense )
chip - > battery . num_properties - = 2 ;
2011-08-13 08:18:18 +04:00
if ( chip - > pdata - > r_sns = = 0 )
chip - > pdata - > r_sns = MAX17042_DEFAULT_SNS_RESISTOR ;
2011-06-30 13:07:41 +04:00
if ( chip - > pdata - > init_data )
2013-10-25 08:55:02 +04:00
for ( i = 0 ; i < chip - > pdata - > num_init_data ; i + + )
regmap_write ( chip - > regmap ,
chip - > pdata - > init_data [ i ] . addr ,
chip - > pdata - > init_data [ i ] . data ) ;
2011-06-30 13:07:41 +04:00
2011-01-14 08:46:11 +03:00
if ( ! chip - > pdata - > enable_current_sense ) {
2013-10-25 08:55:02 +04:00
regmap_write ( chip - > regmap , MAX17042_CGAIN , 0x0000 ) ;
regmap_write ( chip - > regmap , MAX17042_MiscCFG , 0x0003 ) ;
regmap_write ( chip - > regmap , MAX17042_LearnCFG , 0x0007 ) ;
2011-01-14 08:46:11 +03:00
}
2015-03-12 10:44:02 +03:00
ret = power_supply_register ( & client - > dev , & chip - > battery , NULL ) ;
2012-05-05 01:38:37 +04:00
if ( ret ) {
dev_err ( & client - > dev , " failed: power supply register \n " ) ;
return ret ;
}
2012-01-24 21:26:06 +04:00
if ( client - > irq ) {
2012-03-21 01:33:16 +04:00
ret = request_threaded_irq ( client - > irq , NULL ,
2013-12-18 07:53:53 +04:00
max17042_thread_handler ,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT ,
chip - > battery . name , chip ) ;
2012-01-24 21:26:06 +04:00
if ( ! ret ) {
2015-02-24 12:54:47 +03:00
regmap_update_bits ( chip - > regmap , MAX17042_CONFIG ,
CONFIG_ALRT_BIT_ENBL ,
CONFIG_ALRT_BIT_ENBL ) ;
2012-01-24 21:26:06 +04:00
max17042_set_soc_threshold ( chip , 1 ) ;
2012-05-05 03:13:10 +04:00
} else {
client - > irq = 0 ;
2012-01-24 21:26:06 +04:00
dev_err ( & client - > dev , " %s(): cannot get IRQ \n " ,
__func__ ) ;
2012-05-05 03:13:10 +04:00
}
2012-01-24 21:26:06 +04:00
}
2013-10-25 08:55:02 +04:00
regmap_read ( chip - > regmap , MAX17042_STATUS , & val ) ;
if ( val & STATUS_POR_BIT ) {
2012-03-13 22:03:52 +04:00
INIT_WORK ( & chip - > work , max17042_init_worker ) ;
schedule_work ( & chip - > work ) ;
} else {
chip - > init_complete = 1 ;
}
2012-05-05 01:38:37 +04:00
return 0 ;
2011-01-14 08:46:11 +03:00
}
2012-11-19 22:26:07 +04:00
static int max17042_remove ( struct i2c_client * client )
2011-01-14 08:46:11 +03:00
{
struct max17042_chip * chip = i2c_get_clientdata ( client ) ;
2012-03-26 14:08:26 +04:00
if ( client - > irq )
free_irq ( client - > irq , chip ) ;
2011-01-14 08:46:11 +03:00
power_supply_unregister ( & chip - > battery ) ;
return 0 ;
}
2013-10-14 09:26:51 +04:00
# ifdef CONFIG_PM_SLEEP
2012-03-27 00:53:40 +04:00
static int max17042_suspend ( struct device * dev )
{
struct max17042_chip * chip = dev_get_drvdata ( dev ) ;
2012-05-05 07:38:13 +04:00
/*
* disable the irq and enable irq_wake
2012-03-27 00:53:40 +04:00
* capability to the interrupt line .
*/
if ( chip - > client - > irq ) {
disable_irq ( chip - > client - > irq ) ;
enable_irq_wake ( chip - > client - > irq ) ;
}
return 0 ;
}
static int max17042_resume ( struct device * dev )
{
struct max17042_chip * chip = dev_get_drvdata ( dev ) ;
if ( chip - > client - > irq ) {
disable_irq_wake ( chip - > client - > irq ) ;
enable_irq ( chip - > client - > irq ) ;
/* re-program the SOC thresholds to 1% change */
max17042_set_soc_threshold ( chip , 1 ) ;
}
return 0 ;
}
# endif
2013-10-14 09:26:51 +04:00
static SIMPLE_DEV_PM_OPS ( max17042_pm_ops , max17042_suspend ,
max17042_resume ) ;
2012-02-22 22:06:22 +04:00
# ifdef CONFIG_OF
static const struct of_device_id max17042_dt_match [ ] = {
{ . compatible = " maxim,max17042 " } ,
2012-05-05 13:04:26 +04:00
{ . compatible = " maxim,max17047 " } ,
{ . compatible = " maxim,max17050 " } ,
2012-02-22 22:06:22 +04:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , max17042_dt_match ) ;
# endif
2011-01-14 08:46:11 +03:00
static const struct i2c_device_id max17042_id [ ] = {
{ " max17042 " , 0 } ,
2012-05-05 13:04:26 +04:00
{ " max17047 " , 1 } ,
{ " max17050 " , 2 } ,
2011-01-14 08:46:11 +03:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , max17042_id ) ;
static struct i2c_driver max17042_i2c_driver = {
. driver = {
. name = " max17042 " ,
2012-02-22 22:06:22 +04:00
. of_match_table = of_match_ptr ( max17042_dt_match ) ,
2013-10-14 09:26:51 +04:00
. pm = & max17042_pm_ops ,
2011-01-14 08:46:11 +03:00
} ,
. probe = max17042_probe ,
2012-11-19 22:20:40 +04:00
. remove = max17042_remove ,
2011-01-14 08:46:11 +03:00
. id_table = max17042_id ,
} ;
2012-01-21 10:42:54 +04:00
module_i2c_driver ( max17042_i2c_driver ) ;
2011-01-14 08:46:11 +03:00
MODULE_AUTHOR ( " MyungJoo Ham <myungjoo.ham@samsung.com> " ) ;
MODULE_DESCRIPTION ( " MAX17042 Fuel Gauge " ) ;
MODULE_LICENSE ( " GPL " ) ;