From: Mario Limonciello <mario.limonciello@xxxxxxx> During a sleep cycle the system will consume power to keep the platform in s2idle or s3. On systems running on a battery this can be measured by comparing battery before and after the sleep cycle. Add a symbol for the battery to report current energy level and a sysfs file to show this information to a user. Signed-off-by: Mario Limonciello <mario.limonciello@xxxxxxx> --- Documentation/ABI/testing/sysfs-power | 8 ++++++++ include/linux/suspend.h | 2 ++ kernel/power/main.c | 10 ++++++++++ 3 files changed, 20 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power index a3942b1036e25..e263355f99fc1 100644 --- a/Documentation/ABI/testing/sysfs-power +++ b/Documentation/ABI/testing/sysfs-power @@ -442,6 +442,14 @@ Description: 'total_hw_sleep' and 'last_hw_sleep' may not be accurate. This number is measured in microseconds. +What: /sys/power/suspend_stats/last_sleep_energy +Date: March 2025 +Contact: Mario Limonciello <mario.limonciello@xxxxxxx> +Description: + The /sys/power/suspend_stats/last_sleep_energy file + contains the amount of energy that the battery consumed + during the last sleep cycle. This number is measured in mAh. + What: /sys/power/sync_on_suspend Date: October 2019 Contact: Jonas Meurer <jonas@xxxxxxxxxxxxxxx> diff --git a/include/linux/suspend.h b/include/linux/suspend.h index da6ebca3ff774..9627e2394c8a9 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -441,6 +441,7 @@ extern int unregister_pm_notifier(struct notifier_block *nb); extern void ksys_sync_helper(void); extern void pm_report_hw_sleep_time(u64 t); extern void pm_report_max_hw_sleep(u64 t); +extern void pm_report_sleep_energy(u64 t); #define pm_notifier(fn, pri) { \ static struct notifier_block fn##_nb = \ @@ -484,6 +485,7 @@ static inline int unregister_pm_notifier(struct notifier_block *nb) static inline void pm_report_hw_sleep_time(u64 t) {}; static inline void pm_report_max_hw_sleep(u64 t) {}; +static inline void pm_report_sleep_energy(u64 t) {}; static inline void ksys_sync_helper(void) {} diff --git a/kernel/power/main.c b/kernel/power/main.c index 6254814d48171..9305c86e0b91a 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -321,6 +321,7 @@ struct suspend_stats { u64 last_hw_sleep; u64 total_hw_sleep; u64 max_hw_sleep; + u64 last_sleep_energy; enum suspend_stat_step failed_steps[REC_FAILED_NUM]; }; @@ -368,6 +369,12 @@ void pm_report_hw_sleep_time(u64 t) } EXPORT_SYMBOL_GPL(pm_report_hw_sleep_time); +void pm_report_sleep_energy(u64 t) +{ + suspend_stats.last_sleep_energy = t; +} +EXPORT_SYMBOL_GPL(pm_report_sleep_energy); + void pm_report_max_hw_sleep(u64 t) { suspend_stats.max_hw_sleep = t; @@ -399,6 +406,7 @@ suspend_attr(fail, "%u\n"); suspend_attr(last_hw_sleep, "%llu\n"); suspend_attr(total_hw_sleep, "%llu\n"); suspend_attr(max_hw_sleep, "%llu\n"); +suspend_attr(last_sleep_energy, "%llu\n"); #define suspend_step_attr(_name, step) \ static ssize_t _name##_show(struct kobject *kobj, \ @@ -477,6 +485,7 @@ static struct attribute *suspend_attrs[] = { &last_hw_sleep.attr, &total_hw_sleep.attr, &max_hw_sleep.attr, + &last_sleep_energy.attr, NULL, }; @@ -484,6 +493,7 @@ static umode_t suspend_attr_is_visible(struct kobject *kobj, struct attribute *a { if (attr != &last_hw_sleep.attr && attr != &total_hw_sleep.attr && + attr != &last_sleep_energy.attr && attr != &max_hw_sleep.attr) return 0444; -- 2.43.0