2018-08-07 18:21:06 +02:00
// SPDX-License-Identifier: GPL-2.0+
//
// 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 driver is based on max17040_battery.c
2011-01-14 14:46:11 +09:00
2017-08-14 22:18:10 +02:00
# include <linux/acpi.h>
2022-02-18 18:37:37 +01:00
# include <linux/devm-helpers.h>
2011-01-14 14:46:11 +09:00
# include <linux/init.h>
2011-07-03 15:28:29 -04:00
# include <linux/module.h>
2011-01-14 14:46:11 +09:00
# include <linux/slab.h>
# include <linux/i2c.h>
2012-03-13 22:03:52 +04:00
# include <linux/delay.h>
2012-01-24 09:26:06 -08:00
# include <linux/interrupt.h>
2012-03-27 02:23:40 +05:30
# include <linux/pm.h>
2011-01-14 14:46:11 +09:00
# include <linux/mod_devicetable.h>
# include <linux/power_supply.h>
# include <linux/power/max17042_battery.h>
2012-02-22 19:06:22 +01:00
# include <linux/of.h>
2013-10-25 13:55:02 +09:00
# include <linux/regmap.h>
2011-01-14 14:46:11 +09: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 09:26:06 -08:00
/* Interrupt mask bits */
# define CONFIG_ALRT_BIT_ENBL (1 << 2)
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
2015-05-24 09:11:58 +05:30
# define MAX17042_VMAX_TOLERANCE 50 /* 50 mV */
2011-01-14 14:46:11 +09:00
struct max17042_chip {
struct i2c_client * client ;
2013-10-25 13:55:02 +09:00
struct regmap * regmap ;
2015-03-12 08:44:11 +01:00
struct power_supply * battery ;
2012-05-05 14:34:26 +05:30
enum max170xx_chip_type chip_type ;
2011-01-14 14:46:11 +09:00
struct max17042_platform_data * pdata ;
2012-03-13 22:03:52 +04:00
struct work_struct work ;
int init_complete ;
2011-01-14 14:46:11 +09:00
} ;
static enum power_supply_property max17042_battery_props [ ] = {
2017-04-14 20:32:51 +02:00
POWER_SUPPLY_PROP_STATUS ,
2011-06-30 18:07:41 +09:00
POWER_SUPPLY_PROP_PRESENT ,
2017-04-14 20:32:53 +02:00
POWER_SUPPLY_PROP_TECHNOLOGY ,
2011-06-30 18:07:41 +09:00
POWER_SUPPLY_PROP_CYCLE_COUNT ,
POWER_SUPPLY_PROP_VOLTAGE_MAX ,
2017-04-14 20:32:54 +02:00
POWER_SUPPLY_PROP_VOLTAGE_MIN ,
2011-06-30 18:07:41 +09:00
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN ,
2011-01-14 14:46:11 +09:00
POWER_SUPPLY_PROP_VOLTAGE_NOW ,
POWER_SUPPLY_PROP_VOLTAGE_AVG ,
2012-04-10 16:21:20 +05:30
POWER_SUPPLY_PROP_VOLTAGE_OCV ,
2011-01-14 14:46:11 +09:00
POWER_SUPPLY_PROP_CAPACITY ,
2017-04-14 20:32:56 +02:00
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN ,
2011-06-30 18:07:41 +09:00
POWER_SUPPLY_PROP_CHARGE_FULL ,
2017-04-14 20:32:57 +02:00
POWER_SUPPLY_PROP_CHARGE_NOW ,
2012-05-07 10:25:58 +05:30
POWER_SUPPLY_PROP_CHARGE_COUNTER ,
2020-11-25 05:48:30 +01:00
POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT ,
2011-06-30 18:07:41 +09:00
POWER_SUPPLY_PROP_TEMP ,
2015-05-24 09:11:58 +05:30
POWER_SUPPLY_PROP_TEMP_ALERT_MIN ,
POWER_SUPPLY_PROP_TEMP_ALERT_MAX ,
POWER_SUPPLY_PROP_TEMP_MIN ,
POWER_SUPPLY_PROP_TEMP_MAX ,
POWER_SUPPLY_PROP_HEALTH ,
2017-04-14 20:32:58 +02:00
POWER_SUPPLY_PROP_SCOPE ,
2020-11-25 05:44:44 +01:00
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW ,
// these two have to be at the end on the list
2011-06-30 18:07:41 +09:00
POWER_SUPPLY_PROP_CURRENT_NOW ,
POWER_SUPPLY_PROP_CURRENT_AVG ,
2011-01-14 14:46:11 +09:00
} ;
2015-05-24 09:11:58 +05:30
static int max17042_get_temperature ( struct max17042_chip * chip , int * temp )
{
int ret ;
u32 data ;
struct regmap * map = chip - > regmap ;
ret = regmap_read ( map , MAX17042_TEMP , & data ) ;
if ( ret < 0 )
return ret ;
2017-04-14 20:32:47 +02:00
* temp = sign_extend32 ( data , 15 ) ;
2015-05-24 09:11:58 +05:30
/* The value is converted into deci-centigrade scale */
/* Units of LSB = 1 / 256 degree Celsius */
* temp = * temp * 10 / 256 ;
return 0 ;
}
2017-04-14 20:32:51 +02:00
static int max17042_get_status ( struct max17042_chip * chip , int * status )
{
int ret , charge_full , charge_now ;
2018-01-20 14:50:24 +01:00
int avg_current ;
u32 data ;
2017-04-14 20:32:51 +02:00
ret = power_supply_am_i_supplied ( chip - > battery ) ;
if ( ret < 0 ) {
* status = POWER_SUPPLY_STATUS_UNKNOWN ;
return 0 ;
}
if ( ret = = 0 ) {
* status = POWER_SUPPLY_STATUS_DISCHARGING ;
return 0 ;
}
/*
* The MAX170xx has builtin end - of - charge detection and will update
* FullCAP to match RepCap when it detects end of charging .
*
* When this cycle the battery gets charged to a higher ( calculated )
* capacity then the previous cycle then FullCAP will get updated
2021-03-23 18:12:06 +05:30
* continuously once end - of - charge detection kicks in , so allow the
2017-04-14 20:32:51 +02:00
* 2 to differ a bit .
*/
ret = regmap_read ( chip - > regmap , MAX17042_FullCAP , & charge_full ) ;
if ( ret < 0 )
return ret ;
ret = regmap_read ( chip - > regmap , MAX17042_RepCap , & charge_now ) ;
if ( ret < 0 )
return ret ;
2018-01-20 14:50:24 +01:00
if ( ( charge_full - charge_now ) < = MAX17042_FULL_THRESHOLD ) {
2017-04-14 20:32:51 +02:00
* status = POWER_SUPPLY_STATUS_FULL ;
2018-01-20 14:50:24 +01:00
return 0 ;
}
/*
* Even though we are supplied , we may still be discharging if the
* supply is e . g . only delivering 5 V 0.5 A . Check current if available .
*/
if ( ! chip - > pdata - > enable_current_sense ) {
2017-04-14 20:32:51 +02:00
* status = POWER_SUPPLY_STATUS_CHARGING ;
2018-01-20 14:50:24 +01:00
return 0 ;
}
ret = regmap_read ( chip - > regmap , MAX17042_AvgCurrent , & data ) ;
if ( ret < 0 )
return ret ;
avg_current = sign_extend32 ( data , 15 ) ;
avg_current * = 1562500 / chip - > pdata - > r_sns ;
if ( avg_current > 0 )
* status = POWER_SUPPLY_STATUS_CHARGING ;
else
* status = POWER_SUPPLY_STATUS_DISCHARGING ;
2017-04-14 20:32:51 +02:00
return 0 ;
}
2015-05-24 09:11:58 +05:30
static int max17042_get_battery_health ( struct max17042_chip * chip , int * health )
{
int temp , vavg , vbatt , ret ;
u32 val ;
ret = regmap_read ( chip - > regmap , MAX17042_AvgVCELL , & val ) ;
if ( ret < 0 )
goto health_error ;
/* bits [0-3] unused */
vavg = val * 625 / 8 ;
/* Convert to millivolts */
vavg / = 1000 ;
ret = regmap_read ( chip - > regmap , MAX17042_VCELL , & val ) ;
if ( ret < 0 )
goto health_error ;
/* bits [0-3] unused */
vbatt = val * 625 / 8 ;
/* Convert to millivolts */
vbatt / = 1000 ;
if ( vavg < chip - > pdata - > vmin ) {
* health = POWER_SUPPLY_HEALTH_DEAD ;
goto out ;
}
if ( vbatt > chip - > pdata - > vmax + MAX17042_VMAX_TOLERANCE ) {
* health = POWER_SUPPLY_HEALTH_OVERVOLTAGE ;
goto out ;
}
ret = max17042_get_temperature ( chip , & temp ) ;
if ( ret < 0 )
goto health_error ;
2017-04-14 20:32:49 +02:00
if ( temp < chip - > pdata - > temp_min ) {
2015-05-24 09:11:58 +05:30
* health = POWER_SUPPLY_HEALTH_COLD ;
goto out ;
}
2017-04-14 20:32:49 +02:00
if ( temp > chip - > pdata - > temp_max ) {
2015-05-24 09:11:58 +05:30
* health = POWER_SUPPLY_HEALTH_OVERHEAT ;
goto out ;
}
* health = POWER_SUPPLY_HEALTH_GOOD ;
out :
return 0 ;
health_error :
return ret ;
}
2011-01-14 14:46:11 +09:00
static int max17042_get_property ( struct power_supply * psy ,
enum power_supply_property psp ,
union power_supply_propval * val )
{
2015-03-12 08:44:11 +01:00
struct max17042_chip * chip = power_supply_get_drvdata ( psy ) ;
2013-10-25 13:55:02 +09:00
struct regmap * map = chip - > regmap ;
2011-11-26 04:11:15 +04:00
int ret ;
2013-10-25 13:55:02 +09:00
u32 data ;
2017-04-14 20:32:55 +02:00
u64 data64 ;
2011-01-14 14:46:11 +09:00
2012-03-13 22:03:52 +04:00
if ( ! chip - > init_complete )
return - EAGAIN ;
2011-01-14 14:46:11 +09:00
switch ( psp ) {
2017-04-14 20:32:51 +02:00
case POWER_SUPPLY_PROP_STATUS :
ret = max17042_get_status ( chip , & val - > intval ) ;
if ( ret < 0 )
return ret ;
break ;
2011-06-30 18:07:41 +09:00
case POWER_SUPPLY_PROP_PRESENT :
2013-10-25 13:55:02 +09:00
ret = regmap_read ( map , MAX17042_STATUS , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 13:55:02 +09:00
if ( data & MAX17042_STATUS_BattAbsent )
2011-06-30 18:07:41 +09:00
val - > intval = 0 ;
else
val - > intval = 1 ;
break ;
2017-04-14 20:32:53 +02:00
case POWER_SUPPLY_PROP_TECHNOLOGY :
val - > intval = POWER_SUPPLY_TECHNOLOGY_LION ;
break ;
2011-06-30 18:07:41 +09:00
case POWER_SUPPLY_PROP_CYCLE_COUNT :
2013-10-25 13:55:02 +09:00
ret = regmap_read ( map , MAX17042_Cycles , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 13:55:02 +09:00
val - > intval = data ;
2011-06-30 18:07:41 +09:00
break ;
case POWER_SUPPLY_PROP_VOLTAGE_MAX :
2013-10-25 13:55:02 +09:00
ret = regmap_read ( map , MAX17042_MinMaxVolt , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 13:55:02 +09:00
val - > intval = data > > 8 ;
2011-06-30 18:07:41 +09:00
val - > intval * = 20000 ; /* Units of LSB = 20mV */
break ;
2017-04-14 20:32:54 +02:00
case POWER_SUPPLY_PROP_VOLTAGE_MIN :
ret = regmap_read ( map , MAX17042_MinMaxVolt , & data ) ;
if ( ret < 0 )
return ret ;
val - > intval = ( data & 0xff ) * 20000 ; /* Units of 20mV */
break ;
2011-06-30 18:07:41 +09:00
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN :
2015-04-03 17:26:08 +09:00
if ( chip - > chip_type = = MAXIM_DEVICE_TYPE_MAX17042 )
2013-10-25 13:55:02 +09:00
ret = regmap_read ( map , MAX17042_V_empty , & data ) ;
2012-05-05 14:34:26 +05:30
else
2013-10-25 13:55:02 +09: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 13:55:02 +09:00
val - > intval = data > > 7 ;
2011-06-30 18:07:41 +09:00
val - > intval * = 10000 ; /* Units of LSB = 10mV */
break ;
2011-01-14 14:46:11 +09:00
case POWER_SUPPLY_PROP_VOLTAGE_NOW :
2013-10-25 13:55:02 +09:00
ret = regmap_read ( map , MAX17042_VCELL , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 13:55:02 +09:00
val - > intval = data * 625 / 8 ;
2011-01-14 14:46:11 +09:00
break ;
case POWER_SUPPLY_PROP_VOLTAGE_AVG :
2013-10-25 13:55:02 +09:00
ret = regmap_read ( map , MAX17042_AvgVCELL , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 13:55:02 +09:00
val - > intval = data * 625 / 8 ;
2012-04-10 16:21:20 +05:30
break ;
case POWER_SUPPLY_PROP_VOLTAGE_OCV :
2013-10-25 13:55:02 +09:00
ret = regmap_read ( map , MAX17042_OCVInternal , & data ) ;
2012-04-10 16:21:20 +05:30
if ( ret < 0 )
return ret ;
2013-10-25 13:55:02 +09:00
val - > intval = data * 625 / 8 ;
2011-01-14 14:46:11 +09:00
break ;
case POWER_SUPPLY_PROP_CAPACITY :
2021-09-29 20:14:17 +02:00
if ( chip - > pdata - > enable_current_sense )
ret = regmap_read ( map , MAX17042_RepSOC , & data ) ;
else
ret = regmap_read ( map , MAX17042_VFSOC , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2013-10-25 13:55:02 +09:00
val - > intval = data > > 8 ;
2011-01-14 14:46:11 +09:00
break ;
2017-04-14 20:32:56 +02:00
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN :
ret = regmap_read ( map , MAX17042_DesignCap , & data ) ;
if ( ret < 0 )
return ret ;
data64 = data * 5000000ll ;
do_div ( data64 , chip - > pdata - > r_sns ) ;
val - > intval = data64 ;
break ;
2011-06-30 18:07:41 +09:00
case POWER_SUPPLY_PROP_CHARGE_FULL :
2013-10-25 13:55:02 +09:00
ret = regmap_read ( map , MAX17042_FullCAP , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2017-04-14 20:32:57 +02:00
data64 = data * 5000000ll ;
do_div ( data64 , chip - > pdata - > r_sns ) ;
val - > intval = data64 ;
break ;
case POWER_SUPPLY_PROP_CHARGE_NOW :
ret = regmap_read ( map , MAX17042_RepCap , & data ) ;
if ( ret < 0 )
return ret ;
2017-04-14 20:32:55 +02:00
data64 = data * 5000000ll ;
do_div ( data64 , chip - > pdata - > r_sns ) ;
val - > intval = data64 ;
2012-05-07 10:25:58 +05:30
break ;
case POWER_SUPPLY_PROP_CHARGE_COUNTER :
2013-10-25 13:55:02 +09:00
ret = regmap_read ( map , MAX17042_QH , & data ) ;
2012-05-07 10:25:58 +05:30
if ( ret < 0 )
return ret ;
2020-11-25 05:47:04 +01:00
data64 = sign_extend64 ( data , 15 ) * 5000000ll ;
val - > intval = div_s64 ( data64 , chip - > pdata - > r_sns ) ;
2011-06-30 18:07:41 +09:00
break ;
case POWER_SUPPLY_PROP_TEMP :
2015-05-24 09:11:58 +05:30
ret = max17042_get_temperature ( chip , & val - > intval ) ;
if ( ret < 0 )
return ret ;
break ;
case POWER_SUPPLY_PROP_TEMP_ALERT_MIN :
ret = regmap_read ( map , MAX17042_TALRT_Th , & data ) ;
if ( ret < 0 )
return ret ;
/* LSB is Alert Minimum. In deci-centigrade */
2017-04-14 20:32:48 +02:00
val - > intval = sign_extend32 ( data & 0xff , 7 ) * 10 ;
2015-05-24 09:11:58 +05:30
break ;
case POWER_SUPPLY_PROP_TEMP_ALERT_MAX :
ret = regmap_read ( map , MAX17042_TALRT_Th , & data ) ;
if ( ret < 0 )
return ret ;
/* MSB is Alert Maximum. In deci-centigrade */
2017-04-14 20:32:48 +02:00
val - > intval = sign_extend32 ( data > > 8 , 7 ) * 10 ;
2015-05-24 09:11:58 +05:30
break ;
case POWER_SUPPLY_PROP_TEMP_MIN :
val - > intval = chip - > pdata - > temp_min ;
break ;
case POWER_SUPPLY_PROP_TEMP_MAX :
val - > intval = chip - > pdata - > temp_max ;
break ;
case POWER_SUPPLY_PROP_HEALTH :
ret = max17042_get_battery_health ( chip , & val - > intval ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2011-06-30 18:07:41 +09:00
break ;
2017-04-14 20:32:58 +02:00
case POWER_SUPPLY_PROP_SCOPE :
val - > intval = POWER_SUPPLY_SCOPE_SYSTEM ;
break ;
2011-06-30 18:07:41 +09:00
case POWER_SUPPLY_PROP_CURRENT_NOW :
if ( chip - > pdata - > enable_current_sense ) {
2013-10-25 13:55:02 +09:00
ret = regmap_read ( map , MAX17042_Current , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2020-11-25 05:46:17 +01:00
data64 = sign_extend64 ( data , 15 ) * 1562500ll ;
val - > intval = div_s64 ( data64 , chip - > pdata - > r_sns ) ;
2011-06-30 18:07:41 +09:00
} else {
return - EINVAL ;
}
break ;
case POWER_SUPPLY_PROP_CURRENT_AVG :
if ( chip - > pdata - > enable_current_sense ) {
2013-10-25 13:55:02 +09:00
ret = regmap_read ( map , MAX17042_AvgCurrent , & data ) ;
2011-11-26 04:11:15 +04:00
if ( ret < 0 )
return ret ;
2020-11-25 05:46:17 +01:00
data64 = sign_extend64 ( data , 15 ) * 1562500ll ;
val - > intval = div_s64 ( data64 , chip - > pdata - > r_sns ) ;
2011-06-30 18:07:41 +09:00
} else {
return - EINVAL ;
}
break ;
2020-11-25 05:48:30 +01:00
case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT :
ret = regmap_read ( map , MAX17042_ICHGTerm , & data ) ;
if ( ret < 0 )
return ret ;
data64 = data * 1562500ll ;
val - > intval = div_s64 ( data64 , chip - > pdata - > r_sns ) ;
break ;
2020-03-30 01:33:55 -04:00
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW :
ret = regmap_read ( map , MAX17042_TTE , & data ) ;
if ( ret < 0 )
return ret ;
val - > intval = data * 5625 / 1000 ;
break ;
2011-01-14 14:46:11 +09:00
default :
return - EINVAL ;
}
return 0 ;
}
2015-05-24 09:11:58 +05:30
static int max17042_set_property ( struct power_supply * psy ,
enum power_supply_property psp ,
const union power_supply_propval * val )
{
struct max17042_chip * chip = power_supply_get_drvdata ( psy ) ;
struct regmap * map = chip - > regmap ;
int ret = 0 ;
u32 data ;
int8_t temp ;
switch ( psp ) {
case POWER_SUPPLY_PROP_TEMP_ALERT_MIN :
ret = regmap_read ( map , MAX17042_TALRT_Th , & data ) ;
if ( ret < 0 )
return ret ;
/* Input in deci-centigrade, convert to centigrade */
temp = val - > intval / 10 ;
/* force min < max */
if ( temp > = ( int8_t ) ( data > > 8 ) )
temp = ( int8_t ) ( data > > 8 ) - 1 ;
/* Write both MAX and MIN ALERT */
data = ( data & 0xff00 ) + temp ;
ret = regmap_write ( map , MAX17042_TALRT_Th , data ) ;
break ;
case POWER_SUPPLY_PROP_TEMP_ALERT_MAX :
ret = regmap_read ( map , MAX17042_TALRT_Th , & data ) ;
if ( ret < 0 )
return ret ;
/* Input in Deci-Centigrade, convert to centigrade */
temp = val - > intval / 10 ;
/* force max > min */
if ( temp < = ( int8_t ) ( data & 0xff ) )
temp = ( int8_t ) ( data & 0xff ) + 1 ;
/* Write both MAX and MIN ALERT */
data = ( data & 0xff ) + ( temp < < 8 ) ;
ret = regmap_write ( map , MAX17042_TALRT_Th , data ) ;
break ;
default :
ret = - EINVAL ;
}
return ret ;
}
static int max17042_property_is_writeable ( struct power_supply * psy ,
enum power_supply_property psp )
{
int ret ;
switch ( psp ) {
case POWER_SUPPLY_PROP_TEMP_ALERT_MIN :
case POWER_SUPPLY_PROP_TEMP_ALERT_MAX :
ret = 1 ;
break ;
default :
ret = 0 ;
}
return ret ;
}
2013-10-25 13:55:02 +09: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 13:55:02 +09:00
u32 read_value ;
2012-03-13 22:03:52 +04:00
do {
2013-10-25 13:55:02 +09: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 13:55:02 +09:00
pr_err ( " %s: err %d \n " , __func__ , ret ) ;
2012-03-13 22:03:52 +04:00
return ret ;
}
2013-10-25 13:55:02 +09: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 13:55:02 +09:00
regmap_write ( map , reg , value ) ;
2012-03-13 22:03:52 +04:00
}
2019-07-21 18:03:28 +02:00
static inline void max17042_unlock_model ( struct max17042_chip * chip )
2012-03-13 22:03:52 +04:00
{
2013-10-25 13:55:02 +09:00
struct regmap * map = chip - > regmap ;
2015-04-03 17:26:09 +09:00
2013-10-25 13:55:02 +09:00
regmap_write ( map , MAX17042_MLOCKReg1 , MODEL_UNLOCK1 ) ;
regmap_write ( map , MAX17042_MLOCKReg2 , MODEL_UNLOCK2 ) ;
2012-03-13 22:03:52 +04:00
}
2019-07-21 18:03:28 +02:00
static inline void max17042_lock_model ( struct max17042_chip * chip )
2012-03-13 22:03:52 +04:00
{
2013-10-25 13:55:02 +09: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 13:55:02 +09:00
struct regmap * map = chip - > regmap ;
2012-03-13 22:03:52 +04:00
int i ;
2015-04-03 17:26:09 +09:00
2012-03-13 22:03:52 +04:00
for ( i = 0 ; i < size ; i + + )
2013-10-25 13:55:02 +09: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 ,
2016-08-12 09:10:27 -04:00
u8 addr , u16 * data , int size )
2012-03-13 22:03:52 +04:00
{
2013-10-25 13:55:02 +09:00
struct regmap * map = chip - > regmap ;
2012-03-13 22:03:52 +04:00
int i ;
2016-08-12 09:10:27 -04:00
u32 tmp ;
2012-03-13 22:03:52 +04:00
2016-08-12 09:10:27 -04:00
for ( i = 0 ; i < size ; i + + ) {
regmap_read ( map , addr + i , & tmp ) ;
data [ i ] = ( u16 ) tmp ;
}
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 14:37:32 +03:00
int table_size = ARRAY_SIZE ( chip - > pdata - > config_data - > cell_char_tbl ) ;
2016-08-12 09:10:27 -04:00
u16 * temp_data ;
2012-03-13 22:03:52 +04:00
2012-03-15 14:37:32 +03:00
temp_data = kcalloc ( table_size , sizeof ( * temp_data ) , GFP_KERNEL ) ;
2012-03-13 22:03:52 +04:00
if ( ! temp_data )
return - ENOMEM ;
2019-07-21 18:03:28 +02:00
max17042_unlock_model ( chip ) ;
2012-03-13 22:03:52 +04:00
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 ,
2016-08-12 09:10:27 -04:00
temp_data ,
2012-03-13 22:03:52 +04:00
table_size ) ;
2019-07-21 18:03:28 +02:00
max17042_lock_model ( chip ) ;
2012-03-13 22:03:52 +04:00
kfree ( temp_data ) ;
return ret ;
}
static int max17042_verify_model_lock ( struct max17042_chip * chip )
{
int i ;
2012-03-15 14:37:32 +03:00
int table_size = ARRAY_SIZE ( chip - > pdata - > config_data - > cell_char_tbl ) ;
2016-08-12 09:10:27 -04:00
u16 * temp_data ;
2012-03-13 22:03:52 +04:00
int ret = 0 ;
2012-03-15 14:37:32 +03: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 13:55:02 +09:00
struct regmap * map = chip - > regmap ;
2012-03-13 22:03:52 +04:00
2013-10-25 13:55:02 +09: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 13:55:02 +09:00
regmap_write ( map , MAX17042_RelaxCFG , config - > relax_cfg ) ;
2015-04-03 17:26:08 +09:00
if ( chip - > chip_type = = MAXIM_DEVICE_TYPE_MAX17047 | |
2019-12-14 07:27:54 -08:00
chip - > chip_type = = MAXIM_DEVICE_TYPE_MAX17050 | |
chip - > chip_type = = MAXIM_DEVICE_TYPE_MAX17055 )
2013-10-25 13:55:02 +09:00
regmap_write ( map , MAX17047_FullSOCThr ,
2012-05-05 14:34:26 +05:30
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 13:55:02 +09:00
struct regmap * map = chip - > regmap ;
2012-03-13 22:03:52 +04:00
2013-10-25 13:55:02 +09: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 ) ;
2015-04-03 17:26:08 +09:00
if ( chip - > chip_type = = MAXIM_DEVICE_TYPE_MAX17042 ) {
2013-10-25 13:55:02 +09:00
regmap_write ( map , MAX17042_EmptyTempCo , config - > empty_tempco ) ;
max17042_write_verify_reg ( map , MAX17042_K_empty0 ,
2012-05-05 14:34:26 +05:30
config - > kempty0 ) ;
} else {
2013-10-25 13:55:02 +09:00
max17042_write_verify_reg ( map , MAX17047_QRTbl00 ,
2012-05-05 14:34:26 +05:30
config - > qrtbl00 ) ;
2013-10-25 13:55:02 +09:00
max17042_write_verify_reg ( map , MAX17047_QRTbl10 ,
2012-05-05 14:34:26 +05:30
config - > qrtbl10 ) ;
2013-10-25 13:55:02 +09:00
max17042_write_verify_reg ( map , MAX17047_QRTbl20 ,
2012-05-05 14:34:26 +05:30
config - > qrtbl20 ) ;
2013-10-25 13:55:02 +09:00
max17042_write_verify_reg ( map , MAX17047_QRTbl30 ,
2012-05-05 14:34:26 +05:30
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 13:55:02 +09:00
struct regmap * map = chip - > regmap ;
2012-03-13 22:03:52 +04:00
2013-10-25 13:55:02 +09:00
max17042_write_verify_reg ( map , MAX17042_FullCAP ,
2012-03-13 22:03:52 +04:00
config - > fullcap ) ;
2013-10-25 13:55:02 +09: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 13:55:02 +09:00
unsigned int vfSoc ;
struct regmap * map = chip - > regmap ;
2012-03-13 22:03:52 +04:00
2013-10-25 13:55:02 +09: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 13:55:02 +09: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 13:55:02 +09:00
struct regmap * map = chip - > regmap ;
2012-03-13 22:03:52 +04:00
2013-10-25 13:55:02 +09: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 13:55:02 +09:00
max17042_write_verify_reg ( map , MAX17042_RemCap , rem_cap ) ;
2012-03-13 22:03:52 +04:00
2013-10-25 13:55:02 +09: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 13:55:02 +09: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 13:55:02 +09:00
max17042_write_verify_reg ( map , MAX17042_FullCAP ,
2012-03-13 22:03:52 +04:00
config - > fullcap ) ;
2013-10-25 13:55:02 +09:00
regmap_write ( map , MAX17042_DesignCap ,
2012-03-13 22:03:52 +04:00
config - > design_cap ) ;
2013-10-25 13:55:02 +09:00
max17042_write_verify_reg ( map , MAX17042_FullCAPNom ,
2012-03-13 22:03:52 +04:00
config - > fullcapnom ) ;
2012-05-05 14:34:26 +05:30
/* Update SOC register with new SOC */
2013-10-25 13:55:02 +09: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 .
2021-03-23 18:12:06 +05:30
* This function MUST be called before the POR initialization procedure
2012-03-13 22:03:52 +04:00
* specified by maxim .
*/
static inline void max17042_override_por_values ( struct max17042_chip * chip )
{
2013-10-25 13:55:02 +09: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 13:55:02 +09:00
max17042_override_por ( map , MAX17042_TGAIN , config - > tgain ) ;
2021-08-16 18:50:14 +02:00
max17042_override_por ( map , MAX17042_TOFF , config - > toff ) ;
2013-10-25 13:55:02 +09:00
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_FullCAP , config - > fullcap ) ;
max17042_override_por ( map , MAX17042_FullCAPNom , config - > fullcapnom ) ;
max17042_override_por ( map , MAX17042_dQacc , config - > dqacc ) ;
max17042_override_por ( map , MAX17042_dPacc , config - > dpacc ) ;
2012-03-13 22:03:52 +04:00
2013-10-25 13:55:02 +09:00
max17042_override_por ( map , MAX17042_RCOMP0 , config - > rcomp0 ) ;
max17042_override_por ( map , MAX17042_TempCo , config - > tcompc0 ) ;
2021-08-16 18:50:15 +02:00
if ( chip - > chip_type = = MAXIM_DEVICE_TYPE_MAX17042 ) {
max17042_override_por ( map , MAX17042_MaskSOC , config - > masksoc ) ;
max17042_override_por ( map , MAX17042_SOC_empty , config - > socempty ) ;
max17042_override_por ( map , MAX17042_V_empty , config - > vempty ) ;
max17042_override_por ( map , MAX17042_EmptyTempCo , config - > empty_tempco ) ;
max17042_override_por ( map , MAX17042_K_empty0 , config - > kempty0 ) ;
}
if ( ( chip - > chip_type = = MAXIM_DEVICE_TYPE_MAX17042 ) | |
2019-12-14 07:27:54 -08:00
( chip - > chip_type = = MAXIM_DEVICE_TYPE_MAX17047 ) | |
2021-08-16 18:50:15 +02:00
( chip - > chip_type = = MAXIM_DEVICE_TYPE_MAX17050 ) ) {
2021-09-29 20:14:18 +02:00
max17042_override_por ( map , MAX17042_IAvg_empty , config - > iavg_empty ) ;
2021-08-16 18:50:15 +02:00
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 ) ;
}
if ( ( chip - > chip_type = = MAXIM_DEVICE_TYPE_MAX17047 ) | |
( chip - > chip_type = = MAXIM_DEVICE_TYPE_MAX17050 ) | |
( chip - > chip_type = = MAXIM_DEVICE_TYPE_MAX17055 ) ) {
max17042_override_por ( map , MAX17047_V_empty , config - > vempty ) ;
2012-05-05 14:34:26 +05:30
}
2012-03-13 22:03:52 +04:00
}
static int max17042_init_chip ( struct max17042_chip * chip )
{
2013-10-25 13:55:02 +09: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 ) ;
2021-03-23 18:12:06 +05:30
/* Initialize configuration */
2012-03-13 22:03:52 +04:00
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-18 14:59:47 -08: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 10:54:47 +01:00
regmap_update_bits ( map , MAX17042_STATUS , STATUS_POR_BIT , 0x0 ) ;
2012-03-13 22:03:52 +04:00
return 0 ;
}
2012-01-24 09:26:06 -08:00
static void max17042_set_soc_threshold ( struct max17042_chip * chip , u16 off )
{
2013-10-25 13:55:02 +09:00
struct regmap * map = chip - > regmap ;
u32 soc , soc_tr ;
2012-01-24 09:26:06 -08:00
2021-03-23 18:12:06 +05:30
/* program interrupt thresholds such that we should
2012-01-24 09:26:06 -08:00
* get interrupt for every ' off ' perc change in the soc
*/
2013-10-25 13:55:02 +09:00
regmap_read ( map , MAX17042_RepSOC , & soc ) ;
soc > > = 8 ;
2012-01-24 09:26:06 -08:00
soc_tr = ( soc + off ) < < 8 ;
2021-09-14 14:18:06 +02:00
if ( off < soc )
soc_tr | = soc - off ;
2013-10-25 13:55:02 +09:00
regmap_write ( map , MAX17042_SALRT_Th , soc_tr ) ;
2012-01-24 09:26:06 -08:00
}
static irqreturn_t max17042_thread_handler ( int id , void * dev )
{
struct max17042_chip * chip = dev ;
2013-10-25 13:55:02 +09:00
u32 val ;
2021-08-16 10:27:14 +02:00
int ret ;
ret = regmap_read ( chip - > regmap , MAX17042_STATUS , & val ) ;
if ( ret )
return IRQ_HANDLED ;
2012-01-24 09:26:06 -08:00
2021-08-16 10:27:15 +02:00
if ( ( val & STATUS_SMN_BIT ) | | ( val & STATUS_SMX_BIT ) ) {
2021-08-16 18:50:16 +02:00
dev_dbg ( & chip - > client - > dev , " SOC threshold INTR \n " ) ;
2012-01-24 09:26:06 -08:00
max17042_set_soc_threshold ( chip , 1 ) ;
}
2021-09-14 14:18:05 +02:00
/* we implicitly handle all alerts via power_supply_changed */
regmap_clear_bits ( chip - > regmap , MAX17042_STATUS ,
0xFFFF & ~ ( STATUS_POR_BIT | STATUS_BST_BIT ) ) ;
2015-03-12 08:44:11 +01:00
power_supply_changed ( chip - > battery ) ;
2012-01-24 09:26:06 -08:00
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 19:06:22 +01:00
# ifdef CONFIG_OF
static struct max17042_platform_data *
2018-01-22 18:42:18 +01:00
max17042_get_of_pdata ( struct max17042_chip * chip )
2012-02-22 19:06:22 +01:00
{
2017-04-14 20:32:49 +02:00
struct device * dev = & chip - > client - > dev ;
2012-02-22 19:06:22 +01:00
struct device_node * np = dev - > of_node ;
u32 prop ;
struct max17042_platform_data * pdata ;
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 ;
}
2015-06-08 10:11:38 +09:00
if ( of_property_read_s32 ( np , " maxim,cold-temp " , & pdata - > temp_min ) )
pdata - > temp_min = INT_MIN ;
if ( of_property_read_s32 ( np , " maxim,over-heat-temp " , & pdata - > temp_max ) )
pdata - > temp_max = INT_MAX ;
if ( of_property_read_s32 ( np , " maxim,dead-volt " , & pdata - > vmin ) )
pdata - > vmin = INT_MIN ;
if ( of_property_read_s32 ( np , " maxim,over-volt " , & pdata - > vmax ) )
pdata - > vmax = INT_MAX ;
2012-02-22 19:06:22 +01:00
return pdata ;
}
2018-01-22 18:42:18 +01:00
# endif
2017-04-14 20:32:49 +02:00
static struct max17042_reg_data max17047_default_pdata_init_regs [ ] = {
/*
* Some firmwares do not set FullSOCThr , Enable End - of - Charge Detection
* when the voltage FG reports 95 % , as recommended in the datasheet .
*/
{ MAX17047_FullSOCThr , MAX17042_BATTERY_FULL < < 8 } ,
} ;
2012-02-22 19:06:22 +01:00
static struct max17042_platform_data *
2018-01-22 18:42:18 +01:00
max17042_get_default_pdata ( struct max17042_chip * chip )
2012-02-22 19:06:22 +01:00
{
2017-04-14 20:32:49 +02:00
struct device * dev = & chip - > client - > dev ;
struct max17042_platform_data * pdata ;
int ret , misc_cfg ;
/*
* The MAX17047 gets used on x86 where we might not have pdata , assume
* the firmware will already have initialized the fuel - gauge and provide
* default values for the non init bits to make things work .
*/
pdata = devm_kzalloc ( dev , sizeof ( * pdata ) , GFP_KERNEL ) ;
if ( ! pdata )
return pdata ;
2019-12-14 07:27:54 -08:00
if ( ( chip - > chip_type = = MAXIM_DEVICE_TYPE_MAX17047 ) | |
( chip - > chip_type = = MAXIM_DEVICE_TYPE_MAX17050 ) ) {
2017-04-14 20:32:49 +02:00
pdata - > init_data = max17047_default_pdata_init_regs ;
pdata - > num_init_data =
ARRAY_SIZE ( max17047_default_pdata_init_regs ) ;
}
ret = regmap_read ( chip - > regmap , MAX17042_MiscCFG , & misc_cfg ) ;
if ( ret < 0 )
return NULL ;
/* If bits 0-1 are set to 3 then only Voltage readings are used */
if ( ( misc_cfg & 0x3 ) = = 0x3 )
pdata - > enable_current_sense = false ;
else
pdata - > enable_current_sense = true ;
pdata - > vmin = MAX17042_DEFAULT_VMIN ;
pdata - > vmax = MAX17042_DEFAULT_VMAX ;
pdata - > temp_min = MAX17042_DEFAULT_TEMP_MIN ;
pdata - > temp_max = MAX17042_DEFAULT_TEMP_MAX ;
return pdata ;
2012-02-22 19:06:22 +01:00
}
2018-01-22 18:42:18 +01:00
static struct max17042_platform_data *
max17042_get_pdata ( struct max17042_chip * chip )
{
struct device * dev = & chip - > client - > dev ;
# ifdef CONFIG_OF
if ( dev - > of_node )
return max17042_get_of_pdata ( chip ) ;
2012-02-22 19:06:22 +01:00
# endif
2018-01-22 18:42:18 +01:00
if ( dev - > platform_data )
return dev - > platform_data ;
return max17042_get_default_pdata ( chip ) ;
}
2012-02-22 19:06:22 +01:00
2015-01-05 09:50:17 +01:00
static const struct regmap_config max17042_regmap_config = {
2013-10-25 13:55:02 +09:00
. reg_bits = 8 ,
. val_bits = 16 ,
. val_format_endian = REGMAP_ENDIAN_NATIVE ,
} ;
2015-03-12 08:44:11 +01:00
static const struct power_supply_desc max17042_psy_desc = {
. name = " max170xx_battery " ,
. type = POWER_SUPPLY_TYPE_BATTERY ,
. get_property = max17042_get_property ,
2015-05-24 09:11:58 +05:30
. set_property = max17042_set_property ,
. property_is_writeable = max17042_property_is_writeable ,
2023-04-15 18:07:33 +02:00
. external_power_changed = power_supply_changed ,
2015-03-12 08:44:11 +01:00
. properties = max17042_battery_props ,
. num_properties = ARRAY_SIZE ( max17042_battery_props ) ,
} ;
static const struct power_supply_desc max17042_no_current_sense_psy_desc = {
. name = " max170xx_battery " ,
. type = POWER_SUPPLY_TYPE_BATTERY ,
. get_property = max17042_get_property ,
2015-05-24 09:11:58 +05:30
. set_property = max17042_set_property ,
. property_is_writeable = max17042_property_is_writeable ,
2015-03-12 08:44:11 +01:00
. properties = max17042_battery_props ,
. num_properties = ARRAY_SIZE ( max17042_battery_props ) - 2 ,
} ;
2022-11-18 23:44:23 +01:00
static int max17042_probe ( struct i2c_client * client )
2011-01-14 14:46:11 +09:00
{
2022-11-18 23:44:23 +01:00
const struct i2c_device_id * id = i2c_client_get_device_id ( client ) ;
2019-06-08 12:56:00 +02:00
struct i2c_adapter * adapter = client - > adapter ;
2015-03-12 08:44:11 +01:00
const struct power_supply_desc * max17042_desc = & max17042_psy_desc ;
struct power_supply_config psy_cfg = { } ;
2017-08-29 11:27:28 +02:00
const struct acpi_device_id * acpi_id = NULL ;
2017-08-14 22:18:10 +02:00
struct device * dev = & client - > dev ;
2011-01-14 14:46:11 +09:00
struct max17042_chip * chip ;
int ret ;
2013-10-25 13:55:02 +09:00
int i ;
u32 val ;
2011-01-14 14:46:11 +09:00
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_WORD_DATA ) )
return - EIO ;
2012-02-22 19:06:20 +01:00
chip = devm_kzalloc ( & client - > dev , sizeof ( * chip ) , GFP_KERNEL ) ;
2011-01-14 14:46:11 +09:00
if ( ! chip )
return - ENOMEM ;
chip - > client = client ;
2017-08-14 22:18:10 +02:00
if ( id ) {
chip - > chip_type = id - > driver_data ;
} else {
acpi_id = acpi_match_device ( dev - > driver - > acpi_match_table , dev ) ;
if ( ! acpi_id )
return - ENODEV ;
chip - > chip_type = acpi_id - > driver_data ;
}
2013-10-25 13:55:02 +09: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 ;
}
2017-04-14 20:32:49 +02:00
chip - > pdata = max17042_get_pdata ( chip ) ;
2012-02-22 19:06:22 +01:00
if ( ! chip - > pdata ) {
dev_err ( & client - > dev , " no platform data provided \n " ) ;
return - EINVAL ;
}
2011-01-14 14:46:11 +09:00
i2c_set_clientdata ( client , chip ) ;
2015-03-12 08:44:11 +01:00
psy_cfg . drv_data = chip ;
2018-02-20 16:03:18 +01:00
psy_cfg . of_node = dev - > of_node ;
2011-01-14 14:46:11 +09:00
2011-06-30 18:07:41 +09:00
/* When current is not measured,
* CURRENT_NOW and CURRENT_AVG properties should be invisible . */
if ( ! chip - > pdata - > enable_current_sense )
2015-03-12 08:44:11 +01:00
max17042_desc = & max17042_no_current_sense_psy_desc ;
2011-06-30 18:07:41 +09:00
2011-08-12 21:18:18 -07:00
if ( chip - > pdata - > r_sns = = 0 )
chip - > pdata - > r_sns = MAX17042_DEFAULT_SNS_RESISTOR ;
2011-06-30 18:07:41 +09:00
if ( chip - > pdata - > init_data )
2013-10-25 13:55:02 +09: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 18:07:41 +09:00
2011-01-14 14:46:11 +09:00
if ( ! chip - > pdata - > enable_current_sense ) {
2013-10-25 13:55:02 +09: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 14:46:11 +09:00
}
2015-09-17 18:27:52 +05:30
chip - > battery = devm_power_supply_register ( & client - > dev , max17042_desc ,
& psy_cfg ) ;
2015-03-12 08:44:11 +01:00
if ( IS_ERR ( chip - > battery ) ) {
2012-05-05 03:08:37 +05:30
dev_err ( & client - > dev , " failed: power supply register \n " ) ;
2015-03-12 08:44:11 +01:00
return PTR_ERR ( chip - > battery ) ;
2012-05-05 03:08:37 +05:30
}
2012-01-24 09:26:06 -08:00
if ( client - > irq ) {
2021-05-26 13:20:35 -04:00
unsigned int flags = IRQF_ONESHOT ;
2017-08-14 22:18:11 +02:00
/*
* On ACPI systems the IRQ may be handled by ACPI - event code ,
* so we need to share ( if the ACPI code is willing to share ) .
*/
if ( acpi_id )
flags | = IRQF_SHARED | IRQF_PROBE_SHARED ;
2015-09-17 18:27:52 +05:30
ret = devm_request_threaded_irq ( & client - > dev , client - > irq ,
NULL ,
2017-08-14 22:18:11 +02:00
max17042_thread_handler , flags ,
2015-09-17 18:27:52 +05:30
chip - > battery - > desc - > name ,
chip ) ;
2012-01-24 09:26:06 -08:00
if ( ! ret ) {
2015-02-24 10:54:47 +01:00
regmap_update_bits ( chip - > regmap , MAX17042_CONFIG ,
CONFIG_ALRT_BIT_ENBL ,
CONFIG_ALRT_BIT_ENBL ) ;
2012-01-24 09:26:06 -08:00
max17042_set_soc_threshold ( chip , 1 ) ;
2012-05-05 04:43:10 +05:30
} else {
client - > irq = 0 ;
2017-08-14 22:18:11 +02:00
if ( ret ! = - EBUSY )
dev_err ( & client - > dev , " Failed to get IRQ \n " ) ;
2012-05-05 04:43:10 +05:30
}
2012-01-24 09:26:06 -08:00
}
2017-08-14 22:18:11 +02:00
/* Not able to update the charge threshold when exceeded? -> disable */
if ( ! client - > irq )
regmap_write ( chip - > regmap , MAX17042_SALRT_Th , 0xff00 ) ;
2012-01-24 09:26:06 -08:00
2013-10-25 13:55:02 +09:00
regmap_read ( chip - > regmap , MAX17042_STATUS , & val ) ;
if ( val & STATUS_POR_BIT ) {
2022-02-18 18:37:37 +01:00
ret = devm_work_autocancel ( & client - > dev , & chip - > work ,
max17042_init_worker ) ;
2019-02-15 17:03:44 -05:00
if ( ret )
return ret ;
2012-03-13 22:03:52 +04:00
schedule_work ( & chip - > work ) ;
} else {
chip - > init_complete = 1 ;
}
2012-05-05 03:08:37 +05:30
return 0 ;
2011-01-14 14:46:11 +09:00
}
2013-10-14 10:56:51 +05:30
# ifdef CONFIG_PM_SLEEP
2012-03-27 02:23:40 +05:30
static int max17042_suspend ( struct device * dev )
{
struct max17042_chip * chip = dev_get_drvdata ( dev ) ;
2012-05-04 20:38:13 -07:00
/*
* disable the irq and enable irq_wake
2012-03-27 02:23:40 +05:30
* 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 10:56:51 +05:30
static SIMPLE_DEV_PM_OPS ( max17042_pm_ops , max17042_suspend ,
max17042_resume ) ;
2017-08-14 22:18:10 +02:00
# ifdef CONFIG_ACPI
static const struct acpi_device_id max17042_acpi_match [ ] = {
{ " MAX17047 " , MAXIM_DEVICE_TYPE_MAX17047 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( acpi , max17042_acpi_match ) ;
# endif
2012-02-22 19:06:22 +01:00
# ifdef CONFIG_OF
static const struct of_device_id max17042_dt_match [ ] = {
{ . compatible = " maxim,max17042 " } ,
2012-05-05 14:34:26 +05:30
{ . compatible = " maxim,max17047 " } ,
{ . compatible = " maxim,max17050 " } ,
2019-12-14 07:27:54 -08:00
{ . compatible = " maxim,max17055 " } ,
2021-07-27 22:03:45 +05:00
{ . compatible = " maxim,max77849-battery " } ,
2012-02-22 19:06:22 +01:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , max17042_dt_match ) ;
# endif
2011-01-14 14:46:11 +09:00
static const struct i2c_device_id max17042_id [ ] = {
2015-04-03 17:26:08 +09:00
{ " max17042 " , MAXIM_DEVICE_TYPE_MAX17042 } ,
{ " max17047 " , MAXIM_DEVICE_TYPE_MAX17047 } ,
{ " max17050 " , MAXIM_DEVICE_TYPE_MAX17050 } ,
2019-12-14 07:27:54 -08:00
{ " max17055 " , MAXIM_DEVICE_TYPE_MAX17055 } ,
2021-07-27 22:03:45 +05:00
{ " max77849-battery " , MAXIM_DEVICE_TYPE_MAX17047 } ,
2011-01-14 14:46:11 +09:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , max17042_id ) ;
static struct i2c_driver max17042_i2c_driver = {
. driver = {
. name = " max17042 " ,
2017-08-14 22:18:10 +02:00
. acpi_match_table = ACPI_PTR ( max17042_acpi_match ) ,
2012-02-22 19:06:22 +01:00
. of_match_table = of_match_ptr ( max17042_dt_match ) ,
2013-10-14 10:56:51 +05:30
. pm = & max17042_pm_ops ,
2011-01-14 14:46:11 +09:00
} ,
2023-05-17 18:55:14 +02:00
. probe = max17042_probe ,
2011-01-14 14:46:11 +09:00
. id_table = max17042_id ,
} ;
2012-01-21 14:42:54 +08:00
module_i2c_driver ( max17042_i2c_driver ) ;
2011-01-14 14:46:11 +09:00
MODULE_AUTHOR ( " MyungJoo Ham <myungjoo.ham@samsung.com> " ) ;
MODULE_DESCRIPTION ( " MAX17042 Fuel Gauge " ) ;
MODULE_LICENSE ( " GPL " ) ;