drivers: power: supply: import xiaomi changes

Signed-off-by: UtsavBalar1231 <utsavbalar1231@gmail.com>
This commit is contained in:
UtsavBalar1231
2019-12-01 12:20:45 +05:30
parent f72c4531a4
commit 62e6edac0c
26 changed files with 8434 additions and 143 deletions

View File

@@ -610,6 +610,11 @@ config CHARGER_RT9455
help
Say Y to enable support for Richtek RT9455 battery charger.
config CHARGER_NU1618
tristate "nuvolta nu1618 wireless charger driver"
help
say y here to enable support for nu1618 charger driver.
source "drivers/power/supply/qcom/Kconfig"
endif # POWER_SUPPLY

View File

@@ -82,4 +82,5 @@ obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o
obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o
obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o
obj-$(CONFIG_CHARGER_NU1618) += rx1618.o
obj-$(CONFIG_ARCH_QCOM) += qcom/

View File

@@ -354,7 +354,7 @@ static int __power_supply_is_system_supplied(struct device *dev, void *data)
unsigned int *count = data;
(*count)++;
if (psy->desc->type != POWER_SUPPLY_TYPE_BATTERY)
if ((psy->desc->type != POWER_SUPPLY_TYPE_BATTERY) && (psy->desc->type != POWER_SUPPLY_TYPE_BMS))
if (!psy->desc->get_property(psy, POWER_SUPPLY_PROP_ONLINE,
&ret))
return ret.intval;

View File

@@ -113,6 +113,8 @@ static void power_supply_remove_bat_triggers(struct power_supply *psy)
static void power_supply_update_gen_leds(struct power_supply *psy)
{
/* xiaomi project don't support this feature, return skip this feature*/
#if 0
union power_supply_propval online;
if (power_supply_get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online))
@@ -124,6 +126,7 @@ static void power_supply_update_gen_leds(struct power_supply *psy)
led_trigger_event(psy->online_trig, LED_FULL);
else
led_trigger_event(psy->online_trig, LED_OFF);
#endif
}
static int power_supply_create_gen_triggers(struct power_supply *psy)

View File

@@ -46,7 +46,7 @@ static const char * const power_supply_type_text[] = {
"USB_PD", "USB_PD_DRP", "BrickID",
"USB_HVDCP", "USB_HVDCP_3", "USB_HVDCP_3P5", "Wireless", "USB_FLOAT",
"BMS", "Parallel", "Main", "Wipower", "USB_C_UFP", "USB_C_DFP",
"Charge_Pump",
"Charge_Pump","ZIMI_CAR_POWER"
};
static const char * const power_supply_status_text[] = {
@@ -164,6 +164,21 @@ static ssize_t power_supply_show_property(struct device *dev,
if (off == POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT)
return sprintf(buf, "%lld\n", value.int64val);
else if (off == POWER_SUPPLY_PROP_WIRELESS_VERSION)
return scnprintf(buf, PAGE_SIZE, "0x%x\n",
value.intval);
else if (off == POWER_SUPPLY_PROP_WIRELESS_WAKELOCK)
return scnprintf(buf, PAGE_SIZE, "%d\n",
value.intval);
else if (off == POWER_SUPPLY_PROP_SIGNAL_STRENGTH)
return scnprintf(buf, PAGE_SIZE, "%d\n",
value.intval);
else if (off == POWER_SUPPLY_PROP_WIRELESS_CP_EN)
return scnprintf(buf, PAGE_SIZE, "%d\n",
value.intval);
else if (off == POWER_SUPPLY_PROP_TYPE_RECHECK)
return scnprintf(buf, PAGE_SIZE, "0x%x\n",
value.intval);
else
return sprintf(buf, "%d\n", value.intval);
}
@@ -295,6 +310,8 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(charge_enabled),
POWER_SUPPLY_ATTR(set_ship_mode),
POWER_SUPPLY_ATTR(real_type),
POWER_SUPPLY_ATTR(hvdcp3_type),
POWER_SUPPLY_ATTR(quick_charge_type),
POWER_SUPPLY_ATTR(charge_now_raw),
POWER_SUPPLY_ATTR(charge_now_error),
POWER_SUPPLY_ATTR(capacity_raw),
@@ -349,6 +366,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(typec_src_rp),
POWER_SUPPLY_ATTR(pd_allowed),
POWER_SUPPLY_ATTR(pd_active),
POWER_SUPPLY_ATTR(pd_authentication),
POWER_SUPPLY_ATTR(pd_in_hard_reset),
POWER_SUPPLY_ATTR(pd_current_max),
POWER_SUPPLY_ATTR(pd_usb_suspend_supported),
@@ -372,9 +390,16 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(pd_voltage_max),
POWER_SUPPLY_ATTR(pd_voltage_min),
POWER_SUPPLY_ATTR(sdp_current_max),
POWER_SUPPLY_ATTR(dc_thermal_levels),
POWER_SUPPLY_ATTR(connector_type),
POWER_SUPPLY_ATTR(parallel_batfet_mode),
POWER_SUPPLY_ATTR(parallel_fcc_max),
POWER_SUPPLY_ATTR(wireless_version),
POWER_SUPPLY_ATTR(signal_strength),
POWER_SUPPLY_ATTR(wireless_cp_en),
POWER_SUPPLY_ATTR(wireless_power_good_en),
POWER_SUPPLY_ATTR(wireless_wakelock),
POWER_SUPPLY_ATTR(tx_adapter),
POWER_SUPPLY_ATTR(min_icl),
POWER_SUPPLY_ATTR(moisture_detected),
POWER_SUPPLY_ATTR(batt_profile_version),
@@ -390,6 +415,9 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(force_recharge),
POWER_SUPPLY_ATTR(fcc_stepper_enable),
POWER_SUPPLY_ATTR(toggle_stat),
POWER_SUPPLY_ATTR(type_recheck),
POWER_SUPPLY_ATTR(liquid_detection),
POWER_SUPPLY_ATTR(dynamic_fv_enabled),
POWER_SUPPLY_ATTR(main_fcc_max),
POWER_SUPPLY_ATTR(fg_reset),
POWER_SUPPLY_ATTR(qc_opti_disable),

View File

@@ -48,6 +48,17 @@ config SMB1355_SLAVE_CHARGER
The driver reports the charger status via the power supply framework.
A charger status change triggers an IRQ via the device STAT pin.
config IDT_P9220
tristate "idtp9220 wireless Charger"
depends on I2C
help
Say Y to include support for idtp9220 wireless Charger.
idtp9220 is a wireless battery charger.
The driver supports charger enable/disable.
The driver reports the charger status via the power supply framework.
The driver controls idtp9220 via I2C and
supports device-tree interface.
config QPNP_SMB2
tristate "SMB2 Battery Charger"
depends on MFD_SPMI_PMIC

View File

@@ -9,6 +9,7 @@ obj-$(CONFIG_QPNP_QNOVO) += qpnp-qnovo.o battery.o
obj-$(CONFIG_QPNP_QNOVO5) += qpnp-qnovo5.o battery.o
obj-$(CONFIG_QPNP_SMB5) += step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o schgm-flash.o
obj-$(CONFIG_SMB1390_CHARGE_PUMP) += smb1390-charger.o pmic-voter.o
obj-$(CONFIG_IDT_P9220) += idtp9220.o
obj-$(CONFIG_SMB1390_CHARGE_PUMP_PSY) += smb1390-charger-psy.o pmic-voter.o
obj-$(CONFIG_SMB1398_CHARGER) += smb1398-charger.o pmic-voter.o
obj-$(CONFIG_SMB358_CHARGER) += smb358-charger.o

View File

@@ -1,4 +1,5 @@
/* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
* Copyright (C) 2019 XiaoMi, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1314,6 +1315,27 @@ static int usb_icl_vote_callback(struct votable *votable, void *data,
vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0);
if (!chip->usb_psy)
chip->usb_psy = power_supply_get_by_name("usb");
if (!chip->usb_psy) {
pr_err("Couldn't get usb psy\n");
return -ENODEV;
}
rc = power_supply_get_property(chip->usb_psy,
POWER_SUPPLY_PROP_SMB_EN_REASON, &pval);
if (rc < 0) {
pr_err("Couldn't get cp reason rc=%d\n", rc);
return rc;
}
if (chip->cp_ilim_votable) {
if (pval.intval != POWER_SUPPLY_CP_WIRELESS)
vote(chip->cp_ilim_votable, ICL_CHANGE_VOTER, true, icl_ua);
else
vote(chip->cp_ilim_votable, ICL_CHANGE_VOTER, false, 0);
}
/* Configure ILIM based on AICL result only if input mode is USBMID */
if (cp_get_parallel_mode(chip, PARALLEL_INPUT_MODE)
== POWER_SUPPLY_PL_USBMID_USBMID)

View File

@@ -1,4 +1,5 @@
/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
* Copyright (C) 2019 XiaoMi, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -277,7 +278,28 @@ int get_cycle_counts(struct cycle_counter *counter, const char **buf)
return 0;
}
/**
/**
* set_cycle_count -
* @counter: Cycle counter object
* @value: The cycle count value to be set
*
* Get average cycle count for all buckets
*
*/
int set_cycle_count(struct cycle_counter *counter, u16 count)
{
int rc, id;
for (id = 0; id < BUCKET_COUNT; id++) {
rc = counter->store_count(counter->data, &count, id, 2);
if (rc < 0)
pr_err("failed to clear cycle counter rc=%d\n", rc);
}
return 0;
}
/**
* cycle_count_init -
* @counter: Cycle counter object
*

View File

@@ -1,4 +1,5 @@
/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
* Copyright (C) 2019 XiaoMi, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -157,6 +158,7 @@ void cycle_count_update(struct cycle_counter *counter, int batt_soc,
int charge_status, bool charge_done, bool input_present);
int get_cycle_count(struct cycle_counter *counter, int *count);
int get_cycle_counts(struct cycle_counter *counter, const char **buf);
int set_cycle_count(struct cycle_counter *counter, u16 count);
int cycle_count_init(struct cycle_counter *counter);
void cap_learning_abort(struct cap_learning *cl);
void cap_learning_update(struct cap_learning *cl, int batt_temp,

View File

@@ -1,4 +1,5 @@
/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
* Copyright (C) 2019 XiaoMi, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -92,12 +93,22 @@
#define FULL_CAPACITY 100
#define FULL_SOC_RAW 255
#define FULL_SOC_REPORT_THR 250
#define DEBUG_BATT_SOC 67
#define BATT_MISS_SOC 50
#define ESR_SOH_SOC 50
#define EMPTY_SOC 0
#define VBAT_RESTART_FG_EMPTY_UV 3700000
#define TEMP_THR_RESTART_FG 150
#define RESTART_FG_START_WORK_MS 1000
#define RESTART_FG_WORK_MS 2000
#define EMPTY_REPORT_SOC 1
#define VBAT_CRITICAL_LOW_THR 2800
#define EMPTY_DEBOUNCE_TIME_COUNT_MAX 5
enum prof_load_status {
PROFILE_MISSING,
PROFILE_LOADED,
@@ -333,6 +344,7 @@ struct fg_batt_props {
int float_volt_uv;
int vbatt_full_mv;
int fastchg_curr_ma;
int nom_cap_uah;
int *therm_coeffs;
int therm_ctr_offset;
int therm_pull_up_kohms;
@@ -480,6 +492,8 @@ struct fg_dev {
int last_recharge_volt_mv;
int delta_temp_irq_count;
enum esr_filter_status esr_flt_sts;
int vbatt_full_volt_uv;
int vbat_critical_low_count;
bool profile_available;
enum prof_load_status profile_load_status;
bool battery_missing;
@@ -490,8 +504,11 @@ struct fg_dev {
bool use_ima_single_mode;
bool usb_present;
bool twm_state;
bool report_full;
bool use_dma;
bool qnovo_enable;
bool empty_restart_fg;
bool input_present;
enum fg_version version;
bool suspended;
struct completion soc_update;
@@ -503,6 +520,8 @@ struct fg_dev {
struct work_struct esr_filter_work;
struct alarm esr_filter_alarm;
ktime_t last_delta_temp_time;
struct delayed_work empty_restart_fg_work;
struct delayed_work soc_work;
};
/* Debugfs data structures are below */

