Merge "qpnp-fg-gen3: Add support to hold soc at 100 when charge is full"
This commit is contained in:
commit
4a10b1c33d
4 changed files with 235 additions and 37 deletions
|
@ -216,6 +216,12 @@ First Level Node - FG Gen3 device
|
||||||
Definition: Battery temperature delta interrupt threshold. Possible
|
Definition: Battery temperature delta interrupt threshold. Possible
|
||||||
values are: 2, 4, 6 and 10. Unit is in Kelvin.
|
values are: 2, 4, 6 and 10. Unit is in Kelvin.
|
||||||
|
|
||||||
|
- qcom,hold-soc-while-full:
|
||||||
|
Usage: optional
|
||||||
|
Value type: <bool>
|
||||||
|
Definition: A boolean property that when defined holds SOC at 100% when
|
||||||
|
the battery is full.
|
||||||
|
|
||||||
==========================================================
|
==========================================================
|
||||||
Second Level Nodes - Peripherals managed by FG Gen3 driver
|
Second Level Nodes - Peripherals managed by FG Gen3 driver
|
||||||
==========================================================
|
==========================================================
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/power_supply.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/string_helpers.h>
|
#include <linux/string_helpers.h>
|
||||||
|
@ -38,6 +39,7 @@
|
||||||
pr_debug(fmt, ##__VA_ARGS__); \
|
pr_debug(fmt, ##__VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
/* Awake votable reasons */
|
||||||
#define SRAM_READ "fg_sram_read"
|
#define SRAM_READ "fg_sram_read"
|
||||||
#define SRAM_WRITE "fg_sram_write"
|
#define SRAM_WRITE "fg_sram_write"
|
||||||
#define PROFILE_LOAD "fg_profile_load"
|
#define PROFILE_LOAD "fg_profile_load"
|
||||||
|
@ -173,6 +175,8 @@ struct fg_alg_flag {
|
||||||
|
|
||||||
/* DT parameters for FG device */
|
/* DT parameters for FG device */
|
||||||
struct fg_dt_props {
|
struct fg_dt_props {
|
||||||
|
bool force_load_profile;
|
||||||
|
bool hold_soc_while_full;
|
||||||
int cutoff_volt_mv;
|
int cutoff_volt_mv;
|
||||||
int empty_volt_mv;
|
int empty_volt_mv;
|
||||||
int vbatt_low_thr_mv;
|
int vbatt_low_thr_mv;
|
||||||
|
@ -185,7 +189,6 @@ struct fg_dt_props {
|
||||||
int esr_timer_charging;
|
int esr_timer_charging;
|
||||||
int esr_timer_awake;
|
int esr_timer_awake;
|
||||||
int esr_timer_asleep;
|
int esr_timer_asleep;
|
||||||
bool force_load_profile;
|
|
||||||
int cl_start_soc;
|
int cl_start_soc;
|
||||||
int cl_max_temp;
|
int cl_max_temp;
|
||||||
int cl_min_temp;
|
int cl_min_temp;
|
||||||
|
@ -240,6 +243,8 @@ struct fg_chip {
|
||||||
struct dentry *dfs_root;
|
struct dentry *dfs_root;
|
||||||
struct power_supply *fg_psy;
|
struct power_supply *fg_psy;
|
||||||
struct power_supply *batt_psy;
|
struct power_supply *batt_psy;
|
||||||
|
struct power_supply *usb_psy;
|
||||||
|
struct power_supply *dc_psy;
|
||||||
struct iio_channel *batt_id_chan;
|
struct iio_channel *batt_id_chan;
|
||||||
struct fg_memif *sram;
|
struct fg_memif *sram;
|
||||||
struct fg_irq_info *irqs;
|
struct fg_irq_info *irqs;
|
||||||
|
@ -268,6 +273,8 @@ struct fg_chip {
|
||||||
bool profile_loaded;
|
bool profile_loaded;
|
||||||
bool battery_missing;
|
bool battery_missing;
|
||||||
bool fg_restarting;
|
bool fg_restarting;
|
||||||
|
bool charge_full;
|
||||||
|
bool recharge_soc_adjusted;
|
||||||
struct completion soc_update;
|
struct completion soc_update;
|
||||||
struct completion soc_ready;
|
struct completion soc_ready;
|
||||||
struct delayed_work profile_load_work;
|
struct delayed_work profile_load_work;
|
||||||
|
@ -321,4 +328,5 @@ extern int fg_debugfs_create(struct fg_chip *chip);
|
||||||
extern void fill_string(char *str, size_t str_len, u8 *buf, int buf_len);
|
extern void fill_string(char *str, size_t str_len, u8 *buf, int buf_len);
|
||||||
extern int64_t twos_compliment_extend(int64_t val, int s_bit_pos);
|
extern int64_t twos_compliment_extend(int64_t val, int s_bit_pos);
|
||||||
extern s64 fg_float_decode(u16 val);
|
extern s64 fg_float_decode(u16 val);
|
||||||
|
extern bool is_input_present(struct fg_chip *chip);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -29,6 +29,43 @@ static struct fg_dbgfs dbgfs_data = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool is_usb_present(struct fg_chip *chip)
|
||||||
|
{
|
||||||
|
union power_supply_propval pval = {0, };
|
||||||
|
|
||||||
|
if (!chip->usb_psy)
|
||||||
|
chip->usb_psy = power_supply_get_by_name("usb");
|
||||||
|
|
||||||
|
if (chip->usb_psy)
|
||||||
|
power_supply_get_property(chip->usb_psy,
|
||||||
|
POWER_SUPPLY_PROP_PRESENT, &pval);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return pval.intval != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_dc_present(struct fg_chip *chip)
|
||||||
|
{
|
||||||
|
union power_supply_propval pval = {0, };
|
||||||
|
|
||||||
|
if (!chip->dc_psy)
|
||||||
|
chip->dc_psy = power_supply_get_by_name("dc");
|
||||||
|
|
||||||
|
if (chip->dc_psy)
|
||||||
|
power_supply_get_property(chip->dc_psy,
|
||||||
|
POWER_SUPPLY_PROP_PRESENT, &pval);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return pval.intval != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_input_present(struct fg_chip *chip)
|
||||||
|
{
|
||||||
|
return is_usb_present(chip) || is_dc_present(chip);
|
||||||
|
}
|
||||||
|
|
||||||
#define EXPONENT_SHIFT 11
|
#define EXPONENT_SHIFT 11
|
||||||
#define EXPONENT_OFFSET -9
|
#define EXPONENT_OFFSET -9
|
||||||
#define MANTISSA_SIGN_BIT 10
|
#define MANTISSA_SIGN_BIT 10
|
||||||
|
@ -98,6 +135,7 @@ int fg_sram_write(struct fg_chip *chip, u16 address, u8 offset,
|
||||||
* This interrupt need to be enabled only when it is
|
* This interrupt need to be enabled only when it is
|
||||||
* required. It will be kept disabled other times.
|
* required. It will be kept disabled other times.
|
||||||
*/
|
*/
|
||||||
|
reinit_completion(&chip->soc_update);
|
||||||
enable_irq(chip->irqs[SOC_UPDATE_IRQ].irq);
|
enable_irq(chip->irqs[SOC_UPDATE_IRQ].irq);
|
||||||
atomic_access = true;
|
atomic_access = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/of_batterydata.h>
|
#include <linux/of_batterydata.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/power_supply.h>
|
|
||||||
#include <linux/iio/consumer.h>
|
#include <linux/iio/consumer.h>
|
||||||
#include <linux/qpnp/qpnp-revid.h>
|
#include <linux/qpnp/qpnp-revid.h>
|
||||||
#include "fg-core.h"
|
#include "fg-core.h"
|
||||||
|
@ -65,6 +64,8 @@
|
||||||
#define PROFILE_INTEGRITY_OFFSET 3
|
#define PROFILE_INTEGRITY_OFFSET 3
|
||||||
#define BATT_SOC_WORD 91
|
#define BATT_SOC_WORD 91
|
||||||
#define BATT_SOC_OFFSET 0
|
#define BATT_SOC_OFFSET 0
|
||||||
|
#define FULL_SOC_WORD 93
|
||||||
|
#define FULL_SOC_OFFSET 2
|
||||||
#define MONOTONIC_SOC_WORD 94
|
#define MONOTONIC_SOC_WORD 94
|
||||||
#define MONOTONIC_SOC_OFFSET 2
|
#define MONOTONIC_SOC_OFFSET 2
|
||||||
#define CC_SOC_WORD 95
|
#define CC_SOC_WORD 95
|
||||||
|
@ -106,8 +107,6 @@ static int fg_decode_value_16b(struct fg_sram_param *sp,
|
||||||
enum fg_sram_param_id id, int val);
|
enum fg_sram_param_id id, int val);
|
||||||
static int fg_decode_default(struct fg_sram_param *sp,
|
static int fg_decode_default(struct fg_sram_param *sp,
|
||||||
enum fg_sram_param_id id, int val);
|
enum fg_sram_param_id id, int val);
|
||||||
static int fg_decode_batt_soc(struct fg_sram_param *sp,
|
|
||||||
enum fg_sram_param_id id, int val);
|
|
||||||
static int fg_decode_cc_soc(struct fg_sram_param *sp,
|
static int fg_decode_cc_soc(struct fg_sram_param *sp,
|
||||||
enum fg_sram_param_id id, int value);
|
enum fg_sram_param_id id, int value);
|
||||||
static void fg_encode_voltage(struct fg_sram_param *sp,
|
static void fg_encode_voltage(struct fg_sram_param *sp,
|
||||||
|
@ -132,7 +131,7 @@ static void fg_encode_default(struct fg_sram_param *sp,
|
||||||
|
|
||||||
static struct fg_sram_param pmicobalt_v1_sram_params[] = {
|
static struct fg_sram_param pmicobalt_v1_sram_params[] = {
|
||||||
PARAM(BATT_SOC, BATT_SOC_WORD, BATT_SOC_OFFSET, 4, 1, 1, 0, NULL,
|
PARAM(BATT_SOC, BATT_SOC_WORD, BATT_SOC_OFFSET, 4, 1, 1, 0, NULL,
|
||||||
fg_decode_batt_soc),
|
fg_decode_default),
|
||||||
PARAM(VOLTAGE_PRED, VOLTAGE_PRED_WORD, VOLTAGE_PRED_OFFSET, 2, 244141,
|
PARAM(VOLTAGE_PRED, VOLTAGE_PRED_WORD, VOLTAGE_PRED_OFFSET, 2, 244141,
|
||||||
1000, 0, NULL, fg_decode_voltage_15b),
|
1000, 0, NULL, fg_decode_voltage_15b),
|
||||||
PARAM(OCV, OCV_WORD, OCV_OFFSET, 2, 244141, 1000, 0, NULL,
|
PARAM(OCV, OCV_WORD, OCV_OFFSET, 2, 244141, 1000, 0, NULL,
|
||||||
|
@ -178,7 +177,7 @@ static struct fg_sram_param pmicobalt_v1_sram_params[] = {
|
||||||
|
|
||||||
static struct fg_sram_param pmicobalt_v2_sram_params[] = {
|
static struct fg_sram_param pmicobalt_v2_sram_params[] = {
|
||||||
PARAM(BATT_SOC, BATT_SOC_WORD, BATT_SOC_OFFSET, 4, 1, 1, 0, NULL,
|
PARAM(BATT_SOC, BATT_SOC_WORD, BATT_SOC_OFFSET, 4, 1, 1, 0, NULL,
|
||||||
fg_decode_batt_soc),
|
fg_decode_default),
|
||||||
PARAM(VOLTAGE_PRED, VOLTAGE_PRED_WORD, VOLTAGE_PRED_OFFSET, 2, 244141,
|
PARAM(VOLTAGE_PRED, VOLTAGE_PRED_WORD, VOLTAGE_PRED_OFFSET, 2, 244141,
|
||||||
1000, 0, NULL, fg_decode_voltage_15b),
|
1000, 0, NULL, fg_decode_voltage_15b),
|
||||||
PARAM(OCV, OCV_WORD, OCV_OFFSET, 2, 244141, 1000, 0, NULL,
|
PARAM(OCV, OCV_WORD, OCV_OFFSET, 2, 244141, 1000, 0, NULL,
|
||||||
|
@ -335,19 +334,11 @@ static int fg_decode_value_16b(struct fg_sram_param *sp,
|
||||||
return sp[id].value;
|
return sp[id].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fg_decode_batt_soc(struct fg_sram_param *sp,
|
|
||||||
enum fg_sram_param_id id, int value)
|
|
||||||
{
|
|
||||||
sp[id].value = (u32)value >> 24;
|
|
||||||
pr_debug("id: %d raw value: %x decoded value: %x\n", id, value,
|
|
||||||
sp[id].value);
|
|
||||||
return sp[id].value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fg_decode_default(struct fg_sram_param *sp, enum fg_sram_param_id id,
|
static int fg_decode_default(struct fg_sram_param *sp, enum fg_sram_param_id id,
|
||||||
int value)
|
int value)
|
||||||
{
|
{
|
||||||
return value;
|
sp[id].value = value;
|
||||||
|
return sp[id].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fg_decode(struct fg_sram_param *sp, enum fg_sram_param_id id,
|
static int fg_decode(struct fg_sram_param *sp, enum fg_sram_param_id id,
|
||||||
|
@ -645,6 +636,11 @@ static int fg_get_prop_capacity(struct fg_chip *chip, int *val)
|
||||||
{
|
{
|
||||||
int rc, msoc;
|
int rc, msoc;
|
||||||
|
|
||||||
|
if (chip->charge_full) {
|
||||||
|
*val = FULL_CAPACITY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
rc = fg_get_msoc_raw(chip, &msoc);
|
rc = fg_get_msoc_raw(chip, &msoc);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -1059,7 +1055,7 @@ static int fg_cap_learning_done(struct fg_chip *chip)
|
||||||
cc_soc_sw = CC_SOC_30BIT;
|
cc_soc_sw = CC_SOC_30BIT;
|
||||||
rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
|
rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
|
||||||
chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
|
chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
|
||||||
chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_DEFAULT);
|
chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
|
pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1092,6 +1088,9 @@ static void fg_cap_learning_update(struct fg_chip *chip)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We need only the most significant byte here */
|
||||||
|
batt_soc = (u32)batt_soc >> 24;
|
||||||
|
|
||||||
fg_dbg(chip, FG_CAP_LEARN, "Chg_status: %d cl_active: %d batt_soc: %d\n",
|
fg_dbg(chip, FG_CAP_LEARN, "Chg_status: %d cl_active: %d batt_soc: %d\n",
|
||||||
chip->status, chip->cl.active, batt_soc);
|
chip->status, chip->cl.active, batt_soc);
|
||||||
|
|
||||||
|
@ -1103,8 +1102,7 @@ static void fg_cap_learning_update(struct fg_chip *chip)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (chip->status == POWER_SUPPLY_STATUS_FULL &&
|
if (chip->charge_done) {
|
||||||
chip->charge_done) {
|
|
||||||
rc = fg_cap_learning_done(chip);
|
rc = fg_cap_learning_done(chip);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
pr_err("Error in completing capacity learning, rc=%d\n",
|
pr_err("Error in completing capacity learning, rc=%d\n",
|
||||||
|
@ -1126,19 +1124,157 @@ out:
|
||||||
mutex_unlock(&chip->cl.lock);
|
mutex_unlock(&chip->cl.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int fg_charge_full_update(struct fg_chip *chip)
|
||||||
|
{
|
||||||
|
union power_supply_propval prop = {0, };
|
||||||
|
int rc, msoc, bsoc, recharge_soc;
|
||||||
|
u8 full_soc[2] = {0xFF, 0xFF};
|
||||||
|
|
||||||
|
if (!chip->dt.hold_soc_while_full)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!is_charger_available(chip))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
|
||||||
|
&prop);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Error in getting battery health, rc=%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
chip->health = prop.intval;
|
||||||
|
recharge_soc = chip->dt.recharge_soc_thr;
|
||||||
|
recharge_soc = DIV_ROUND_CLOSEST(recharge_soc * FULL_SOC_RAW,
|
||||||
|
FULL_CAPACITY);
|
||||||
|
rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &bsoc);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need 2 most significant bytes here */
|
||||||
|
bsoc = (u32)bsoc >> 16;
|
||||||
|
rc = fg_get_prop_capacity(chip, &msoc);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Error in getting capacity, rc=%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
fg_dbg(chip, FG_STATUS, "msoc: %d health: %d status: %d\n", msoc,
|
||||||
|
chip->health, chip->status);
|
||||||
|
if (chip->charge_done) {
|
||||||
|
if (msoc >= 99 && chip->health == POWER_SUPPLY_HEALTH_GOOD)
|
||||||
|
chip->charge_full = true;
|
||||||
|
else
|
||||||
|
fg_dbg(chip, FG_STATUS, "Terminated charging @ SOC%d\n",
|
||||||
|
msoc);
|
||||||
|
} else if ((bsoc >> 8) <= recharge_soc) {
|
||||||
|
fg_dbg(chip, FG_STATUS, "bsoc: %d recharge_soc: %d\n",
|
||||||
|
bsoc >> 8, recharge_soc);
|
||||||
|
chip->charge_full = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chip->charge_full)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* During JEITA conditions, charge_full can happen early. FULL_SOC
|
||||||
|
* and MONOTONIC_SOC needs to be updated to reflect the same. Write
|
||||||
|
* battery SOC to FULL_SOC and write a full value to MONOTONIC_SOC.
|
||||||
|
*/
|
||||||
|
rc = fg_sram_write(chip, FULL_SOC_WORD, FULL_SOC_OFFSET, (u8 *)&bsoc, 2,
|
||||||
|
FG_IMA_ATOMIC);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("failed to write full_soc rc=%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = fg_sram_write(chip, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET,
|
||||||
|
full_soc, 2, FG_IMA_ATOMIC);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("failed to write monotonic_soc rc=%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
fg_dbg(chip, FG_STATUS, "Set charge_full to true @ soc %d\n", msoc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fg_set_recharge_soc(struct fg_chip *chip, int recharge_soc)
|
||||||
|
{
|
||||||
|
u8 buf[4];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
fg_encode(chip->sp, FG_SRAM_RECHARGE_SOC_THR, recharge_soc, buf);
|
||||||
|
rc = fg_sram_write(chip,
|
||||||
|
chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_word,
|
||||||
|
chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_byte, buf,
|
||||||
|
chip->sp[FG_SRAM_RECHARGE_SOC_THR].len, FG_IMA_DEFAULT);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Error in writing recharge_soc_thr, rc=%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fg_adjust_recharge_soc(struct fg_chip *chip)
|
||||||
|
{
|
||||||
|
int rc, msoc, recharge_soc, new_recharge_soc = 0;
|
||||||
|
|
||||||
|
recharge_soc = chip->dt.recharge_soc_thr;
|
||||||
|
/*
|
||||||
|
* If the input is present and charging had been terminated, adjust
|
||||||
|
* the recharge SOC threshold based on the monotonic SOC at which
|
||||||
|
* the charge termination had happened.
|
||||||
|
*/
|
||||||
|
if (is_input_present(chip) && !chip->recharge_soc_adjusted
|
||||||
|
&& chip->charge_done) {
|
||||||
|
/* Get raw monotonic SOC for calculation */
|
||||||
|
rc = fg_get_msoc_raw(chip, &msoc);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Error in getting msoc, rc=%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
msoc = DIV_ROUND_CLOSEST(msoc * FULL_CAPACITY, FULL_SOC_RAW);
|
||||||
|
/* Adjust the recharge_soc threshold */
|
||||||
|
new_recharge_soc = msoc - (FULL_CAPACITY - recharge_soc);
|
||||||
|
} else if (chip->recharge_soc_adjusted && (!is_input_present(chip)
|
||||||
|
|| chip->health == POWER_SUPPLY_HEALTH_GOOD)) {
|
||||||
|
/* Restore the default value */
|
||||||
|
new_recharge_soc = recharge_soc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_recharge_soc > 0 && new_recharge_soc < FULL_CAPACITY) {
|
||||||
|
rc = fg_set_recharge_soc(chip, new_recharge_soc);
|
||||||
|
if (rc) {
|
||||||
|
pr_err("Couldn't set resume SOC for FG, rc=%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
chip->recharge_soc_adjusted = (new_recharge_soc !=
|
||||||
|
recharge_soc);
|
||||||
|
fg_dbg(chip, FG_STATUS, "resume soc set to %d\n",
|
||||||
|
new_recharge_soc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void status_change_work(struct work_struct *work)
|
static void status_change_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct fg_chip *chip = container_of(work,
|
struct fg_chip *chip = container_of(work,
|
||||||
struct fg_chip, status_change_work);
|
struct fg_chip, status_change_work);
|
||||||
union power_supply_propval prop = {0, };
|
union power_supply_propval prop = {0, };
|
||||||
int prev_status, rc;
|
int rc;
|
||||||
|
|
||||||
if (!is_charger_available(chip)) {
|
if (!is_charger_available(chip)) {
|
||||||
fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
|
fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_status = chip->status;
|
|
||||||
rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS,
|
rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS,
|
||||||
&prop);
|
&prop);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
|
@ -1155,13 +1291,20 @@ static void status_change_work(struct work_struct *work)
|
||||||
}
|
}
|
||||||
|
|
||||||
chip->charge_done = prop.intval;
|
chip->charge_done = prop.intval;
|
||||||
fg_dbg(chip, FG_POWER_SUPPLY, "prev_status: %d curr_status:%d charge_done: %d\n",
|
fg_dbg(chip, FG_POWER_SUPPLY, "curr_status:%d charge_done: %d\n",
|
||||||
prev_status, chip->status, chip->charge_done);
|
chip->status, chip->charge_done);
|
||||||
if (prev_status != chip->status) {
|
|
||||||
if (chip->cyc_ctr.en)
|
if (chip->cyc_ctr.en)
|
||||||
schedule_work(&chip->cycle_count_work);
|
schedule_work(&chip->cycle_count_work);
|
||||||
fg_cap_learning_update(chip);
|
|
||||||
}
|
fg_cap_learning_update(chip);
|
||||||
|
rc = fg_charge_full_update(chip);
|
||||||
|
if (rc < 0)
|
||||||
|
pr_err("Error in charge_full_update, rc=%d\n", rc);
|
||||||
|
|
||||||
|
rc = fg_adjust_recharge_soc(chip);
|
||||||
|
if (rc < 0)
|
||||||
|
pr_err("Error in adjusting recharge_soc, rc=%d\n", rc);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
pm_relax(chip->dev);
|
pm_relax(chip->dev);
|
||||||
|
@ -1247,6 +1390,9 @@ static void cycle_count_work(struct work_struct *work)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We need only the most significant byte here */
|
||||||
|
batt_soc = (u32)batt_soc >> 24;
|
||||||
|
|
||||||
if (chip->status == POWER_SUPPLY_STATUS_CHARGING) {
|
if (chip->status == POWER_SUPPLY_STATUS_CHARGING) {
|
||||||
/* Find out which bucket the SOC falls in */
|
/* Find out which bucket the SOC falls in */
|
||||||
bucket = batt_soc / BUCKET_SOC_PCT;
|
bucket = batt_soc / BUCKET_SOC_PCT;
|
||||||
|
@ -1787,16 +1933,9 @@ static int fg_hw_init(struct fg_chip *chip)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chip->dt.recharge_soc_thr > 0 && chip->dt.recharge_soc_thr < 100) {
|
if (chip->dt.recharge_soc_thr > 0 && chip->dt.recharge_soc_thr < 100) {
|
||||||
fg_encode(chip->sp, FG_SRAM_RECHARGE_SOC_THR,
|
rc = fg_set_recharge_soc(chip, chip->dt.recharge_soc_thr);
|
||||||
chip->dt.recharge_soc_thr, buf);
|
|
||||||
rc = fg_sram_write(chip,
|
|
||||||
chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_word,
|
|
||||||
chip->sp[FG_SRAM_RECHARGE_SOC_THR].addr_byte,
|
|
||||||
buf, chip->sp[FG_SRAM_RECHARGE_SOC_THR].len,
|
|
||||||
FG_IMA_DEFAULT);
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
pr_err("Error in writing recharge_soc_thr, rc=%d\n",
|
pr_err("Error in setting recharge_soc, rc=%d\n", rc);
|
||||||
rc);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1982,6 +2121,7 @@ static irqreturn_t fg_soc_update_irq_handler(int irq, void *data)
|
||||||
static irqreturn_t fg_delta_soc_irq_handler(int irq, void *data)
|
static irqreturn_t fg_delta_soc_irq_handler(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct fg_chip *chip = data;
|
struct fg_chip *chip = data;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (chip->cyc_ctr.en)
|
if (chip->cyc_ctr.en)
|
||||||
schedule_work(&chip->cycle_count_work);
|
schedule_work(&chip->cycle_count_work);
|
||||||
|
@ -1994,6 +2134,10 @@ static irqreturn_t fg_delta_soc_irq_handler(int irq, void *data)
|
||||||
if (chip->cl.active)
|
if (chip->cl.active)
|
||||||
fg_cap_learning_update(chip);
|
fg_cap_learning_update(chip);
|
||||||
|
|
||||||
|
rc = fg_charge_full_update(chip);
|
||||||
|
if (rc < 0)
|
||||||
|
pr_err("Error in charge_full_update, rc=%d\n", rc);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2416,6 +2560,8 @@ static int fg_parse_dt(struct fg_chip *chip)
|
||||||
else if (temp > BTEMP_DELTA_LOW && temp <= BTEMP_DELTA_HIGH)
|
else if (temp > BTEMP_DELTA_LOW && temp <= BTEMP_DELTA_HIGH)
|
||||||
chip->dt.batt_temp_delta = temp;
|
chip->dt.batt_temp_delta = temp;
|
||||||
|
|
||||||
|
chip->dt.hold_soc_while_full = of_property_read_bool(node,
|
||||||
|
"qcom,hold-soc-while-full");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue