diff options
Diffstat (limited to 'baseboard/kukui/battery_bq27541.c')
-rw-r--r-- | baseboard/kukui/battery_bq27541.c | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/baseboard/kukui/battery_bq27541.c b/baseboard/kukui/battery_bq27541.c new file mode 100644 index 0000000000..94f46b3326 --- /dev/null +++ b/baseboard/kukui/battery_bq27541.c @@ -0,0 +1,225 @@ +/* Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Battery pack vendor provided charging profile + */ + +#include "battery.h" +#include "charge_state.h" +#include "charger_mt6370.h" +#include "console.h" +#include "driver/tcpm/mt6370.h" +#include "ec_commands.h" +#include "util.h" + +#define TEMP_OUT_OF_RANGE TEMP_ZONE_COUNT + +#define BATT_ID 0 + +#define BATTERY_CPT_CHARGE_MIN_TEMP 0 +#define BATTERY_CPT_CHARGE_MAX_TEMP 50 + +#define CHARGER_LIMIT_TIMEOUT_HOURS 48 +#define CHARGER_LIMIT_TIMEOUT_HOURS_TEMP 2 + +#define BAT_LEVEL_PD_LIMIT 85 + +#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args) + +enum battery_type { + BATTERY_CPT = 0, + BATTERY_COUNT +}; + +static const struct battery_info info[] = { + [BATTERY_CPT] = { + .voltage_max = 4400, + .voltage_normal = 3850, + .voltage_min = 3000, + .precharge_voltage = 3400, + .precharge_current = 256, + .start_charging_min_c = 0, + .start_charging_max_c = 45, + .charging_min_c = 0, + .charging_max_c = 50, + .discharging_min_c = -20, + .discharging_max_c = 60, + }, +}; + +const struct battery_info *battery_get_info(void) +{ + return &info[BATT_ID]; +} + +int charger_profile_override(struct charge_state_data *curr) +{ + static timestamp_t deadline_48; + static timestamp_t deadline_2; + int cycle_count = 0, rv, val; + unsigned char rcv = 0, rcv_cycle = 0, rcv_soh = 0; + /* (FullCharge Capacity / Design Capacity) * 100 = SOH */ + int full_cap = 0, design_cap = 0, soh = 0; + /* battery temp in 0.1 deg C */ + int bat_temp_c = curr->batt.temperature - 2731; + /* + * Keep track of battery temperature range: + * + * ZONE_0 ZONE_1 ZONE_2 + * -----+--------+--------+------------+----- Temperature (C) + * t0 t1 t2 t3 + */ + enum { + TEMP_ZONE_0, /* t0 < bat_temp_c <= t1 */ + TEMP_ZONE_1, /* t1 < bat_temp_c <= t2 */ + TEMP_ZONE_2, /* t2 < bat_temp_c <= t3 */ + TEMP_ZONE_3, /* t3 < bat_temp_c <= t4 */ + TEMP_ZONE_COUNT + } temp_zone; + + static struct { + int temp_min; /* 0.1 deg C */ + int temp_max; /* 0.1 deg C */ + int desired_current; /* mA */ + int desired_voltage; /* mV */ + } temp_zones[BATTERY_COUNT][TEMP_ZONE_COUNT] = { + [BATTERY_CPT] = { + /* TEMP_ZONE_0 */ + {BATTERY_CPT_CHARGE_MIN_TEMP * 10, 150, 1408, 4370}, + /* TEMP_ZONE_1 */ + {150, 430, 3520, 4370}, + /* TEMP_ZONE_2 */ + {430, 450, 2112, 4320}, + /* TEMP_ZONE_3 */ + {450, BATTERY_CPT_CHARGE_MAX_TEMP * 10, 1760, 4170}, + }, + }; + BUILD_ASSERT(ARRAY_SIZE(temp_zones[0]) == TEMP_ZONE_COUNT); + BUILD_ASSERT(ARRAY_SIZE(temp_zones) == BATTERY_COUNT); + + if ((curr->batt.flags & BATT_FLAG_BAD_TEMPERATURE) || + (bat_temp_c < temp_zones[BATT_ID][0].temp_min) || + (bat_temp_c >= temp_zones[BATT_ID][TEMP_ZONE_COUNT - 1].temp_max)) + temp_zone = TEMP_OUT_OF_RANGE; + else { + for (temp_zone = 0; temp_zone < TEMP_ZONE_COUNT; temp_zone++) { + if (bat_temp_c < + temp_zones[BATT_ID][temp_zone].temp_max) + break; + } + } + + switch (temp_zone) { + case TEMP_ZONE_0: + case TEMP_ZONE_1: + case TEMP_ZONE_2: + case TEMP_ZONE_3: + curr->requested_current = + temp_zones[BATT_ID][temp_zone].desired_current; + curr->requested_voltage = + temp_zones[BATT_ID][temp_zone].desired_voltage; + break; + case TEMP_OUT_OF_RANGE: + curr->requested_current = curr->requested_voltage = 0; + curr->batt.flags &= ~BATT_FLAG_WANT_CHARGE; + curr->state = ST_IDLE; + break; + } + + /* Check cycle count to decrease charging voltage. */ + rv = battery_cycle_count(&val); + if (!rv) + cycle_count = val; + if (cycle_count > 20 && cycle_count <= 50) + rcv_cycle = 50; + else if (cycle_count > 50 && cycle_count <= 300) + rcv_cycle = 65; + else if (cycle_count > 300 && cycle_count <= 600) + rcv_cycle = 80; + else if (cycle_count > 600 && cycle_count <= 1000) + rcv_cycle = 100; + else if (cycle_count > 1000) + rcv_cycle = 150; + /* Check SOH to decrease charging voltage. */ + if (!battery_full_charge_capacity(&full_cap) && + !battery_design_capacity(&design_cap)) + soh = ((full_cap * 100) / design_cap); + if (soh > 70 && soh <= 75) + rcv_soh = 50; + else if (soh > 60 && soh <= 70) + rcv_soh = 65; + else if (soh > 55 && soh <= 60) + rcv_soh = 80; + else if (soh > 50 && soh <= 55) + rcv_soh = 100; + else if (soh <= 50) + rcv_soh = 150; + rcv = MAX(rcv_cycle, rcv_soh); + curr->requested_voltage -= rcv; + + /* Should not keep charging voltage > 4250mV for 48hrs. */ + if ((curr->state == ST_DISCHARGE) || + curr->chg.voltage < 4250) { + deadline_48.val = 0; + /* Starting count 48hours */ + } else if (curr->state == ST_CHARGE || + curr->state == ST_PRECHARGE) { + if (deadline_48.val == 0) + deadline_48.val = get_time().val + + CHARGER_LIMIT_TIMEOUT_HOURS * HOUR; + /* If charging voltage keep > 4250 for 48hrs, + * set charging voltage = 4250 + */ + else if (timestamp_expired(deadline_48, NULL)) + curr->requested_voltage = 4250; + } + /* Should not keeep battery voltage > 4100mV and + * battery temperature > 45C for two hour + */ + if (curr->state == ST_DISCHARGE || + curr->batt.voltage < 4100 || + bat_temp_c < 450) { + deadline_2.val = 0; + } else if (curr->state == ST_CHARGE || + curr->state == ST_PRECHARGE) { + if (deadline_2.val == 0) + deadline_2.val = get_time().val + + CHARGER_LIMIT_TIMEOUT_HOURS_TEMP * HOUR; + else if (timestamp_expired(deadline_2, NULL)) { + /* Set discharge and charging voltage = 4100mV */ + if (curr->batt.voltage >= 4100) { + curr->requested_current = 0; + curr->requested_voltage = 4100; + } + } + } + +#ifdef VARIANT_KUKUI_CHARGER_MT6370 + mt6370_charger_profile_override(curr); +#endif /* CONFIG_CHARGER_MT6370 */ + + return 0; +} + +enum ec_status charger_profile_override_get_param(uint32_t param, + uint32_t *value) +{ + return EC_RES_INVALID_PARAM; +} + +enum ec_status charger_profile_override_set_param(uint32_t param, + uint32_t value) +{ + return EC_RES_INVALID_PARAM; +} + +int get_battery_manufacturer_name(char *dest, int size) +{ + static const char * const name[] = { + [BATTERY_CPT] = "AS1XXXD3Ka", + }; + ASSERT(dest); + strzcpy(dest, name[BATT_ID], size); + return EC_SUCCESS; +} |