View File

@@ -1,4 +1,5 @@
/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
* Copyright (C) 2019 XiaoMi, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -407,7 +408,9 @@ void fg_notify_charger(struct fg_dev *fg)
}
}
if (fg->bp.fastchg_curr_ma > 0) {
fg_dbg(fg, FG_STATUS, "Notified charger on float voltage and FCC\n");
/*if (fg->bp.fastchg_curr_ma > 0) {
prop.intval = fg->bp.fastchg_curr_ma * 1000;
rc = power_supply_set_property(fg->batt_psy,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
@@ -417,7 +420,7 @@ void fg_notify_charger(struct fg_dev *fg)
rc);
return;
}
}
}*/
}
bool batt_psy_initialized(struct fg_dev *fg)
@@ -867,6 +870,8 @@ wait:
goto out;
}
out:
if (fg->empty_restart_fg)
fg->empty_restart_fg = false;
fg->fg_restarting = false;
return rc;
}
@@ -916,10 +921,17 @@ int fg_get_msoc(struct fg_dev *fg, int *msoc)
* of the values 1-254 will be scaled to 1-99. DIV_ROUND_UP will not
* be suitable here as it rounds up any value higher than 252 to 100.
*/
if (*msoc == FULL_SOC_RAW)
if ((*msoc >= FULL_SOC_REPORT_THR - 2)
&& (*msoc < FULL_SOC_RAW) && fg->report_full) {
*msoc = DIV_ROUND_CLOSEST(*msoc * FULL_CAPACITY, FULL_SOC_RAW) + 1;
if (*msoc >= FULL_CAPACITY)
*msoc = FULL_CAPACITY;
} else if (*msoc == FULL_SOC_RAW)
*msoc = 100;
else if (*msoc == 0)
*msoc = 0;
else if (*msoc >= FULL_SOC_REPORT_THR - 4 && *msoc <= FULL_SOC_REPORT_THR - 3 && fg->report_full)
*msoc = DIV_ROUND_CLOSEST(*msoc * FULL_CAPACITY, FULL_SOC_RAW);
else
*msoc = DIV_ROUND_CLOSEST((*msoc - 1) * (FULL_CAPACITY - 2),
FULL_SOC_RAW - 2) + 1;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
/* Copyright (c) 2015-2017, 2019 The Linux Foundation. All rights reserved.
* Copyright (C) 2019 XiaoMi, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -487,8 +488,15 @@ int vote(struct votable *votable, const char *client_str, bool enabled, int val)
*/
if (!votable->voted_on
|| (effective_result != votable->effective_result)) {
if (strcmp(votable->name, "FG_WS") != 0) {
pr_info("%s: current vote is now %d voted by %s,%d, previous voted %d\n",
votable->name, effective_result,
get_client_str(votable, effective_id),
effective_id, votable->effective_result);
}
votable->effective_client_id = effective_id;
votable->effective_result = effective_result;
pr_debug("%s: effective vote is now %d voted by %s,%d\n",
votable->name, effective_result,
get_client_str(votable, effective_id),

View File

@@ -23,6 +23,7 @@
#include <linux/qpnp/qpnp-pbs.h>
#include <linux/qpnp/qpnp-revid.h>
#include <linux/thermal.h>
#include <linux/syscalls.h>
#include "fg-core.h"
#include "fg-reg.h"
#include "fg-alg.h"
@@ -280,6 +281,7 @@ struct fg_gen4_chip {
struct votable *parallel_current_en_votable;
struct votable *mem_attn_irq_en_votable;
struct work_struct esr_calib_work;
struct work_struct vbat_sync_work;
struct work_struct soc_scale_work;
struct alarm esr_fast_cal_timer;
struct alarm soc_scale_alarm_timer;
@@ -332,7 +334,7 @@ struct bias_config {
int bias_kohms;
};
static int fg_gen4_debug_mask;
static int fg_gen4_debug_mask = FG_STATUS | FG_IRQ;
module_param_named(
debug_mask, fg_gen4_debug_mask, int, 0600
);
@@ -917,6 +919,18 @@ static int fg_gen4_get_prop_capacity(struct fg_dev *fg, int *val)
return 0;
}
rc = fg_get_msoc(fg, &msoc);
if (rc < 0)
return rc;
if (fg->empty_restart_fg && (msoc == 0))
msoc = EMPTY_REPORT_SOC;
if (chip->dt.linearize_soc && fg->delta_soc > 0)
*val = fg->maint_soc;
else
*val = msoc;
if (chip->soc_scale_mode) {
mutex_lock(&chip->soc_scale_lock);
*val = chip->soc_scale_msoc;
@@ -1770,6 +1784,13 @@ static int fg_gen4_get_batt_profile(struct fg_dev *fg)
fg->bp.vbatt_full_mv = -EINVAL;
}
rc = of_property_read_u32(profile_node, "qcom,nom-batt-capacity-mah",
&fg->bp.nom_cap_uah);
if (rc < 0) {
pr_err("battery nominal capacity unavailable, rc:%d\n", rc);
fg->bp.nom_cap_uah = -EINVAL;
}
if (of_find_property(profile_node, "qcom,therm-coefficients", &len)) {
len /= sizeof(u32);
if (len == BATT_THERM_NUM_COEFFS) {
@@ -2738,6 +2759,8 @@ static int fg_gen4_adjust_recharge_soc(struct fg_gen4_chip *chip)
if (is_input_present(fg)) {
if (fg->charge_done) {
if (!fg->recharge_soc_adjusted) {
if (fg->health == POWER_SUPPLY_HEALTH_GOOD)
return 0;
/* Get raw monotonic SOC for calculation */
rc = fg_get_msoc(fg, &msoc);
if (rc < 0) {
@@ -3407,6 +3430,7 @@ static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data)
int rc, vbatt_mv, msoc_raw;
s64 time_us;
schedule_work(&chip->vbat_sync_work);
rc = fg_get_battery_voltage(fg, &vbatt_mv);
if (rc < 0)
return IRQ_HANDLED;
@@ -3435,6 +3459,20 @@ static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data)
if (vbatt_mv < chip->dt.cutoff_volt_mv) {
if (chip->dt.rapid_soc_dec_en) {
/*
* Set vbat_low debounce window to avoid shutdown in low temperature and high
* current scene, we set the counter to maxium 5, if fg_vbatt_low_irq trigger
* exceed 5 times, decrease soc to 0% very rapidly.
*/
fg->vbat_critical_low_count++;
if (fg->vbat_critical_low_count < EMPTY_DEBOUNCE_TIME_COUNT_MAX
&& vbatt_mv > VBAT_CRITICAL_LOW_THR) {
pr_info("fg->vbat_critical_low_count:%d\n",
fg->vbat_critical_low_count);
if (batt_psy_initialized(fg))
power_supply_changed(fg->batt_psy);
return IRQ_HANDLED;
}
/*
* Set this flag so that slope limiter coefficient
* cannot be configured during rapid SOC decrease.
@@ -3581,6 +3619,29 @@ static irqreturn_t fg_delta_bsoc_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
static bool fg_is_input_suspend(struct fg_dev *fg)
{
int rc = 0;
union power_supply_propval prop = {0, };
int input_suspend = 0;
if (fg->batt_psy) {
rc = power_supply_get_property(fg->batt_psy,
POWER_SUPPLY_PROP_INPUT_SUSPEND,
&prop);
if (rc < 0) {
pr_err("Error in getting input suspend property, rc=%d\n", rc);
return false;
}
input_suspend = prop.intval;
}
if (input_suspend == 1)
return true;
else
return false;
}
#define CENTI_FULL_SOC 10000
static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data)
{
@@ -3589,6 +3650,7 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data)
int rc, batt_soc, batt_temp, msoc_raw;
bool input_present = is_input_present(fg);
u32 batt_soc_cp;
bool input_suspend = false;
rc = fg_get_msoc_raw(fg, &msoc_raw);
if (!rc)
@@ -3597,12 +3659,15 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data)
get_batt_psy_props(fg);
input_suspend = fg_is_input_suspend(fg);
rc = fg_get_sram_prop(fg, FG_SRAM_BATT_SOC, &batt_soc);
if (rc < 0)
pr_err("Failed to read battery soc rc: %d\n", rc);
else
cycle_count_update(chip->counter, (u32)batt_soc >> 24,
fg->charge_status, fg->charge_done, input_present);
fg->charge_status, fg->charge_done,
(input_present & (!input_suspend)));
rc = fg_gen4_get_battery_temp(fg, &batt_temp);
if (rc < 0) {
@@ -4037,6 +4102,8 @@ static void pl_current_en_work(struct work_struct *work)
return;
vote(chip->parallel_current_en_votable, FG_PARALLEL_EN_VOTER, en, 0);
vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, false, 0);
}
static void pl_enable_work(struct work_struct *work)
@@ -4053,14 +4120,21 @@ static void pl_enable_work(struct work_struct *work)
vote(fg->awake_votable, ESR_FCC_VOTER, false, 0);
}
static void vbat_sync_work(struct work_struct *work)
{
pr_err("sys_sync:vbat_sync_work\n");
sys_sync();
}
static void status_change_work(struct work_struct *work)
{
struct fg_dev *fg = container_of(work,
struct fg_dev, status_change_work);
struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg);
int rc, batt_soc, batt_temp;
int rc, batt_soc, batt_temp, msoc_raw;
bool input_present, qnovo_en;
u32 batt_soc_cp;
bool input_suspend = false;
if (fg->battery_missing) {
pm_relax(fg->dev);
@@ -4085,6 +4159,16 @@ static void status_change_work(struct work_struct *work)
get_batt_psy_props(fg);
if (fg->charge_done && !fg->report_full) {
fg->report_full = true;
} else if (!fg->charge_done && fg->report_full) {
rc = fg_get_msoc_raw(fg, &msoc_raw);
if (rc < 0)
pr_err("Error in getting msoc, rc=%d\n", rc);
if (msoc_raw < FULL_SOC_REPORT_THR - 4)
fg->report_full = false;
}
rc = fg_get_sram_prop(fg, FG_SRAM_BATT_SOC, &batt_soc);
if (rc < 0) {
pr_err("Failed to read battery soc rc: %d\n", rc);
@@ -4098,9 +4182,12 @@ static void status_change_work(struct work_struct *work)
}
input_present = is_input_present(fg);
fg->input_present = input_present;
input_suspend = fg_is_input_suspend(fg);
qnovo_en = is_qnovo_en(fg);
cycle_count_update(chip->counter, (u32)batt_soc >> 24,
fg->charge_status, fg->charge_done, input_present);
fg->charge_status, fg->charge_done,
(input_present & (!input_suspend)));
batt_soc_cp = div64_u64((u64)(u32)batt_soc * CENTI_FULL_SOC,
BATT_SOC_32BIT);
@@ -4401,9 +4488,13 @@ static int fg_psy_get_property(struct power_supply *psy,
pval->intval = (int)temp;
break;
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
rc = fg_gen4_get_nominal_capacity(chip, &temp);
if (!rc)
pval->intval = (int)temp;
if (-EINVAL != fg->bp.nom_cap_uah) {
pval->intval = fg->bp.nom_cap_uah * 1000;
} else {
rc = fg_gen4_get_nominal_capacity(chip, &temp);
if (!rc)
pval->intval = (int)temp;
}
break;
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
rc = fg_gen4_get_charge_counter(chip, &pval->intval);
@@ -4537,6 +4628,10 @@ static int fg_psy_set_property(struct power_supply *psy,
if (chip->sp)
soh_profile_update(chip->sp, chip->soh);
break;
case POWER_SUPPLY_PROP_CYCLE_COUNT:
rc = set_cycle_count(chip->counter, pval->intval);
pr_info("Cycle count is modified to %d by userspace\n", pval->intval);
break;
case POWER_SUPPLY_PROP_CLEAR_SOH:
if (chip->first_profile_load && !pval->intval) {
fg_dbg(fg, FG_STATUS, "Clearing first profile load bit\n");
@@ -4560,6 +4655,11 @@ static int fg_psy_set_property(struct power_supply *psy,
chip->batt_age_level = pval->intval;
schedule_delayed_work(&fg->profile_load_work, 0);
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
if (fg->vbatt_full_volt_uv != pval->intval)
rc = fg_set_constant_chg_voltage(fg, pval->intval);
fg->vbatt_full_volt_uv = pval->intval;
break;
case POWER_SUPPLY_PROP_CALIBRATE:
rc = fg_gen4_set_calibrate_level(chip, pval->intval);
break;
@@ -4580,8 +4680,10 @@ static int fg_property_is_writeable(struct power_supply *psy,
case POWER_SUPPLY_PROP_ESR_ACTUAL:
case POWER_SUPPLY_PROP_ESR_NOMINAL:
case POWER_SUPPLY_PROP_SOH:
case POWER_SUPPLY_PROP_CYCLE_COUNT:
case POWER_SUPPLY_PROP_CLEAR_SOH:
case POWER_SUPPLY_PROP_BATT_AGE_LEVEL:
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
case POWER_SUPPLY_PROP_CALIBRATE:
return 1;
default:
@@ -4614,6 +4716,7 @@ static enum power_supply_property fg_psy_props[] = {
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_COUNTER,
POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW,
POWER_SUPPLY_PROP_CYCLE_COUNT,
POWER_SUPPLY_PROP_CYCLE_COUNTS,
POWER_SUPPLY_PROP_SOC_REPORTING_READY,
POWER_SUPPLY_PROP_CLEAR_SOH,
@@ -4745,6 +4848,7 @@ static int fg_parallel_current_en_cb(struct votable *votable, void *data,
return rc;
val = enable ? SMB_MEASURE_EN_BIT : 0;
mask = SMB_MEASURE_EN_BIT;
rc = fg_masked_write(fg, BATT_INFO_FG_CNV_CHAR_CFG(fg), mask, val);
if (rc < 0)
@@ -4754,6 +4858,8 @@ static int fg_parallel_current_en_cb(struct votable *votable, void *data,
vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, false, 0);
fg_dbg(fg, FG_STATUS, "Parallel current summing: %d\n", enable);
/*vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, false, 0);*/
return rc;
}
@@ -5612,7 +5718,7 @@ static int fg_gen4_parse_nvmem_dt(struct fg_gen4_chip *chip)
#define DEFAULT_CL_MAX_LIM_DECIPERC 0
#define DEFAULT_CL_DELTA_BATT_SOC 10
#define BTEMP_DELTA_LOW 0
#define BTEMP_DELTA_HIGH 3
#define BTEMP_DELTA_HIGH 10
#define DEFAULT_ESR_PULSE_THRESH_MA 47
#define DEFAULT_ESR_MEAS_CURR_MA 120
#define DEFAULT_SCALE_VBATT_THR_MV 3400
@@ -5946,6 +6052,116 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip)
return 0;
}
#define SOC_WORK_MS 20000
static void soc_work_fn(struct work_struct *work)
{
struct fg_dev *fg = container_of(work,
struct fg_dev, soc_work.work);
struct fg_gen4_chip *chip = container_of(fg,
struct fg_gen4_chip, fg);
int msoc = 0, soc = 0, curr_ua = 0, volt_uv = 0, temp = 0;
int esr_uohms = 0;
int cycle_count;
int rc;
static int prev_soc = -EINVAL;
rc = fg_gen4_get_prop_capacity(fg, &soc);
if (rc < 0)
pr_err("Error in getting capacity, rc=%d\n", rc);
rc = fg_get_msoc_raw(fg, &msoc);
if (rc < 0)
pr_err("Error in getting msoc, rc=%d\n", rc);
rc = fg_get_battery_resistance(fg, &esr_uohms);
if (rc < 0)
pr_err("Error in getting esr_uohms, rc=%d\n", rc);
fg_get_battery_current(fg, &curr_ua);
if (rc < 0)
pr_err("failed to get current, rc=%d\n", rc);
rc = fg_get_battery_voltage(fg, &volt_uv);
if (rc < 0)
pr_err("failed to get voltage, rc=%d\n", rc);
rc = fg_gen4_get_battery_temp(fg, &temp);
if (rc < 0)
pr_err("Error in getting batt_temp, rc=%d\n", rc);
rc = get_cycle_count(chip->counter, &cycle_count);
if (rc < 0)
pr_err("failed to get cycle count, rc=%d\n", rc);
pr_info("adjust_soc: s %d r %d i %d v %d t %d cc %d m 0x%02x\n",
soc,
esr_uohms,
curr_ua/1000,
volt_uv/1000,
temp,
cycle_count,
msoc);
if (temp < 450 && fg->last_batt_temp >= 450) {
/* follow the way that fg_notifier_cb use wake lock */
pm_stay_awake(fg->dev);
schedule_work(&fg->status_change_work);
}
fg->last_batt_temp = temp;
/* if soc changes, report power supply changed uevent */
if (soc != prev_soc) {
if (fg->batt_psy)
power_supply_changed(fg->batt_psy);
prev_soc = soc;
}
schedule_delayed_work(
&fg->soc_work,
msecs_to_jiffies(SOC_WORK_MS));
}
static void empty_restart_fg_work(struct work_struct *work)
{
struct fg_dev *fg = container_of(work, struct fg_dev,
empty_restart_fg_work.work);
union power_supply_propval prop = {0, };
int usb_present = 0;
int rc;
if (usb_psy_initialized(fg)) {
rc = power_supply_get_property(fg->usb_psy,
POWER_SUPPLY_PROP_PRESENT, &prop);
if (rc < 0) {
pr_err("Couldn't read usb present prop rc=%d\n", rc);
return;
}
usb_present = prop.intval;
}
/* only when usb is absent, restart fg */
if (!usb_present) {
if (fg->profile_load_status == PROFILE_LOADED) {
pr_info("soc empty after cold to warm, need to restart fg\n");
fg->empty_restart_fg = true;
rc = fg_restart(fg, SOC_READY_WAIT_TIME_MS);
if (rc < 0) {
pr_err("Error in restarting FG, rc=%d\n", rc);
fg->empty_restart_fg = false;
return;
}
pr_info("FG restart done\n");
if (batt_psy_initialized(fg))
power_supply_changed(fg->batt_psy);
} else {
schedule_delayed_work(
&fg->empty_restart_fg_work,
msecs_to_jiffies(RESTART_FG_WORK_MS));
}
}
}
static void fg_gen4_cleanup(struct fg_gen4_chip *chip)
{
struct fg_dev *fg = &chip->fg;
@@ -5957,7 +6173,9 @@ static void fg_gen4_cleanup(struct fg_gen4_chip *chip)
fg_gen4_exit_soc_scale(chip);
cancel_delayed_work_sync(&fg->profile_load_work);
cancel_delayed_work_sync(&fg->empty_restart_fg_work);
cancel_delayed_work_sync(&fg->sram_dump_work);
cancel_delayed_work_sync(&fg->soc_work);
cancel_work_sync(&chip->pl_current_en_work);
power_supply_unreg_notifier(&fg->nb);
@@ -5981,6 +6199,35 @@ static void fg_gen4_cleanup(struct fg_gen4_chip *chip)
dev_set_drvdata(fg->dev, NULL);
}
#define IBAT_OLD_WORD 317
#define IBAT_OLD_OFFSET 0
#define BATT_CURRENT_NUMR 488281
#define BATT_CURRENT_DENR 1000
int fg_get_batt_isense(struct fg_dev *fg, int *val)
{
int rc;
u8 buf[2];
int64_t temp = 0;
rc = fg_sram_read(fg, IBAT_OLD_WORD, IBAT_OLD_OFFSET, buf, 2,
FG_IMA_DEFAULT);
if (rc < 0) {
pr_err("Error in reading %04x[%d] rc=%d\n", IBAT_OLD_WORD,
IBAT_OLD_OFFSET, rc);
return rc;
}
temp = buf[0] | buf[1] << 8;
/* Sign bit is bit 15 */
temp = sign_extend32(temp, 15);
*val = div_s64((s64)temp * BATT_CURRENT_NUMR, BATT_CURRENT_DENR);
pr_info("read batt isense: %d[%d]%d\n",
(*val)/10, *val, (*val)/1000);
return 0;
}
static void fg_gen4_post_init(struct fg_gen4_chip *chip)
{
int i;
@@ -6030,6 +6277,8 @@ static int fg_gen4_probe(struct platform_device *pdev)
chip->ki_coeff_full_soc[0] = -EINVAL;
chip->ki_coeff_full_soc[1] = -EINVAL;
chip->esr_soh_cycle_count = -EINVAL;
fg->vbat_critical_low_count = 0;
fg->vbatt_full_volt_uv = 0;
chip->calib_level = -EINVAL;
fg->regmap = dev_get_regmap(fg->dev->parent, NULL);
if (!fg->regmap) {
@@ -6047,9 +6296,12 @@ static int fg_gen4_probe(struct platform_device *pdev)
init_completion(&chip->mem_attn);
INIT_WORK(&fg->status_change_work, status_change_work);
INIT_WORK(&chip->esr_calib_work, esr_calib_work);
INIT_WORK(&chip->vbat_sync_work, vbat_sync_work);
INIT_WORK(&chip->soc_scale_work, soc_scale_work);
INIT_DELAYED_WORK(&fg->profile_load_work, profile_load_work);
INIT_DELAYED_WORK(&fg->sram_dump_work, sram_dump_work);
INIT_DELAYED_WORK(&fg->soc_work, soc_work_fn);
INIT_DELAYED_WORK(&fg->empty_restart_fg_work, empty_restart_fg_work);
INIT_DELAYED_WORK(&chip->pl_enable_work, pl_enable_work);
INIT_WORK(&chip->pl_current_en_work, pl_current_en_work);
@@ -6226,6 +6478,12 @@ static int fg_gen4_probe(struct platform_device *pdev)
if (!fg->battery_missing)
schedule_delayed_work(&fg->profile_load_work, 0);
schedule_delayed_work(&fg->soc_work, 0);
if ((volt_uv >= VBAT_RESTART_FG_EMPTY_UV)
&& (msoc == 0) && (batt_temp >= TEMP_THR_RESTART_FG))
schedule_delayed_work(&fg->empty_restart_fg_work,
msecs_to_jiffies(RESTART_FG_START_WORK_MS));
fg_gen4_post_init(chip);
pr_debug("FG GEN4 driver probed successfully\n");
@@ -6247,7 +6505,7 @@ static void fg_gen4_shutdown(struct platform_device *pdev)
{
struct fg_gen4_chip *chip = dev_get_drvdata(&pdev->dev);
struct fg_dev *fg = &chip->fg;
int rc, bsoc;
int rc, bsoc, msoc;
fg_unregister_interrupts(fg, chip, FG_GEN4_IRQ_MAX);
@@ -6261,13 +6519,19 @@ static void fg_gen4_shutdown(struct platform_device *pdev)
rc);
}
rc = fg_gen4_get_prop_capacity(fg, &msoc);
if (rc < 0) {
pr_err("Error in getting capacity, rc=%d\n", rc);
return;
}
rc = fg_get_sram_prop(fg, FG_SRAM_BATT_SOC, &bsoc);
if (rc < 0) {
pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
return;
}
if (fg->charge_full) {
if (fg->charge_full || (msoc == 100)) {
/* We need 2 most significant bytes here */
bsoc = (u32)bsoc >> 16;
@@ -6291,6 +6555,7 @@ static int fg_gen4_suspend(struct device *dev)
struct fg_gen4_chip *chip = dev_get_drvdata(dev);
struct fg_dev *fg = &chip->fg;
cancel_delayed_work_sync(&fg->soc_work);
cancel_delayed_work_sync(&chip->ttf->ttf_work);
if (fg_sram_dump)
cancel_delayed_work_sync(&fg->sram_dump_work);
@@ -6301,11 +6566,18 @@ static int fg_gen4_resume(struct device *dev)
{
struct fg_gen4_chip *chip = dev_get_drvdata(dev);
struct fg_dev *fg = &chip->fg;
int val = 0;
if (!fg->input_present)
fg_get_batt_isense(fg, &val);
schedule_delayed_work(
&fg->soc_work, msecs_to_jiffies(SOC_WORK_MS));
schedule_delayed_work(&chip->ttf->ttf_work, 0);
if (fg_sram_dump)
schedule_delayed_work(&fg->sram_dump_work,
msecs_to_jiffies(fg_sram_dump_period_ms));
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
/* Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
* Copyright (C) 2019 XiaoMi, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -87,6 +88,7 @@
#define ILIM_VOTER "ILIM_VOTER"
#define FCC_VOTER "FCC_VOTER"
#define ICL_VOTER "ICL_VOTER"
#define ICL_CHANGE_VOTER "ICL_CHANGE_VOTER"
#define TAPER_END_VOTER "TAPER_END_VOTER"
#define WIRELESS_VOTER "WIRELESS_VOTER"
#define SRC_VOTER "SRC_VOTER"
@@ -139,6 +141,7 @@ struct smb1390 {
int irqs[NUM_IRQS];
bool status_change_running;
bool taper_work_running;
bool taper_early_trigger;
struct smb1390_iio iio;
int irq_status;
int taper_entry_fv;
@@ -343,6 +346,20 @@ static ssize_t stat2_show(struct class *c, struct class_attribute *attr,
}
static CLASS_ATTR_RO(stat2);
static ssize_t model_name_show(struct class *c, struct class_attribute *attr,
char *buf)
{
struct smb1390 *chip = container_of(c, struct smb1390, cp_class);
int rc, val;
rc = smb1390_read(chip, CORE_STATUS1_REG, &val);
if (rc < 0)
return snprintf(buf, PAGE_SIZE, "%s\n", "unknown");
else
return snprintf(buf, PAGE_SIZE, "%s\n", "smb1390");
}
static CLASS_ATTR_RO(model_name);
static ssize_t enable_show(struct class *c, struct class_attribute *attr,
char *buf)
{
@@ -469,6 +486,7 @@ static struct attribute *cp_class_attrs[] = {
&class_attr_toggle_switcher.attr,
&class_attr_die_temp.attr,
&class_attr_isns.attr,
&class_attr_model_name.attr,
NULL,
};
ATTRIBUTE_GROUPS(cp_class);
@@ -519,11 +537,11 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data,
}
/* ILIM less than 1A is not accurate; disable charging */
if (ilim_uA < 1000000) {
pr_debug("ILIM %duA is too low to allow charging\n", ilim_uA);
if (ilim_uA < 900000) {
pr_info("ILIM %duA is too low to allow charging\n", ilim_uA);
vote(chip->disable_votable, ILIM_VOTER, true, 0);
} else {
pr_debug("setting ILIM to %duA\n", ilim_uA);
pr_info("setting ILIM to %duA\n", ilim_uA);
rc = smb1390_masked_write(chip, CORE_FTRIM_ILIM_REG,
CFG_ILIM_MASK,
DIV_ROUND_CLOSEST(ilim_uA - 500000, 100000));
@@ -575,12 +593,17 @@ static int smb1390_notifier_cb(struct notifier_block *nb,
return NOTIFY_OK;
}
#define TAPER_CAPACITY_THR 55
#define TAPER_CAPCITY_DELTA 1
#define BATT_COOL_THR 220
static void smb1390_status_change_work(struct work_struct *work)
{
struct smb1390 *chip = container_of(work, struct smb1390,
status_change_work);
union power_supply_propval pval = {0, };
int max_fcc_ma, rc;
int capacity, batt_temp, charge_type;
if (!is_psy_voter_available(chip))
goto out;
@@ -612,6 +635,7 @@ static void smb1390_status_change_work(struct work_struct *work)
*/
if (pval.intval == POWER_SUPPLY_CP_WIRELESS) {
vote(chip->ilim_votable, ICL_VOTER, false, 0);
vote(chip->ilim_votable, ICL_CHANGE_VOTER, false, 0);
rc = power_supply_get_property(chip->dc_psy,
POWER_SUPPLY_PROP_CURRENT_MAX, &pval);
if (rc < 0)
@@ -650,6 +674,49 @@ static void smb1390_status_change_work(struct work_struct *work)
if (get_effective_result(chip->disable_votable))
goto out;
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_CAPACITY, &pval);
if (rc < 0) {
pr_err("Couldn't get batt capacity rc=%d\n", rc);
goto out;
}
capacity = pval.intval;
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_TEMP, &pval);
if (rc < 0) {
pr_err("Couldn't get batt temp rc=%d\n", rc);
goto out;
}
batt_temp = pval.intval;
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
if (rc < 0) {
pr_err("Couldn't get charge type rc=%d\n", rc);
goto out;
}
charge_type = pval.intval;
pr_info("capacity:%d, batt_temp:%d, charge_type:%d\n",
capacity, batt_temp, charge_type);
if ((capacity < TAPER_CAPACITY_THR)
&& (batt_temp >= BATT_COOL_THR)
&& (charge_type == POWER_SUPPLY_CHARGE_TYPE_FAST)
&& chip->taper_early_trigger) {
if (is_client_vote_enabled(chip->fcc_votable,
CP_VOTER)) {
/* reset cp_voter here */
vote(chip->fcc_votable, CP_VOTER, false, 0);
/* input current is always half the charge current */
vote(chip->ilim_votable, FCC_VOTER, true,
get_effective_result(chip->fcc_votable) / 2);
chip->taper_early_trigger = false;
}
}
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
if (rc < 0) {
@@ -673,6 +740,7 @@ static void smb1390_status_change_work(struct work_struct *work)
BATT_PROFILE_VOTER);
vote(chip->fcc_votable, CP_VOTER,
max_fcc_ma > 0 ? true : false, max_fcc_ma);
chip->taper_early_trigger = false;
vote(chip->disable_votable, SOC_LEVEL_VOTER, true, 0);
}
@@ -686,12 +754,24 @@ static void smb1390_taper_work(struct work_struct *work)
struct smb1390 *chip = container_of(work, struct smb1390, taper_work);
union power_supply_propval pval = {0, };
int rc, fcc_uA;
int capacity;
if (!is_psy_voter_available(chip))
goto out;
chip->taper_entry_fv = get_effective_result(chip->fv_votable);
while (true) {
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_CAPACITY, &pval);
if (rc < 0) {
pr_err("Couldn't get batt capacity rc=%d\n", rc);
goto out;
}
capacity = pval.intval;
if ((capacity < (TAPER_CAPACITY_THR - TAPER_CAPCITY_DELTA))
&& !chip->taper_early_trigger)
chip->taper_early_trigger = true;
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
if (rc < 0) {
@@ -794,7 +874,7 @@ static void smb1390_destroy_votables(struct smb1390 *chip)
static int smb1390_init_hw(struct smb1390 *chip)
{
int rc;
int rc, val;
/*
* charge pump is initially disabled; this indirectly votes to allow
@@ -820,6 +900,15 @@ static int smb1390_init_hw(struct smb1390 *chip)
if (rc < 0)
return rc;
rc = smb1390_read(chip, 0x1032, &val);
pr_err("default smb1390 400K 0x1032_REG: 0x%x\n", val);
rc = smb1390_masked_write(chip, 0x1032, 0x0F, 0x07);
rc = smb1390_read(chip, 0x1032, &val);
pr_err("modify smb1390 800K 0x1032_REG: 0x%x\n", val);
if (rc < 0)
return rc;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
/* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
* Copyright (C) 2019 XiaoMi, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -32,6 +33,7 @@ enum print_reason {
PR_PARALLEL = BIT(3),
PR_OTG = BIT(4),
PR_WLS = BIT(5),
PR_OEM = BIT(6),
};
#define DEFAULT_VOTER "DEFAULT_VOTER"
@@ -61,14 +63,25 @@ enum print_reason {
#define OTG_DELAY_VOTER "OTG_DELAY_VOTER"
#define USBIN_I_VOTER "USBIN_I_VOTER"
#define WEAK_CHARGER_VOTER "WEAK_CHARGER_VOTER"
#define OTG_VOTER "OTG_VOTER"
#define PL_FCC_LOW_VOTER "PL_FCC_LOW_VOTER"
#define WBC_VOTER "WBC_VOTER"
#define HW_LIMIT_VOTER "HW_LIMIT_VOTER"
#define CHG_AWAKE_VOTER "CHG_AWAKE_VOTER"
#define DCIN_ADAPTER_VOTER "DCIN_ADAPTER_VOTER"
#define DCIN_LIMIT_VOTER "DCIN_LIMIT_VOTER"
#define PL_SMB_EN_VOTER "PL_SMB_EN_VOTER"
#define FORCE_RECHARGE_VOTER "FORCE_RECHARGE_VOTER"
#define LPD_VOTER "LPD_VOTER"
#define DC_AWAKE_VOTER "DC_AWAKE_VOTER"
#define DC_UV_AWAKE_VOTER "DC_UV_AWAKE_VOTER"
#define CLASSA_QC_FCC_VOTER "CLASSA_QC_FCC_VOTER"
#define QC_A_CP_ICL_MAX_VOTER "QC_A_CP_ICL_MAX_VOTER"
#define JEITA_VOTER "JEITA_VOTER"
#define FCC_STEPPER_VOTER "FCC_STEPPER_VOTER"
#define SW_THERM_REGULATION_VOTER "SW_THERM_REGULATION_VOTER"
#define LIQUID_DETECTION_VOTER "LIQUID_DETECTION_VOTER"
#define QC2_UNSUPPORTED_VOTER "QC2_UNSUPPORTED_VOTER"
#define JEITA_ARB_VOTER "JEITA_ARB_VOTER"
#define MOISTURE_VOTER "MOISTURE_VOTER"
#define HVDCP2_ICL_VOTER "HVDCP2_ICL_VOTER"
@@ -86,10 +99,48 @@ enum print_reason {
#define MAIN_FCC_VOTER "MAIN_FCC_VOTER"
#define DCIN_AICL_VOTER "DCIN_AICL_VOTER"
#define OVERHEAT_LIMIT_VOTER "OVERHEAT_LIMIT_VOTER"
#define PD_VERIFED_VOTER "PD_VERIFED_VOTER"
#define BOOST_BACK_STORM_COUNT 3
#define WEAK_CHG_STORM_COUNT 8
#define VOL_THR_FOR_QC_CLASS_AB 12300000
#define COMP_FOR_LOW_RESISTANCE_CABLE 100000
#define QC_CLASS_A_CURRENT_UA 3600000
#define HVDCP_CLASS_A_MAX_UA 2500000
#define HVDCP_CLASS_A_FOR_CP_UA 2000000
#define MAX_PULSE 38
#define MAX_PLUSE_COUNT_ALLOWED 30
#define HIGH_NUM_PULSE_THR 12
#define PD_UNVERIFED_CURRENT 3000000
/* thermal micros */
#define MAX_TEMP_LEVEL 16
/* percent of ICL compared to base 5V for different PD voltage_min voltage */
#define PD_6P5V_PERCENT 85
#define PD_7P5V_PERCENT 75
#define PD_8P5V_PERCENT 70
#define PD_9V_PERCENT 65
#define PD_MICRO_5V 5000000
#define PD_MICRO_5P9V 5900000
#define PD_MICRO_6P5V 6500000
#define PD_MICRO_7P5V 7500000
#define PD_MICRO_8P5V 8500000
#define PD_MICRO_9V 9000000
#define ICL_LIMIT_LEVEL_THR 8
#define QC2_UNSUPPORTED_UA 1800000
/* defined for HVDCP2 */
#define HVDCP2_CURRENT_UA 1500000
/* defined for charger type recheck */
#define CHARGER_RECHECK_DELAY_MS 30000
#define TYPE_RECHECK_TIME_5S 5000
#define TYPE_RECHECK_COUNT 3
/* defined for un_compliant Type-C cable */
#define CC_UN_COMPLIANT_START_DELAY_MS 700
#define VBAT_TO_VRAW_ADC(v) div_u64((u64)v * 1000000UL, 194637UL)
#define ITERM_LIMITS_PMI632_MA 5000
@@ -99,8 +150,8 @@ enum print_reason {
#define SDP_100_MA 100000
#define SDP_CURRENT_UA 500000
#define CDP_CURRENT_UA 1500000
#define DCP_CURRENT_UA 1500000
#define HVDCP_CURRENT_UA 3000000
#define DCP_CURRENT_UA 1600000
#define HVDCP_CURRENT_UA 2800000
#define TYPEC_DEFAULT_CURRENT_UA 900000
#define TYPEC_MEDIUM_CURRENT_UA 1500000
#define TYPEC_HIGH_CURRENT_UA 3000000
@@ -108,6 +159,24 @@ enum print_reason {
#define DCIN_ICL_MAX_UA 1500000
#define DCIN_ICL_STEP_UA 100000
/*DCIN ICL*/
#define PSNS_CURRENT_SAMPLE_RATE 1053
#define PSNS_CURRENT_SAMPLE_RESIS 392
#define PSNS_COMP_UV_FOR_HIGH_THERMAL 40000
/* cutoff voltage threshold */
#define CUTOFF_VOL_THR 3400000
#define RSBU_K_300K_UV 3000000
#define RECHARGE_SOC_THR 99
enum hvdcp3_type {
HVDCP3_NONE = 0,
HVDCP3_CLASSA_18W,
HVDCP3_CLASSB_27W,
};
#define ROLE_REVERSAL_DELAY_MS 2000
enum smb_mode {
@@ -376,6 +445,8 @@ struct smb_iio {
struct iio_channel *die_temp_chan;
struct iio_channel *skin_temp_chan;
struct iio_channel *smb_temp_chan;
struct iio_channel *hw_version_gpio5;
struct iio_channel *project_gpio6;
};
struct smb_charger {
@@ -392,6 +463,9 @@ struct smb_charger {
int otg_delay_ms;
int *weak_chg_icl_ua;
bool pd_not_supported;
bool init_once;
bool support_liquid;
bool dynamic_fv_enabled;
/* locks */
struct mutex smb_lock;
@@ -408,11 +482,17 @@ struct smb_charger {
struct power_supply *usb_psy;
struct power_supply *dc_psy;
struct power_supply *bms_psy;
struct power_supply_desc usb_psy_desc;
struct power_supply *usb_main_psy;
struct power_supply *usb_port_psy;
struct power_supply *wls_psy;
struct power_supply *idtp_psy;
struct power_supply *wip_psy;
struct power_supply *wireless_psy;
struct power_supply *wls_chip_psy;
struct power_supply *cp_psy;
enum power_supply_type real_charger_type;
enum power_supply_type wireless_charger_type;
/* dual role class */
struct dual_role_phy_instance *dual_role;
@@ -438,6 +518,7 @@ struct smb_charger {
struct votable *fcc_main_votable;
struct votable *fv_votable;
struct votable *usb_icl_votable;
struct votable *dc_icl_votable;
struct votable *awake_votable;
struct votable *pl_disable_votable;
struct votable *chg_disable_votable;
@@ -456,16 +537,22 @@ struct smb_charger {
struct work_struct moisture_protection_work;
struct work_struct chg_termination_work;
struct work_struct dcin_aicl_work;
struct work_struct lpd_disable_chg_work;
struct delayed_work ps_change_timeout_work;
struct delayed_work clear_hdc_work;
struct delayed_work icl_change_work;
struct delayed_work pl_enable_work;
struct delayed_work uusb_otg_work;
struct delayed_work bb_removal_work;
struct delayed_work raise_qc3_vbus_work;
struct delayed_work lpd_ra_open_work;
struct delayed_work lpd_detach_work;
struct delayed_work charger_type_recheck;
struct delayed_work cc_un_compliant_charge_work;
struct delayed_work reg_work;
struct delayed_work thermal_regulation_work;
struct delayed_work usbov_dbc_work;
struct delayed_work dc_plug_out_delay_work;
struct delayed_work role_reversal_check;
struct delayed_work pr_swap_detach_work;
struct delayed_work pr_lock_clear_work;
@@ -488,10 +575,13 @@ struct smb_charger {
int voltage_min_uv;
int voltage_max_uv;
int pd_active;
int pd_verifed;
bool pd_hard_reset;
bool pr_lock_in_progress;
bool pr_swap_in_progress;
bool early_usb_attach;
bool early_dc_attach;
bool batt_temp_irq_enabled;
bool ok_to_pd;
bool typec_legacy;
bool typec_irq_en;
@@ -502,13 +592,34 @@ struct smb_charger {
int boost_threshold_ua;
int system_temp_level;
int thermal_levels;
int lpd_levels;
int dc_temp_level;
int dc_thermal_levels;
#ifdef CONFIG_THERMAL
int *thermal_mitigation_dcp;
int *thermal_mitigation_qc2;
int *thermal_mitigation_pd_base;
int *thermal_mitigation_icl;
int *thermal_fcc_qc3_normal;
int *thermal_fcc_qc3_cp;
int *thermal_fcc_qc3_classb_cp;
int *thermal_fcc_pps_cp;
int *thermal_mitigation_dc;
int *lpd_hwversion;
int *thermal_mitigation_epp;
int *thermal_mitigation_bpp_qc3;
int *thermal_mitigation_bpp_qc2;
int *thermal_mitigation_bpp;
#else
int *thermal_mitigation;
#endif
int dcp_icl_ua;
int fake_capacity;
int fake_batt_status;
bool step_chg_enabled;
bool sw_jeita_enabled;
bool typec_legacy_use_rp_icl;
bool lpd_enabled;
bool is_hdc;
bool chg_done;
int connector_type;
@@ -538,6 +649,7 @@ struct smb_charger {
enum lpd_stage lpd_stage;
bool lpd_disabled;
enum lpd_reason lpd_reason;
bool lpd_status;
bool fcc_stepper_enable;
int die_temp;
int smb_temp;
@@ -545,6 +657,7 @@ struct smb_charger {
int connector_temp;
int thermal_status;
int main_fcc_max;
bool report_usb_absent;
u32 jeita_soft_thlds[2];
u32 jeita_soft_hys_thlds[2];
int jeita_soft_fcc[2];
@@ -582,6 +695,8 @@ struct smb_charger {
int qc2_max_pulses;
enum qc2_non_comp_voltage qc2_unsupported_voltage;
bool dbc_usbov;
bool fake_usb_insertion;
bool qc2_unsupported;
/* extcon for VBUS / ID notification to USB for uUSB */
struct extcon_dev *extcon;
@@ -595,6 +710,13 @@ struct smb_charger {
int die_health;
int connector_health;
/* raise qc3 vbus flag */
bool qc_class_ab;
bool is_qc_class_a;
bool is_qc_class_b;
bool raise_vbus_to_detect;
bool detect_low_power_qc3_charger;
bool high_vbus_detected;
/* flash */
u32 flash_derating_soc;
@@ -608,6 +730,31 @@ struct smb_charger {
int dcin_uv_count;
ktime_t dcin_uv_last_time;
int last_wls_vout;
int flag_dc_present;
int power_good_en;
int fake_dc_on;
int fake_dc_flag;
int last_batt_stat;
/* charger type recheck */
int recheck_charger;
int precheck_charger_type;
/* workarounds */
bool cc_un_compliant_detected;
bool snk_debug_acc_detected;
bool support_wireless;
};
enum quick_charge_type {
QUICK_CHARGE_NORMAL = 0,
QUICK_CHARGE_FAST,
QUICK_CHARGE_FLASH,
QUICK_CHARGE_TURBE,
QUICK_CHARGE_MAX,
};
struct quick_charge {
enum power_supply_type adap_type;
enum quick_charge_type adap_cap;
};
int smblib_read(struct smb_charger *chg, u16 addr, u8 *val);
@@ -626,6 +773,8 @@ int smblib_set_charge_param(struct smb_charger *chg,
int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend);
int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend);
int smblib_change_psns_to_curr(struct smb_charger *chg, int uv);
int smblib_mapping_soc_from_field_value(struct smb_chg_param *param,
int val_u, u8 *val_raw);
int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param,
@@ -647,6 +796,7 @@ int smblib_vconn_regulator_disable(struct regulator_dev *rdev);
int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev);
irqreturn_t default_irq_handler(int irq, void *data);
irqreturn_t dcin_uv_handler(int irq, void *data);
irqreturn_t smb_en_irq_handler(int irq, void *data);
irqreturn_t chg_state_change_irq_handler(int irq, void *data);
irqreturn_t batt_temp_changed_irq_handler(int irq, void *data);
@@ -685,6 +835,8 @@ int smblib_get_prop_system_temp_level(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_system_temp_level_max(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_dc_temp_level(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_input_current_limited(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_batt_iterm(struct smb_charger *chg,
@@ -697,6 +849,8 @@ int smblib_set_prop_batt_status(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_system_temp_level(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_dc_temp_level(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_input_current_limited(struct smb_charger *chg,
const union power_supply_propval *val);
@@ -716,6 +870,8 @@ int smblib_get_prop_voltage_wls_output(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_set_prop_voltage_wls_output(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_get_prop_wireless_version(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_set_prop_dc_reset(struct smb_charger *chg);
int smblib_get_prop_usb_present(struct smb_charger *chg,
union power_supply_propval *val);
@@ -807,6 +963,23 @@ int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable);
int smblib_icl_override(struct smb_charger *chg, enum icl_override_mode mode);
enum alarmtimer_restart smblib_lpd_recheck_timer(struct alarm *alarm,
ktime_t time);
int smblib_set_prop_wireless_wakelock(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_type_recheck(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_get_prop_type_recheck(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_quick_charge_type(struct smb_charger *chg);
int smblib_set_wirless_cp_enable(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_wirless_power_good_enable(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_get_prop_liquid_status(struct smb_charger *chg,
union power_supply_propval *val);
bool smblib_support_liquid_feature(struct smb_charger *chg);
int smblib_toggle_smb_en(struct smb_charger *chg, int toggle);
void smblib_hvdcp_detect_enable(struct smb_charger *chg, bool enable);
void smblib_hvdcp_exit_config(struct smb_charger *chg);

View File

@@ -1,4 +1,5 @@
/* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (C) 2019 XiaoMi, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -317,6 +318,10 @@ enum {
#define USBIN_5V_AICL_THRESHOLD_REG (USBIN_BASE + 0x81)
#define USBIN_CONT_AICL_THRESHOLD_REG (USBIN_BASE + 0x84)
#define TYPE_C_CFG_REG (USBIN_BASE + 0x58)
#define APSD_START_ON_CC_BIT BIT(7)
/********************************
* DCIN Peripheral Registers *
********************************/
@@ -327,6 +332,12 @@ enum {
#define DCIN_CMD_IL_REG (DCIN_BASE + 0x40)
#define DCIN_SUSPEND_BIT BIT(0)
#define DCIN_EN_OVERRIDE_BIT BIT(1)
#define DCIN_EN_BIT BIT(2)
#define DCIN_CMD_PULLDOWN_REG (DCIN_BASE + 0x45)
#define DCIN_PULLDOWN_EN_BIT BIT(0)
#define DCIN_MID_PULLDOWN_BIT BIT(1)
#define DCIN_EN_MASK GENMASK(2, 1)
#define DCIN_CMD_PON_REG (DCIN_BASE + 0x45)
@@ -349,6 +360,9 @@ enum {
#define SNK_RP_3P0_BIT BIT(1)
#define SNK_RP_SHORT_BIT BIT(0)
#define TYPE_C_SNK_DEBUG_ACC_STATUS_REG (TYPEC_BASE + 0x07)
#define SNK_DEBUG_ACC_RPSTD_PRSTD_BIT BIT(0)
#define TYPE_C_SRC_STATUS_REG (TYPEC_BASE + 0x08)
#define DETECTED_SNK_TYPE_MASK GENMASK(4, 0)
#define SRC_HIGH_BATT_BIT BIT(5)
@@ -400,6 +414,10 @@ enum {
#define TYPEC_CCOUT_VALUE_BIT BIT(1)
#define TYPEC_CCOUT_SRC_BIT BIT(0)
#define TYPE_C_DEBUG_ACC_SNK_CFG (TYPEC_BASE + 0x4A)
#define TYPEC_DEBUG_ACC_SNK_SEL_ICL BIT(2)
#define TYPEC_DEBUG_ACC_SNK_DIS_AICL BIT(3)
#define DEBUG_ACCESS_SRC_CFG_REG (TYPEC_BASE + 0x4C)
#define EN_UNORIENTED_DEBUG_ACCESS_SRC_BIT BIT(0)
@@ -515,6 +533,7 @@ enum {
#define WATCHDOG_TRIGGER_AFP_EN_BIT BIT(7)
#define BARK_WDOG_INT_EN_BIT BIT(6)
#define WDOG_TIMER_EN_ON_PLUGIN_BIT BIT(1)
#define WDOG_TIMER_EN_BIT BIT(0)
#define SNARL_BARK_BITE_WD_CFG_REG (MISC_BASE + 0x53)
#define BITE_WDOG_DISABLE_CHARGING_CFG_BIT BIT(7)

View File

@@ -1,4 +1,5 @@
/* Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
* Copyright (C) 2019 XiaoMi, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -22,6 +23,7 @@
#define STEP_CHG_VOTER "STEP_CHG_VOTER"
#define JEITA_VOTER "JEITA_VOTER"
#define DYNAMIC_FV_VOTER "DYNAMIC_FV_VOTER"
#define is_between(left, right, value) \
(((left) >= (right) && (left) >= (value) \
@@ -44,16 +46,24 @@ struct jeita_fv_cfg {
struct range_data fv_cfg[MAX_STEP_CHG_ENTRIES];
};
struct dynamic_fv_cfg {
char *prop_name;
struct range_data fv_cfg[MAX_STEP_CHG_ENTRIES];
};
struct step_chg_info {
struct device *dev;
ktime_t step_last_update_time;
ktime_t jeita_last_update_time;
ktime_t dynamic_fv_last_update_time;
bool step_chg_enable;
bool sw_jeita_enable;
bool dynamic_fv_enable;
bool jeita_arb_en;
bool config_is_read;
bool step_chg_cfg_valid;
bool sw_jeita_cfg_valid;
bool dynamic_fv_cfg_valid;
bool soc_based_step_chg;
bool ocv_based_step_chg;
bool vbat_avg_based_step_chg;
@@ -61,16 +71,19 @@ struct step_chg_info {
bool taper_fcc;
int jeita_fcc_index;
int jeita_fv_index;
int dynamic_fv_index;
int step_index;
int get_config_retry_count;
struct step_chg_cfg *step_chg_config;
struct jeita_fcc_cfg *jeita_fcc_config;
struct jeita_fv_cfg *jeita_fv_config;
struct dynamic_fv_cfg *dynamic_fv_config;
struct votable *fcc_votable;
struct votable *fv_votable;
struct votable *usb_icl_votable;
struct votable *dc_suspend_votable;
struct wakeup_source *step_chg_ws;
struct power_supply *batt_psy;
struct power_supply *bms_psy;
@@ -360,6 +373,17 @@ static int get_step_chg_jeita_setting_from_profile(struct step_chg_info *chip)
chip->sw_jeita_cfg_valid = false;
}
chip->dynamic_fv_cfg_valid = true;
rc = read_range_data_from_node(profile_node,
"qcom,dynamic-fv-ranges",
chip->dynamic_fv_config->fv_cfg,
BATT_HOT_DECIDEGREE_MAX, max_fv_uv);
if (rc < 0) {
pr_debug("Read qcom,dynamic-fv-ranges failed from battery profile, rc=%d\n",
rc);
chip->dynamic_fv_cfg_valid = false;
}
return rc;
}
@@ -391,16 +415,20 @@ static void get_config_work(struct work_struct *work)
chip->step_chg_config->fcc_cfg[i].high_threshold,
chip->step_chg_config->fcc_cfg[i].value);
for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++)
pr_debug("jeita-fcc-cfg: %ddecidegree ~ %ddecidegre, %duA\n",
pr_info("jeita-fcc-cfg: %ddecidegree ~ %ddecidegre, %duA\n",
chip->jeita_fcc_config->fcc_cfg[i].low_threshold,
chip->jeita_fcc_config->fcc_cfg[i].high_threshold,
chip->jeita_fcc_config->fcc_cfg[i].value);
for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++)
pr_debug("jeita-fv-cfg: %ddecidegree ~ %ddecidegre, %duV\n",
pr_info("jeita-fv-cfg: %ddecidegree ~ %ddecidegre, %duV\n",
chip->jeita_fv_config->fv_cfg[i].low_threshold,
chip->jeita_fv_config->fv_cfg[i].high_threshold,
chip->jeita_fv_config->fv_cfg[i].value);
for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++)
pr_info("dynamic-fv-cfg: %d(count) ~ %d(count), %duV\n",
chip->dynamic_fv_config->fv_cfg[i].low_threshold,
chip->dynamic_fv_config->fv_cfg[i].high_threshold,
chip->dynamic_fv_config->fv_cfg[i].value);
return;
reschedule:
@@ -417,6 +445,14 @@ static int get_val(struct range_data *range, int hysteresis, int current_index,
*new_index = -EINVAL;
/*
* As battery temperature may be below 0, range.xxx is a unsigned int, but battery
* temperature is a signed int, so cannot compare them when battery temp is below 0,
* we treat it as 0 degree when the parameter threshold(battery temp) is below 0.
*/
if (threshold < 0)
threshold = 0;
/*
* If the threshold is lesser than the minimum allowed range,
* return -ENODATA.
@@ -456,6 +492,14 @@ static int get_val(struct range_data *range, int hysteresis, int current_index,
*val = range[*new_index].value;
}
if (threshold < range[0].low_threshold) {
*new_index = 0;
*val = range[*new_index].value;
} else if (threshold > range[MAX_STEP_CHG_ENTRIES - 1].low_threshold) {
*new_index = MAX_STEP_CHG_ENTRIES - 1;
*val = range[*new_index].value;
}
/*
* If we don't have a current_index return this
* newfound value. There is no hysterisis from out of range
@@ -614,7 +658,86 @@ update_time:
return 0;
}
#define JEITA_SUSPEND_HYST_UV 50000
static int handle_dynamic_fv(struct step_chg_info *chip)
{
union power_supply_propval pval = {0, };
int rc = 0, fv_uv, cycle_count;
u64 elapsed_us;
int batt_vol = 0;
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_DYNAMIC_FV_ENABLED, &pval);
if (rc < 0)
chip->dynamic_fv_enable = 0;
else
chip->dynamic_fv_enable = pval.intval;
if (!chip->dynamic_fv_enable || !chip->dynamic_fv_cfg_valid) {
/*need recovery some setting*/
if (chip->fv_votable)
vote(chip->fv_votable, DYNAMIC_FV_VOTER, false, 0);
return 0;
}
elapsed_us = ktime_us_delta(ktime_get(), chip->dynamic_fv_last_update_time);
/* skip processing, event too early */
if (elapsed_us < STEP_CHG_HYSTERISIS_DELAY_US)
return 0;
rc = power_supply_get_property(chip->bms_psy,
POWER_SUPPLY_PROP_CYCLE_COUNT, &pval);
if (rc < 0) {
pr_err("Couldn't read %s property rc=%d\n",
chip->dynamic_fv_config->prop_name, rc);
return rc;
}
cycle_count = pval.intval;
rc = get_val(chip->dynamic_fv_config->fv_cfg,
0,
chip->dynamic_fv_index,
cycle_count,
&chip->dynamic_fv_index,
&fv_uv);
if (rc < 0) {
/* remove the vote if no step-based fv is found */
if (chip->fv_votable)
vote(chip->fv_votable, DYNAMIC_FV_VOTER, false, 0);
goto update_time;
}
power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval);
batt_vol = pval.intval;
if (batt_vol >= fv_uv) {
goto update_time;
}
chip->fv_votable = find_votable("FV");
if (!chip->fv_votable)
goto update_time;
vote(chip->fv_votable, DYNAMIC_FV_VOTER, true, fv_uv);
/*set battery full voltage to FLOAT VOLTAGE - 10mV*/
pval.intval = fv_uv - 10000;
rc = power_supply_set_property(chip->bms_psy,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, &pval);
if (rc < 0) {
pr_err("Couldn't set CONSTANT VOLTAGE property rc=%d\n", rc);
return rc;
}
pr_debug("%s:cycle_count:%d,Batt_full:%d,fv:%d,\n",
__func__, cycle_count, pval.intval, fv_uv);
update_time:
chip->dynamic_fv_last_update_time = ktime_get();
return 0;
}
/* set JEITA_SUSPEND_HYST_UV to 70mV to avoid recharge frequently when jeita warm */
#define JEITA_SUSPEND_HYST_UV 70000
static int handle_jeita(struct step_chg_info *chip)
{
union power_supply_propval pval = {0, };
@@ -635,6 +758,8 @@ static int handle_jeita(struct step_chg_info *chip)
vote(chip->fv_votable, JEITA_VOTER, false, 0);
if (chip->usb_icl_votable)
vote(chip->usb_icl_votable, JEITA_VOTER, false, 0);
if (chip->dc_suspend_votable)
vote(chip->dc_suspend_votable, JEITA_VOTER, 0, 0);
return 0;
}
@@ -692,6 +817,12 @@ static int handle_jeita(struct step_chg_info *chip)
if (!chip->usb_icl_votable)
goto set_jeita_fv;
if (!chip->dc_suspend_votable)
chip->dc_suspend_votable = find_votable("DC_SUSPEND");
if (!chip->dc_suspend_votable)
goto set_jeita_fv;
/*
* If JEITA float voltage is same as max-vfloat of battery then
* skip any further VBAT specific checks.
@@ -700,20 +831,27 @@ static int handle_jeita(struct step_chg_info *chip)
POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
if (rc || (pval.intval == fv_uv)) {
vote(chip->usb_icl_votable, JEITA_VOTER, false, 0);
vote(chip->dc_suspend_votable, JEITA_VOTER, 0, 0);
goto set_jeita_fv;
}
pr_info("%s = %d FCC = %duA FV = %duV\n",
chip->jeita_fcc_config->param.prop_name, pval.intval, fcc_ua, fv_uv);
/*
* Suspend USB input path if battery voltage is above
* JEITA VFLOAT threshold.
*/
if (chip->jeita_arb_en && fv_uv > 0) {
/* if (chip->jeita_arb_en && fv_uv > 0) { */
if (fv_uv > 0) {
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval);
if (!rc && (pval.intval > fv_uv))
if (!rc && (pval.intval > fv_uv)) {
vote(chip->usb_icl_votable, JEITA_VOTER, true, 0);
else if (pval.intval < (fv_uv - JEITA_SUSPEND_HYST_UV))
vote(chip->dc_suspend_votable, JEITA_VOTER, 1, 0);
} else if (pval.intval < (fv_uv - JEITA_SUSPEND_HYST_UV)) {
vote(chip->usb_icl_votable, JEITA_VOTER, false, 0);
vote(chip->dc_suspend_votable, JEITA_VOTER, 0, 0);
}
}
set_jeita_fv:
@@ -744,6 +882,7 @@ static int handle_battery_insertion(struct step_chg_info *chip)
if (chip->batt_missing) {
chip->step_chg_cfg_valid = false;
chip->sw_jeita_cfg_valid = false;
chip->dynamic_fv_cfg_valid = false;
chip->get_config_retry_count = 0;
} else {
/*
@@ -775,6 +914,10 @@ static void status_change_work(struct work_struct *work)
if (rc < 0)
pr_err("Couldn't handle sw jeita rc = %d\n", rc);
rc = handle_dynamic_fv(chip);
if (rc < 0)
pr_err("Couldn't handle sw dynamic fv rc = %d\n", rc);
rc = handle_step_chg_config(chip);
if (rc < 0)
pr_err("Couldn't handle step rc = %d\n", rc);
@@ -860,6 +1003,7 @@ int qcom_step_chg_init(struct device *dev,
chip->step_index = -EINVAL;
chip->jeita_fcc_index = -EINVAL;
chip->jeita_fv_index = -EINVAL;
chip->dynamic_fv_index = -EINVAL;
chip->step_chg_config = devm_kzalloc(dev,
sizeof(struct step_chg_cfg), GFP_KERNEL);
@@ -874,16 +1018,18 @@ int qcom_step_chg_init(struct device *dev,
sizeof(struct jeita_fcc_cfg), GFP_KERNEL);
chip->jeita_fv_config = devm_kzalloc(dev,
sizeof(struct jeita_fv_cfg), GFP_KERNEL);
if (!chip->jeita_fcc_config || !chip->jeita_fv_config)
chip->dynamic_fv_config = devm_kzalloc(dev,
sizeof(struct dynamic_fv_cfg), GFP_KERNEL);
if (!chip->jeita_fcc_config || !chip->jeita_fv_config || !chip->dynamic_fv_config)
return -ENOMEM;
chip->jeita_fcc_config->param.psy_prop = POWER_SUPPLY_PROP_TEMP;
chip->jeita_fcc_config->param.prop_name = "BATT_TEMP";
chip->jeita_fcc_config->param.hysteresis = 10;
chip->jeita_fcc_config->param.hysteresis = 5;
chip->jeita_fv_config->param.psy_prop = POWER_SUPPLY_PROP_TEMP;
chip->jeita_fv_config->param.prop_name = "BATT_TEMP";
chip->jeita_fv_config->param.hysteresis = 10;
chip->jeita_fv_config->param.hysteresis = 5;
chip->dynamic_fv_config->prop_name = "BATT_CYCLE_COUNT";
INIT_DELAYED_WORK(&chip->status_change_work, status_change_work);
INIT_DELAYED_WORK(&chip->get_config_work, get_config_work);

View File

@@ -1,4 +1,5 @@
/* Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
* Copyright (C) 2019 XiaoMi, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -13,7 +14,7 @@
#ifndef __STEP_CHG_H__
#define __STEP_CHG_H__
#define MAX_STEP_CHG_ENTRIES 8
#define MAX_STEP_CHG_ENTRIES 5
struct step_chg_jeita_param {
u32 psy_prop;

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -231,6 +231,8 @@ enum power_supply_property {
POWER_SUPPLY_PROP_CHARGE_ENABLED,
POWER_SUPPLY_PROP_SET_SHIP_MODE,
POWER_SUPPLY_PROP_REAL_TYPE,
POWER_SUPPLY_PROP_HVDCP3_TYPE,
POWER_SUPPLY_PROP_QUICK_CHARGE_TYPE,
POWER_SUPPLY_PROP_CHARGE_NOW_RAW,
POWER_SUPPLY_PROP_CHARGE_NOW_ERROR,
POWER_SUPPLY_PROP_CAPACITY_RAW,
@@ -285,6 +287,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_TYPEC_SRC_RP,
POWER_SUPPLY_PROP_PD_ALLOWED,
POWER_SUPPLY_PROP_PD_ACTIVE,
POWER_SUPPLY_PROP_PD_AUTHENTICATION,
POWER_SUPPLY_PROP_PD_IN_HARD_RESET,
POWER_SUPPLY_PROP_PD_CURRENT_MAX,
POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED,
@@ -308,9 +311,16 @@ enum power_supply_property {
POWER_SUPPLY_PROP_PD_VOLTAGE_MAX,
POWER_SUPPLY_PROP_PD_VOLTAGE_MIN,
POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
POWER_SUPPLY_PROP_DC_THERMAL_LEVELS,
POWER_SUPPLY_PROP_CONNECTOR_TYPE,
POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE,
POWER_SUPPLY_PROP_PARALLEL_FCC_MAX,
POWER_SUPPLY_PROP_WIRELESS_VERSION,
POWER_SUPPLY_PROP_SIGNAL_STRENGTH,
POWER_SUPPLY_PROP_WIRELESS_CP_EN,
POWER_SUPPLY_PROP_WIRELESS_POWER_GOOD_EN,
POWER_SUPPLY_PROP_WIRELESS_WAKELOCK,
POWER_SUPPLY_PROP_TX_ADAPTER,
POWER_SUPPLY_PROP_MIN_ICL,
POWER_SUPPLY_PROP_MOISTURE_DETECTED,
POWER_SUPPLY_PROP_BATT_PROFILE_VERSION,
@@ -326,6 +336,9 @@ enum power_supply_property {
POWER_SUPPLY_PROP_FORCE_RECHARGE,
POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE,
POWER_SUPPLY_PROP_TOGGLE_STAT,
POWER_SUPPLY_PROP_TYPE_RECHECK,
POWER_SUPPLY_PROP_LIQUID_DETECTION,
POWER_SUPPLY_PROP_DYNAMIC_FV_ENABLED,
POWER_SUPPLY_PROP_MAIN_FCC_MAX,
POWER_SUPPLY_PROP_FG_RESET,
POWER_SUPPLY_PROP_QC_OPTI_DISABLE,
@@ -394,6 +407,7 @@ enum power_supply_type {
POWER_SUPPLY_TYPE_UFP, /* Type-C UFP */
POWER_SUPPLY_TYPE_DFP, /* Type-C DFP */
POWER_SUPPLY_TYPE_CHARGE_PUMP, /* Charge Pump */
POWER_SUPPLY_TYPE_ZIMI_CAR_POWER, /* Zimi Car chargr */
};
/* Indicates USB Type-C CC connection status */