summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Peng <robinpeng@google.com>2022-11-10 11:30:08 +0000
committerRobin Peng <robinpeng@google.com>2022-11-10 11:30:08 +0000
commit2437e5ee64944692e67787ebe88c7a784c3536ef (patch)
tree11065270c6b08c9824c09b172ff37230ef4b64bb
parent017b15a47bd025e83510af236cb07a8a4490a789 (diff)
parent28c0ac0f85c1ffa9eaa032be17c02cd2afdce059 (diff)
downloadbms-2437e5ee64944692e67787ebe88c7a784c3536ef.tar.gz
Merge android13-gs-pixel-5.15 into android14-gs-pixel-5.15
Bug: 236259002 Change-Id: Id6c4888abbc79799379e51b360e0de47b2ad5c71 Signed-off-by: Robin Peng <robinpeng@google.com>
-rw-r--r--gbms_power_supply.h1
-rw-r--r--gbms_storage.c2
-rw-r--r--gbms_storage.h2
-rw-r--r--google_battery.c732
-rw-r--r--google_bms.c203
-rw-r--r--google_bms.h51
-rw-r--r--google_charger.c233
-rw-r--r--google_cpm.c105
-rw-r--r--google_dock.c215
-rw-r--r--google_dual_batt_gauge.c51
-rw-r--r--google_eeprom.c16
-rw-r--r--max1720x_battery.c46
-rw-r--r--p9221_charger.c441
-rw-r--r--p9221_charger.h70
-rw-r--r--p9221_chip.c149
-rw-r--r--pca9468_charger.c54
-rw-r--r--pca9468_charger.h1
-rw-r--r--pca9468_gbms_pps.c4
-rw-r--r--wc68_driver.c51
-rw-r--r--wc68_regs.h1
20 files changed, 1750 insertions, 678 deletions
diff --git a/gbms_power_supply.h b/gbms_power_supply.h
index 195a7ce..901e786 100644
--- a/gbms_power_supply.h
+++ b/gbms_power_supply.h
@@ -88,6 +88,7 @@ enum gbms_property {
GBMS_PROP_BATTERY_AGE, /* GBMS time in field */
GBMS_PROP_CAPACITY_FADE_RATE, /* GBMS capaciy fade rate */
GBMS_PROP_CHARGE_FULL_ESTIMATE, /* GBMS google_capacity */
+ GBMS_PROP_POGO_VOUT_ENABLED, /* GBMS gogo vout enabled */
};
union gbms_propval {
diff --git a/gbms_storage.c b/gbms_storage.c
index 940889f..e8a0cd6 100644
--- a/gbms_storage.c
+++ b/gbms_storage.c
@@ -49,7 +49,7 @@ struct gbms_cache_entry {
#define GBMS_PROVIDER_NAME_MAX 32
-#define GBMS_PROVIDERS_MAX 4
+#define GBMS_PROVIDERS_MAX 5
static spinlock_t providers_lock;
static bool gbms_storage_init_done;
diff --git a/gbms_storage.h b/gbms_storage.h
index a536d37..cff6114 100644
--- a/gbms_storage.h
+++ b/gbms_storage.h
@@ -59,6 +59,7 @@ typedef uint32_t gbms_tag_t;
enum gbms_tags {
GBMS_TAG_ACIM = 0x4143494d, /* Activation Impedance */
+ GBMS_TAG_AYMD = 0x41594d44,
GBMS_TAG_BCNT = 0x42434e54,
GBMS_TAG_BGCE = 0x42474345,
GBMS_TAG_BGPN = 0x4247504e,
@@ -80,6 +81,7 @@ enum gbms_tags {
GBMS_TAG_MINF = 0x4d494e46,
GBMS_TAG_MXSN = 0x4d58534e,
GBMS_TAG_MXCN = 0x4d58434e,
+ GBMS_TAG_MYMD = 0x4d594d44,
GBMS_TAG_THAS = 0x54484153,
/* User Space Read/Write scratch */
diff --git a/google_battery.c b/google_battery.c
index f9e8436..d5ce3d6 100644
--- a/google_battery.c
+++ b/google_battery.c
@@ -294,6 +294,15 @@ struct swelling_data {
ktime_t last_update;
};
+
+struct bhi_weight bhi_w[] = {
+ [BHI_ALGO_ACHI] = {100, 0, 0},
+ [BHI_ALGO_ACHI_B] = {100, 0, 0},
+ [BHI_ALGO_ACHI_RAVG] = {95, 5, 0},
+ [BHI_ALGO_ACHI_RAVG_B] = {95, 5, 0},
+ [BHI_ALGO_MIX_N_MATCH] = {90, 10, 5},
+};
+
struct bhi_data
{
/* context */
@@ -331,6 +340,11 @@ struct health_data
int bhi_cap_index;
int bhi_imp_index;
int bhi_sd_index;
+ /* debug health metrics */
+ int bhi_debug_cap_index;
+ int bhi_debug_imp_index;
+ int bhi_debug_sd_index;
+ int bhi_debug_health_index;
/* current battery state */
struct bhi_data bhi_data;
@@ -530,13 +544,13 @@ struct batt_drv {
/* irdrop for DC */
bool dc_irdrop;
+
+ /* shutdown flag */
+ int boot_to_os_attempts;
};
static int gbatt_get_temp(const struct batt_drv *batt_drv, int *temp);
-static int batt_chg_tier_stats_cstr(char *buff, int size,
- const struct gbms_ce_tier_stats *tier_stat,
- bool verbose);
static int gbatt_get_capacity(struct batt_drv *batt_drv);
static inline void batt_update_cycle_count(struct batt_drv *batt_drv)
@@ -1332,6 +1346,8 @@ static void batt_rl_update_status(struct batt_drv *batt_drv)
ssoc_state->bd_trickle_full = false;
ssoc_state->bd_trickle_eoc = false;
}
+
+ dump_ssoc_state(&batt_drv->ssoc_state, batt_drv->ssoc_log);
}
/* ------------------------------------------------------------------------- */
@@ -1432,14 +1448,6 @@ done:
}
/* ------------------------------------------------------------------------- */
-
-static void cev_ts_init(struct gbms_ce_tier_stats *stats, int8_t idx)
-{
- stats->vtier_idx = idx;
- stats->temp_idx = -1;
- stats->soc_in = -1;
-}
-
/* CEV = Charging EVent */
static void cev_stats_init(struct gbms_charging_event *ce_data,
const struct gbms_chg_profile *profile)
@@ -1458,18 +1466,18 @@ static void cev_stats_init(struct gbms_charging_event *ce_data,
ce_data->last_soc = -1;
for (i = 0; i < GBMS_STATS_TIER_COUNT ; i++)
- cev_ts_init(&ce_data->tier_stats[i], i);
+ gbms_tier_stats_init(&ce_data->tier_stats[i], i);
/* batt_chg_health_stats_close() will fix this */
- cev_ts_init(&ce_data->health_stats, GBMS_STATS_AC_TI_INVALID);
- cev_ts_init(&ce_data->health_pause_stats, GBMS_STATS_AC_TI_PAUSE);
- cev_ts_init(&ce_data->health_dryrun_stats, GBMS_STATS_AC_TI_V2_PREDICT);
+ gbms_tier_stats_init(&ce_data->health_stats, GBMS_STATS_AC_TI_INVALID);
+ gbms_tier_stats_init(&ce_data->health_pause_stats, GBMS_STATS_AC_TI_PAUSE);
+ gbms_tier_stats_init(&ce_data->health_dryrun_stats, GBMS_STATS_AC_TI_V2_PREDICT);
- cev_ts_init(&ce_data->full_charge_stats, GBMS_STATS_AC_TI_FULL_CHARGE);
- cev_ts_init(&ce_data->high_soc_stats, GBMS_STATS_AC_TI_HIGH_SOC);
- cev_ts_init(&ce_data->overheat_stats, GBMS_STATS_BD_TI_OVERHEAT_TEMP);
- cev_ts_init(&ce_data->cc_lvl_stats, GBMS_STATS_BD_TI_CUSTOM_LEVELS);
- cev_ts_init(&ce_data->trickle_stats, GBMS_STATS_BD_TI_TRICKLE_CLEARED);
+ gbms_tier_stats_init(&ce_data->full_charge_stats, GBMS_STATS_AC_TI_FULL_CHARGE);
+ gbms_tier_stats_init(&ce_data->high_soc_stats, GBMS_STATS_AC_TI_HIGH_SOC);
+ gbms_tier_stats_init(&ce_data->overheat_stats, GBMS_STATS_BD_TI_OVERHEAT_TEMP);
+ gbms_tier_stats_init(&ce_data->cc_lvl_stats, GBMS_STATS_BD_TI_CUSTOM_LEVELS);
+ gbms_tier_stats_init(&ce_data->trickle_stats, GBMS_STATS_BD_TI_TRICKLE_CLEARED);
}
static void batt_chg_stats_start(struct batt_drv *batt_drv)
@@ -1514,18 +1522,6 @@ static bool batt_chg_stats_qual(const struct batt_drv *batt_drv)
}
/* call holding stats_lock */
-static void batt_chg_stats_tier(struct gbms_ce_tier_stats *tier,
- int msc_state,
- ktime_t elap)
-{
- if (msc_state < 0 || msc_state >= MSC_STATES_COUNT)
- return;
-
- tier->msc_cnt[msc_state] += 1;
- tier->msc_elap[msc_state] += elap;
-}
-
-/* call holding stats_lock */
static void batt_chg_stats_soc_update(struct gbms_charging_event *ce_data,
qnum_t soc, ktime_t elap, int tier_index,
int cc)
@@ -1552,90 +1548,6 @@ static void batt_chg_stats_soc_update(struct gbms_charging_event *ce_data,
ce_data->last_soc = index;
}
-static void batt_chg_stats_update_tier(const struct batt_drv *const batt_drv,
- int temp_idx, int ibatt_ma, int temp,
- ktime_t elap, int cc,
- struct gbms_ce_tier_stats *tier)
-{
- const uint16_t icl_settled = batt_drv->chg_state.f.icl;
-
- /*
- * book time to previous msc_state for this tier, there is an
- * interesting wrinkle here since some tiers (health, full, etc)
- * might be entered and exited multiple times.
- */
- batt_chg_stats_tier(tier, batt_drv->msc_state, elap);
-
- if (tier->soc_in == -1) {
- int soc_in;
-
- soc_in = GPSY_GET_PROP(batt_drv->fg_psy,
- GBMS_PROP_CAPACITY_RAW);
- if (soc_in < 0) {
- pr_info("MSC_STAT cannot read soc_in=%d\n", soc_in);
- return;
- }
-
- tier->temp_idx = temp_idx;
-
- tier->temp_in = temp;
- tier->temp_min = temp;
- tier->temp_max = temp;
-
- tier->ibatt_min = ibatt_ma;
- tier->ibatt_max = ibatt_ma;
-
- tier->icl_min = icl_settled;
- tier->icl_max = icl_settled;
-
- tier->soc_in = soc_in;
- tier->cc_in = cc;
- tier->cc_total = 0;
- } else {
- const u8 flags = batt_drv->chg_state.f.flags;
-
- /* crossed temperature tier */
- if (temp_idx != tier->temp_idx)
- tier->temp_idx = -1;
-
- if (flags & GBMS_CS_FLAG_CC) {
- tier->time_fast += elap;
- } else if (flags & GBMS_CS_FLAG_CV) {
- tier->time_taper += elap;
- } else {
- tier->time_other += elap;
- }
-
- /*
- * averages: temp < 100. icl_settled < 3000, sum(ibatt)
- * is bound to battery capacity, elap in seconds, sums
- * are stored in an s64. For icl_settled I need a tier
- * to last for more than ~97M years.
- */
- if (temp < tier->temp_min)
- tier->temp_min = temp;
- if (temp > tier->temp_max)
- tier->temp_max = temp;
- tier->temp_sum += temp * elap;
-
- if (icl_settled < tier->icl_min)
- tier->icl_min = icl_settled;
- if (icl_settled > tier->icl_max)
- tier->icl_max = icl_settled;
- tier->icl_sum += icl_settled * elap;
-
- if (ibatt_ma < tier->ibatt_min)
- tier->ibatt_min = ibatt_ma;
- if (ibatt_ma > tier->ibatt_max)
- tier->ibatt_max = ibatt_ma;
- tier->ibatt_sum += ibatt_ma * elap;
-
- tier->cc_total = cc - tier->cc_in;
- }
-
- tier->sample_count += 1;
-}
-
/* call holding stats_lock */
static void batt_chg_stats_update(struct batt_drv *batt_drv, int temp_idx,
int tier_idx, int ibatt_ma, int temp,
@@ -1645,7 +1557,7 @@ static void batt_chg_stats_update(struct batt_drv *batt_drv, int temp_idx,
const int msc_state = batt_drv->msc_state; /* last msc_state */
struct gbms_charging_event *ce_data = &batt_drv->ce_data;
struct gbms_ce_tier_stats *tier = NULL;
- int cc;
+ int cc, soc_in;
if (elap == 0)
return;
@@ -1658,26 +1570,32 @@ static void batt_chg_stats_update(struct batt_drv *batt_drv, int temp_idx,
}
cc = cc / 1000;
+ soc_in = GPSY_GET_PROP(batt_drv->fg_psy, GBMS_PROP_CAPACITY_RAW);
+ if (soc_in < 0) {
+ pr_info("MSC_STAT cannot read soc_in=%d\n", soc_in);
+ return;
+ }
+
/* Note: To log new voltage tiers, add to list in go/pixel-vtier-defs */
/* --- Log tiers in PARALLEL below --- */
if (soc_real >= SSOC_HIGH_SOC)
- batt_chg_stats_update_tier(batt_drv, temp_idx, ibatt_ma, temp,
- elap, cc,
- &ce_data->high_soc_stats);
+ gbms_stats_update_tier(temp_idx, ibatt_ma, temp, elap, cc,
+ &batt_drv->chg_state, msc_state, soc_in,
+ &ce_data->high_soc_stats);
if (batt_drv->chg_health.dry_run_deadline > 0)
- batt_chg_stats_update_tier(batt_drv, temp_idx, ibatt_ma, temp,
- elap, cc,
- &ce_data->health_dryrun_stats);
+ gbms_stats_update_tier(temp_idx, ibatt_ma, temp, elap, cc,
+ &batt_drv->chg_state, msc_state, soc_in,
+ &ce_data->health_dryrun_stats);
/* --- Log tiers in SERIES below --- */
if (batt_drv->batt_full) {
/* Override regular charge tiers when fully charged */
- batt_chg_stats_update_tier(batt_drv, temp_idx, ibatt_ma,
- temp, elap, cc,
- &ce_data->full_charge_stats);
+ gbms_stats_update_tier(temp_idx, ibatt_ma, temp, elap, cc,
+ &batt_drv->chg_state, msc_state, soc_in,
+ &ce_data->full_charge_stats);
} else if (msc_state == MSC_HEALTH_PAUSE) {
@@ -1685,9 +1603,9 @@ static void batt_chg_stats_update(struct batt_drv *batt_drv, int temp_idx,
* We log the pause tier in different AC tier groups so that we
* can capture pause time separately.
*/
- batt_chg_stats_update_tier(batt_drv, temp_idx, ibatt_ma, temp,
- elap, cc,
- &ce_data->health_pause_stats);
+ gbms_stats_update_tier(temp_idx, ibatt_ma, temp, elap, cc,
+ &batt_drv->chg_state, msc_state, soc_in,
+ &ce_data->health_pause_stats);
} else if (msc_state == MSC_HEALTH || msc_state == MSC_HEALTH_ALWAYS_ON) {
/*
@@ -1703,9 +1621,9 @@ static void batt_chg_stats_update(struct batt_drv *batt_drv, int temp_idx,
*/
/* tier used for TTF during HC, check msc_logic_health() */
- batt_chg_stats_update_tier(batt_drv, temp_idx, ibatt_ma,
- temp, elap, cc,
- &ce_data->health_stats);
+ gbms_stats_update_tier(temp_idx, ibatt_ma, temp, elap, cc,
+ &batt_drv->chg_state, msc_state, soc_in,
+ &ce_data->health_stats);
} else {
const qnum_t soc = ssoc_get_capacity_raw(&batt_drv->ssoc_state);
@@ -1727,17 +1645,17 @@ static void batt_chg_stats_update(struct batt_drv *batt_drv, int temp_idx,
/* batt_drv->batt_health is protected with chg_lock, */
if (batt_drv->batt_health == POWER_SUPPLY_HEALTH_OVERHEAT) {
- batt_chg_stats_update_tier(batt_drv, temp_idx, ibatt_ma, temp,
- elap, cc,
- &ce_data->overheat_stats);
+ gbms_stats_update_tier(temp_idx, ibatt_ma, temp, elap, cc,
+ &batt_drv->chg_state, msc_state, soc_in,
+ &ce_data->overheat_stats);
tier = NULL;
}
/* custom charge levels (DWELL-DEFEND or RETAIL) */
if (batt_drv->chg_state.f.flags & GBMS_CS_FLAG_CCLVL) {
- batt_chg_stats_update_tier(batt_drv, temp_idx, ibatt_ma, temp,
- elap, cc,
- &ce_data->cc_lvl_stats);
+ gbms_stats_update_tier(temp_idx, ibatt_ma, temp, elap, cc,
+ &batt_drv->chg_state, msc_state, soc_in,
+ &ce_data->cc_lvl_stats);
tier = NULL;
}
@@ -1748,8 +1666,8 @@ static void batt_chg_stats_update(struct batt_drv *batt_drv, int temp_idx,
if (!tier)
return;
- batt_chg_stats_update_tier(batt_drv, temp_idx, ibatt_ma, temp,
- elap, cc, tier);
+ gbms_stats_update_tier(temp_idx, ibatt_ma, temp, elap, cc,
+ &batt_drv->chg_state, msc_state, soc_in, tier);
}
static int batt_chg_health_vti(const struct batt_chg_health *chg_health)
@@ -1919,31 +1837,6 @@ static int batt_chg_stats_soc_next(const struct gbms_charging_event *ce_data,
return soc_next;
}
-static void bat_log_cstr_handler(struct logbuffer *log, char *buf, int len)
-{
- int i, j = 0;
- char tmp[LOG_BUFFER_ENTRY_SIZE];
-
- buf[len] = '\n';
- for (i = 0; i <= len; i++) {
- if (buf[i] == '\n') {
- tmp[j] = '\0';
- /* skip first blank line */
- if (i != 0)
- logbuffer_log(log, "%s", tmp);
- j = 0;
- } else if (j >= LOG_BUFFER_ENTRY_SIZE - 1) {
- tmp[j] = '\0';
- logbuffer_log(log, "%s", tmp);
- i--;
- j = 0;
- } else {
- tmp[j] = buf[i];
- j++;
- }
- }
-}
-
static void bat_log_chg_stats(struct logbuffer *log,
const struct gbms_charging_event *ce_data)
{
@@ -1982,15 +1875,15 @@ static void bat_log_chg_stats(struct logbuffer *log,
if (!elap)
continue;
- len = batt_chg_tier_stats_cstr(buff, sizeof(buff),
+ len = gbms_tier_stats_cstr(buff, sizeof(buff),
&ce_data->tier_stats[i], true);
- bat_log_cstr_handler(log, buff, len);
+ gbms_log_cstr_handler(log, buff, len);
if (soc_next) {
len = ttf_soc_cstr(buff, sizeof(buff),
&ce_data->soc_stats,
soc_in, soc_next);
- bat_log_cstr_handler(log, buff, len);
+ gbms_log_cstr_handler(log, buff, len);
}
}
}
@@ -2015,75 +1908,6 @@ static void batt_chg_stats_pub(struct batt_drv *batt_drv, char *reason,
mutex_unlock(&batt_drv->stats_lock);
}
-/* Log only when elap != 0 add a special meaning for health status */
-static int batt_chg_tier_stats_cstr(char *buff, int size,
- const struct gbms_ce_tier_stats *tier_stat,
- bool verbose)
-{
- const int soc_in = tier_stat->soc_in >> 8;
- const long elap = tier_stat->time_fast + tier_stat->time_taper +
- tier_stat->time_other;
- const static char *codes[] = {"n", "s", "d", "l", "v", "vo", "p", "f",
- "t", "dl", "st", "tc", "r", "w", "rs",
- "n", "ny", "h", "hp", "ha"};
- long temp_avg, ibatt_avg, icl_avg;
- int j, len = 0;
-
- if (elap) {
- temp_avg = div_u64(tier_stat->temp_sum, elap);
- ibatt_avg = div_u64(tier_stat->ibatt_sum, elap);
- icl_avg = div_u64(tier_stat->icl_sum, elap);
- } else {
- temp_avg = 0;
- ibatt_avg = 0;
- icl_avg = 0;
- }
-
- len += scnprintf(&buff[len], size - len, "\n%d%c ",
- tier_stat->vtier_idx,
- (verbose) ? ':' : ',');
-
- len += scnprintf(&buff[len], size - len,
- "%d.%d,%d,%d, %d,%d,%d, %d,%ld,%d, %d,%ld,%d, %d,%ld,%d",
- soc_in,
- tier_stat->soc_in & 0xff,
- tier_stat->cc_in,
- tier_stat->temp_in,
- tier_stat->time_fast,
- tier_stat->time_taper,
- tier_stat->time_other,
- tier_stat->temp_min,
- temp_avg,
- tier_stat->temp_max,
- tier_stat->ibatt_min,
- ibatt_avg,
- tier_stat->ibatt_max,
- tier_stat->icl_min,
- icl_avg,
- tier_stat->icl_max);
-
- if (!verbose || !elap)
- return len;
-
- /* time spent in every multi step charging state */
- len += scnprintf(&buff[len], size - len, "\n%d:",
- tier_stat->vtier_idx);
-
- for (j = 0; j < MSC_STATES_COUNT; j++)
- len += scnprintf(&buff[len], size - len, " %s=%d",
- codes[j], tier_stat->msc_elap[j]);
-
- /* count spent in each step charging state */
- len += scnprintf(&buff[len], size - len, "\n%d:",
- tier_stat->vtier_idx);
-
- for (j = 0; j < MSC_STATES_COUNT; j++)
- len += scnprintf(&buff[len], size - len, " %s=%d",
- codes[j], tier_stat->msc_cnt[j]);
-
- return len;
-}
-
/* health_stats->tier_index is set on stats_close() */
static int batt_health_stats_cstr(char *buff, int size,
const struct gbms_charging_event *ce_data,
@@ -2102,15 +1926,14 @@ static int batt_health_stats_cstr(char *buff, int size,
if (vti == GBMS_STATS_AC_TI_INVALID)
return len;
- len += batt_chg_tier_stats_cstr(&buff[len], size - len,
- health_stats,
- verbose);
+ len += gbms_tier_stats_cstr(&buff[len], size - len,
+ health_stats, verbose);
/* Only add pause tier logging if there is pause time */
if (ce_data->health_pause_stats.soc_in != -1)
- len += batt_chg_tier_stats_cstr(&buff[len], size - len,
- &ce_data->health_pause_stats,
- verbose);
+ len += gbms_tier_stats_cstr(&buff[len], size - len,
+ &ce_data->health_pause_stats,
+ verbose);
return len;
}
@@ -2165,9 +1988,9 @@ static int batt_chg_stats_cstr(char *buff, int size,
if (!elap)
continue;
- len += batt_chg_tier_stats_cstr(&buff[len], size - len,
- &ce_data->tier_stats[i],
- verbose);
+ len += gbms_tier_stats_cstr(&buff[len], size - len,
+ &ce_data->tier_stats[i],
+ verbose);
if (soc_next)
len += ttf_soc_cstr(&buff[len], size - len,
@@ -2177,37 +2000,37 @@ static int batt_chg_stats_cstr(char *buff, int size,
/* Does not currently check MSC_HEALTH */
if (ce_data->health_dryrun_stats.soc_in != -1)
- len += batt_chg_tier_stats_cstr(&buff[len], size - len,
- &ce_data->health_dryrun_stats,
- verbose);
+ len += gbms_tier_stats_cstr(&buff[len], size - len,
+ &ce_data->health_dryrun_stats,
+ verbose);
if (ce_data->full_charge_stats.soc_in != -1)
- len += batt_chg_tier_stats_cstr(&buff[len], size - len,
- &ce_data->full_charge_stats,
- verbose);
+ len += gbms_tier_stats_cstr(&buff[len], size - len,
+ &ce_data->full_charge_stats,
+ verbose);
if (ce_data->high_soc_stats.soc_in != -1)
- len += batt_chg_tier_stats_cstr(&buff[len], size - len,
- &ce_data->high_soc_stats,
- verbose);
+ len += gbms_tier_stats_cstr(&buff[len], size - len,
+ &ce_data->high_soc_stats,
+ verbose);
if (ce_data->overheat_stats.soc_in != -1)
- len += batt_chg_tier_stats_cstr(&buff[len], size - len,
- &ce_data->overheat_stats,
- verbose);
+ len += gbms_tier_stats_cstr(&buff[len], size - len,
+ &ce_data->overheat_stats,
+ verbose);
if (ce_data->cc_lvl_stats.soc_in != -1)
- len += batt_chg_tier_stats_cstr(&buff[len], size - len,
- &ce_data->cc_lvl_stats,
- verbose);
+ len += gbms_tier_stats_cstr(&buff[len], size - len,
+ &ce_data->cc_lvl_stats,
+ verbose);
/* If bd_clear triggers, we need to know about it even if trickle hasn't
* triggered
*/
if (ce_data->trickle_stats.soc_in != -1 || ce_data->bd_clear_trickle)
- len += batt_chg_tier_stats_cstr(&buff[len], size - len,
- &ce_data->trickle_stats,
- verbose);
+ len += gbms_tier_stats_cstr(&buff[len], size - len,
+ &ce_data->trickle_stats,
+ verbose);
return len;
}
@@ -2366,7 +2189,7 @@ static void batt_res_work(struct batt_drv *batt_drv)
/* ------------------------------------------------------------------------- */
-static void batt_log_csi_info(struct batt_drv *batt_drv)
+static void batt_log_csi_ttf_info(struct batt_drv *batt_drv)
{
struct csi_stats *csi_stats = &batt_drv->csi_stats;
const bool same_type_and_status =
@@ -2377,6 +2200,9 @@ static void batt_log_csi_info(struct batt_drv *batt_drv)
const ktime_t right_now = get_boot_sec();
int ssoc = -1;
+ if (!batt_drv->init_complete)
+ return;
+
if (chg_state_is_disconnected(&batt_drv->chg_state))
goto log_and_done;
@@ -2408,14 +2234,21 @@ log_and_done:
const int csi_speed_avg = csi_stats->csi_time_sum == 0 ?
csi_stats->speed_sum :
(csi_stats->speed_sum / csi_stats->csi_time_sum);
+ const int cc = GPSY_GET_PROP(batt_drv->fg_psy, POWER_SUPPLY_PROP_CHARGE_COUNTER);
+ ktime_t res = 0;
+ const int max_ratio = batt_ttf_estimate(&res, batt_drv);
+
+ if (max_ratio < 0)
+ res = 0;
gbms_logbuffer_prlog(batt_drv->ttf_stats.ttf_log, LOGLEVEL_INFO, 0, LOGLEVEL_DEBUG,
- "CSI ssoc=%d min=%d max=%d avg=%d type=%d status=%d",
- csi_stats->ssoc,
- csi_stats->csi_speed_min, csi_stats->csi_speed_max,
- csi_speed_avg,
- csi_stats->csi_current_type,
- csi_stats->csi_current_status);
+ "ssoc=%d CSI[min=%d max=%d avg=%d type=%d status=%d] "
+ "TTF[cc=%d time=%lld %lld:%lld:%lld (est=%lld max_ratio=%d)]",
+ csi_stats->ssoc, csi_stats->csi_speed_min,
+ csi_stats->csi_speed_max, csi_speed_avg,
+ csi_stats->csi_current_type, csi_stats->csi_current_status,
+ cc / 1000, right_now, res / 3600, (res % 3600) / 60, (res % 3600) % 60,
+ res, max_ratio);
}
/* ssoc == -1 on disconnect */
@@ -2427,7 +2260,7 @@ log_and_done:
csi_stats->csi_speed_max = current_speed;
csi_stats->csi_time_sum = 0;
- csi_stats->speed_sum = current_speed;
+ csi_stats->speed_sum = 0;
csi_stats->last_update = right_now;
}
@@ -2441,7 +2274,7 @@ static int csi_status_cb(struct gvotable_election *el, const char *reason,
return 0;
batt_drv->csi_current_status = status;
- batt_log_csi_info(batt_drv);
+ batt_log_csi_ttf_info(batt_drv);
if (batt_drv->psy)
power_supply_changed(batt_drv->psy);
@@ -2459,7 +2292,7 @@ static int csi_type_cb(struct gvotable_election *el, const char *reason,
return 0;
batt_drv->csi_current_type = type;
- batt_log_csi_info(batt_drv);
+ batt_log_csi_ttf_info(batt_drv);
if (batt_drv->psy)
power_supply_changed(batt_drv->psy);
@@ -2538,7 +2371,7 @@ static bool batt_csi_check_ad_power(const union gbms_ce_adapter_details *ad)
case CHG_EV_ADAPTER_TYPE_WLC:
case CHG_EV_ADAPTER_TYPE_WLC_EPP:
case CHG_EV_ADAPTER_TYPE_WLC_SPP:
- limit_mw = 7500;
+ limit_mw = 7500000;
break;
default:
break;
@@ -2568,21 +2401,21 @@ static void batt_update_csi_status(struct batt_drv *batt_drv)
return;
}
- gvotable_cast_long_vote(batt_drv->csi_status_votable, "CSI_STATUS_CHG",
- CSI_STATUS_Charging, !is_disconnected);
-
/*
* discharging when the battery current is negative. There will likely
* be a more specific reason (e.g System_* or Adapter_* or one of
* Defender_*).
*/
- gvotable_cast_long_vote(batt_drv->csi_status_votable, "CSI_STATUS_DSG",
- CSI_STATUS_NotCharging,
- !is_disconnected && batt_drv->msc_state == MSC_DSG);
- gvotable_cast_long_vote(batt_drv->csi_status_votable, "CSI_STATUS_100",
- CSI_STATUS_Charging,
- !is_disconnected && batt_drv->chg_done);
+ /* Charging Status Health_Cold */
+ gvotable_cast_long_vote(batt_drv->csi_status_votable, "CSI_STATUS_COLD",
+ CSI_STATUS_Health_Cold,
+ !is_disconnected && is_cold);
+
+ /* Charging Status Health_Hot */
+ gvotable_cast_long_vote(batt_drv->csi_status_votable, "CSI_STATUS_HOT",
+ CSI_STATUS_Health_Hot,
+ !is_disconnected && is_hot);
/* looks at absolute power, it could look also look at golden adapter */
gvotable_cast_long_vote(batt_drv->csi_status_votable, "CSI_STATUS_ADA_POWR",
@@ -2595,20 +2428,21 @@ static void batt_update_csi_status(struct batt_drv *batt_drv)
CSI_STATUS_Adapter_Quality,
!is_disconnected && batt_csi_check_ad_qual(batt_drv));
- /* Charging Status Health_Cold */
- gvotable_cast_long_vote(batt_drv->csi_status_votable, "CSI_STATUS_COLD",
- CSI_STATUS_Health_Cold,
- !is_disconnected && is_cold);
-
- /* Charging Status Health_Hot */
- gvotable_cast_long_vote(batt_drv->csi_status_votable, "CSI_STATUS_HOT",
- CSI_STATUS_Health_Hot,
- !is_disconnected && is_hot);
-
/* Charging Status Defender_Trickle */
gvotable_cast_long_vote(batt_drv->csi_status_votable, "CSI_STATUS_DEFEND_TRICKLE",
CSI_STATUS_Defender_Trickle,
!is_disconnected && is_trickle);
+
+ gvotable_cast_long_vote(batt_drv->csi_status_votable, "CSI_STATUS_DSG",
+ CSI_STATUS_NotCharging,
+ !is_disconnected && batt_drv->msc_state == MSC_DSG);
+
+ gvotable_cast_long_vote(batt_drv->csi_status_votable, "CSI_STATUS_100",
+ CSI_STATUS_Charging,
+ !is_disconnected && batt_drv->chg_done);
+
+ gvotable_cast_long_vote(batt_drv->csi_status_votable, "CSI_STATUS_CHG",
+ CSI_STATUS_Charging, !is_disconnected);
}
#define CSI_CHG_SPEED_MAX 100
@@ -2683,7 +2517,7 @@ static void batt_update_csi_info(struct batt_drv *batt_drv)
charging_speed = batt_calc_charging_speed(batt_drv);
if (batt_drv->csi_current_speed != charging_speed) {
batt_drv->csi_current_speed = charging_speed;
- batt_log_csi_info(batt_drv);
+ batt_log_csi_ttf_info(batt_drv);
}
}
@@ -3129,13 +2963,7 @@ static bool batt_health_set_chg_deadline(struct batt_chg_health *chg_health,
return new_deadline || rest_state != chg_health->rest_state;
}
-/* cc_max in ua: capacity in mAh, rest_rate in deciPct */
-static int msc_logic_health_get_rate(const struct batt_chg_health *rest,
- int capacity_ma)
-{
- return capacity_ma * rest->rest_rate * 10;
-}
-
+#define HEALTH_CHG_RATE_BEFORE_TRIGGER 80
/* health based charging trade charging speed for battery cycle life. */
static bool msc_logic_health(struct batt_drv *batt_drv)
{
@@ -3144,6 +2972,7 @@ static bool msc_logic_health(struct batt_drv *batt_drv)
const ktime_t deadline = rest->rest_deadline;
enum chg_health_state rest_state = rest->rest_state;
const bool aon_enabled = rest->always_on_soc != -1;
+ const int capacity_ma = batt_drv->battery_capacity;
const ktime_t now = get_boot_sec();
int fv_uv = -1, cc_max = -1;
bool changed = false;
@@ -3232,9 +3061,8 @@ static bool msc_logic_health(struct batt_drv *batt_drv)
done_exit:
if (rest_state == CHG_HEALTH_ACTIVE || rest_state == CHG_HEALTH_DONE) {
- const int capacity_ma = batt_drv->battery_capacity;
-
- cc_max = msc_logic_health_get_rate(rest, capacity_ma);
+ /* cc_max in ua: capacity in mAh, rest_rate in deciPct */
+ cc_max = capacity_ma * rest->rest_rate * 10;
/*
* default FV_UV to the last charge tier since fv_uv will be
@@ -3245,6 +3073,8 @@ done_exit:
fv_uv = profile->volt_limits[profile->volt_nb_limits - 1];
/* TODO: make sure that we wakeup when we are close to ttf */
+ } else if (rest_state == CHG_HEALTH_ENABLED) {
+ cc_max = capacity_ma * rest->rest_rate_before_trigger * 10;
} else if (rest_state == CHG_HEALTH_PAUSE) {
/*
* pause charging behavior when the the deadline is longer than
@@ -3637,7 +3467,8 @@ static int bhi_calc_sd_index(int algo, const struct bhi_data *bhi_data)
return bhi_data->ccbin_index;
}
-static int bhi_calc_health_index(int algo, int cap_index, int imp_index, int sd_index)
+static int bhi_calc_health_index(int algo, const struct health_data *health_data,
+ int cap_index, int imp_index, int sd_index)
{
int ratio, index;
int w_ci = 0;
@@ -3652,21 +3483,17 @@ static int bhi_calc_health_index(int algo, int cap_index, int imp_index, int sd_
return BHI_ALGO_FULL_HEALTH;
case BHI_ALGO_ACHI:
case BHI_ALGO_ACHI_B:
- w_ci = 100;
- w_ii = 0;
- w_sd = 0;
- break;
case BHI_ALGO_ACHI_RAVG:
case BHI_ALGO_ACHI_RAVG_B:
- w_ci = 95;
- w_ii = 5;
- w_sd = 0;
- break;
case BHI_ALGO_MIX_N_MATCH:
- /* TODO: use the weights in health_data */
- w_ci = 90;
- w_ii = 10;
- w_sd = 5;
+ w_ci = bhi_w[algo].w_ci;
+ w_ii = bhi_w[algo].w_ii;
+ w_sd = bhi_w[algo].w_sd;
+ break;
+ case BHI_ALGO_DEBUG:
+ w_ci = health_data->bhi_w_ci;
+ w_ii = health_data->bhi_w_pi;
+ w_sd = health_data->bhi_w_sd;
break;
default:
return -EINVAL;
@@ -3769,7 +3596,7 @@ static int batt_bhi_stats_update(struct batt_drv *batt_drv)
changed |= health_data->bhi_sd_index != index;
health_data->bhi_sd_index = index;
- index = bhi_calc_health_index(bhi_algo,
+ index = bhi_calc_health_index(bhi_algo, health_data,
health_data->bhi_cap_index,
health_data->bhi_imp_index,
health_data->bhi_sd_index);
@@ -3779,7 +3606,7 @@ static int batt_bhi_stats_update(struct batt_drv *batt_drv)
changed |= health_data->bhi_index != index;
health_data->bhi_index = index;
- status = bhi_calc_health_status(bhi_algo, index, health_data);
+ status = bhi_calc_health_status(bhi_algo, BHI_ROUND_INDEX(index), health_data);
changed |= health_data->bhi_status != status;
health_data->bhi_status = status;
@@ -4002,7 +3829,7 @@ static int msc_logic(struct batt_drv *batt_drv)
}
mutex_lock(&batt_drv->stats_lock);
- batt_chg_stats_tier(&batt_drv->ce_data.tier_stats[tier_idx],
+ gbms_chg_stats_tier(&batt_drv->ce_data.tier_stats[tier_idx],
batt_drv->msc_irdrop_state, elap);
batt_drv->msc_irdrop_state = msc_state;
mutex_unlock(&batt_drv->stats_lock);
@@ -4181,9 +4008,9 @@ static void google_battery_dump_profile(const struct gbms_chg_profile *profile)
{
char *buff;
- buff = kzalloc(GBMS_CHG_ALG_BUF, GFP_KERNEL);
+ buff = kzalloc(GBMS_CHG_ALG_BUF_SZ, GFP_KERNEL);
if (buff) {
- gbms_dump_chg_profile(buff, GBMS_CHG_ALG_BUF, profile);
+ gbms_dump_chg_profile(buff, GBMS_CHG_ALG_BUF_SZ, profile);
pr_info("%s", buff);
kfree(buff);
}
@@ -4322,7 +4149,7 @@ static int batt_chg_logic(struct batt_drv *batt_drv)
mutex_unlock(&batt_drv->bpst_state.lock);
/* here on: disconnect */
- batt_log_csi_info(batt_drv);
+ batt_log_csi_ttf_info(batt_drv);
batt_chg_stats_pub(batt_drv, "disconnect", false, false);
/* change curve before changing the state. */
@@ -4931,6 +4758,31 @@ static int debug_set_ssoc_rls(void *data, u64 val)
DEFINE_SIMPLE_ATTRIBUTE(debug_ssoc_rls_fops,
debug_get_ssoc_rls, debug_set_ssoc_rls, "%llu\n");
+static int debug_get_fv_dc_ratio(void *data, u64 *val)
+{
+ struct batt_drv *batt_drv = (struct batt_drv *)data;
+
+ *val = batt_drv->chg_profile.fv_dc_ratio;
+
+ return 0;
+}
+
+static int debug_set_fv_dc_ratio(void *data, u64 val)
+{
+ struct batt_drv *batt_drv = (struct batt_drv *)data;
+
+ if (val < 0)
+ return -EINVAL;
+
+ mutex_lock(&batt_drv->chg_lock);
+ batt_drv->chg_profile.fv_dc_ratio = val;
+ mutex_unlock(&batt_drv->chg_lock);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_fv_dc_ratio_fops,
+ debug_get_fv_dc_ratio, debug_set_fv_dc_ratio, "%llu\n");
static ssize_t debug_get_ssoc_uicurve(struct file *filp,
char __user *buf,
@@ -4996,7 +4848,7 @@ DEFINE_SIMPLE_ATTRIBUTE(debug_force_psy_update_fops,
/* Adaptive Charging */
static int debug_chg_health_rest_rate_read(void *data, u64 *val)
{
- struct batt_drv *batt_drv = (struct batt_drv *)data;
+ struct batt_drv *batt_drv = data;
if (!batt_drv->psy)
return -EINVAL;
@@ -5008,7 +4860,7 @@ static int debug_chg_health_rest_rate_read(void *data, u64 *val)
/* Adaptive Charging */
static int debug_chg_health_rest_rate_write(void *data, u64 val)
{
- struct batt_drv *batt_drv = (struct batt_drv *)data;
+ struct batt_drv *batt_drv = data;
if (!batt_drv->psy)
return -EINVAL;
@@ -5022,6 +4874,36 @@ DEFINE_SIMPLE_ATTRIBUTE(debug_chg_health_rest_rate_fops,
debug_chg_health_rest_rate_read,
debug_chg_health_rest_rate_write, "%llu\n");
+
+/* Adaptive Charging */
+static int debug_chg_health_rest_rate_before_trigger_read(void *data, u64 *val)
+{
+ struct batt_drv *batt_drv = data;
+
+ if (!batt_drv->psy)
+ return -EINVAL;
+
+ *val = batt_drv->chg_health.rest_rate_before_trigger;
+ return 0;
+}
+
+/* Adaptive Charging */
+static int debug_chg_health_rest_rate_before_trigger_write(void *data, u64 val)
+{
+ struct batt_drv *batt_drv = data;
+
+ if (!batt_drv->psy)
+ return -EINVAL;
+
+ batt_drv->chg_health.rest_rate_before_trigger = val;
+ return 0;
+}
+
+/* Adaptive Charging */
+DEFINE_SIMPLE_ATTRIBUTE(debug_chg_health_rest_rate_before_trigger_fops,
+ debug_chg_health_rest_rate_before_trigger_read,
+ debug_chg_health_rest_rate_before_trigger_write, "%llu\n");
+
/* Adaptive Charging */
static int debug_chg_health_thr_soc_read(void *data, u64 *val)
{
@@ -5345,6 +5227,42 @@ static ssize_t debug_get_blf_state(struct file *filp, char __user *buf,
}
BATTERY_DEBUG_ATTRIBUTE(debug_blf_state_fops, debug_get_blf_state, 0);
+static ssize_t debug_get_bhi_status(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct batt_drv *batt_drv = (struct batt_drv *)filp->private_data;
+ struct health_data *health_data = &batt_drv->health_data;
+ const int cap_idx = health_data->bhi_debug_cap_index;
+ const int imp_idx = health_data->bhi_debug_imp_index;
+ const int sd_idx = health_data->bhi_debug_sd_index;
+ const int algo = BHI_ALGO_DEBUG;
+ int health_idx = health_data->bhi_debug_health_index;
+ int health_status, len;
+ char *tmp;
+
+ tmp = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ if (health_idx == 0)
+ health_idx = bhi_calc_health_index(algo, health_data, cap_idx, imp_idx, sd_idx);
+
+ health_status = bhi_calc_health_status(algo, BHI_ROUND_INDEX(health_idx), health_data);
+
+ if (health_data->bhi_debug_health_index != 0)
+ scnprintf(tmp, PAGE_SIZE, "%d, %d\n", health_status, health_idx);
+ else
+ scnprintf(tmp, PAGE_SIZE, "%d, %d [%d/%d %d/%d %d/%d]\n", health_status,
+ health_idx, cap_idx, health_data->bhi_w_ci, imp_idx,
+ health_data->bhi_w_pi, sd_idx, health_data->bhi_w_sd);
+
+ len = simple_read_from_buffer(buf, count, ppos, tmp, strlen(tmp));
+ kfree(tmp);
+
+ return len;
+}
+BATTERY_DEBUG_ATTRIBUTE(debug_bhi_status_fops, debug_get_bhi_status, 0);
+
/* TODO: add writes to restart pairing (i.e. provide key) */
static ssize_t batt_pairing_state_show(struct device *dev,
struct device_attribute *attr,
@@ -5502,11 +5420,11 @@ static ssize_t batt_show_chg_details(struct device *dev,
/* NOTE: vtier_idx is -1, can also check elap */
if (h->soc_in != -1)
- len += batt_chg_tier_stats_cstr(&buf[len],
- PAGE_SIZE - len, h, !!elap_h);
+ len += gbms_tier_stats_cstr(&buf[len],
+ PAGE_SIZE - len, h, !!elap_h);
if (p->soc_in != -1)
- len += batt_chg_tier_stats_cstr(&buf[len],
- PAGE_SIZE - len, p, !!elap_p);
+ len += gbms_tier_stats_cstr(&buf[len],
+ PAGE_SIZE - len, p, !!elap_p);
}
len += scnprintf(&buf[len], PAGE_SIZE - len, "\n");
@@ -6500,7 +6418,7 @@ static ssize_t health_index_stats_show(struct device *dev,
struct power_supply *psy = container_of(dev, struct power_supply, dev);
struct batt_drv *batt_drv = power_supply_get_drvdata(psy);
struct bhi_data *bhi_data = &batt_drv->health_data.bhi_data;
- struct health_data *health_data = &batt_drv->health_data;
+ struct health_data *health_data = &batt_drv->health_data;
int len = 0, i;
mutex_lock(&batt_drv->chg_lock);
@@ -6511,7 +6429,7 @@ static ssize_t health_index_stats_show(struct device *dev,
cap_index = bhi_calc_cap_index(i, batt_drv);
imp_index = bhi_calc_imp_index(i, bhi_data);
sd_index = bhi_calc_sd_index(i, bhi_data);
- health_index = bhi_calc_health_index(i, cap_index, imp_index, sd_index);
+ health_index = bhi_calc_health_index(i, health_data, cap_index, imp_index, sd_index);
health_status = bhi_calc_health_status(i, BHI_ROUND_INDEX(health_index), health_data);
if (health_index < 0)
continue;
@@ -6830,41 +6748,6 @@ static ssize_t dev_sn_show(struct device *dev,
static const DEVICE_ATTR_RW(dev_sn);
-#define USER_SHUTDOWN_FLAG 0x01
-static int batt_set_charger_mode(bool enable)
-{
- u8 data;
- int ret;
-
- data = enable ? USER_SHUTDOWN_FLAG : 0;
- ret = gbms_storage_write(GBMS_TAG_SUFG, &data, sizeof(data));
- if (ret < 0)
- return -EIO;
-
- return 0;
-}
-
-static ssize_t charger_mode_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int ret = 0, val = 0;
-
- ret = kstrtoint(buf, 0, &val);
- if (ret < 0)
- return ret;
-
- if (val >= 0) {
- ret = batt_set_charger_mode((val > 0));
- if (ret < 0)
- pr_err("Cannot set charger mode, ret=%d\n", ret);
- }
-
- return count;
-}
-
-static DEVICE_ATTR_WO(charger_mode);
-
/* ------------------------------------------------------------------------- */
static int batt_init_fs(struct batt_drv *batt_drv)
@@ -7043,9 +6926,6 @@ static int batt_init_fs(struct batt_drv *batt_drv)
ret = device_create_file(&batt_drv->psy->dev, &dev_attr_dev_sn);
if (ret)
dev_err(&batt_drv->psy->dev, "Failed to create dev sn\n");
- ret = device_create_file(&batt_drv->psy->dev, &dev_attr_charger_mode);
- if (ret)
- dev_err(&batt_drv->psy->dev, "Failed to create charger_mode\n");
return 0;
@@ -7065,6 +6945,7 @@ static int batt_init_debugfs(struct batt_drv *batt_drv)
debugfs_create_file("ssoc_gdf", 0644, de, batt_drv, &debug_ssoc_gdf_fops);
debugfs_create_file("ssoc_uic", 0644, de, batt_drv, &debug_ssoc_uic_fops);
debugfs_create_file("ssoc_rls", 0444, de, batt_drv, &debug_ssoc_rls_fops);
+ debugfs_create_file("fv_dc_ratio", 0644, de, batt_drv, &debug_fv_dc_ratio_fops);
debugfs_create_file("ssoc_uicurve", 0644, de, batt_drv,
&debug_ssoc_uicurve_cstr_fops);
debugfs_create_file("force_psy_update", 0400, de, batt_drv,
@@ -7091,6 +6972,8 @@ static int batt_init_debugfs(struct batt_drv *batt_drv)
&debug_chg_health_thr_soc_fops);
debugfs_create_file("chg_health_rest_rate", 0600, de, batt_drv,
&debug_chg_health_rest_rate_fops);
+ debugfs_create_file("chg_health_rest_rate_before_trigger", 0600, de, batt_drv,
+ &debug_chg_health_rest_rate_before_trigger_fops);
debugfs_create_file("chg_health_stage", 0600, de, batt_drv,
&debug_chg_health_stage_fops);
@@ -7106,10 +6989,20 @@ static int batt_init_debugfs(struct batt_drv *batt_drv)
/* bhi fullcapnom count */
debugfs_create_u32("bhi_w_ci", 0644, de, &batt_drv->health_data.bhi_w_ci);
- debugfs_create_u32("bhi_w_pi", 0644, de, &batt_drv->health_data.bhi_w_ci);
- debugfs_create_u32("bhi_w_sd", 0644, de, &batt_drv->health_data.bhi_w_ci);
+ debugfs_create_u32("bhi_w_pi", 0644, de, &batt_drv->health_data.bhi_w_pi);
+ debugfs_create_u32("bhi_w_sd", 0644, de, &batt_drv->health_data.bhi_w_sd);
debugfs_create_u32("act_impedance", 0644, de,
&batt_drv->health_data.bhi_data.act_impedance);
+ debugfs_create_u32("bhi_debug_cap_idx", 0644, de,
+ &batt_drv->health_data.bhi_debug_cap_index);
+ debugfs_create_u32("bhi_debug_imp_idx", 0644, de,
+ &batt_drv->health_data.bhi_debug_imp_index);
+ debugfs_create_u32("bhi_debug_sd_idx", 0644, de,
+ &batt_drv->health_data.bhi_debug_sd_index);
+ debugfs_create_u32("bhi_debug_health_idx", 0644, de,
+ &batt_drv->health_data.bhi_debug_health_index);
+ debugfs_create_file("bhi_debug_status", 0644, de, batt_drv,
+ &debug_bhi_status_fops);
/* google_resistance, tuning */
debugfs_create_u32("ravg_temp_low", 0644, de,
@@ -7122,6 +7015,9 @@ static int batt_init_debugfs(struct batt_drv *batt_drv)
&batt_drv->health_data.bhi_data.res_state.ravg_soc_high);
debugfs_create_file("ravg", 0400, de, batt_drv, &debug_ravg_fops);
+ /* shutdown flag */
+ debugfs_create_u32("boot_to_os_attempts", 0660, de, &batt_drv->boot_to_os_attempts);
+
return 0;
}
@@ -7230,32 +7126,6 @@ static int gbatt_get_temp(const struct batt_drv *batt_drv, int *temp)
return err;
}
-static void bat_log_ttf_estimate(const char *label, int ssoc,
- struct batt_drv *batt_drv)
-{
- int cc, err;
- ktime_t res = 0;
- u64 hours;
- int remaining_sec;
-
- err = batt_ttf_estimate(&res, batt_drv);
- if (err < 0) {
- logbuffer_log(batt_drv->ttf_stats.ttf_log,
- "%s ssoc=%d time=%ld err=%d",
- (label) ? label : "", ssoc, get_boot_sec(), err);
- return;
- }
-
- hours = div_u64_rem(res, 3600, &remaining_sec);
-
- cc = GPSY_GET_PROP(batt_drv->fg_psy, POWER_SUPPLY_PROP_CHARGE_COUNTER);
- logbuffer_log(batt_drv->ttf_stats.ttf_log,
- "%s ssoc=%d cc=%d time=%ld %d:%d:%d (est=%ld, max_ratio=%d)",
- (label) ? label : "", ssoc, cc / 1000, get_boot_sec(),
- hours, remaining_sec / 60, remaining_sec % 60,
- res, err);
-}
-
static int batt_do_md5(const u8 *data, unsigned int len, u8 *result)
{
struct crypto_shash *tfm;
@@ -7534,6 +7404,38 @@ static int google_battery_init_hist_work(struct batt_drv *batt_drv )
return 0;
}
+#define BOOT_TO_OS_ATTEMPTS 3
+
+static int batt_init_shutdown_flag(struct batt_drv *batt_drv)
+{
+ u8 data;
+ int ret;
+
+ ret = gbms_storage_read(GBMS_TAG_SUFG, &data, sizeof(data));
+ if (ret < 0)
+ return -EIO;
+
+ batt_drv->boot_to_os_attempts = data;
+
+ /* reset battery shutdown flag */
+ data = 0;
+ ret = gbms_storage_write(GBMS_TAG_SUFG, &data, sizeof(data));
+
+ return (ret < 0) ? -EIO : 0;
+}
+
+static int batt_set_shutdown_flag(struct batt_drv *batt_drv)
+{
+ u8 data = batt_drv->boot_to_os_attempts;
+ int ret;
+
+ if (data == 0)
+ data = BOOT_TO_OS_ATTEMPTS;
+
+ ret = gbms_storage_write(GBMS_TAG_SUFG, &data, sizeof(data));
+
+ return (ret < 0) ? -EIO : 0;
+}
/*
* poll the battery, run SOC%, dead battery, critical.
@@ -7606,11 +7508,8 @@ static void google_battery_work(struct work_struct *work)
pr_debug("%s: change of ssoc %d->%d\n", __func__,
prev_ssoc, ssoc);
- if (ssoc > prev_ssoc)
- bat_log_ttf_estimate("SSOC", ssoc, batt_drv);
-
dump_ssoc_state(ssoc_state, batt_drv->ssoc_log);
- batt_log_csi_info(batt_drv);
+ batt_log_csi_ttf_info(batt_drv);
notify_psy_changed = true;
}
@@ -7625,6 +7524,13 @@ static void google_battery_work(struct work_struct *work)
__func__, batt_drv->capacity_level,
level);
+ /* set battery critical shutdown */
+ if (level == POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL) {
+ ret = batt_set_shutdown_flag(batt_drv);
+ if (ret < 0)
+ pr_warn("failed to write shutdown flag, ret=%d\n", ret);
+ }
+
batt_drv->capacity_level = level;
notify_psy_changed = true;
}
@@ -7640,7 +7546,7 @@ static void google_battery_work(struct work_struct *work)
/* fuel gauge triggered recharge logic. */
full = (ssoc == SSOC_FULL);
if (full && !batt_drv->batt_full) {
- bat_log_ttf_estimate("Full", ssoc, batt_drv);
+ batt_log_csi_ttf_info(batt_drv);
batt_chg_stats_pub(batt_drv, "100%", false, true);
}
batt_drv->batt_full = full;
@@ -7710,7 +7616,7 @@ static void google_battery_work(struct work_struct *work)
}
} else if (batt_drv->ttf_debounce) {
batt_drv->ttf_debounce = 0;
- bat_log_ttf_estimate("Start", prev_ssoc, batt_drv);
+ batt_log_csi_ttf_info(batt_drv);
}
/* acquired in msc_logic */
@@ -8414,6 +8320,12 @@ static int batt_bhi_init(struct batt_drv *batt_drv)
/* design is the value used to build the charge table */
health_data->bhi_data.capacity_design = batt_drv->battery_capacity;
+ /* debug data initialization */
+ health_data->bhi_debug_cap_index = 0;
+ health_data->bhi_debug_imp_index = 0;
+ health_data->bhi_debug_sd_index = 0;
+ health_data->bhi_debug_health_index = 0;
+
return 0;
}
@@ -8476,6 +8388,7 @@ static void google_battery_init_work(struct work_struct *work)
batt_drv->hold_taper_ws = false;
batt_drv->fake_temp = 0;
batt_drv->fake_battery_present = -1;
+ batt_drv->boot_to_os_attempts = 0;
batt_reset_chg_drv_state(batt_drv);
mutex_init(&batt_drv->chg_lock);
@@ -8561,6 +8474,11 @@ static void google_battery_init_work(struct work_struct *work)
if (ret < 0)
pr_err("bpst profile disabled, ret=%d\n", ret);
+ /* init shutdown flag */
+ ret = batt_init_shutdown_flag(batt_drv);
+ if (ret < 0)
+ pr_err("failed to init shutdown flag, ret=%d\n", ret);
+
/* cycle count is cached: read here bc SSOC, chg_profile might use it */
batt_update_cycle_count(batt_drv);
@@ -8678,6 +8596,12 @@ static void google_battery_init_work(struct work_struct *work)
if (ret < 0)
batt_drv->chg_health.rest_rate = 0;
+ ret = of_property_read_u32(batt_drv->device->of_node,
+ "google,chg-rest-rate-before-trigger",
+ &batt_drv->chg_health.rest_rate_before_trigger);
+ if (ret < 0)
+ batt_drv->chg_health.rest_rate_before_trigger = HEALTH_CHG_RATE_BEFORE_TRIGGER;
+
/* override setting google,battery-roundtrip = 0 in device tree */
batt_drv->disable_votes =
of_property_read_bool(node, "google,disable-votes");
diff --git a/google_bms.c b/google_bms.c
index f4f7a83..673ffa2 100644
--- a/google_bms.c
+++ b/google_bms.c
@@ -33,6 +33,9 @@
#include "google_psy.h"
#include "google_bms.h"
+/* sync from google/logbuffer.c */
+#define LOG_BUFFER_ENTRY_SIZE 256
+
#define GBMS_DEFAULT_FV_UV_RESOLUTION 25000
#define GBMS_DEFAULT_FV_UV_MARGIN_DPCT 1020
#define GBMS_DEFAULT_FV_DC_RATIO 20
@@ -89,6 +92,16 @@ const char *gbms_chg_ev_adapter_s(int adapter)
}
EXPORT_SYMBOL_GPL(gbms_chg_ev_adapter_s);
+static const char *gbms_get_code(const int index)
+{
+ const static char *codes[] = {"n", "s", "d", "l", "v", "vo", "p", "f",
+ "t", "dl", "st", "tc", "r", "w", "rs",
+ "n", "ny", "h", "hp", "ha"};
+ const int len = ARRAY_SIZE(codes);
+
+ return (index >= 0 && index < len) ? codes[index] : "?";
+}
+
/* convert C rates to current. Caller can account for tolerances reducing
* battery_capacity. fv_uv_resolution is used to create discrete steps.
* NOTE: the call covert C rates to chanrge currents IN PLACE, ie you cannot
@@ -729,3 +742,193 @@ bool chg_state_is_disconnected(const union gbms_charger_state *chg_state)
chg_state->f.chg_status == POWER_SUPPLY_STATUS_UNKNOWN);
}
EXPORT_SYMBOL_GPL(chg_state_is_disconnected);
+
+/* Tier stats common routines */
+void gbms_tier_stats_init(struct gbms_ce_tier_stats *stats, int8_t idx)
+{
+ stats->vtier_idx = idx;
+ stats->temp_idx = -1;
+ stats->soc_in = -1;
+}
+EXPORT_SYMBOL_GPL(gbms_tier_stats_init);
+
+/* call holding stats_lock */
+void gbms_chg_stats_tier(struct gbms_ce_tier_stats *tier,
+ int msc_state,
+ ktime_t elap)
+{
+ if (msc_state < 0 || msc_state >= MSC_STATES_COUNT)
+ return;
+
+ tier->msc_cnt[msc_state] += 1;
+ tier->msc_elap[msc_state] += elap;
+}
+EXPORT_SYMBOL_GPL(gbms_chg_stats_tier);
+
+ void gbms_stats_update_tier(int temp_idx, int ibatt_ma, int temp, ktime_t elap,
+ int cc, union gbms_charger_state *chg_state,
+ enum gbms_msc_states_t msc_state, int soc_in,
+ struct gbms_ce_tier_stats *tier)
+{
+ const uint16_t icl_settled = chg_state->f.icl;
+
+ /*
+ * book time to previous msc_state for this tier, there is an
+ * interesting wrinkle here since some tiers (health, full, etc)
+ * might be entered and exited multiple times.
+ */
+ gbms_chg_stats_tier(tier, msc_state, elap);
+ tier->sample_count += 1;
+
+ if (tier->soc_in == -1) {
+ tier->temp_idx = temp_idx;
+
+ tier->temp_in = temp;
+ tier->temp_min = temp;
+ tier->temp_max = temp;
+
+ tier->ibatt_min = ibatt_ma;
+ tier->ibatt_max = ibatt_ma;
+
+ tier->icl_min = icl_settled;
+ tier->icl_max = icl_settled;
+
+ tier->soc_in = soc_in;
+ tier->cc_in = cc;
+ tier->cc_total = 0;
+ return;
+ }
+
+ /* crossed temperature tier */
+ if (temp_idx != tier->temp_idx)
+ tier->temp_idx = -1;
+
+ if (chg_state->f.chg_type == POWER_SUPPLY_CHARGE_TYPE_FAST) {
+ tier->time_fast += elap;
+ } else if (chg_state->f.chg_type == POWER_SUPPLY_CHARGE_TYPE_TAPER_EXT) {
+ tier->time_taper += elap;
+ } else {
+ tier->time_other += elap;
+ }
+
+ /*
+ * averages: temp < 100. icl_settled < 3000, sum(ibatt)
+ * is bound to battery capacity, elap in seconds, sums
+ * are stored in an s64. For icl_settled I need a tier
+ * to last for more than ~97M years.
+ */
+ if (temp < tier->temp_min)
+ tier->temp_min = temp;
+ if (temp > tier->temp_max)
+ tier->temp_max = temp;
+ tier->temp_sum += temp * elap;
+
+ if (icl_settled < tier->icl_min)
+ tier->icl_min = icl_settled;
+ if (icl_settled > tier->icl_max)
+ tier->icl_max = icl_settled;
+ tier->icl_sum += icl_settled * elap;
+
+ if (ibatt_ma < tier->ibatt_min)
+ tier->ibatt_min = ibatt_ma;
+ if (ibatt_ma > tier->ibatt_max)
+ tier->ibatt_max = ibatt_ma;
+ tier->ibatt_sum += ibatt_ma * elap;
+
+ tier->cc_total = cc - tier->cc_in;
+}
+EXPORT_SYMBOL_GPL(gbms_stats_update_tier);
+
+/* Log only when elap != 0 */
+int gbms_tier_stats_cstr(char *buff, int size,
+ const struct gbms_ce_tier_stats *tier_stat,
+ bool verbose)
+{
+ const int soc_in = tier_stat->soc_in >> 8;
+ const long elap = tier_stat->time_fast + tier_stat->time_taper +
+ tier_stat->time_other;
+
+ long temp_avg, ibatt_avg, icl_avg;
+ int j, len = 0;
+
+ if (elap) {
+ temp_avg = tier_stat->temp_sum / elap;
+ ibatt_avg = tier_stat->ibatt_sum / elap;
+ icl_avg = tier_stat->icl_sum / elap;
+ } else {
+ temp_avg = 0;
+ ibatt_avg = 0;
+ icl_avg = 0;
+ }
+
+ len += scnprintf(&buff[len], size - len, "\n%d%c ",
+ tier_stat->vtier_idx,
+ (verbose) ? ':' : ',');
+
+ len += scnprintf(&buff[len], size - len,
+ "%d.%d,%d,%d, %d,%d,%d, %d,%ld,%d, %d,%ld,%d, %d,%ld,%d",
+ soc_in,
+ tier_stat->soc_in & 0xff,
+ tier_stat->cc_in,
+ tier_stat->temp_in,
+ tier_stat->time_fast,
+ tier_stat->time_taper,
+ tier_stat->time_other,
+ tier_stat->temp_min,
+ temp_avg,
+ tier_stat->temp_max,
+ tier_stat->ibatt_min,
+ ibatt_avg,
+ tier_stat->ibatt_max,
+ tier_stat->icl_min,
+ icl_avg,
+ tier_stat->icl_max);
+
+ if (!verbose || !elap)
+ return len;
+
+ /* time spent in every multi step charging state */
+ len += scnprintf(&buff[len], size - len, "\n%d:",
+ tier_stat->vtier_idx);
+
+ for (j = 0; j < MSC_STATES_COUNT; j++)
+ len += scnprintf(&buff[len], size - len, " %s=%d",
+ gbms_get_code(j), tier_stat->msc_elap[j]);
+
+ /* count spent in each step charging state */
+ len += scnprintf(&buff[len], size - len, "\n%d:",
+ tier_stat->vtier_idx);
+
+ for (j = 0; j < MSC_STATES_COUNT; j++)
+ len += scnprintf(&buff[len], size - len, " %s=%d",
+ gbms_get_code(j), tier_stat->msc_cnt[j]);
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(gbms_tier_stats_cstr);
+
+void gbms_log_cstr_handler(struct logbuffer *log, char *buf, int len)
+{
+ int i, j = 0;
+ char tmp[LOG_BUFFER_ENTRY_SIZE];
+
+ buf[len] = '\n';
+ for (i = 0; i <= len; i++) {
+ if (buf[i] == '\n') {
+ tmp[j] = '\0';
+ /* skip first blank line */
+ if (i != 0)
+ logbuffer_log(log, "%s", tmp);
+ j = 0;
+ } else if (j >= LOG_BUFFER_ENTRY_SIZE - 1) {
+ tmp[j] = '\0';
+ logbuffer_log(log, "%s", tmp);
+ i--;
+ j = 0;
+ } else {
+ tmp[j] = buf[i];
+ j++;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(gbms_log_cstr_handler);
diff --git a/google_bms.h b/google_bms.h
index c2f42d2..4183f4f 100644
--- a/google_bms.h
+++ b/google_bms.h
@@ -30,7 +30,7 @@ struct device_node;
#define GBMS_CHG_TEMP_NB_LIMITS_MAX 10
#define GBMS_CHG_VOLT_NB_LIMITS_MAX 5
-#define GBMS_CHG_ALG_BUF 500
+#define GBMS_CHG_ALG_BUF_SZ 500
#define GBMS_CHG_TOPOFF_NB_LIMITS_MAX 6
#define GBMS_AACR_DATA_MAX 10
@@ -67,8 +67,8 @@ struct gbms_chg_profile {
u32 aacr_nb_limits;
};
-#define WLC_BPP_THRESHOLD_UV 700000
-#define WLC_EPP_THRESHOLD_UV 1100000
+#define WLC_BPP_THRESHOLD_UV 7000000
+#define WLC_EPP_THRESHOLD_UV 11000000
#define FOREACH_CHG_EV_ADAPTER(S) \
S(UNKNOWN), \
@@ -84,10 +84,23 @@ struct gbms_chg_profile {
S(USB_BRICKID), \
S(USB_HVDCP), \
S(USB_HVDCP3), \
+ S(FLOAT), \
S(WLC), \
S(WLC_EPP), \
S(WLC_SPP), \
- S(POGO), \
+ S(GPP), \
+ S(10W), \
+ S(L7), \
+ S(DL), \
+ S(WPC_EPP), \
+ S(WPC_GPP), \
+ S(WPC_10W), \
+ S(WPC_BPP), \
+ S(WPC_L7), \
+ S(EXT), \
+ S(EXT1), \
+ S(EXT2), \
+ S(EXT_UNKNOWN), \
#define CHG_EV_ADAPTER_STRING(s) #s
#define _CHG_EV_ADAPTER_PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
@@ -296,8 +309,10 @@ enum gbms_stats_tier_idx_t {
GBMS_STATS_BD_TI_OVERHEAT_TEMP = 110,
GBMS_STATS_BD_TI_CUSTOM_LEVELS = 111,
GBMS_STATS_BD_TI_TRICKLE = 112,
+ GBMS_STATS_BD_TI_DOCK = 113,
GBMS_STATS_BD_TI_TRICKLE_CLEARED = 122,
+ GBMS_STATS_BD_TI_DOCK_CLEARED = 123,
};
/* health state */
@@ -309,6 +324,7 @@ struct batt_chg_health {
ktime_t rest_deadline; /* full by this in seconds */
ktime_t dry_run_deadline; /* full by this in seconds (prediction) */
int rest_rate; /* centirate once enter */
+ int rest_rate_before_trigger;
enum chg_health_state rest_state;
int rest_cc_max;
@@ -522,6 +538,26 @@ int gbms_read_aacr_limits(struct gbms_chg_profile *profile,
bool chg_state_is_disconnected(const union gbms_charger_state *chg_state);
+/* Voltage tier stats */
+void gbms_tier_stats_init(struct gbms_ce_tier_stats *stats, int8_t idx);
+
+void gbms_chg_stats_tier(struct gbms_ce_tier_stats *tier,
+ int msc_state, ktime_t elap);
+
+void gbms_stats_update_tier(int temp_idx, int ibatt_ma, int temp, ktime_t elap,
+ int cc, union gbms_charger_state *chg_state,
+ enum gbms_msc_states_t msc_state, int soc_in,
+ struct gbms_ce_tier_stats *tier);
+
+int gbms_tier_stats_cstr(char *buff, int size,
+ const struct gbms_ce_tier_stats *tier_stat,
+ bool verbose);
+
+void gbms_log_cstr_handler(struct logbuffer *log, char *buf, int len);
+
+
+
+
/*
* Charger modes
*
@@ -559,6 +595,7 @@ enum bhi_algo {
*/
BHI_ALGO_MIX_N_MATCH = 6,
+ BHI_ALGO_DEBUG = 7,
BHI_ALGO_MAX,
};
@@ -570,6 +607,12 @@ enum bhi_status {
BH_FAILED,
};
+struct bhi_weight {
+ int w_ci;
+ int w_ii;
+ int w_sd;
+};
+
/* Charging Speed */
enum csi_type {
CSI_TYPE_UNKNOWN = -1,
diff --git a/google_charger.c b/google_charger.c
index e9e67c7..9b29cd3 100644
--- a/google_charger.c
+++ b/google_charger.c
@@ -72,6 +72,7 @@
#define MSC_USER_VOTER "msc_user"
#define MSC_USER_CHG_LEVEL_VOTER "msc_user_chg_level"
#define MSC_CHG_TERM_VOTER "msc_chg_term"
+#define MSC_PWR_VOTER "msc_pwr_disable"
#define CHG_TERM_LONG_DELAY_MS 300000 /* 5 min */
#define CHG_TERM_SHORT_DELAY_MS 60000 /* 1 min */
@@ -103,6 +104,10 @@
#define PD_SNK_MAX_MA_9V 2200
#define OP_SNK_MW 7600 /* see b/159863291 */
+/* type detection */
+#define EXT1_DETECT_THRESHOLD_UV (10500000)
+#define EXT2_DETECT_THRESHOLD_UV (5000000)
+
#define usb_pd_is_high_volt(ad) \
((ad)->ad_type == CHG_EV_ADAPTER_TYPE_USB_PD && \
(ad)->ad_voltage * 100 > PD_SNK_MIN_MV)
@@ -137,6 +142,7 @@ struct chg_thermal_device {
int *thermal_budgets;
int thermal_levels;
int current_level;
+ int therm_fan_alarm_level;
};
struct chg_termination {
@@ -295,6 +301,7 @@ struct chg_drv {
int charge_start_level; /* retail, userspace bd config */
/* pps charging */
+ bool pps_enable;
struct pd_pps_data pps_data;
unsigned int pps_cc_tolerance_pct;
union gbms_charger_state chg_state;
@@ -314,6 +321,14 @@ struct chg_drv {
/* debug */
struct dentry *debug_entry;
+
+ /* dock_defend */
+ struct delayed_work bd_dd_work;
+ bool ext_volt_complete;
+
+ struct mutex stats_lock;
+ struct gbms_ce_tier_stats dd_stats;
+ ktime_t last_update;
};
static void reschedule_chg_work(struct chg_drv *chg_drv)
@@ -400,6 +415,60 @@ static char *psy_usbc_type_str[] = {
"PD", "PD_DRP", "PD_PPS", "BrickID"
};
+static int chg_work_read_soc(struct power_supply *bat_psy, int *soc);
+
+static void chg_stats_init(struct chg_drv *chg_drv, struct gbms_ce_tier_stats *tier, int8_t idx)
+{
+ ktime_t now = get_boot_sec();
+
+ mutex_lock(&chg_drv->stats_lock);
+ gbms_tier_stats_init(tier, idx);
+ chg_drv->last_update = now;
+ mutex_unlock(&chg_drv->stats_lock);
+}
+
+static void chg_stats_update(struct chg_drv *chg_drv, struct gbms_ce_tier_stats *tier)
+{
+ int ibatt_ma, temp;
+ int cc, soc_in;
+ ktime_t elap, now = get_boot_sec();
+ int ioerr;
+
+ mutex_lock(&chg_drv->stats_lock);
+ if (tier->soc_in == -1)
+ elap = 0;
+ else
+ elap = now - chg_drv->last_update;
+ chg_drv->last_update = now;
+
+ ibatt_ma = GPSY_GET_INT_PROP(chg_drv->bat_psy, POWER_SUPPLY_PROP_CURRENT_NOW, &ioerr);
+ if (ioerr < 0) {
+ pr_err("%s: read ibatt_ma=%d, ioerr=%d\n", __func__, ibatt_ma, ioerr);
+ goto stats_update_unlock;
+ }
+ ibatt_ma /= 1000;
+
+ temp = GPSY_GET_INT_PROP(chg_drv->bat_psy, POWER_SUPPLY_PROP_TEMP, &ioerr);
+ if (ioerr < 0)
+ goto stats_update_unlock;
+
+ cc = GPSY_GET_INT_PROP(chg_drv->bat_psy, POWER_SUPPLY_PROP_CHARGE_COUNTER, &ioerr);
+ if (ioerr < 0)
+ goto stats_update_unlock;
+
+ cc /= 1000;
+
+ /* Ignore error in soc_in read */
+ ioerr = chg_work_read_soc(chg_drv->bat_psy, &soc_in);
+ if (ioerr != 0)
+ soc_in = -1;
+
+ gbms_stats_update_tier(0, ibatt_ma, temp, elap, cc, &chg_drv->chg_state, -1,
+ soc_in << 8, tier);
+stats_update_unlock:
+ mutex_unlock(&chg_drv->stats_lock);
+}
+
/* called on google_charger_init_work() and on every disconnect */
static inline void chg_init_state(struct chg_drv *chg_drv)
{
@@ -420,7 +489,9 @@ static inline void chg_init_state(struct chg_drv *chg_drv)
/* reset and re-enable PPS detection */
pps_init_state(&chg_drv->pps_data);
- if (chg_drv->pps_data.nr_snk_pdo)
+ if (!chg_drv->pps_enable)
+ chg_drv->pps_data.stage = PPS_DISABLED;
+ else if (chg_drv->pps_data.nr_snk_pdo)
chg_drv->pps_data.stage = PPS_NONE;
}
@@ -588,9 +659,9 @@ static int info_wlc_state(union gbms_ce_adapter_details *ad,
return -EINVAL;
}
- if (amperage_max >= WLC_EPP_THRESHOLD_UV) {
+ if (voltage_max >= WLC_EPP_THRESHOLD_UV) {
ad->ad_type = CHG_EV_ADAPTER_TYPE_WLC_EPP;
- } else if (amperage_max >= WLC_BPP_THRESHOLD_UV) {
+ } else if (voltage_max >= WLC_BPP_THRESHOLD_UV) {
ad->ad_type = CHG_EV_ADAPTER_TYPE_WLC_SPP;
}
@@ -617,13 +688,18 @@ static int info_ext_state(union gbms_ce_adapter_details *ad,
return 0;
if (voltage_max < 0 || amperage_max < 0) {
- ad->ad_type = CHG_EV_ADAPTER_TYPE_UNKNOWN;
+ ad->ad_type = CHG_EV_ADAPTER_TYPE_EXT_UNKNOWN;
ad->ad_voltage = voltage_max;
ad->ad_amperage = amperage_max;
return -EINVAL;
+ } else if (voltage_max > EXT1_DETECT_THRESHOLD_UV) {
+ ad->ad_type = CHG_EV_ADAPTER_TYPE_EXT1;
+ } else if (voltage_max > EXT2_DETECT_THRESHOLD_UV) {
+ ad->ad_type = CHG_EV_ADAPTER_TYPE_EXT2;
+ } else {
+ ad->ad_type = CHG_EV_ADAPTER_TYPE_EXT;
}
- ad->ad_type = CHG_EV_ADAPTER_TYPE_POGO;
ad->ad_voltage = voltage_max / 100000;
ad->ad_amperage = amperage_max / 100000;
@@ -1395,7 +1471,6 @@ static void thermal_stats_init(struct thermal_stats_data *thermal_stats) {
thermal_stats->ibatt_sum = 0;
}
-static int chg_work_read_soc(struct power_supply *bat_psy, int *soc);
static void thermal_stats_work(struct chg_drv *chg_drv) {
struct thermal_stats_data *thermal_stats = &chg_drv->thermal_stats;
struct power_supply *bat_psy = chg_drv->bat_psy;
@@ -1917,6 +1992,10 @@ static void bd_dd_run_defender(struct chg_drv *chg_drv, int soc, int *disable_ch
bd_state->dd_triggered,
(soc >= lowerbd));
+ /* Start DD stats */
+ if (bd_state->dd_state == DOCK_DEFEND_ACTIVE)
+ chg_stats_update(chg_drv, &chg_drv->dd_stats);
+
/* need icl_ramp_work when disable_pwrsrc 1 -> 0 */
if (!*disable_pwrsrc && chg_drv->disable_pwrsrc) {
struct power_supply *dc_psy;
@@ -1986,6 +2065,11 @@ static int chg_run_defender(struct chg_drv *chg_drv)
/* force TEMP-DEFEND off */
chg_drv->bd_state.enabled = 0;
+ /* set dd_state to inactive state (DOCK_DEFEND_ENABLED) */
+ if (chg_drv->bd_state.dd_enabled)
+ chg_drv->bd_state.dd_state = bd_dd_state_update(chg_drv->bd_state.dd_state,
+ false, false);
+
} else if (chg_drv->bd_state.enabled) {
const bool was_triggered = bd_state->triggered;
@@ -2027,6 +2111,11 @@ static int chg_run_defender(struct chg_drv *chg_drv)
was_triggered, chg_drv->stop_charging,
lock_soc);
}
+
+ /* set dd_state to inactive state (DOCK_DEFEND_ENABLED) */
+ if (bd_state->dd_enabled)
+ bd_state->dd_state = bd_dd_state_update(bd_state->dd_state,
+ false, false);
}
/* run dock_defend */
if (!bd_state->triggered && bd_state->dd_enabled)
@@ -2264,6 +2353,14 @@ static void chg_work(struct work_struct *work)
const int upperbd = chg_drv->charge_stop_level;
const int lowerbd = chg_drv->charge_start_level;
+ /*
+ * Update DD stats last time if DD is active.
+ * NOTE: *** Ensure this is done before disconnect indication to google_battery
+ */
+ if (chg_drv->dd_stats.vtier_idx == GBMS_STATS_BD_TI_DOCK &&
+ chg_drv->bd_state.dd_state == DOCK_DEFEND_ACTIVE)
+ chg_stats_update(chg_drv, &chg_drv->dd_stats);
+
/* reset dock_defend */
if (chg_drv->bd_state.dd_triggered) {
chg_update_charging_state(chg_drv, false, false);
@@ -2318,7 +2415,7 @@ static void chg_work(struct work_struct *work)
goto exit_chg_work;
} else {
- // Run thermal stats when connected to power (preset || online)
+ /* Run thermal stats when connected to power (preset || online) */
thermal_stats_work(chg_drv);
if (chg_drv->stop_charging != 0 && present) {
@@ -2360,6 +2457,11 @@ static void chg_work(struct work_struct *work)
rc = 0;
}
+ /* Book dd stats to correct charging type if DD active */
+ if (chg_drv->dd_stats.vtier_idx == GBMS_STATS_BD_TI_DOCK &&
+ chg_drv->bd_state.dd_state == DOCK_DEFEND_ACTIVE)
+ chg_stats_update(chg_drv, &chg_drv->dd_stats);
+
/*
* chg_drv->disable_pwrsrc -> chg_drv->disable_charging
* update_interval = 0 will reschedule if TEMP-DEFEND is enabled
@@ -3147,6 +3249,13 @@ static ssize_t set_dd_settings(struct device *dev, struct device_attribute *attr
if (chg_drv->bd_state.dd_settings != val) {
chg_drv->bd_state.dd_settings = val;
+
+ /* Update DD stats tier. Book stats till now to DOCK tier */
+ if (DOCK_DEFEND_USER_CLEARED == chg_drv->bd_state.dd_settings) {
+ chg_stats_update(chg_drv, &chg_drv->dd_stats);
+ chg_drv->dd_stats.vtier_idx = GBMS_STATS_BD_TI_DOCK_CLEARED;
+ }
+
if (chg_drv->bat_psy)
power_supply_changed(chg_drv->bat_psy);
}
@@ -3659,6 +3768,68 @@ static ssize_t thermal_stats_store(struct device *dev,
static DEVICE_ATTR_RW(thermal_stats);
+static ssize_t
+thermal_dc_fan_alarm_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct chg_drv *chg_drv = dev_get_drvdata(dev);
+ struct chg_thermal_device *ctdev_dcin = &chg_drv->thermal_devices[CHG_TERMAL_DEVICE_DC_IN];
+ int value = ctdev_dcin->therm_fan_alarm_level;
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", value);;
+}
+
+static ssize_t thermal_dc_fan_alarm_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct chg_drv *chg_drv = dev_get_drvdata(dev);
+ struct chg_thermal_device *ctdev_dcin = &chg_drv->thermal_devices[CHG_TERMAL_DEVICE_DC_IN];
+ int ret = 0;
+ u32 value;
+
+ ret = kstrtou32(buf, 0, &value);
+ if (ret < 0)
+ return ret;
+
+ if (value <= ctdev_dcin->thermal_levels)
+ ctdev_dcin->therm_fan_alarm_level = value;
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(thermal_dc_fan_alarm);
+
+static ssize_t
+charge_stats_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct chg_drv *chg_drv = dev_get_drvdata(dev);
+ struct gbms_ce_tier_stats *dd_stats = &chg_drv->dd_stats;
+ ssize_t len;
+
+ mutex_lock(&chg_drv->stats_lock);
+ len = gbms_tier_stats_cstr(buf, PAGE_SIZE, dd_stats, false);
+ mutex_unlock(&chg_drv->stats_lock);
+
+ return len;
+}
+
+static ssize_t charge_stats_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct chg_drv *chg_drv = dev_get_drvdata(dev);
+
+ if (count < 1)
+ return -ENODATA;
+
+ if (buf[0] == '0')
+ chg_stats_init(chg_drv, &chg_drv->dd_stats, GBMS_STATS_BD_TI_DOCK);
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(charge_stats);
+
static int chg_init_fs(struct chg_drv *chg_drv)
{
int ret;
@@ -3780,6 +3951,18 @@ static int chg_init_fs(struct chg_drv *chg_drv)
return ret;
}
+ ret = device_create_file(chg_drv->device, &dev_attr_thermal_dc_fan_alarm);
+ if (ret != 0) {
+ pr_err("Failed to create thermal_dc_fan_alarm, ret=%d\n", ret);
+ return ret;
+ }
+
+ ret = device_create_file(chg_drv->device, &dev_attr_charge_stats);
+ if (ret != 0) {
+ pr_err("Failed to create charge_stats files, ret=%d\n", ret);
+ return ret;
+ }
+
/* dock_defend */
if (chg_drv->ext_psy_name) {
ret = device_create_file(chg_drv->device, &dev_attr_dd_state);
@@ -4076,7 +4259,7 @@ static int msc_pwr_disable_cb(struct gvotable_election *el,
if (!chg_drv->chg_psy)
return 0;
- chg_vote_input_suspend(chg_drv, MSC_CHG_VOTER, pwr_disable);
+ chg_vote_input_suspend(chg_drv, MSC_PWR_VOTER, pwr_disable);
return 0;
}
@@ -4244,10 +4427,11 @@ static void chg_init_votables(struct chg_drv *chg_drv)
static int fan_get_level(struct chg_thermal_device *tdev)
{
int level = FAN_LVL_UNKNOWN;
+ int alarm_level = tdev->therm_fan_alarm_level;
if (tdev->current_level == 0)
level = FAN_LVL_NOT_CARE;
- else if (tdev->current_level == tdev->thermal_levels)
+ else if (tdev->current_level >= alarm_level)
level = FAN_LVL_ALARM;
else
level = FAN_LVL_MED;
@@ -4790,6 +4974,12 @@ static int chg_tdev_init(struct chg_thermal_device *tdev, const char *name,
return -ENODATA;
}
+ rc = of_property_read_u32(chg_drv->device->of_node,
+ "google,wlc-thermal-dc-fan-alarm",
+ &tdev->therm_fan_alarm_level);
+ if (rc < 0)
+ tdev->therm_fan_alarm_level = tdev->thermal_levels;
+
tdev->chg_drv = chg_drv;
return 0;
@@ -5060,7 +5250,6 @@ static void google_charger_init_work(struct work_struct *work)
struct power_supply *chg_psy = NULL, *usb_psy = NULL;
struct power_supply *wlc_psy = NULL, *bat_psy = NULL;
struct power_supply *ext_psy = NULL, *tcpm_psy = NULL;
- bool pps_enable;
int ret = 0;
chg_psy = psy_get_by_name(chg_drv, chg_drv->chg_psy_name);
@@ -5110,22 +5299,25 @@ static void google_charger_init_work(struct work_struct *work)
chg_drv->tcpm_psy = tcpm_psy;
/* PPS negotiation handled in google_charger */
- pps_enable = of_property_read_bool(chg_drv->device->of_node,
- "google,pps-enable");
if (!tcpm_psy) {
pr_info("PPS not available\n");
- } else if (!pps_enable) {
- pr_info("PPS not enabled\n");
} else {
const char *name = tcpm_psy->desc->name;
+ const bool pps_enable = of_property_read_bool(chg_drv->device->of_node,
+ "google,pps-enable");
ret = pps_init(&chg_drv->pps_data, chg_drv->device, tcpm_psy);
- if (ret == 0 && chg_drv->debug_entry)
- pps_init_fs(&chg_drv->pps_data, chg_drv->debug_entry);
- if (ret < 0)
+ if (ret < 0) {
pr_err("PPS init failure for %s (%d)\n", name, ret);
- else
+ } else if (pps_enable) {
+ if (chg_drv->debug_entry)
+ pps_init_fs(&chg_drv->pps_data, chg_drv->debug_entry);
+ chg_drv->pps_enable = true;
pr_info("PPS available for %s\n", name);
+ } else {
+ chg_drv->pps_data.stage = PPS_DISABLED;
+ pr_info("PPS not enabled\n");
+ }
}
ret = chg_thermal_device_init(chg_drv);
@@ -5142,14 +5334,17 @@ static void google_charger_init_work(struct work_struct *work)
chg_drv->charge_start_level = DEFAULT_CHARGE_START_LEVEL;
mutex_init(&chg_drv->thermal_stats.lock);
thermal_stats_init(&chg_drv->thermal_stats);
+ mutex_init(&chg_drv->stats_lock);
/* reset override charging parameters */
chg_drv->user_fv_uv = -1;
chg_drv->user_cc_max = -1;
/* dock_defend */
- if (chg_drv->ext_psy)
+ if (chg_drv->ext_psy) {
bd_dd_init(chg_drv);
+ chg_stats_init(chg_drv, &chg_drv->dd_stats, GBMS_STATS_BD_TI_DOCK);
+ }
chg_drv->psy_nb.notifier_call = chg_psy_changed;
ret = power_supply_reg_notifier(&chg_drv->psy_nb);
diff --git a/google_cpm.c b/google_cpm.c
index 9fc7644..3339efe 100644
--- a/google_cpm.c
+++ b/google_cpm.c
@@ -124,6 +124,7 @@ struct mdis_thermal_device
u32 *thermal_mitigation;
int thermal_levels;
int current_level;
+ int therm_fan_alarm_level;
};
struct gcpm_drv {
@@ -153,6 +154,7 @@ struct gcpm_drv {
/* MDIS: device and current budget */
struct mdis_thermal_device thermal_device;
struct gvotable_election *mdis_votable;
+ struct gvotable_election *fan_level_votable;
/* CSI */
struct gvotable_election *csi_status_votable;
@@ -252,6 +254,8 @@ struct gcpm_drv {
/* debug fs */
struct dentry *debug_entry;
+
+ int wlc_dc_fcc;
};
#define gcpm_psy_name(psy) \
@@ -696,6 +700,12 @@ static int gcpm_dc_start(struct gcpm_drv *gcpm, int index)
if (ret < 0)
pr_debug("PPS_DC: start cannot update votes (%d)\n", ret);
+ if (gcpm->pps_index == PPS_INDEX_WLC) {
+ gcpm_update_gcpm_fcc(gcpm, "WLC_FCC", gcpm->wlc_dc_fcc, gcpm->wlc_dc_fcc > 0);
+ pr_info("PPS_DC: index=%d vote gcpm_fcc to %d\n",
+ gcpm->pps_index, gcpm->wlc_dc_fcc);
+ }
+
/* this is the CP */
dc_psy = gcpm_chg_get_active_cp(gcpm);
if (!dc_psy) {
@@ -956,6 +966,7 @@ exit_done:
static int gcpm_chg_select(struct gcpm_drv *gcpm)
{
int index = GCPM_DEFAULT_CHARGER;
+ int ret;
if (!gcpm->dc_init_complete)
goto exit_done; /* index == GCPM_DEFAULT_CHARGER; */
@@ -968,6 +979,11 @@ static int gcpm_chg_select(struct gcpm_drv *gcpm)
if (gcpm->dc_ctl == GCPM_DC_CTL_DISABLE_BOTH)
goto exit_done; /* index == GCPM_DEFAULT_CHARGER; */
+ ret = gvotable_get_current_int_vote(gcpm->dc_chg_avail_votable);
+ dev_dbg(gcpm->device, "%s: dc_chg_avail vote: %d\n", __func__, ret);
+ if (ret <= 0)
+ goto exit_done;
+
/*
* check demand first to react to thermal engine, then voltage to
* make sure that we are over min and that we don't start over high
@@ -1001,18 +1017,11 @@ exit_done:
static bool gcpm_chg_dc_check_source(const struct gcpm_drv *gcpm, int index)
{
- int ret;
-
/* Will run detection only the first time */
if (gcpm->tcpm_pps_data.stage == PPS_NOTSUPP &&
gcpm->wlc_pps_data.stage == PPS_NOTSUPP )
return false;
- ret = gvotable_get_current_int_vote(gcpm->dc_chg_avail_votable);
- dev_dbg(gcpm->device, "%s: dc_chg_avail vote: %d\n", __func__, ret);
- if (ret <= 0)
- return false;
-
return gcpm_is_dc(gcpm, index);
}
@@ -1469,6 +1478,9 @@ static int gcpm_pps_wlc_dc_restart_default(struct gcpm_drv *gcpm)
if (ret < 0)
pr_err("PPS_DC: wlc_dc_rd cannot update votes (%d)\n", ret);
+ pr_debug("PPS_DC: gcpm_update_gcpm_fcc unvote\n");
+ gcpm_update_gcpm_fcc(gcpm, "WLC_FCC", 0, false);
+
/* Clear taper count if not complete */
gcpm_taper_ctl(gcpm, 0);
@@ -2315,6 +2327,34 @@ static ssize_t dc_ctl_store(struct device *dev,
}
static DEVICE_ATTR_RW(dc_ctl);
+static ssize_t thermal_mdis_fan_alarm_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct gcpm_drv *gcpm = dev_get_drvdata(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", gcpm->thermal_device.therm_fan_alarm_level);
+}
+
+static ssize_t thermal_mdis_fan_alarm_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct gcpm_drv *gcpm = dev_get_drvdata(dev);
+ int ret = 0;
+ u32 value;
+
+ ret = kstrtou32(buf, 0, &value);
+ if (ret < 0)
+ return ret;
+
+ if (value <= gcpm->thermal_device.thermal_levels)
+ gcpm->thermal_device.therm_fan_alarm_level = value;
+
+ return count;
+}
+static DEVICE_ATTR_RW(thermal_mdis_fan_alarm);
+
/* ------------------------------------------------------------------------ */
static int gcpm_get_max_charge_cntl_limit(struct thermal_cooling_device *tcd,
@@ -2335,6 +2375,40 @@ static int gcpm_get_cur_charge_cntl_limit(struct thermal_cooling_device *tcd,
return 0;
}
+#define FAN_MDIS_ALARM_DEFAULT 3
+static int fan_get_level(struct mdis_thermal_device *tdev)
+{
+ int fan_level = FAN_LVL_UNKNOWN;
+
+ if (tdev->current_level <= 0)
+ fan_level = FAN_LVL_NOT_CARE;
+ else if (tdev->current_level >= tdev->therm_fan_alarm_level)
+ fan_level = FAN_LVL_ALARM;
+ else
+ fan_level = FAN_LVL_MED;
+
+ return fan_level;
+}
+
+static int gcpm_mdis_update_fan(struct gcpm_drv *gcpm)
+{
+ int ret = 0;
+
+ if (!gcpm->fan_level_votable)
+ gcpm->fan_level_votable = gvotable_election_get_handle(VOTABLE_FAN_LEVEL);
+
+ if (gcpm->fan_level_votable) {
+ const int level = fan_get_level(&gcpm->thermal_device);
+
+ ret = gvotable_cast_int_vote(gcpm->fan_level_votable, "THERMAL_MDIS",
+ level, true);
+ if (ret < 0)
+ pr_err("%s: cannot update fan level (%d)", __func__, ret);
+ }
+
+ return ret;
+}
+
static inline int mdis_cast_vote(struct gvotable_election *el, int vote, bool enabled)
{
int ret = 0;
@@ -2428,7 +2502,7 @@ static int gcpm_mdis_update_limits(struct gcpm_drv *gcpm, int msc_fcc,
if (dc_icl != 0 && dc_icl_votable) {
int wlc_state;
- /* need to set online WLC if not onlne */
+ /* need to set online WLC if not online */
wlc_state = mdis_set_wlc_online(gcpm);
if (wlc_state == PPS_PSY_OFFLINE)
dev_err(gcpm->device, "MDIS: WLC offine\n");
@@ -2903,6 +2977,8 @@ static int gcpm_mdis_callback(struct gvotable_election *el, const char *reason,
}
}
+ gcpm_mdis_update_fan(gcpm);
+
if (!gcpm->csi_status_votable) {
gcpm->csi_status_votable = gvotable_election_get_handle(VOTABLE_CSI_STATUS);
if (!gcpm->csi_status_votable)
@@ -3022,6 +3098,11 @@ static int gcpm_init_mdis(struct gcpm_drv *gcpm)
gcpm->mdis_out_limits[i] = limits;
}
+ ret = of_property_read_u32(gcpm->device->of_node, "google,mdis-fan-alarm-level",
+ &tdev->therm_fan_alarm_level);
+ if (ret < 0)
+ tdev->therm_fan_alarm_level = FAN_MDIS_ALARM_DEFAULT;
+
/* mdis thermal engine uses this callback */
gcpm->mdis_votable =
gvotable_create_int_election(NULL, gvotable_comparator_int_min,
@@ -3894,6 +3975,10 @@ static int google_cpm_probe(struct platform_device *pdev)
&gcpm->taper_step_current);
if (ret < 0)
gcpm->taper_step_current = GCPM_TAPER_STEP_CURRENT;
+ ret = of_property_read_u32(pdev->dev.of_node, "google,wlc-dc-fcc-ua",
+ &gcpm->wlc_dc_fcc);
+ if (ret < 0)
+ gcpm->wlc_dc_fcc = 0;
dev_info(gcpm->device, "taper ts_m=%d ts_ccs=%d ts_i=%d ts_cnt=%d ts_g=%d ts_v=%d ts_c=%d\n",
gcpm->taper_step_fv_margin, gcpm->taper_step_cc_step,
@@ -4006,6 +4091,10 @@ static int google_cpm_probe(struct platform_device *pdev)
if (ret)
dev_err(gcpm->device, "Failed to create dc_crl\n");
+ ret = device_create_file(gcpm->device, &dev_attr_thermal_mdis_fan_alarm);
+ if (ret)
+ dev_err(gcpm->device, "Failed to create thermal_mdis_fan_alarm\n");
+
/* give time to fg driver to start */
schedule_delayed_work(&gcpm->init_work,
msecs_to_jiffies(INIT_DELAY_MS));
diff --git a/google_dock.c b/google_dock.c
index 05b1b41..3d6b387 100644
--- a/google_dock.c
+++ b/google_dock.c
@@ -42,6 +42,10 @@
#define DOCK_13_5W_VOUT_UV 9000000
#define DOCK_ICL_RAMP_DELAY_DEFAULT_MS (4 * 1000) /* 4 seconds */
+/* type detection */
+#define EXT_DETECT_DELAY_MS (1000)
+#define EXT_DETECT_RETRIES (3)
+
struct dock_drv {
struct device *device;
struct power_supply *psy;
@@ -51,6 +55,7 @@ struct dock_drv {
struct delayed_work init_work;
struct delayed_work notifier_work;
struct delayed_work icl_ramp_work;
+ struct delayed_work detect_work;
struct alarm icl_ramp_alarm;
struct notifier_block nb;
struct gvotable_election *dc_icl_votable;
@@ -63,11 +68,39 @@ struct dock_drv {
u32 icl_ramp_delay_ms;
int online;
int pogo_ovp_en;
- int pogo_acc_gpio;
- int pogo_acc_irq;
+ int voltage_max; /* > 10.5V mean Ext1 else > 5V mean Ext2. */
+ int detect_retries;
+ struct wakeup_source *detect_ws;
};
-static bool google_dock_find_mode_votable(struct dock_drv *dock);
+/* ------------------------------------------------------------------------- */
+
+static bool google_dock_find_mode_votable(struct dock_drv *dock)
+{
+ if (!dock->chg_mode_votable) {
+ dock->chg_mode_votable = gvotable_election_get_handle(GBMS_MODE_VOTABLE);
+ if (!dock->chg_mode_votable) {
+ dev_err(dock->device, "Could not get CHARGER_MODE votable\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static int google_dock_set_pogo_vout(struct dock_drv *dock,
+ int enabled)
+{
+ if (!google_dock_find_mode_votable(dock))
+ return -EINVAL;
+
+ dev_dbg(dock->device, "pogo_vout_enabled=%d\n", enabled);
+
+ return gvotable_cast_long_vote(dock->chg_mode_votable,
+ DOCK_VOUT_VOTER,
+ GBMS_CHGR_MODE_VOUT,
+ enabled != 0);
+}
/* ------------------------------------------------------------------------- */
static ssize_t is_dock_show(struct device *dev,
@@ -87,15 +120,14 @@ static DEVICE_ATTR_RO(is_dock);
static int debug_pogo_vout_write(void *data, u64 val)
{
struct dock_drv *dock = (struct dock_drv *)data;
+ int ret;
if (val < 0 || val > 1)
return -EINVAL;
- if (google_dock_find_mode_votable(dock))
- gvotable_cast_long_vote(dock->chg_mode_votable,
- DOCK_VOUT_VOTER,
- GBMS_CHGR_MODE_VOUT,
- val != 0);
+ ret = google_dock_set_pogo_vout(dock, val);
+ if (ret)
+ dev_err(dock->device, "Failed to set pogo vout: %d\n", ret);
return 0;
}
@@ -265,9 +297,13 @@ static void google_dock_notifier_check_dc(struct dock_drv *dock)
google_dock_set_icl(dock);
google_dock_icl_ramp_reset(dock);
google_dock_icl_ramp_start(dock);
+ dock->voltage_max = -1; /* Dock detection started, but not done */
+ schedule_delayed_work(&dock->detect_work,
+ msecs_to_jiffies(EXT_DETECT_DELAY_MS));
} else {
google_dock_vote_defaults(dock);
google_dock_icl_ramp_reset(dock);
+ dock->voltage_max = 0;
dev_info(dock->device, "%s: online: %d->0\n",
__func__, dock->online);
@@ -328,99 +364,6 @@ static int google_dock_parse_dt(struct device *dev,
return 0;
}
-static bool google_dock_find_mode_votable(struct dock_drv *dock)
-{
- if (!dock->chg_mode_votable) {
- dock->chg_mode_votable = gvotable_election_get_handle(GBMS_MODE_VOTABLE);
- if (!dock->chg_mode_votable) {
- dev_err(dock->device, "Could not get CHARGER_MODE votable\n");
- return false;
- }
- }
-
- return true;
-}
-
-static irqreturn_t pogo_acc_irq(int irq, void *irq_data)
-{
- struct dock_drv *dock = irq_data;
-
- dev_info(dock->device, "POGO IRQ triggered\n");
-
- /*
- * TODO: b/237977206, rework board doesn't have accessory circuit.
- * use /d/google_dock/pogo_vout as WA instead when accessory
- * is attached/detected.
- */
- if (google_dock_find_mode_votable(dock)) {
- int gpio_en;
-
- gpio_en = gpio_get_value_cansleep(dock->pogo_acc_gpio);
- gvotable_cast_long_vote(dock->chg_mode_votable,
- DOCK_VOUT_VOTER,
- GBMS_CHGR_MODE_VOUT,
- gpio_en != 0);
- }
-
- return IRQ_HANDLED;
-}
-
-static int google_dock_power_out_init(struct device *dev,
- struct dock_drv *dock)
-{
- int ret;
- struct device_node *node = dev->of_node;
-
- /* Accessory Detect IRQ */
- dock->pogo_acc_gpio = of_get_named_gpio(node, "google,pogo-accessory-detect", 0);
- if (dock->pogo_acc_gpio < 0) {
- dev_warn(dev, "pogo accessory detect gpio not found ret:%d\n",
- dock->pogo_acc_gpio);
- return dock->pogo_acc_gpio;
- }
-
- ret = devm_gpio_request(dev, dock->pogo_acc_gpio, "google,pogo-accessory-detect");
- if (ret) {
- dev_err(dev, "failed to request pogo-accessory-detect gpio, ret:%d\n", ret);
- return ret;
- }
-
- ret = gpio_direction_input(dock->pogo_acc_gpio);
- if (ret) {
- dev_err(dev, "failed set pogo-accessory-detect as input, ret:%d\n", ret);
- return ret;
- }
-
- dock->pogo_acc_irq = gpio_to_irq(dock->pogo_acc_gpio);
- if (dock->pogo_acc_irq <= 0) {
- dev_err(dev, "Pogo irq not found\n");
- return -ENODEV;
- }
-
- ret = devm_request_threaded_irq(dev, dock->pogo_acc_irq,
- NULL, pogo_acc_irq,
- (IRQF_SHARED | IRQF_ONESHOT |
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING),
- dev_name(dev), dock);
- if (ret < 0) {
- dev_err(dev, "pogo-accessory-detect request irq failed ret:%d\n", ret);
- return ret;
- }
-
- ret = enable_irq_wake(dock->pogo_acc_irq);
- if (ret) {
- dev_err(dev, "Enable irq wake failed ret:%d\n", ret);
- goto free_irq;
- }
-
- return 0;
-
-free_irq:
- devm_free_irq(dev, dock->pogo_acc_irq, dock);
-
- return ret;
-}
-
static enum power_supply_property dock_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
@@ -465,6 +408,10 @@ static int dock_get_property(struct power_supply *psy,
ret = 0;
break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ val->intval = dock->voltage_max;
+ break;
+
default:
ret = power_supply_get_property(dock->dc_psy, psp, val);
break;
@@ -505,6 +452,9 @@ static int dock_set_property(struct power_supply *psy,
val->intval, true);
changed = true;
break;
+ case GBMS_PROP_POGO_VOUT_ENABLED:
+ ret = google_dock_set_pogo_vout(dock, val->intval);
+ break;
default:
return -EINVAL;
}
@@ -523,6 +473,7 @@ static int dock_property_is_writeable(struct power_supply *psy,
{
switch (psp) {
case POWER_SUPPLY_PROP_CURRENT_MAX:
+ case GBMS_PROP_POGO_VOUT_ENABLED:
return 1;
default:
break;
@@ -582,6 +533,52 @@ retry_init_work:
msecs_to_jiffies(DOCK_DELAY_INIT_MS));
}
+static void google_dock_detect_work(struct work_struct *work)
+{
+ struct dock_drv *dock = container_of(work, struct dock_drv,
+ detect_work.work);
+ union power_supply_propval val;
+ int err = 0;
+
+ if (!dock->dc_psy)
+ return;
+
+ __pm_stay_awake(dock->detect_ws);
+ err = power_supply_get_property(dock->dc_psy, POWER_SUPPLY_PROP_PRESENT, &val);
+ if (err < 0 || val.intval == 0) {
+ if (err < 0)
+ dev_dbg(dock->device, "Error getting charging status: %d\n", err);
+ else
+ dev_dbg(dock->device, "dc_psy not present. Retrying detection\n");
+ goto dock_detect_retry;
+ }
+
+ err = power_supply_get_property(dock->dc_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &val);
+ if (err) {
+ if (err != -EAGAIN)
+ dev_dbg(dock->device, "failed to read dc supply voltage err: %d\n", err);
+
+ goto dock_detect_retry;
+ }
+
+ dev_info(dock->device, "dc_psy v=%d, retries=%d\n", val.intval, dock->detect_retries);
+
+ dock->voltage_max = val.intval;
+ dock->detect_retries = EXT_DETECT_RETRIES;
+ __pm_relax(dock->detect_ws);
+ power_supply_changed(dock->psy);
+ return;
+
+dock_detect_retry:
+ if (dock->detect_retries) {
+ dock->detect_retries--;
+ schedule_delayed_work(&dock->detect_work, msecs_to_jiffies(EXT_DETECT_DELAY_MS));
+ } else {
+ dock->detect_retries = EXT_DETECT_RETRIES;
+ __pm_relax(dock->detect_ws);
+ }
+}
+
static int google_dock_probe(struct platform_device *pdev)
{
const char *dc_psy_name;
@@ -611,12 +608,22 @@ static int google_dock_probe(struct platform_device *pdev)
mutex_init(&dock->dock_lock);
INIT_DELAYED_WORK(&dock->init_work, google_dock_init_work);
INIT_DELAYED_WORK(&dock->icl_ramp_work, google_dock_icl_ramp_work);
+ INIT_DELAYED_WORK(&dock->detect_work, google_dock_detect_work);
alarm_init(&dock->icl_ramp_alarm, ALARM_BOOTTIME,
google_dock_icl_ramp_alarm_cb);
dock->icl_ramp_delay_ms = DOCK_ICL_RAMP_DELAY_DEFAULT_MS;
dock->online = 0;
+ dock->voltage_max = 0;
+ dock->detect_retries = EXT_DETECT_RETRIES;
+
+ dock->detect_ws = wakeup_source_register(NULL, "Detect");
+ if (!dock->detect_ws) {
+ dev_err(dock->device, "Failed to register dock detect wakeup source\n");
+ return -ENOMEM;
+ }
+
platform_set_drvdata(pdev, dock);
psy_cfg.drv_data = dock;
@@ -653,10 +660,6 @@ static int google_dock_probe(struct platform_device *pdev)
return ret;
}
- ret = google_dock_power_out_init(dock->device, dock);
- if (ret)
- dev_warn(dock->device, "Fail to init pogo power out: %d\n", ret);
-
if (dock->pogo_ovp_en >= 0)
gpio_direction_output(dock->pogo_ovp_en, 1);
@@ -676,6 +679,8 @@ static int google_dock_remove(struct platform_device *pdev)
cancel_delayed_work(&dock->notifier_work);
cancel_delayed_work(&dock->icl_ramp_work);
alarm_try_to_cancel(&dock->icl_ramp_alarm);
+ cancel_delayed_work(&dock->detect_work);
+ wakeup_source_unregister(dock->detect_ws);
return 0;
}
diff --git a/google_dual_batt_gauge.c b/google_dual_batt_gauge.c
index b7e4848..33297bf 100644
--- a/google_dual_batt_gauge.c
+++ b/google_dual_batt_gauge.c
@@ -52,6 +52,8 @@ struct dual_fg_drv {
struct gbms_chg_profile chg_profile;
+ struct notifier_block fg_nb;
+
u32 battery_capacity;
int cc_max;
@@ -326,6 +328,17 @@ static int gdbatt_get_property(struct power_supply *psy,
/* TODO: need hash SN */
val->strval = fg_1.strval;
break;
+ /* support bhi */
+ case GBMS_PROP_HEALTH_ACT_IMPEDANCE:
+ case GBMS_PROP_HEALTH_IMPEDANCE:
+ case GBMS_PROP_RESISTANCE:
+ case GBMS_PROP_RESISTANCE_RAW:
+ case GBMS_PROP_RESISTANCE_AVG:
+ case GBMS_PROP_BATTERY_AGE:
+ case GBMS_PROP_CHARGE_FULL_ESTIMATE:
+ case GBMS_PROP_CAPACITY_FADE_RATE:
+ val->intval = fg_1.intval;
+ break;
default:
pr_debug("getting unsupported property: %d\n", psp);
break;
@@ -375,6 +388,14 @@ static int gdbatt_set_property(struct power_supply *psy,
}
dual_fg_drv->cable_in = !!val->intval;
break;
+ case GBMS_PROP_HEALTH_ACT_IMPEDANCE:
+ /* TODO: discuss with BattEng to decide save data */
+ /* if (dual_fg_drv->first_fg_psy) {
+ ret = GPSY_SET_PROP(dual_fg_drv->first_fg_psy, psp, val->intval);
+ if (ret < 0)
+ pr_err("Cannot set the first HEALTH_ACT_IMPEDANCE, ret=%d\n", ret);
+ } */
+ break;
default:
return -EINVAL;
}
@@ -435,6 +456,31 @@ static int gdbatt_init_chg_profile(struct dual_fg_drv *dual_fg_drv)
return ret;
}
+static int psy_changed(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct power_supply *psy = data;
+ struct dual_fg_drv *dual_fg_drv = container_of(nb, struct dual_fg_drv, fg_nb);
+
+ if ((action != PSY_EVENT_PROP_CHANGED) || (psy == NULL) || (psy->desc == NULL) ||
+ (psy->desc->name == NULL))
+ return NOTIFY_OK;
+
+ pr_debug("name=%s evt=%lu\n", psy->desc->name, action);
+
+ if (action == PSY_EVENT_PROP_CHANGED) {
+ bool is_first_fg = (dual_fg_drv->first_fg_psy_name != NULL) &&
+ !strcmp(psy->desc->name, dual_fg_drv->first_fg_psy_name);
+ bool is_second_fg = (dual_fg_drv->second_fg_psy_name != NULL) &&
+ !strcmp(psy->desc->name, dual_fg_drv->second_fg_psy_name);
+
+ if (is_first_fg || is_second_fg)
+ power_supply_changed(dual_fg_drv->psy);
+ }
+
+ return NOTIFY_OK;
+}
+
static void google_dual_batt_gauge_init_work(struct work_struct *work)
{
struct dual_fg_drv *dual_fg_drv = container_of(work, struct dual_fg_drv,
@@ -494,6 +540,11 @@ static void google_dual_batt_gauge_init_work(struct work_struct *work)
if (err < 0)
dev_info(dual_fg_drv->device,"fail to init chg profile (%d)\n", err);
+ dual_fg_drv->fg_nb.notifier_call = psy_changed;
+ err = power_supply_reg_notifier(&dual_fg_drv->fg_nb);
+ if (err < 0)
+ pr_err("cannot register power supply notifer (%d)\n", err);
+
dual_fg_drv->init_complete = true;
dual_fg_drv->resume_complete = true;
mod_delayed_work(system_wq, &dual_fg_drv->gdbatt_work, 0);
diff --git a/google_eeprom.c b/google_eeprom.c
index 75b2755..6260ba1 100644
--- a/google_eeprom.c
+++ b/google_eeprom.c
@@ -22,6 +22,8 @@
#define BATT_EEPROM_TAG_BGPN_LEN GBMS_BGPN_LEN
#define BATT_EEPROM_TAG_BRID_OFFSET 0x17
#define BATT_EEPROM_TAG_BRID_LEN 1
+#define BATT_EEPROM_TAG_MYMD_OFFSET 0x1A
+#define BATT_EEPROM_TAG_MYMD_LEN 4
#define BATT_EEPROM_TAG_STRD_OFFSET 0x1E
#define BATT_EEPROM_TAG_STRD_LEN 12
#define BATT_EEPROM_TAG_RSOC_OFFSET 0x2A
@@ -48,6 +50,8 @@
#define BATT_EEPROM_TAG_EXTRA_START (BATT_EEPROM_TAG_HIST_OFFSET + BATT_TOTAL_HIST_LEN)
// 0x3E2 is the first free with 75 history entries
+#define BATT_EEPROM_TAG_AYMD_OFFSET 0x3E4
+#define BATT_EEPROM_TAG_AYMD_LEN 4
#define BATT_EEPROM_TAG_GCFE_OFFSET 0x3E8
#define BATT_EEPROM_TAG_GCFE_LEN 2
#define BATT_EEPROM_TAG_RAVG_OFFSET 0x3EA
@@ -147,6 +151,14 @@ int gbee_storage_info(gbms_tag_t tag, size_t *addr, size_t *count, void *ptr)
*addr = BATT_EEPROM_TAG_THAS_OFFSET;
*count = BATT_EEPROM_TAG_THAS_LEN;
break;
+ case GBMS_TAG_AYMD:
+ *addr = BATT_EEPROM_TAG_AYMD_OFFSET;
+ *count = BATT_EEPROM_TAG_AYMD_LEN;
+ break;
+ case GBMS_TAG_MYMD:
+ *addr = BATT_EEPROM_TAG_MYMD_OFFSET;
+ *count = BATT_EEPROM_TAG_MYMD_LEN;
+ break;
default:
ret = -ENOENT;
break;
@@ -166,7 +178,8 @@ static int gbee_storage_iter(int index, gbms_tag_t *tag, void *ptr)
GBMS_TAG_STRD, GBMS_TAG_RSOC,
GBMS_TAG_ACIM, GBMS_TAG_GCFE,
GBMS_TAG_RAVG, GBMS_TAG_RFCN,
- GBMS_TAG_THAS};
+ GBMS_TAG_THAS, GBMS_TAG_AYMD,
+ GBMS_TAG_MYMD};
const int count = ARRAY_SIZE(keys);
if (index < 0 || index >= count)
@@ -229,6 +242,7 @@ static bool gbee_storage_is_writable(gbms_tag_t tag)
case GBMS_TAG_RAVG:
case GBMS_TAG_RFCN:
case GBMS_TAG_THAS:
+ case GBMS_TAG_AYMD:
return true;
default:
return false;
diff --git a/max1720x_battery.c b/max1720x_battery.c
index 3a26a1d..784c8c0 100644
--- a/max1720x_battery.c
+++ b/max1720x_battery.c
@@ -259,6 +259,9 @@ struct max1720x_chip {
int bhi_acim;
struct max1720x_rc_switch rc_switch;
+
+ /* support no_battery */
+ bool no_battery;
};
#define MAX1720_EMPTY_VOLTAGE(profile, temp, cycle) \
@@ -266,6 +269,7 @@ struct max1720x_chip {
static irqreturn_t max1720x_fg_irq_thread_fn(int irq, void *obj);
+static int max1720x_set_next_update(struct max1720x_chip *chip);
static bool max17x0x_reglog_init(struct max1720x_chip *chip)
{
@@ -1633,6 +1637,13 @@ static int max1720x_get_cycle_count(struct max1720x_chip *chip)
chip->cycle_count = cycle_count + chip->cycle_count_offset;
+ if (chip->model_ok && reg_cycle >= chip->model_next_update) {
+ err = max1720x_set_next_update(chip);
+ if (err < 0)
+ dev_err(chip->dev, "%s cannot set next update (%d)\n",
+ __func__, err);
+ }
+
return chip->cycle_count;
}
@@ -2830,13 +2841,17 @@ static irqreturn_t max1720x_fg_irq_thread_fn(int irq, void *obj)
if (fg_status & MAX1720X_STATUS_POR) {
mutex_lock(&chip->model_lock);
chip->por = true;
- dev_warn(chip->dev, "POR is set(%04x), model reload:%d\n",
- fg_status, chip->model_reload);
- /* trigger model load if not on-going */
- if (chip->model_reload != MAX_M5_LOAD_MODEL_REQUEST) {
- err = max1720x_model_reload(chip, true);
- if (err < 0)
- fg_status_clr &= ~MAX1720X_STATUS_POR;
+ if (chip->no_battery) {
+ fg_status_clr &= ~MAX1720X_STATUS_POR;
+ } else {
+ dev_warn(chip->dev, "POR is set(%04x), model reload:%d\n",
+ fg_status, chip->model_reload);
+ /* trigger model load if not on-going */
+ if (chip->model_reload != MAX_M5_LOAD_MODEL_REQUEST) {
+ err = max1720x_model_reload(chip, true);
+ if (err < 0)
+ fg_status_clr &= ~MAX1720X_STATUS_POR;
+ }
}
mutex_unlock(&chip->model_lock);
}
@@ -3509,6 +3524,9 @@ static int max1720x_init_model(struct max1720x_chip *chip)
if (chip->gauge_type != MAX_M5_GAUGE_TYPE)
return 0;
+ if (chip->no_battery)
+ return 0;
+
/* ->batt_id negative for no lookup */
if (chip->batt_id >= 0) {
chip->batt_node = max1720x_find_batt_node(chip);
@@ -4281,8 +4299,6 @@ static int max1720x_model_load(struct max1720x_chip *chip)
if (ret < 0)
dev_err(chip->dev, "Load Model fixing drift data rc=%d\n", ret);
- /* The caller need to call max1720x_set_next_update() */
-
/* mark model state as "safe" */
chip->reg_prop_capacity_raw = MAX1720X_REPSOC;
chip->model_state_valid = true;
@@ -4335,14 +4351,6 @@ static void max1720x_model_work(struct work_struct *work)
if (max1720x_check_drift_enabled(&chip->drift_data))
max1720x_fixup_capacity(chip, chip->cap_estimate.cable_in);
- /* save state only when model is running */
- if (chip->model_ok) {
- rc = max1720x_set_next_update(chip);
- if (rc < 0)
- dev_err(chip->dev, "%s cannot set next update (%d)\n",
- __func__, rc);
- }
-
if (chip->model_reload >= MAX_M5_LOAD_MODEL_REQUEST) {
const unsigned long delay = msecs_to_jiffies(60 * 1000);
@@ -4678,6 +4686,9 @@ static int max1720x_init_max_m5(struct max1720x_chip *chip)
{
int ret;
+ if (!chip->model_data)
+ return 0;
+
if (!max_m5_fg_model_check_version(chip->model_data)) {
if (max_m5_needs_reset_model_data(chip->model_data)) {
ret = max_m5_reset_state_data(chip->model_data);
@@ -5846,6 +5857,7 @@ static int max1720x_probe(struct i2c_client *client,
chip->dev = dev;
chip->fake_battery = of_property_read_bool(dev->of_node, "maxim,no-battery") ? 0 : -1;
+ chip->no_battery = of_property_read_bool(dev->of_node, "maxim,no-battery");
chip->primary = client;
chip->batt_id_defer_cnt = DEFAULT_BATTERY_ID_RETRIES;
i2c_set_clientdata(client, chip);
diff --git a/p9221_charger.c b/p9221_charger.c
index 6937e75..0a76190 100644
--- a/p9221_charger.c
+++ b/p9221_charger.c
@@ -53,6 +53,13 @@
#define RTX_BEN_ENABLED 2
#define REENABLE_RTX_DELAY 3000
+#define P9XXX_CHK_RP_DELAY_MS 200
+
+#define P9XXX_VOUT_5480MV 5480
+#define P9XXX_VOUT_5000MV 5000
+#define P9XXX_FOD_CHK_DELAY_MS 2000
+
+#define P9XXX_VOUT_5480MV 5480
enum wlc_align_codes {
WLC_ALIGN_CHECKING = 0,
@@ -64,6 +71,7 @@ enum wlc_align_codes {
enum wlc_chg_mode {
WLC_BPP = 0,
WLC_EPP,
+ WLC_EPP_COMP,
WLC_HPP,
WLC_HPP_HV,
};
@@ -288,6 +296,30 @@ bool p9xxx_is_capdiv_en(struct p9221_charger_data *charger)
return false;
}
+static int p9221_check_fod_by_fsw(struct p9221_charger_data *charger)
+{
+ const int freq_high_thres = charger->pdata->fod_fsw_high;
+ const int freq_low_thres = charger->pdata->fod_fsw_low;
+ u32 vout_mv = 0, freq_khz = 0;
+ int ret;
+
+ ret = charger->chip_get_vout_max(charger, &vout_mv);
+ if (ret == 0 && vout_mv == P9XXX_VOUT_5000MV)
+ return WLC_BPP;
+
+ if (!charger->is_mfg_google || freq_high_thres < 0 || freq_low_thres < 0)
+ return WLC_EPP;
+
+ ret = charger->chip_get_op_freq(charger, &freq_khz);
+ if (ret != 0)
+ return WLC_EPP;
+ if (freq_khz < freq_low_thres ||
+ (charger->fod_mode == WLC_EPP_COMP && freq_khz < freq_high_thres))
+ return WLC_EPP_COMP;
+
+ return WLC_EPP;
+}
+
static void p9221_write_fod(struct p9221_charger_data *charger)
{
int mode = WLC_BPP;
@@ -295,7 +327,7 @@ static void p9221_write_fod(struct p9221_charger_data *charger)
int fod_count = charger->pdata->fod_num;
int ret;
int retries = 3;
- static char *wlc_mode[] = { "BPP", "EPP", "HPP" , "HPP_HV" };
+ static char *wlc_mode[] = { "BPP", "EPP", "EPP_COMP" , "HPP" , "HPP_HV" };
if (charger->no_fod)
@@ -311,9 +343,16 @@ static void p9221_write_fod(struct p9221_charger_data *charger)
fod = charger->pdata->fod;
if (p9221_is_epp(charger) && charger->pdata->fod_epp_num) {
- fod = charger->pdata->fod_epp;
- fod_count = charger->pdata->fod_epp_num;
mode = WLC_EPP;
+ if (charger->pdata->fod_fsw)
+ mode = p9221_check_fod_by_fsw(charger);
+ if (mode == WLC_EPP) {
+ fod = charger->pdata->fod_epp;
+ fod_count = charger->pdata->fod_epp_num;
+ } else if (mode == WLC_EPP_COMP) {
+ fod = charger->pdata->fod_epp_comp;
+ fod_count = charger->pdata->fod_epp_comp_num;
+ }
}
if (p9xxx_is_capdiv_en(charger) && charger->pdata->fod_hpp_num) {
@@ -327,9 +366,8 @@ static void p9221_write_fod(struct p9221_charger_data *charger)
}
}
- if (mode == charger->fod_mode &&
- (mode == WLC_HPP || mode == WLC_HPP_HV))
- return;
+ if (mode == charger->fod_mode)
+ goto done;
charger->fod_mode = mode;
@@ -361,7 +399,7 @@ static void p9221_write_fod(struct p9221_charger_data *charger)
}
if (memcmp(fod, fod_read, fod_count) == 0)
- return;
+ goto done;
p9221_hex_str(fod_read, fod_count, s, sizeof(s), 0);
dev_err(&charger->client->dev,
@@ -375,6 +413,10 @@ no_fod:
dev_warn(&charger->client->dev, "FOD not set! bpp:%d epp:%d hpp:%d hpp_hv:%d r:%d\n",
charger->pdata->fod_num, charger->pdata->fod_epp_num,
charger->pdata->fod_hpp_num, charger->pdata->fod_hpp_hv_num, retries);
+done:
+ if (charger->pdata->fod_fsw)
+ mod_delayed_work(system_wq, &charger->chk_fod_work,
+ msecs_to_jiffies(P9XXX_FOD_CHK_DELAY_MS));
}
#define CC_DATA_LOCK_MS 250
@@ -457,7 +499,7 @@ static int p9221_send_csp(struct p9221_charger_data *charger, u8 stat)
}
if (charger->online) {
- ret = p9221_reg_write_8(charger, P9221R5_CHARGE_STAT_REG, stat);
+ ret = p9221_reg_write_8(charger, charger->reg_csp_addr, stat);
if (ret == 0)
ret = charger->chip_set_cmd(charger, P9221R5_COM_SENDCSP);
if (ret < 0)
@@ -596,19 +638,56 @@ static int p9221_set_switch_reg(struct p9221_charger_data *charger, bool enable)
#define EPP_MODE_REQ_PWR 15
#define EPP_MODE_REQ_VOUT 12000
+#define WLC_VOUT_RAMP_DOWN_MV 15300
+#define WLC_VOUT_CFG_STEP 40 /* b/194346461 ramp down VOUT */
static int p9xxx_set_bypass_mode(struct p9221_charger_data *charger)
{
const int req_pwr = EPP_MODE_REQ_PWR;
+ const int vout_target = WLC_VOUT_RAMP_DOWN_MV;
int i, count, ret;
u8 cdmode, currpwr;
u32 vout_mv;
+ if (!charger->online)
+ return 0;
+
/* Check it's in Cap Div mode */
ret = charger->reg_read_8(charger, P9412_CDMODE_STS_REG, &cdmode);
if (ret || (cdmode & CDMODE_BYPASS_MODE))
return ret;
dev_info(&charger->client->dev, "cdmode_reg=%02x\n", cdmode);
+ usleep_range(500 * USEC_PER_MSEC, 510 * USEC_PER_MSEC);
+ /* Ramp down WLC Vout to 15.3V */
+ while (true) {
+ ret = charger->chip_get_vout(charger, &vout_mv);
+ if (ret < 0 || vout_mv == 0) {
+ dev_err(&charger->client->dev, "%s: invalid vout %d\n", __func__, ret);
+ return ret;
+ }
+
+ if (vout_mv < vout_target) {
+ dev_info(&charger->client->dev, "%s: underflow vout=%d, (target=%d)\n",
+ __func__, vout_mv, vout_target);
+ break;
+ }
+
+ vout_mv -= WLC_VOUT_CFG_STEP;
+
+ ret = charger->chip_set_vout_max(charger, vout_mv);
+ if (ret < 0) {
+ dev_err(&charger->client->dev, "%s: cannot set vout %d\n", __func__, ret);
+ return ret;
+ } else {
+ dev_info(&charger->client->dev, "%s: vout set to %d\n", __func__, vout_mv);
+ usleep_range(250 * USEC_PER_MSEC, 260 * USEC_PER_MSEC);
+ }
+ }
+
+ if (!charger->online)
+ return 0;
+
+ usleep_range(500 * USEC_PER_MSEC, 510 * USEC_PER_MSEC);
for (count = 0; count < 3; count++) {
/* Change the Requested Power to 15W */
ret = charger->reg_write_8(charger, P9412_PROP_REQ_PWR_REG, req_pwr * 2);
@@ -665,8 +744,12 @@ static int p9221_reset_wlc_dc(struct p9221_charger_data *charger)
const int extben_gpio = charger->pdata->ext_ben_gpio;
int ret;
+ if (!charger->pdata->has_wlc_dc)
+ return -EOPNOTSUPP;
+
charger->wlc_dc_enabled = false;
+ usleep_range(500 * USEC_PER_MSEC, 510 * USEC_PER_MSEC);
p9xxx_gpio_set_value(charger, dc_sw_gpio, 0);
p9xxx_gpio_set_value(charger, extben_gpio, 0);
@@ -696,6 +779,10 @@ static int p9221_reset_wlc_dc(struct p9221_charger_data *charger)
p9221_write_fod(charger);
}
+ ret = p9221_reg_write_8(charger, P9412_MOT_REG, P9412_MOT_65PCT);
+ if (ret < 0)
+ dev_warn(&charger->client->dev, "Fail to set MOT register(%d)\n", ret);
+
return ret;
}
@@ -872,6 +959,7 @@ static void p9221_set_offline(struct p9221_charger_data *charger)
mutex_lock(&charger->stats_lock);
charger->online = false;
charger->online_at = 0;
+ charger->check_rp = RP_NOTSET;
cancel_delayed_work(&charger->charge_stats_work);
p9221_dump_charge_stats(charger);
mutex_unlock(&charger->stats_lock);
@@ -1062,7 +1150,7 @@ static void p9221_power_mitigation_work(struct work_struct *work)
{
struct p9221_charger_data *charger = container_of(work,
struct p9221_charger_data, power_mitigation_work.work);
- const u32 vout_5500mv = 5500;
+ int ret = 0;
charger->wait_for_online = false;
@@ -1077,17 +1165,19 @@ static void p9221_power_mitigation_work(struct work_struct *work)
}
if (!p9221_is_epp(charger)) {
- if (charger->trigger_power_mitigation) {
- dev_info(&charger->client->dev, "power_mitigate: change Vout to 5.5V\n");
- charger->chip_set_vout_max(charger, vout_5500mv);
- dev_info(&charger->client->dev, "power_mitigate: write 0 to 0xF4\n");
- p9221_reg_write_8(charger, 0xF4, 0);
- if (charger->ll_bpp_cep == 1)
- p9221_ll_bpp_cep(charger, charger->last_capacity);
+ /* only for LL */
+ if (charger->trigger_power_mitigation && charger->ll_bpp_cep == 1) {
+ dev_info(&charger->client->dev,
+ "power_mitigate: change Vout to %d mV and disable CMFET\n",
+ P9XXX_VOUT_5480MV);
+ ret = charger->chip_set_vout_max(charger, P9XXX_VOUT_5480MV);
+ ret |= p9221_reg_write_8(charger, P9412_CMFET_L_REG, 0);
+ if (ret < 0)
+ dev_err(&charger->client->dev, "Fail to configure LL\n");
+ p9221_ll_bpp_cep(charger, charger->last_capacity);
}
charger->fod_cnt = 0;
- dev_info(&charger->client->dev,
- "power_mitigate: already BPP\n");
+ dev_info(&charger->client->dev, "power_mitigate: already BPP\n");
return;
}
@@ -2152,6 +2242,7 @@ static int p9221_set_psy_online(struct p9221_charger_data *charger, int online)
if (online == PPS_PSY_PROG_ONLINE) {
const int extben_gpio = charger->pdata->ext_ben_gpio;
bool feat_enable;
+ u8 val8;
pr_info("%s: online=%d, enabled=%d wlc_dc_enabled=%d prop_mode_en=%d\n",
__func__, online, enabled, wlc_dc_enabled,
@@ -2177,7 +2268,8 @@ static int p9221_set_psy_online(struct p9221_charger_data *charger, int online)
}
/* not there, must return not supp */
- if (!charger->pdata->has_wlc_dc || !p9221_is_online(charger))
+ if (!charger->pdata->has_wlc_dc || !p9221_is_online(charger)
+ || !p9221_is_epp(charger))
return -EOPNOTSUPP;
if (charger->last_capacity > WLC_HPP_SOC_LIMIT)
@@ -2189,6 +2281,15 @@ static int p9221_set_psy_online(struct p9221_charger_data *charger, int online)
return -EAGAIN;
}
+ ret = charger->reg_read_8(charger, P9221R5_EPP_TX_GUARANTEED_POWER_REG, &val8);
+ if (ret < 0)
+ return -EINVAL;
+ if (val8 < P9XXX_TX_GUAR_PWR_15W) {
+ dev_warn(&charger->client->dev, "Tx guar_pwr=%dW\n", val8 / 2);
+ p9221_set_auth_dc_icl(charger, false);
+ return -EOPNOTSUPP;
+ }
+
/* will return -EAGAIN until the feature is supported */
mutex_lock(&charger->auth_lock);
@@ -2257,6 +2358,11 @@ static int p9221_set_psy_online(struct p9221_charger_data *charger, int online)
p9221_set_switch_reg(charger, true);
+ /* Adjusting the minimum on time(MOT) for mitigate LC node voltage overshoot */
+ ret = p9221_reg_write_8(charger, P9412_MOT_REG, P9412_MOT_40PCT);
+ if (ret < 0)
+ dev_warn(&charger->client->dev, "Fail to adjust MOT(%d)\n", ret);
+
return 1;
} else if (wlc_dc_enabled) {
/* TODO: thermals might come in and disable with 0 */
@@ -2329,15 +2435,22 @@ static void p9221_dream_defend(struct p9221_charger_data *charger)
static void p9221_ll_check_chg_term(struct p9221_charger_data *charger, int capacity)
{
+ int ll_icl_ua;
+
+ ll_icl_ua = gvotable_get_int_vote(charger->dc_icl_votable, LL_BPP_CEP_VOTER);
+
if (capacity < 97) {
+ if (ll_icl_ua == P9221_LL_BPP_CHG_TERM_UA)
+ dev_info(&charger->client->dev, "power_mitigate: remove LL_BPP_CEP_VOTER(capacity=%d)\n",
+ capacity);
gvotable_cast_int_vote(charger->dc_icl_votable, LL_BPP_CEP_VOTER, 0, false);
- dev_dbg(&charger->client->dev, "power_mitigate: remove LL_BPP_CEP_VOTER\n");
} else if (capacity == 101) {
/* when gdf==100, it's chg_term and vote 200mA */
+ if (ll_icl_ua != P9221_LL_BPP_CHG_TERM_UA)
+ dev_info(&charger->client->dev, "power_mitigate: LL_BPP vote DC_ICL=%duA(capacity=%d)\n",
+ P9221_LL_BPP_CHG_TERM_UA, capacity);
gvotable_cast_int_vote(charger->dc_icl_votable, LL_BPP_CEP_VOTER,
P9221_LL_BPP_CHG_TERM_UA, true);
- dev_dbg(&charger->client->dev, "power_mitigate: vote DC_ICL=%duA\n",
- P9221_LL_BPP_CHG_TERM_UA);
}
}
@@ -2359,9 +2472,9 @@ static void p9221_ll_bpp_cep(struct p9221_charger_data *charger, int capacity)
p9221_ll_check_chg_term(charger, capacity);
if (icl_ua > 0)
- dev_info(&charger->client->dev,
- "power_mitigate: set ICL to %duA\n",
- gvotable_get_current_int_vote(charger->dc_icl_votable));
+ dev_dbg(&charger->client->dev,
+ "power_mitigate: DD vote ICL = %duA\n",
+ gvotable_get_int_vote(charger->dc_icl_votable, DD_VOTER));
}
/*
@@ -2634,7 +2747,8 @@ static int p9221_enable_interrupts(struct p9221_charger_data *charger)
mask = charger->ints.stat_rtx_mask;
} else {
mask = charger->ints.stat_limit_mask | charger->ints.stat_cc_mask |
- charger->ints.vrecton_bit | charger->ints.prop_mode_mask;
+ charger->ints.vrecton_bit | charger->ints.prop_mode_mask |
+ charger->ints.extended_mode_bit;
if (charger->pdata->needs_dcin_reset ==
P9221_WC_DC_RESET_VOUTCHANGED)
@@ -2709,6 +2823,13 @@ static int p9221_set_dc_icl(struct p9221_charger_data *charger)
}
}
+ if (!p9221_is_epp(charger) && charger->last_capacity == 100 && charger->ll_bpp_cep < 0) {
+ dev_info(&charger->client->dev, "vote ICL as %d for BPP mode(capacity=%d)\n",
+ P9221_LL_BPP_CHG_TERM_UA, charger->last_capacity);
+ gvotable_cast_int_vote(charger->dc_icl_votable, LL_BPP_CEP_VOTER,
+ P9221_LL_BPP_CHG_TERM_UA, true);
+ }
+
/* Default to BPP ICL */
icl = P9221_DC_ICL_BPP_UA;
@@ -2923,6 +3044,39 @@ static void p9221_icl_ramp_start(struct p9221_charger_data *charger)
ms_to_ktime(charger->pdata->icl_ramp_delay_ms));
}
+static void p9xxx_check_ll_bpp_cep(struct p9221_charger_data *charger)
+{
+ int ret, ll_icl_ua;
+ u32 vout_mv = 0;
+ u8 val8 = 0;
+ bool is_ll_bpp = true;
+
+ ll_icl_ua = gvotable_get_int_vote(charger->dc_icl_votable, LL_BPP_CEP_VOTER);
+
+ if (ll_icl_ua <= 0 || charger->ll_bpp_cep == 1)
+ return;
+
+ if (p9221_is_epp(charger))
+ is_ll_bpp = false;
+
+ ret = charger->chip_get_vout_max(charger, &vout_mv);
+ if (ret < 0 || vout_mv != P9XXX_VOUT_5480MV)
+ is_ll_bpp = false;
+ ret = p9221_reg_read_8(charger, P9412_CMFET_L_REG, &val8);
+ if (ret < 0 || val8 != 0)
+ is_ll_bpp = false;
+
+ if (is_ll_bpp) {
+ charger->ll_bpp_cep = 1;
+ dev_info(&charger->client->dev, "ll_bpp_cep = %d\n", charger->ll_bpp_cep);
+ } else {
+ charger->ll_bpp_cep = 0;
+ dev_info(&charger->client->dev,
+ "remove LL_BPP_CEP_VOTER(capacity=%d)\n", charger->last_capacity);
+ gvotable_cast_int_vote(charger->dc_icl_votable, LL_BPP_CEP_VOTER, 0, false);
+ }
+}
+
static void p9221_set_online(struct p9221_charger_data *charger)
{
int ret;
@@ -3156,6 +3310,9 @@ static void p9221_notifier_check_dc(struct p9221_charger_data *charger)
if (!charger->dc_icl_bpp)
p9221_icl_ramp_start(charger);
+ /* Check if Tx in LL BPP mode */
+ p9xxx_check_ll_bpp_cep(charger);
+
ret = p9221_reg_read_16(charger, P9221_OTP_FW_MINOR_REV_REG,
&charger->fw_rev);
if (ret)
@@ -3267,6 +3424,10 @@ static void p9221_notifier_work(struct work_struct *work)
goto done_relax;
}
+ /* Calibrate light load */
+ if (charger->pdata->light_load)
+ p9xxx_chip_set_light_load_reg(charger, P9222_LIGHT_LOAD_VALUE);
+
p9xxx_write_q_factor(charger);
if (charger->pdata->tx_4191q > 0)
p9xxx_update_q_factor(charger);
@@ -3827,6 +3988,10 @@ static ssize_t p9221_store_txlen(struct device *dev,
if (!charger->online)
return -ENODEV;
+ /* Don't send bidi data in cases of BPP and NOT dream-defend */
+ if (!p9221_is_epp(charger) && !charger->trigger_power_mitigation)
+ return -EINVAL;
+
charger->tx_len = len;
ret = set_renego_state(charger, P9XXX_SEND_DATA);
@@ -4195,6 +4360,10 @@ static ssize_t wpc_ready_show(struct device *dev,
struct i2c_client *client = to_i2c_client(dev);
struct p9221_charger_data *charger = i2c_get_clientdata(client);
+ /* Skip it on BPP */
+ if (!p9221_is_epp(charger) || !charger->pdata->has_wlc_dc)
+ return scnprintf(buf, PAGE_SIZE, "N\n");
+
return scnprintf(buf, PAGE_SIZE, "%c\n",
p9412_is_calibration_done(charger) ? 'Y' : 'N');
}
@@ -4615,11 +4784,14 @@ static int p9382_set_rtx(struct p9221_charger_data *charger, bool enable)
{
int ret = 0, tx_icl = -1;
+ if ((enable && charger->ben_state) || (!enable && !charger->ben_state)) {
+ logbuffer_prlog(charger->rtx_log, "RTx is %s\n", enable ? "enabled" : "disabled");
+ return 0;
+ }
+
mutex_lock(&charger->rtx_lock);
if (enable == 0) {
- logbuffer_log(charger->rtx_log, "disable rtx\n");
-
if (charger->is_rtx_mode) {
ret = charger->chip_tx_mode_en(charger, false);
charger->is_rtx_mode = false;
@@ -4632,6 +4804,9 @@ static int p9382_set_rtx(struct p9221_charger_data *charger, bool enable)
if (ret)
dev_err(&charger->client->dev,
"fail to enable dcin, ret=%d\n", ret);
+
+ logbuffer_log(charger->rtx_log, "disable rtx\n");
+
goto done;
} else {
logbuffer_log(charger->rtx_log, "enable rtx");
@@ -4685,7 +4860,7 @@ static int p9382_set_rtx(struct p9221_charger_data *charger, bool enable)
dev_err(&charger->client->dev,
"cannot enter rTX mode (%d)\n", ret);
logbuffer_log(charger->rtx_log,
- "cannot enter rTX mode (%d)\n", ret);
+ "cannot enter rTX mode (%d)", ret);
p9382_ben_cfg(charger, RTX_BEN_DISABLED);
ret = p9382_disable_dcin_en(charger, false);
@@ -4746,6 +4921,79 @@ done:
return ret;
}
+#define P9412_RTX_OCP_THRES_MA 900
+static int p9412_check_rtx_ocp(struct p9221_charger_data *chgr)
+{
+ int ret, cnt, retry, ocp_count = 0, current_now, chk_ms, total_delay;
+ u16 status_reg;
+
+ total_delay = chgr->rtx_total_delay > 0 ? chgr->rtx_total_delay : 3000;
+ chk_ms = chgr->rtx_ocp_chk_ms > 0 ? chgr->rtx_ocp_chk_ms : 20;
+ retry = (total_delay / chk_ms > 0) ? (total_delay / chk_ms) : 1;
+
+ logbuffer_log(chgr->rtx_log, "use rtx_ocp_chk_ms=%d retry=%d", chk_ms, retry);
+
+ for (cnt = 0; cnt < retry; cnt++) {
+ if (!chgr->ben_state)
+ return -EIO;
+ /* check if rx_is_connected: if yes, goto 7V */
+ ret = chgr->reg_read_16(chgr, P9221_STATUS_REG, &status_reg);
+ if (ret < 0) {
+ logbuffer_log(chgr->rtx_log, "ioerr disable RTx(%d)", ret);
+ return -EIO;
+ }
+ if (status_reg & chgr->ints.rx_connected_bit) {
+ logbuffer_log(chgr->rtx_log, "rx is connected, goto 7V");
+ return 0;
+ }
+ /* check if (ocp_cnt > 2): if yes, disable rtx */
+ ret = chgr->chip_get_iout(chgr, &current_now);
+ if (ret == 0 && current_now > P9412_RTX_OCP_THRES_MA) {
+ ocp_count++;
+ logbuffer_log(chgr->rtx_log, "cnt=%d,current_now=%d,ocp_count=%d",
+ cnt, current_now, ocp_count);
+ }
+ if (ret < 0) {
+ logbuffer_log(chgr->rtx_log, "iout disable RTx(%d)", ret);
+ return -EINVAL;
+ }
+ if (ocp_count > 2 || current_now == 0) {
+ logbuffer_log(chgr->rtx_log, "ocp_count=%d current_now=%d disable RTx",
+ ocp_count, current_now);
+ return -EINVAL;
+ }
+ usleep_range(chk_ms * USEC_PER_MSEC, (chk_ms + 2) * USEC_PER_MSEC);
+ }
+
+ return 0;
+}
+
+static void p9412_chk_rtx_ocp_work(struct work_struct *work)
+{
+ struct p9221_charger_data *chgr = container_of(work,
+ struct p9221_charger_data, chk_rtx_ocp_work.work);
+ int ret;
+
+ /* check TX OCP before enable 7V */
+ ret = p9412_check_rtx_ocp(chgr);
+ if (!chgr->ben_state)
+ return;
+ if (ret < 0) {
+ p9382_set_rtx(chgr, false);
+ return;
+ }
+
+ ret = chgr->reg_write_8(chgr, P9412_APBSTPING_REG, P9412_APBSTPING_7V);
+ ret |= chgr->reg_write_8(chgr, P9412_APBSTCONTROL_REG, P9412_APBSTPING_7V);
+ if (ret == 0) {
+ schedule_delayed_work(&chgr->rtx_work, msecs_to_jiffies(P9382_RTX_TIMEOUT_MS));
+ } else {
+ logbuffer_log(chgr->rtx_log, "Failed to configure Ext-Boost Vout registers(%d)",
+ ret);
+ p9382_set_rtx(chgr, false);
+ }
+}
+
static ssize_t rtx_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -4768,15 +5016,19 @@ static ssize_t rtx_store(struct device *dev,
int ret;
if (buf[0] == '0') {
- dev_info(&charger->client->dev, "battery share off\n");
- logbuffer_log(charger->rtx_log, "battery share off");
- cancel_delayed_work_sync(&charger->rtx_work);
+ logbuffer_prlog(charger->rtx_log, "battery share off");
+ mutex_lock(&charger->rtx_lock);
charger->rtx_reset_cnt = 0;
+ mutex_unlock(&charger->rtx_lock);
ret = p9382_set_rtx(charger, false);
+ cancel_delayed_work_sync(&charger->rtx_work);
+ if (charger->pdata->apbst_en)
+ cancel_delayed_work_sync(&charger->chk_rtx_ocp_work);
} else if (buf[0] == '1') {
- dev_info(&charger->client->dev, "battery share on\n");
- logbuffer_log(charger->rtx_log, "battery share on");
+ logbuffer_prlog(charger->rtx_log, "battery share on");
+ mutex_lock(&charger->rtx_lock);
charger->rtx_reset_cnt = 0;
+ mutex_unlock(&charger->rtx_lock);
ret = p9382_set_rtx(charger, true);
} else {
return -EINVAL;
@@ -5126,22 +5378,26 @@ static void p9xxx_reset_rtx_for_ocp(struct p9221_charger_data *charger)
{
int ext_bst_on = 0;
- if (charger->pdata->ben_gpio > 0)
- ext_bst_on = gpio_get_value_cansleep(charger->pdata->ben_gpio);
-
+ mutex_lock(&charger->rtx_lock);
charger->rtx_reset_cnt += 1;
- if ((charger->rtx_reset_cnt >= RTX_RESET_COUNT_MAX) || ext_bst_on) {
+ if (charger->rtx_reset_cnt >= RTX_RESET_COUNT_MAX) {
if (charger->rtx_reset_cnt == RTX_RESET_COUNT_MAX)
charger->rtx_err = RTX_HARD_OCP;
charger->rtx_reset_cnt = 0;
}
+ mutex_unlock(&charger->rtx_lock);
charger->is_rtx_mode = false;
p9382_set_rtx(charger, false);
msleep(REENABLE_RTX_DELAY);
+ if (charger->pdata->ben_gpio > 0)
+ ext_bst_on = gpio_get_value_cansleep(charger->pdata->ben_gpio);
+ if (ext_bst_on)
+ return;
+
if (charger->rtx_reset_cnt) {
dev_info(&charger->client->dev, "re-enable RTx mode, cnt=%d\n", charger->rtx_reset_cnt);
logbuffer_log(charger->rtx_log, "re-enable RTx mode, cnt=%d\n", charger->rtx_reset_cnt);
@@ -5210,8 +5466,8 @@ static void rtx_irq_handler(struct p9221_charger_data *charger, u16 irq_src)
if (mode_reg == P9XXX_SYS_OP_MODE_TX_MODE) {
charger->is_rtx_mode = true;
cancel_delayed_work_sync(&charger->rtx_work);
- schedule_delayed_work(&charger->rtx_work,
- msecs_to_jiffies(P9382_RTX_TIMEOUT_MS));
+ if (!charger->pdata->apbst_en)
+ schedule_delayed_work(&charger->rtx_work, msecs_to_jiffies(P9382_RTX_TIMEOUT_MS));
}
dev_info(&charger->client->dev,
"P9221_SYSTEM_MODE_REG reg: %02x\n",
@@ -5273,12 +5529,9 @@ static void rtx_irq_handler(struct p9221_charger_data *charger, u16 irq_src)
}
if (irq_src & csp_bit) {
- ret = p9221_reg_read_8(charger, P9382A_CHARGE_STAT_REG,
- &csp_reg);
+ ret = p9221_reg_read_8(charger, charger->reg_csp_addr, &csp_reg);
if (ret) {
- logbuffer_log(charger->rtx_log,
- "failed to read CSP_REG reg: %d",
- ret);
+ logbuffer_log(charger->rtx_log, "failed to read CSP_REG reg: %d", ret);
} else {
charger->rtx_csp = csp_reg;
schedule_work(&charger->uevent_work);
@@ -5523,6 +5776,18 @@ static void p9221_irq_handler(struct p9221_charger_data *charger, u16 irq_src)
/* charger->prop_mode_en is reset on disconnect */
}
+
+ /* This only necessary for P9222 */
+ if (irq_src & charger->ints.extended_mode_bit) {
+ if (charger->check_rp == RP_NOTSET &&
+ charger->pdata->epp_rp_value != -1) {
+ pm_stay_awake(charger->dev);
+ charger->check_rp = RP_CHECKING;
+ cancel_delayed_work_sync(&charger->chk_rp_work);
+ schedule_delayed_work(&charger->chk_rp_work,
+ msecs_to_jiffies(P9XXX_CHK_RP_DELAY_MS));
+ }
+ }
}
#define IRQ_DEBOUNCE_TIME_MS 4
@@ -5639,6 +5904,27 @@ static irqreturn_t p9221_irq_det_thread(int irq, void *irq_data)
return IRQ_HANDLED;
}
+static void p9xxx_chk_fod_work(struct work_struct *work)
+{
+ struct p9221_charger_data *charger = container_of(work,
+ struct p9221_charger_data, chk_fod_work.work);
+
+ if (!charger->online)
+ return;
+
+ p9221_write_fod(charger);
+}
+
+static void p9xxx_chk_rp_work(struct work_struct *work)
+{
+ struct p9221_charger_data *charger = container_of(work,
+ struct p9221_charger_data, chk_rp_work.work);
+
+ charger->chip_renegotiate_pwr(charger);
+ pm_relax(charger->dev);
+}
+
+
static void p9382_rtx_disable_work(struct work_struct *work)
{
struct p9221_charger_data *charger = container_of(work,
@@ -5907,6 +6193,31 @@ static int p9221_parse_dt(struct device *dev,
}
}
+
+ pdata->fod_epp_comp_num =
+ of_property_count_elems_of_size(node, "fod_epp_comp", sizeof(u8));
+ if (pdata->fod_epp_comp_num <= 0) {
+ dev_err(dev, "No dt fod epp comp provided (%d)\n",
+ pdata->fod_epp_comp_num);
+ pdata->fod_epp_comp_num = 0;
+ } else {
+ if (pdata->fod_epp_comp_num > P9221R5_NUM_FOD) {
+ dev_err(dev, "Incorrect num of EPP COMP FOD %d, using first %d\n",
+ pdata->fod_epp_comp_num, P9221R5_NUM_FOD);
+ pdata->fod_epp_comp_num = P9221R5_NUM_FOD;
+ }
+ ret = of_property_read_u8_array(node, "fod_epp_comp", pdata->fod_epp_comp,
+ pdata->fod_epp_comp_num);
+ if (ret == 0) {
+ char buf[P9221R5_NUM_FOD * 3 + 1];
+
+ p9221_hex_str(pdata->fod_epp_comp, pdata->fod_epp_comp_num, buf,
+ pdata->fod_epp_comp_num * 3 + 1, false);
+ dev_info(dev, "dt fod_epp_comp: %s (%d)\n", buf,
+ pdata->fod_epp_comp_num);
+ }
+ }
+
pdata->fod_hpp_num =
of_property_count_elems_of_size(node, "fod_hpp", sizeof(u8));
if (pdata->fod_hpp_num <= 0) {
@@ -5951,6 +6262,26 @@ static int p9221_parse_dt(struct device *dev,
}
}
+ ret = of_property_read_bool(node, "google,fod_fsw_base");
+ if (ret)
+ pdata->fod_fsw = true;
+
+ ret = of_property_read_u32(node, "google,fod_fsw_high_thres", &data);
+ if (ret < 0) {
+ pdata->fod_fsw_high = -1;
+ } else {
+ pdata->fod_fsw_high = data;
+ dev_info(dev, "dt fod_fsw_high_thres:%d\n", pdata->fod_fsw_high);
+ }
+
+ ret = of_property_read_u32(node, "google,fod_fsw_low_thres", &data);
+ if (ret < 0) {
+ pdata->fod_fsw_low = -1;
+ } else {
+ pdata->fod_fsw_low = data;
+ dev_info(dev, "dt fod_fsw_low_thres:%d\n", pdata->fod_fsw_low);
+ }
+
ret = of_property_read_u32(node, "google,q_value", &data);
if (ret < 0) {
pdata->q_value = -1;
@@ -5975,6 +6306,14 @@ static int p9221_parse_dt(struct device *dev,
dev_info(dev, "dt epp_rp_value: %d\n", pdata->epp_rp_value);
}
+ ret = of_property_read_u32(node, "google,epp_rp_low_value", &data);
+ if (ret < 0) {
+ pdata->epp_rp_low_value = -1;
+ } else {
+ pdata->epp_rp_low_value = data;
+ dev_info(dev, "dt epp_rp_low_value: %d\n", pdata->epp_rp_low_value);
+ }
+
pdata->epp_vout_mv = P9221_MAX_VOUT_SET_MV_DEFAULT;
ret = of_property_read_u32(node, "google,epp_vout_mv", &data);
if (ret == 0) {
@@ -6126,6 +6465,9 @@ static int p9221_parse_dt(struct device *dev,
else
pdata->epp_icl = data;
+ /* Calibrate light load */
+ pdata->light_load = of_property_read_bool(node, "google,light_load");
+
return 0;
}
@@ -6350,6 +6692,7 @@ static int p9221_charger_probe(struct i2c_client *client,
charger->last_disable = -1;
charger->irq_at = 0;
charger->ll_bpp_cep = -EINVAL;
+ charger->check_rp = RP_NOTSET;
mutex_init(&charger->io_lock);
mutex_init(&charger->cmd_lock);
mutex_init(&charger->stats_lock);
@@ -6369,6 +6712,9 @@ static int p9221_charger_probe(struct i2c_client *client,
INIT_DELAYED_WORK(&charger->rtx_work, p9382_rtx_work);
INIT_DELAYED_WORK(&charger->auth_dc_icl_work, p9221_auth_dc_icl_work);
INIT_DELAYED_WORK(&charger->fg_work, p9221_fg_work);
+ INIT_DELAYED_WORK(&charger->chk_rp_work, p9xxx_chk_rp_work);
+ INIT_DELAYED_WORK(&charger->chk_rtx_ocp_work, p9412_chk_rtx_ocp_work);
+ INIT_DELAYED_WORK(&charger->chk_fod_work, p9xxx_chk_fod_work);
INIT_WORK(&charger->uevent_work, p9221_uevent_work);
INIT_WORK(&charger->rtx_disable_work, p9382_rtx_disable_work);
INIT_WORK(&charger->rtx_reset_work, p9xxx_rtx_reset_work);
@@ -6594,6 +6940,8 @@ static int p9221_charger_probe(struct i2c_client *client,
} else {
debugfs_create_bool("no_fod", 0644, charger->debug_entry, &charger->no_fod);
debugfs_create_u32("de_q_value", 0644, charger->debug_entry, &charger->de_q_value);
+ debugfs_create_u32("de_chk_ocp_ms", 0644, charger->debug_entry, &charger->rtx_ocp_chk_ms);
+ debugfs_create_u32("de_rtx_delay_ms", 0644, charger->debug_entry, &charger->rtx_total_delay);
}
/* can independently read battery capacity */
@@ -6673,6 +7021,9 @@ static int p9221_charger_remove(struct i2c_client *client)
cancel_delayed_work_sync(&charger->align_work);
cancel_delayed_work_sync(&charger->rtx_work);
cancel_delayed_work_sync(&charger->auth_dc_icl_work);
+ cancel_delayed_work_sync(&charger->chk_rp_work);
+ cancel_delayed_work_sync(&charger->chk_rtx_ocp_work);
+ cancel_delayed_work_sync(&charger->chk_fod_work);
cancel_work_sync(&charger->uevent_work);
cancel_work_sync(&charger->rtx_disable_work);
cancel_work_sync(&charger->rtx_reset_work);
diff --git a/p9221_charger.h b/p9221_charger.h
index b141764..a889aad 100644
--- a/p9221_charger.h
+++ b/p9221_charger.h
@@ -72,18 +72,22 @@
#define P9221R5_ILIM_MAX_UA (1600 * 1000)
#define P9221_CHECK_NP_DELAY_MS 50
-#define P9221_NEG_POWER_5W (5 / 0.5)
-#define P9221_NEG_POWER_10W (10 / 0.5)
+#define P9221_NEG_POWER_5W (5 * 2)
+#define P9221_NEG_POWER_10W (10 * 2)
#define P9221_PTMC_EPP_TX_1912 0x32
#define P9221_PTMC_EPP_TX_4191 0x50
+#define P9222_RX_CALIBRATION_LIGHT_LOAD 0x5831
+#define P9222_LIGHT_LOAD_VALUE 0x0C
+
#define P9221_DCIN_RETRY_DELAY_MS 50
#define P9XXX_DC_ICL_EPP_1000 1000000
#define P9XXX_DC_ICL_EPP_750 750000
#define P9XXX_DC_ICL_EPP_100 100000
-#define P9XXX_NEG_POWER_10W (10 / 0.5)
-#define P9XXX_NEG_POWER_11W (11 / 0.5)
+#define P9XXX_NEG_POWER_10W (10 * 2)
+#define P9XXX_NEG_POWER_11W (11 * 2)
+#define P9XXX_TX_GUAR_PWR_15W (15 * 2)
#define P9382_RTX_TIMEOUT_MS (2 * 1000)
#define WLCDC_DEBOUNCE_TIME_S 400
#define WLCDC_AUTH_CHECK_S 15
@@ -287,21 +291,32 @@
*/
#define P9222_CHIP_ID 0x9222
#define P9222RE_SYSTEM_MODE_REG 0x3F
+#define P9222RE_CHARGE_STAT_REG 0x4E
+#define P9222RE_EPT_REG 0x4F
#define P9222RE_VOUT_REG 0x50
#define P9222RE_VOUT_SET_REG 0x52
#define P9222RE_VRECT_REG 0x54
#define P9222RE_IOUT_REG 0x58
#define P9222RE_DIE_TEMP_REG 0x5A
#define P9222RE_OP_FREQ_REG 0x5C
+#define P9222RE_TX_PINGFREQ_REG 0x5E
#define P9222RE_ILIM_SET_REG 0x60
-#define P9222_COM_REG 0x62
+#define P9222RE_COM_REG 0x62
#define P9222RE_FOD_REG 0x84
+#define P9222RE_COM_CHAN_RECV_SIZE_REG 0x98
+#define P9222RE_EPP_TX_GUARANTEED_POWER_REG 0xB4
#define P9222RE_EPP_REQ_NEGOTIATED_POWER_REG 0xBD
+#define P9222RE_EPP_REQ_MAXIMUM_POWER_REG 0xBE
#define P9222RE_EPP_Q_FACTOR_REG 0xD2
#define P9222RE_TX_MFG_CODE_REG 0x106
#define P9222RE_PROP_TX_ID_REG 0x118
+#define P9222RE_DIE_TEMP_ADC_REG 0x12A
+#define P9222RE_COM_PACKET_TYPE_ADDR 0x600
+#define P9222RE_COM_CHAN_SEND_SIZE_REG 0x601
+#define P9222RE_DATA_BUF_START 0x604
+#define P9222RE_DATA_BUF_SIZE 0x100
-#define P9222_EPT_REG 0x4F
+#define P9222RE_COM_CCACTIVATE BIT(9)
/*
* P9222 SYSTEM_MODE_REG bits
@@ -311,7 +326,7 @@
#define P9222_VOUT_SET_MIN_MV 3500
#define P9222_VOUT_SET_MAX_MV 12500
-
+#define P9222_NEG_POWER_10W 10000
/*
* Interrupt/Status flags for P9222
@@ -320,6 +335,7 @@
#define P9222_STAT_OVT BIT(2)
#define P9222_STAT_OVC BIT(3)
#define P9222_STAT_OVV BIT(4)
+#define P9222_EXTENDED_MODE BIT(12)
#define P9222_STAT_PPRCVD BIT(15)
/*
@@ -488,7 +504,18 @@
/* p9412 AP BOOST PING register */
#define P9412_APBSTPING_REG 0xF0
+#define P9412_APBSTCONTROL_REG 0xF1
#define P9412_APBSTPING_7V BIT(0)
+#define P9412_TXOCP_REG 0xA0
+#define P9412_TXOCP_1400MA 1400
+
+#define P9412_MOT_REG 0xD0
+#define P9412_MOT_40PCT 0x10
+#define P9412_MOT_65PCT 0x1A
+
+#define P9412_MOT_REG 0xD0
+#define P9412_MOT_40PCT 0x10
+#define P9412_MOT_65PCT 0x1A
/* Features */
typedef enum {
@@ -513,6 +540,12 @@ enum p9221_align_mfg_chk_state {
ALIGN_MFG_PASSED,
};
+enum p9xxx_chk_rp {
+ RP_NOTSET = -1,
+ RP_CHECKING,
+ RP_DONE,
+};
+
#define WLC_SOC_STATS_LEN 101
struct p9221_soc_data {
@@ -587,15 +620,21 @@ struct p9221_charger_platform_data {
int epp_vout_mv;
u8 fod[P9221R5_NUM_FOD];
u8 fod_epp[P9221R5_NUM_FOD];
+ u8 fod_epp_comp[P9221R5_NUM_FOD];
u8 fod_hpp[P9221R5_NUM_FOD];
u8 fod_hpp_hv[P9221R5_NUM_FOD];
int fod_num;
int fod_epp_num;
+ int fod_epp_comp_num;
int fod_hpp_num;
int fod_hpp_hv_num;
+ bool fod_fsw;
+ int fod_fsw_high;
+ int fod_fsw_low;
int q_value;
int tx_4191q;
int epp_rp_value;
+ int epp_rp_low_value;
int needs_dcin_reset;
int nb_alignment_freq;
int *alignment_freq;
@@ -617,6 +656,8 @@ struct p9221_charger_platform_data {
/* phone type for tx_id*/
u8 phone_type;
u32 epp_icl;
+ /* calibrate light load */
+ bool light_load;
};
struct p9221_charger_ints_bit {
@@ -639,6 +680,7 @@ struct p9221_charger_ints_bit {
u16 stat_limit_mask;
u16 stat_cc_mask;
u16 prop_mode_mask;
+ u16 extended_mode_bit;
/* Tx mode */
u16 hard_ocp_bit;
u16 tx_conflict_bit;
@@ -680,6 +722,9 @@ struct p9221_charger_data {
struct delayed_work power_mitigation_work;
struct delayed_work auth_dc_icl_work;
struct delayed_work fg_work;
+ struct delayed_work chk_rp_work;
+ struct delayed_work chk_rtx_ocp_work;
+ struct delayed_work chk_fod_work;
struct work_struct uevent_work;
struct work_struct rtx_disable_work;
struct work_struct rtx_reset_work;
@@ -753,6 +798,8 @@ struct p9221_charger_data {
u32 rtx_csp;
int rtx_err;
int rtx_reset_cnt;
+ int rtx_ocp_chk_ms;
+ int rtx_total_delay;
bool chg_on_rtx;
bool is_rtx_mode;
bool prop_mode_en;
@@ -783,6 +830,7 @@ struct p9221_charger_data {
bool sw_ramp_done;
bool hpp_hv;
int fod_mode;
+ enum p9xxx_chk_rp check_rp;
#if IS_ENABLED(CONFIG_GPIOLIB)
struct gpio_chip gpio;
@@ -801,6 +849,8 @@ struct p9221_charger_data {
u16 reg_get_pp_buf_addr;
u16 reg_set_fod_addr;
u16 reg_q_factor_addr;
+ u16 reg_csp_addr;
+ u16 reg_light_load_addr;
int (*reg_read_n)(struct p9221_charger_data *chgr, u16 reg,
void *buf, size_t n);
@@ -857,7 +907,7 @@ bool p9xxx_is_capdiv_en(struct p9221_charger_data *charger);
int p9221_wlc_disable(struct p9221_charger_data *charger, int disable, u8 reason);
int p9221_set_auth_dc_icl(struct p9221_charger_data *charger, bool enable);
int p9xxx_sw_ramp_icl(struct p9221_charger_data *charger, const int icl_target);
-int p9xxx_gpio_set_value(struct p9221_charger_data *charger, unsigned gpio, int value);
+int p9xxx_gpio_set_value(struct p9221_charger_data *charger, int gpio, int value);
void p9xxx_gpio_init(struct p9221_charger_data *charger);
extern int p9221_chip_init_funcs(struct p9221_charger_data *charger,
@@ -916,4 +966,8 @@ enum p9xxx_renego_state {
-ENOTSUPP : chgr->reg_read_n(chgr, chgr->reg_set_fod_addr, data, len))
#define p9xxx_chip_set_q_factor_reg(chgr, data) (chgr->reg_q_factor_addr == 0 ? \
-ENOTSUPP : chgr->reg_write_8(chgr, chgr->reg_q_factor_addr, data))
+#define p9xxx_chip_set_light_load_reg(chgr, data) (chgr->reg_light_load_addr == 0 ? \
+ -ENOTSUPP : chgr->reg_write_8(chgr, chgr->reg_light_load_addr, data))
+#define logbuffer_prlog(p, fmt, ...) \
+ gbms_logbuffer_prlog(p, LOGLEVEL_INFO, 0, LOGLEVEL_DEBUG, fmt, ##__VA_ARGS__)
#endif /* __P9221_CHARGER_H__ */
diff --git a/p9221_chip.c b/p9221_chip.c
index 2b76996..24f93e5 100644
--- a/p9221_chip.c
+++ b/p9221_chip.c
@@ -523,6 +523,15 @@ static int p9221_get_data_buf(struct p9221_charger_data *chgr,
return chgr->reg_read_n(chgr, P9221R5_DATA_RECV_BUF_START, data, len);
}
+static int p9222_get_data_buf(struct p9221_charger_data *chgr,
+ u8 data[], size_t len)
+{
+ if (!len || len > P9222RE_DATA_BUF_SIZE)
+ return -EINVAL;
+
+ return chgr->reg_read_n(chgr, P9222RE_DATA_BUF_START, data, len);
+}
+
static int p9382_get_data_buf(struct p9221_charger_data *chgr,
u8 data[], size_t len)
{
@@ -551,6 +560,15 @@ static int p9221_set_data_buf(struct p9221_charger_data *chgr,
return chgr->reg_write_n(chgr, P9221R5_DATA_SEND_BUF_START, data, len);
}
+static int p9222_set_data_buf(struct p9221_charger_data *chgr,
+ const u8 data[], size_t len)
+{
+ if (!len || len > P9222RE_DATA_BUF_SIZE)
+ return -EINVAL;
+
+ return chgr->reg_write_n(chgr, P9222RE_DATA_BUF_START, data, len);
+}
+
static int p9382_set_data_buf(struct p9221_charger_data *chgr,
const u8 data[], size_t len)
{
@@ -581,6 +599,17 @@ static int p9221_get_cc_recv_size(struct p9221_charger_data *chgr, size_t *len)
return ret;
}
+static int p9222_get_cc_recv_size(struct p9221_charger_data *chgr, size_t *len)
+{
+ int ret;
+ u8 len8;
+
+ ret = chgr->reg_read_8(chgr, P9222RE_COM_CHAN_RECV_SIZE_REG, &len8);
+ if (ret == 0)
+ *len = len8;
+ return ret;
+}
+
static int p9412_get_cc_recv_size(struct p9221_charger_data *chgr, size_t *len)
{
int ret;
@@ -598,6 +627,22 @@ static int p9221_set_cc_send_size(struct p9221_charger_data *chgr, size_t len)
return chgr->reg_write_8(chgr, P9221R5_COM_CHAN_SEND_SIZE_REG, len);
}
+static int p9222_set_cc_send_size(struct p9221_charger_data *chgr, size_t len)
+{
+ int ret;
+
+ /* set packet type(BiDi) */
+ ret = chgr->reg_write_8(chgr, chgr->reg_packet_type_addr,
+ BIDI_COM_PACKET_TYPE);
+ if (ret) {
+ dev_err(&chgr->client->dev,
+ "Failed to write packet type %d\n", ret);
+ return ret;
+ }
+
+ return chgr->reg_write_16(chgr, P9222RE_COM_CHAN_SEND_SIZE_REG, len);
+}
+
static int p9382_set_cc_send_size(struct p9221_charger_data *chgr, size_t len)
{
int ret;
@@ -719,35 +764,45 @@ static int p9412_chip_tx_mode(struct p9221_charger_data *chgr, bool enable)
if (enable) {
if (chgr->pdata->apbst_en) {
- ret = chgr->reg_write_8(chgr, P9412_APBSTPING_REG,
- P9412_APBSTPING_7V);
+ ret = chgr->reg_write_8(chgr, P9412_APBSTPING_REG, 0);
+ ret |= chgr->reg_write_8(chgr, P9412_APBSTCONTROL_REG, P9412_APBSTPING_7V);
logbuffer_log(chgr->rtx_log,
- "configure Ext-Boost Vout to 7V.(%d)\n", ret);
+ "configure Ext-Boost Vout to 5V.(%d)", ret);
if (ret < 0)
return ret;
}
- ret = chgr->reg_write_8(chgr, P9412_TX_CMD_REG,
- P9412_TX_CMD_TX_MODE_EN);
+ ret = chgr->reg_write_8(chgr, P9412_TX_CMD_REG, P9412_TX_CMD_TX_MODE_EN);
if (ret) {
logbuffer_log(chgr->rtx_log,
- "tx_cmd_reg write failed (%d)\n", ret);
+ "tx_cmd_reg write failed (%d)", ret);
return ret;
}
ret = p9382_wait_for_mode(chgr, P9XXX_SYS_OP_MODE_TX_MODE);
- if (ret)
+ if (ret) {
logbuffer_log(chgr->rtx_log,
"error waiting for tx_mode (%d)", ret);
+ return ret;
+ }
+
+ ret = chgr->reg_write_16(chgr, P9412_TXOCP_REG, P9412_TXOCP_1400MA);
+ logbuffer_log(chgr->rtx_log, "configure TX OCP to %dMA", P9412_TXOCP_1400MA);
+ if (ret < 0)
+ return ret;
+
+ if (!chgr->pdata->apbst_en)
+ return ret;
+ mod_delayed_work(system_wq, &chgr->chk_rtx_ocp_work, 0);
} else {
ret = chgr->chip_set_cmd(chgr, P9412_CMD_TXMODE_EXIT);
if (ret == 0) {
ret = p9382_wait_for_mode(chgr, 0);
if (ret < 0)
- pr_err("cannot exit rTX mode (%d)\n", ret);
+ pr_err("cannot exit rTX mode (%d)", ret);
}
if (chgr->pdata->apbst_en) {
ret = chgr->reg_write_8(chgr, P9412_APBSTPING_REG, 0);
logbuffer_log(chgr->rtx_log,
- "configure Ext-Boost back to 5V.(%d)\n", ret);
+ "configure Ext-Boost back to 5V.(%d)", ret);
}
}
@@ -761,7 +816,7 @@ static int p9222_chip_set_cmd_reg(struct p9221_charger_data *chgr, u16 cmd)
int ret;
for (retry = 0; retry < P9221_COM_CHAN_RETRIES; retry++) {
- ret = chgr->reg_read_16(chgr, P9222_COM_REG, &cur_cmd);
+ ret = chgr->reg_read_16(chgr, P9222RE_COM_REG, &cur_cmd);
if (ret == 0 && cur_cmd == 0)
break;
msleep(25);
@@ -773,7 +828,7 @@ static int p9222_chip_set_cmd_reg(struct p9221_charger_data *chgr, u16 cmd)
return -EBUSY;
}
- ret = chgr->reg_write_16(chgr, P9222_COM_REG, (u16)cmd);
+ ret = chgr->reg_write_16(chgr, P9222RE_COM_REG, (u16)cmd);
if (ret)
dev_err(&chgr->client->dev,
"Failed to set cmd reg %02x: %d\n", (u16)cmd, ret);
@@ -904,7 +959,7 @@ static int p9222_send_eop(struct p9221_charger_data *chgr, u8 reason)
mutex_lock(&chgr->cmd_lock);
- ret = chgr->reg_write_8(chgr, P9222_EPT_REG, reason);
+ ret = chgr->reg_write_8(chgr, P9222RE_EPT_REG, reason);
if (ret == 0)
ret = chgr->chip_set_cmd(chgr, P9221R5_COM_SENDEPT);
@@ -1078,16 +1133,42 @@ static int p9221_chip_renegotiate_pwr(struct p9221_charger_data *chgr)
static int p9222_chip_renegotiate_pwr(struct p9221_charger_data *chgr)
{
- int ret;
- int val8 = P9412_MW_TO_HW(chgr->pdata->epp_rp_value);
+ int ret = 0, guar_pwr_mw, cnt;
+ u8 val8, rp8;
+
+ if (chgr->check_rp != RP_CHECKING)
+ return ret;
+
+ ret = chgr->reg_read_8(chgr, P9222RE_EPP_TX_GUARANTEED_POWER_REG, &val8);
+ if (ret)
+ return ret;
+ guar_pwr_mw = P9412_HW_TO_MW(val8);
+
+ /* write renegotiated power to 11W(>10W) or 10W(<=10W) */
+ if (chgr->pdata->epp_rp_low_value != -1 && guar_pwr_mw <= P9222_NEG_POWER_10W)
+ rp8 = P9412_MW_TO_HW(chgr->pdata->epp_rp_low_value);
+ else
+ rp8 = P9412_MW_TO_HW(chgr->pdata->epp_rp_value);
+
+ /*
+ * The neg_pwr write window is 200ms to 340ms, write every 20ms to make
+ * sure it works
+ */
+ for (cnt = 0; cnt < 7 ; cnt++) {
+ /* units 0.5 W */
+ ret = chgr->reg_write_8(chgr, P9222RE_EPP_REQ_NEGOTIATED_POWER_REG, rp8);
+ ret |= chgr->reg_write_8(chgr, P9222RE_EPP_REQ_MAXIMUM_POWER_REG, rp8);
+
+ usleep_range(20 * USEC_PER_MSEC, 22 * USEC_PER_MSEC);
+ if (!chgr->online)
+ return -ENODEV;
+ }
+ if (ret == 0)
+ logbuffer_log(chgr->log, "read neg_pwr=0x%x, write neg_pwr=0x%x(guar_pwr=%dW)",
+ val8, rp8, guar_pwr_mw/1000);
+
+ chgr->check_rp = RP_DONE;
- /* units 0.5 W*/
- ret = chgr->reg_write_8(chgr,
- P9222RE_EPP_REQ_NEGOTIATED_POWER_REG, val8);
- if (ret < 0)
- dev_err(&chgr->client->dev,
- "cannot write to EPP_NEG_POWER=%d (%d)\n",
- val8, ret);
return ret;
}
@@ -1563,6 +1644,7 @@ void p9221_chip_init_interrupt_bits(struct p9221_charger_data *chgr, u16 chip_id
chgr->ints.propmode_stat_bit = P9412_PROP_MODE_STAT_INT;
chgr->ints.cdmode_change_bit = P9412_CDMODE_CHANGE_INT;
chgr->ints.cdmode_err_bit = P9412_CDMODE_ERROR_INT;
+ chgr->ints.extended_mode_bit = 0;
chgr->ints.hard_ocp_bit = P9412_STAT_OVC;
chgr->ints.tx_conflict_bit = P9412_STAT_TXCONFLICT;
@@ -1586,6 +1668,7 @@ void p9221_chip_init_interrupt_bits(struct p9221_charger_data *chgr, u16 chip_id
chgr->ints.propmode_stat_bit = 0;
chgr->ints.cdmode_change_bit = 0;
chgr->ints.cdmode_err_bit = 0;
+ chgr->ints.extended_mode_bit = 0;
chgr->ints.hard_ocp_bit = P9382_STAT_HARD_OCP;
chgr->ints.tx_conflict_bit = P9382_STAT_TXCONFLICT;
@@ -1609,6 +1692,7 @@ void p9221_chip_init_interrupt_bits(struct p9221_charger_data *chgr, u16 chip_id
chgr->ints.propmode_stat_bit = 0;
chgr->ints.cdmode_change_bit = 0;
chgr->ints.cdmode_err_bit = 0;
+ chgr->ints.extended_mode_bit = P9222_EXTENDED_MODE;
chgr->ints.hard_ocp_bit = 0;
chgr->ints.tx_conflict_bit = 0;
@@ -1632,6 +1716,7 @@ void p9221_chip_init_interrupt_bits(struct p9221_charger_data *chgr, u16 chip_id
chgr->ints.propmode_stat_bit = 0;
chgr->ints.cdmode_change_bit = 0;
chgr->ints.cdmode_err_bit = 0;
+ chgr->ints.extended_mode_bit = 0;
chgr->ints.hard_ocp_bit = 0;
chgr->ints.tx_conflict_bit = 0;
@@ -1683,6 +1768,8 @@ void p9221_chip_init_params(struct p9221_charger_data *chgr, u16 chip_id)
chgr->set_cmd_ccactivate_bit = P9412_COM_CCACTIVATE;
chgr->reg_set_fod_addr = P9221R5_FOD_REG;
chgr->reg_q_factor_addr = P9221R5_EPP_Q_FACTOR_REG;
+ chgr->reg_csp_addr = P9221R5_CHARGE_STAT_REG;
+ chgr->reg_light_load_addr = 0;
break;
case P9382A_CHIP_ID:
chgr->reg_tx_id_addr = P9382_PROP_TX_ID_REG;
@@ -1693,16 +1780,20 @@ void p9221_chip_init_params(struct p9221_charger_data *chgr, u16 chip_id)
chgr->set_cmd_ccactivate_bit = P9221R5_COM_CCACTIVATE;
chgr->reg_set_fod_addr = P9221R5_FOD_REG;
chgr->reg_q_factor_addr = P9221R5_EPP_Q_FACTOR_REG;
+ chgr->reg_csp_addr = P9221R5_CHARGE_STAT_REG;
+ chgr->reg_light_load_addr = 0;
break;
case P9222_CHIP_ID:
chgr->reg_tx_id_addr = P9222RE_PROP_TX_ID_REG;
chgr->reg_tx_mfg_code_addr = P9222RE_TX_MFG_CODE_REG;
- chgr->reg_packet_type_addr = 0;
+ chgr->reg_packet_type_addr = P9222RE_COM_PACKET_TYPE_ADDR;
chgr->reg_set_pp_buf_addr = P9221R5_DATA_SEND_BUF_START;
chgr->reg_get_pp_buf_addr = P9221R5_DATA_RECV_BUF_START;
- chgr->set_cmd_ccactivate_bit = P9221R5_COM_CCACTIVATE;
+ chgr->set_cmd_ccactivate_bit = P9222RE_COM_CCACTIVATE;
chgr->reg_set_fod_addr = P9222RE_FOD_REG;
chgr->reg_q_factor_addr = P9222RE_EPP_Q_FACTOR_REG;
+ chgr->reg_csp_addr = P9222RE_CHARGE_STAT_REG;
+ chgr->reg_light_load_addr = P9222_RX_CALIBRATION_LIGHT_LOAD;
break;
default:
chgr->reg_tx_id_addr = P9221R5_PROP_TX_ID_REG;
@@ -1713,6 +1804,8 @@ void p9221_chip_init_params(struct p9221_charger_data *chgr, u16 chip_id)
chgr->set_cmd_ccactivate_bit = P9221R5_COM_CCACTIVATE;
chgr->reg_set_fod_addr = P9221R5_FOD_REG;
chgr->reg_q_factor_addr = P9221R5_EPP_Q_FACTOR_REG;
+ chgr->reg_csp_addr = P9221R5_CHARGE_STAT_REG;
+ chgr->reg_light_load_addr = 0;
break;
}
}
@@ -1803,10 +1896,10 @@ int p9221_chip_init_funcs(struct p9221_charger_data *chgr, u16 chip_id)
chgr->chip_get_vout_max = p9222_chip_get_vout_max;
chgr->chip_set_vout_max = p9222_chip_set_vout_max;
chgr->chip_tx_mode_en = p9221_chip_tx_mode;
- chgr->chip_set_data_buf = p9221_set_data_buf;
- chgr->chip_get_data_buf = p9221_get_data_buf;
- chgr->chip_get_cc_recv_size = p9221_get_cc_recv_size;
- chgr->chip_set_cc_send_size = p9221_set_cc_send_size;
+ chgr->chip_get_data_buf = p9222_get_data_buf;
+ chgr->chip_set_data_buf = p9222_set_data_buf;
+ chgr->chip_get_cc_recv_size = p9222_get_cc_recv_size;
+ chgr->chip_set_cc_send_size = p9222_set_cc_send_size;
chgr->chip_get_align_x = p9221_get_align_x;
chgr->chip_get_align_y = p9221_get_align_y;
chgr->chip_send_ccreset = p9221_send_ccreset;
@@ -1862,7 +1955,7 @@ int p9221_chip_init_funcs(struct p9221_charger_data *chgr, u16 chip_id)
}
#if IS_ENABLED(CONFIG_GPIOLIB)
-int p9xxx_gpio_set_value(struct p9221_charger_data *chgr, unsigned gpio, int value)
+int p9xxx_gpio_set_value(struct p9221_charger_data *chgr, int gpio, int value)
{
if (gpio <= 0)
return -EINVAL;
diff --git a/pca9468_charger.c b/pca9468_charger.c
index 7a574b8..70011f5 100644
--- a/pca9468_charger.c
+++ b/pca9468_charger.c
@@ -2665,6 +2665,7 @@ static int pca9468_charge_adjust_ccmode(struct pca9468_charger *pca9468)
switch(ccmode) {
case STS_MODE_IIN_LOOP:
+ pca9468->chg_data.iin_loop_count++;
case STS_MODE_CHG_LOOP: /* CHG_LOOP does't exist */
apply_ircomp = true;
@@ -2881,6 +2882,7 @@ static int pca9468_charge_ccmode(struct pca9468_charger *pca9468)
break;
case STS_MODE_IIN_LOOP:
+ pca9468->chg_data.iin_loop_count++;
case STS_MODE_CHG_LOOP:
iin = pca9468_read_adc(pca9468, ADCCH_IIN);
if (iin < 0)
@@ -2980,8 +2982,9 @@ static int pca9468_charge_start_cvmode(struct pca9468_charger *pca9468)
}
switch(cvmode) {
- case STS_MODE_CHG_LOOP:
case STS_MODE_IIN_LOOP:
+ pca9468->chg_data.iin_loop_count++;
+ case STS_MODE_CHG_LOOP:
if (pca9468->ta_type == TA_TYPE_WIRELESS) {
/* Decrease RX voltage (100mV) */
@@ -3175,8 +3178,9 @@ static int pca9468_charge_cvmode(struct pca9468_charger *pca9468)
pca9468->timer_period = PCA9468_CVMODE_CHECK_T;
} break;
- case STS_MODE_CHG_LOOP:
case STS_MODE_IIN_LOOP:
+ pca9468->chg_data.iin_loop_count++;
+ case STS_MODE_CHG_LOOP:
/* Check the TA type */
if (pca9468->ta_type == TA_TYPE_WIRELESS) {
/* Decrease RX Voltage (100mV) */
@@ -3356,9 +3360,25 @@ static int pca9468_preset_dcmode(struct pca9468_charger *pca9468)
PCA9468_TA_MAX_CUR);
ret = pca9468_get_apdo_max_power(pca9468, ta_max_vol, 0);
}
+
if (ret < 0) {
+ int ret1;
+
pr_err("%s: No APDO to support 2:1\n", __func__);
pca9468->chg_mode = CHG_NO_DC_MODE;
+
+ if (!pca9468->dc_avail)
+ pca9468->dc_avail =
+ gvotable_election_get_handle(VOTABLE_DC_CHG_AVAIL);
+
+ if (pca9468->dc_avail) {
+ ret1 = gvotable_cast_int_vote(pca9468->dc_avail,
+ REASON_DC_DRV, 0, 1);
+ if (ret1 < 0)
+ dev_err(pca9468->dev,
+ "Unable to cast vote for DC Chg avail (%d)\n",
+ ret1);
+ }
goto error;
}
@@ -3864,15 +3884,6 @@ error:
__func__, timer_id, pca9468->timer_id, charging_state,
pca9468->charging_state, pca9468->timer_period, ret);
- if (!pca9468->dc_avail)
- pca9468->dc_avail = gvotable_election_get_handle(VOTABLE_DC_CHG_AVAIL);
-
- if (pca9468->dc_avail) {
- ret = gvotable_cast_int_vote(pca9468->dc_avail, REASON_DC_DRV, 0, 1);
- if (ret < 0)
- dev_err(pca9468->dev, "Unable to cast vote for DC Chg avail (%d)\n", ret);
- }
-
pca9468_stop_charging(pca9468);
}
@@ -4319,6 +4330,20 @@ static int pca9468_mains_set_property(struct power_supply *psy,
__func__, ret);
pca9468->mains_online = false;
+
+ /* Reset DC Chg un-avail on disconnect */
+ if (!pca9468->dc_avail)
+ pca9468->dc_avail =
+ gvotable_election_get_handle(VOTABLE_DC_CHG_AVAIL);
+
+ if (pca9468->dc_avail) {
+ ret = gvotable_cast_int_vote(pca9468->dc_avail,
+ REASON_DC_DRV, 1, 1);
+ if (ret < 0)
+ dev_err(pca9468->dev,
+ "Unable to cast vote for DC Chg avail (%d)\n",
+ ret);
+ }
} else if (pca9468->mains_online == false) {
pca9468->mains_online = true;
}
@@ -4843,10 +4868,11 @@ static ssize_t p9468_show_chg_stats(struct device *dev, struct device_attribute
chg_data->receiver_state[3],
chg_data->receiver_state[4]);
len += scnprintf(&buff[len], max_size - len,
- "N: ovc=%d,ovc_ibatt=%d,ovc_delta=%d rcp=%d,stby=%d\n",
+ "N: ovc=%d,ovc_ibatt=%d,ovc_delta=%d rcp=%d,stby=%d, iin_loop=%d\n",
chg_data->ovc_count, chg_data->ovc_max_ibatt, chg_data->ovc_max_delta,
chg_data->rcp_count,
- chg_data->stby_count);
+ chg_data->stby_count,
+ chg_data->iin_loop_count);
len += scnprintf(&buff[len], max_size - len,
"C: nc=%d,pre=%d,ca=%d,cc=%d,cv=%d,adj=%d\n",
chg_data->nc_count,
@@ -4993,7 +5019,7 @@ static int pca9468_probe(struct i2c_client *client,
pca9468_chg->pdata = pdata;
pca9468_chg->charging_state = DC_STATE_NO_CHARGING;
pca9468_chg->wlc_ramp_out_iin = true;
- pca9468_chg->wlc_ramp_out_vout_target = 15300000; /* 15.3V as default */
+ pca9468_chg->wlc_ramp_out_vout_target = 0; /* use Vbatt*4 as default */
pca9468_chg->wlc_ramp_out_delay = 250; /* 250 ms default */
/* Create a work queue for the direct charger */
diff --git a/pca9468_charger.h b/pca9468_charger.h
index d5f7a25..d1f3ee8 100644
--- a/pca9468_charger.h
+++ b/pca9468_charger.h
@@ -102,6 +102,7 @@ struct p9468_chg_stats {
unsigned int cv_count;
unsigned int adj_count;
unsigned int stby_count;
+ unsigned int iin_loop_count;
};
#define p9468_chg_stats_valid(chg_data) ((chg_data)->valid)
diff --git a/pca9468_gbms_pps.c b/pca9468_gbms_pps.c
index 37b1bfa..4cdd75e 100644
--- a/pca9468_gbms_pps.c
+++ b/pca9468_gbms_pps.c
@@ -672,10 +672,10 @@ void p9468_chg_stats_dump(const struct pca9468_charger *pca9468)
const struct p9468_chg_stats *chg_data = &pca9468->chg_data;
logbuffer_prlog(pca9468, LOGLEVEL_INFO,
- "N: ovc=%d,ovc_ibatt=%d,ovc_delta=%d rcp=%d,stby=%d",
+ "N: ovc=%d,ovc_ibatt=%d,ovc_delta=%d rcp=%d,stby=%d,iin_loop=%d",
chg_data->ovc_count,
chg_data->ovc_max_ibatt, chg_data->ovc_max_delta,
- chg_data->rcp_count, chg_data->stby_count);
+ chg_data->rcp_count, chg_data->stby_count, chg_data->iin_loop_count);
logbuffer_prlog(pca9468, LOGLEVEL_INFO,
"C: nc=%d,pre=%d,ca=%d,cc=%d,cv=%d,adj=%d\n",
chg_data->nc_count, chg_data->pre_count,
diff --git a/wc68_driver.c b/wc68_driver.c
index 609da84..61463e4 100644
--- a/wc68_driver.c
+++ b/wc68_driver.c
@@ -41,8 +41,6 @@
#define WC68_IIN_CFG_DFT 2500000 /* uA*/
/* Charging Float Voltage default value */
#define WC68_VFLOAT_DFT 4350000 /* uV */
-/* Charging Sub Float Voltage default value */
-#define WC68_VFLOAT_SUB_DFT 5000000 /* 5000000uV */
/* Charging Float Voltage max voltage for comp */
#define WC68_COMP_VFLOAT_MAX 4450000 /* uV */
@@ -89,8 +87,6 @@
#define WC68_MAX_RETRY_CNT 3 /* retries */
/* TA IIN tolerance */
#define WC68_TA_IIN_OFFSET 100000 /* uA */
-/* IIN_CC upper protection offset in Power Limit Mode TA */
-#define WC68_IIN_CC_UPPER_OFFSET 50000 /* 50mA */
/* PD Message Voltage and Current Step */
#define PD_MSG_TA_VOL_STEP 20000 /* uV */
@@ -101,18 +97,12 @@
/* WCRX voltage Step */
#define WCRX_VOL_STEP 100000 /* uV */
-#define WC68_OTV_MARGIN 12000 /* uV */
-
/* irdrop default limit */
#define WC68_IRDROP_LIMIT_CNT 3 /* tiers */
#define WC68_IRDROP_LIMIT_TIER1 -30000 /* uV */
#define WC68_IRDROP_LIMIT_TIER2 -19000 /* uV */
#define WC68_IRDROP_LIMIT_TIER3 0 /* uV */
-/* Spread Spectrum default settings */
-#define WC68_SC_CLK_DITHER_RATE_DEF 0 /* 25kHz */
-#define WC68_SC_CLK_DITHER_LIMIT_DEF 0xF /* 10% */
-
#define CBUS_UCP_DFT 400000 /* 400 mV, actual value TBD */
/* Status */
@@ -646,8 +636,8 @@ static int wc68_check_state(u8 val[8], struct wc68_charger *wc68, int loglevel)
return ret;
logbuffer_prlog(wc68, loglevel,
- "%s: INTR_FLG reg[1]=%#x,[2]=%#x,[3]=%#x,[4]=%#x,[5]=%#x,[6]=%#x,[7]=%#x",
- __func__, val[1], val[2], val[3], val[4], val[5], val[6], val[7]);
+ "%s: INTR_FLG reg[0]=%#x,reg[1]=%#x,[2]=%#x,[3]=%#x,[4]=%#x,[5]=%#x,[6]=%#x,[7]=%#x",
+ __func__, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]);
return 0;
}
@@ -3246,8 +3236,22 @@ static int wc68_preset_dcmode(struct wc68_charger *wc68)
ret = wc68_get_apdo_max_power(wc68, ta_max_vol, 0);
}
if (ret < 0) {
+ int ret1;
+
dev_err(wc68->dev, "%s: No APDO to support 2:1\n", __func__);
wc68->chg_mode = CHG_NO_DC_MODE;
+
+ if (!wc68->dc_avail)
+ wc68->dc_avail = gvotable_election_get_handle(VOTABLE_DC_CHG_AVAIL);
+
+ if (wc68->dc_avail) {
+ ret1 = gvotable_cast_int_vote(wc68->dc_avail, REASON_DC_DRV, 0, 1);
+ if (ret1 < 0)
+ dev_err(wc68->dev,
+ "Unable to cast vote for DC Chg avail (%d)\n",
+ ret1);
+ }
+
goto error;
}
@@ -3739,15 +3743,6 @@ error:
__func__, timer_id, wc68->timer_id, charging_state,
wc68->charging_state, wc68->timer_period, ret);
- if (!wc68->dc_avail)
- wc68->dc_avail = gvotable_election_get_handle(VOTABLE_DC_CHG_AVAIL);
-
- if (wc68->dc_avail) {
- ret = gvotable_cast_int_vote(wc68->dc_avail, REASON_DC_DRV, 0, 1);
- if (ret < 0)
- dev_err(wc68->dev, "Unable to cast vote for DC Chg avail (%d)\n", ret);
- }
-
wc68_stop_charging(wc68);
}
@@ -4169,6 +4164,20 @@ static int wc68_mains_set_property(struct power_supply *psy,
__func__, ret);
wc68->mains_online = false;
+
+ /* Reset DC Chg un-avail on disconnect */
+ if (!wc68->dc_avail)
+ wc68->dc_avail = gvotable_election_get_handle(VOTABLE_DC_CHG_AVAIL);
+
+ if (wc68->dc_avail) {
+ ret = gvotable_cast_int_vote(wc68->dc_avail,
+ REASON_DC_DRV, 1, 1);
+ if (ret < 0)
+ dev_err(wc68->dev,
+ "Unable to cast vote for DC Chg avail (%d)\n",
+ ret);
+ }
+
} else if (wc68->mains_online == false) {
wc68->mains_online = true;
}
diff --git a/wc68_regs.h b/wc68_regs.h
index 38553b8..a3b6f5f 100644
--- a/wc68_regs.h
+++ b/wc68_regs.h
@@ -85,7 +85,6 @@ enum {
};
/* ADC step */
-#define VIN_STEP 16000 /* 16mV(16000uV) LSB, Range(0V ~ 16.368V) */
#define VBAT_STEP 3076 /* (3076uV) LSB, Range(0V ~ 6.297V) */
#define IIN_STEP 3662 /* (3662uA) LSB, Range(-7.5A ~ 7.496A) */
#define DIETEMP_STEP -116 /* 0.116C LSB, Range(-40 ~ 150C) */