diff options
author | Daisuke Nojiri <dnojiri@chromium.org> | 2020-05-11 14:58:01 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-06-20 02:17:16 +0000 |
commit | 6218ae98872846970d52024b04f01874534889dd (patch) | |
tree | 8526840700425d10748249c094fe4315c0ce5fba /power | |
parent | f4a6e87bd1fcc7932fc4cba148b171c514b21a1c (diff) | |
download | chrome-ec-6218ae98872846970d52024b04f01874534889dd.tar.gz |
Battery: Implement smart discharge system
Currently, CrOS EC chooses only one of the two powre-saving states
when the system is left idle. One is to hibernate and the other is
to cut off the battery. And these are determined at compile time.
If the system hibernates, EC will not have a chance to cut off the
battery before the state of charge reaches critical low. If the
system is in cutoff, it requires an AC adapter to wake up. So, neither
behavior is ideal.
This patch introduces the smart discharge system. Given the number
of hours to zero capacity as a target, it tries to choose the better
state for idling.
For example, if the state of charge is high, it will hibernate the
system because the target can be met before the battery completely
drains. If the state of charge is low, it will keep the EC up so
that it can cutoff the battery.
Tests are done on Bloog as follows:
Verify EC selects not to hibernate when the remaining capacity is
below the stay-up threshold.
The ectool smartdischarge command is tested as follows:
localhost ~ # ectool smartdischarge
Hours to zero capacity: 0 h
Stay-up threshold: 0 mAh
Cutoff threshold: 0 mAh
Hibernate discharge rate: 0 uA
Cutoff discharge rate: 0 uA
localhost ~ # ectool smartdischarge 2160
Hours to zero capacity: 2160 h
Stay-up threshold: 0 mAh
Cutoff threshold: 0 mAh
Hibernate discharge rate: 0 uA
Cutoff discharge rate: 0 uA
localhost ~ # ectool smartdischarge 2160 200 1500
EC result 3 (INVALID_PARAM)
localhost ~ # ectool smartdischarge 2160 1500 200
Hours to zero capacity: 2160 h
Stay-up threshold: 3240 mAh
Cutoff threshold: 432 mAh
Hibernate discharge rate: 1500 uA
Cutoff discharge rate: 200 uA
localhost ~ # ectool smartdischarge 2160 1500 0
EC result 3 (INVALID_PARAM)
localhost ~ # ectool smartdischarge 0
Hours to zero capacity: 0 h
Stay-up threshold: 0 mAh
Cutoff threshold: 0 mAh
Hibernate discharge rate: 1500 uA
Cutoff discharge rate: 200 uA
Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org>
BUG=b:152431365, b:157602162
BRANCH=none
TEST=See above
Change-Id: I1470b13203f3653ae0e495cd5ec8ed05f3c5102f
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2216392
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org>
Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Auto-Submit: Daisuke Nojiri <dnojiri@chromium.org>
Diffstat (limited to 'power')
-rw-r--r-- | power/common.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/power/common.c b/power/common.c index cc06d0891a..0cdabca0fa 100644 --- a/power/common.c +++ b/power/common.c @@ -309,12 +309,104 @@ static void power_set_active_wake_mask(void) static void power_set_active_wake_mask(void) { } #endif +#ifdef CONFIG_HIBERNATE +#ifdef CONFIG_BATTERY +/* + * Smart discharge system + * + * EC controls how the system discharges differently depending on the remaining + * capacity and the expected hours to zero. + * + * 0 X1 X2 full + * |----------|-------------------|------------------------------------| + * cutoff stay-up safe + * + * EC cuts off the battery at X1 mAh and hibernates the system at X2 mAh. X1 and + * X2 are derived from the cutoff and hibernation discharge rate, respectively. + * + * TODO: Learn discharge rates dynamically. + * + * TODO: Save sdzone in non-volatile memory and restore it when waking up from + * cutoff or hibernation. + */ +static struct smart_discharge_zone sdzone; + +static enum ec_status hc_smart_discharge(struct host_cmd_handler_args *args) +{ + static uint16_t hours_to_zero; + static struct discharge_rate drate; + const struct ec_params_smart_discharge *p = args->params; + struct ec_response_smart_discharge *r = args->response; + + if (p->flags & EC_SMART_DISCHARGE_FLAGS_SET) { + int cap; + + if (battery_full_charge_capacity(&cap)) + return EC_RES_UNAVAILABLE; + + if (p->drate.hibern < p->drate.cutoff) + /* Hibernation discharge rate should be always higher */ + return EC_RES_INVALID_PARAM; + else if (p->drate.cutoff > 0 && p->drate.hibern > 0) + drate = p->drate; + else if (p->drate.cutoff == 0 && p->drate.hibern == 0) + ; /* no-op. use the current drate. */ + else + return EC_RES_INVALID_PARAM; + + /* Commit */ + hours_to_zero = p->hours_to_zero; + sdzone.stayup = MIN(hours_to_zero * drate.hibern / 1000, cap); + sdzone.cutoff = MIN(hours_to_zero * drate.cutoff / 1000, + sdzone.stayup); + } + + /* Return the effective values. */ + r->hours_to_zero = hours_to_zero; + r->dzone = sdzone; + r->drate = drate; + args->response_size = sizeof(*r); + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_SMART_DISCHARGE, + hc_smart_discharge, + EC_VER_MASK(0)); + +__overridable enum critical_shutdown board_system_is_idle( + uint64_t last_shutdown_time, uint64_t *target, uint64_t now) +{ + int remain; + + if (now < *target) + return CRITICAL_SHUTDOWN_IGNORE; + + if (battery_remaining_capacity(&remain)) { + CPRINTS("SDC Failed to get remaining capacity"); + return CRITICAL_SHUTDOWN_HIBERNATE; + } + + if (remain < sdzone.cutoff) { + CPRINTS("SDC Cutoff"); + return CRITICAL_SHUTDOWN_CUTOFF; + } else if (remain < sdzone.stayup) { + CPRINTS("SDC Stay-up"); + return CRITICAL_SHUTDOWN_IGNORE; + } + + CPRINTS("SDC Safe"); + return CRITICAL_SHUTDOWN_HIBERNATE; +} +#else +/* Default implementation for battery-less systems */ __overridable enum critical_shutdown board_system_is_idle( uint64_t last_shutdown_time, uint64_t *target, uint64_t now) { return now > *target ? CRITICAL_SHUTDOWN_HIBERNATE : CRITICAL_SHUTDOWN_IGNORE; } +#endif /* CONFIG_BATTERY */ +#endif /* CONFIG_HIBERNATE */ /** * Common handler for steady states |