Upower

https://gitlab.freedesktop.org/upower/upower/-/merge_requests/49 https://gitlab.gnome.org/GNOME/gnome-control-center/-/issues/1135 https://gitlab.gnome.org/Teams/Design/settings-mockups/-/blob/master/power/power.png https://gitlab.gnome.org/GNOME/gnome-control-center/-/issues/1461 https://gitlab.gnome.org/GNOME/gnome-control-center/-/issues/1461

Battery charge limits / profiles

Hacking

meson setup --prefix /tmp --libexecdir lib --sbindir bin --reconfigure build
meson compile -C build
  • Figure out how to read udev env variables in upower
  • Check if the steamdeck supports battery charge limits
  • ChargeLimitEnabled property which also can be set by the client, and monitored for changes
  • Save the state if battery limitting is enabled in /var/lib/upower/battery_saving as the embedded controller, might not save the start/stop threshold and resetting the bios/battery at 0% might reset it.
  • Figure out how to expose the dbus option, so a property
  • LG/Asus/Toshiba only have end charge limits
  • Ask the Valve guys about power charge limitting interests (likely not due to gamescope / KDE) can it be done in firmware
  • Hack control-center to read UPower properties and setting
  • Investigate Surface BIOS it supports setting Enable Battery Limit Mode, which limits charging to 80%.
  • When upower sets the charge limits it should read then back as not all hardware support arbitrary percentages. FIXME? Required?
  • Mail Arvid Norlander lkml@vorpal.se if Toshiba laptops have a start limit
  • leaf requies GNOME to know what is up (Battery status). Depends on Alan / GNOME Design descision
  • borrow framework and write EC charge_control_support
  • wCPO Asus https://www.asus.com/us/support/FAQ/1032726/ suggests 58/60%
  • LG only has 80 and 100 as end charge limit
  • Toshiba only has 80 and 100 as end charge limit
  • Extend the kernel API to show valid charge options?
  • Add an allowed values? sysfs entry for charge_control_end_limits [80 100] => send a RFC to the mailing list
  • Add documentation for the LG/ASUS/Toshiba stop thresholds special cases
  • Ask Dell about exposting charge_control_*_threshold's
  • Framework driver https://github.com/DHowett/framework-laptop-kmod

Gnome Settings

busctl set-property org.freedesktop.UPower /org/freedesktop/UPower/devices/battery_BAT0 org.freedesktop.UPower.Device  ChargeThresholdEnabled b true

UPower Git issues

  • On startup charge-threshold-supported is FALSE, after I toggle a dbus setting we re-read it and it's true this should be read on startup!!!
  • Implement the switch functionality, setting the DBus property
  • Removes lid handling 07565ef6a1aa4a115f8ce51e259e408edbaed4cc as systemd does it? What should gnome do? https://gitlab.freedesktop.org/upower/upower/-/merge_requests/5#note_540149
$ busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager LidClosed
b false
15:50:57 hansg | Hmm, mutter depend ook op upower for LID change monitoring, maar alleen via DBUS. Dus ik zou zeggen reverten met de change die LID support dropped van upower voor nu. Tot dat
               | er een alternatief is.  (alternatief is waarschijnlijk LID-switch support toevoegen aan libinput en dan mutter dat laten gebruiken en gnome-control-center het aan mutter laten
               | vragen ..,)
  • Unrelated, but we could easily implement a Linger property changed Just emit here?
static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bus_error *error) {
        _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
  • Handle get_devices changes => REVERT
  • How do we get the current charge levels into the translated text label?

GTK tutorial/intro

Follow up

  • framework charge_control settings
  • multiple USB keyboard's with backlight laptop + USB
  • Dell privacy screen switch state to libinput to mutter (ask Hans for hardware)
  • USB re-pluggable usb keyboard backlight support in upower (ask Hans for hardware)
  • Steam Deck enhancements? https://gitlab.freedesktop.org/upower/upower/-/issues/245

meson warnings

Build targets in project: 34
NOTICE: Future-deprecated features used:
 * 0.60.0: {'install_subdir with empty directory'}
 * 1.1.0: {'"boolean option" keyword argument "value" of type str'}

Battery charge limit

New idea, use hwdb for profiles

Match if /sys/class/power_supply/*

/etc/udev/rules.d/60-battery.rules

ACTION=="remove", GOTO="battery_end"

# sensor:<model_name>:dmi:<dmi pattern>

SUBSYSTEM=="power_supply", KERNEL=="BAT*", \
  IMPORT{builtin}="hwdb 'battery:$attr{model_name}:$attr{[dmi/id]modalias}'", \
  GOTO="battery_end"

LABEL="battery_end"

/etc/udev/hwdb.d/60-battery.rules

battery:*:dmi:*
 CHARGE_LIMIT=docked;20;60

battery:*:dmi:*T14s*
 CHARGE_LIMIT=docked;50;80

Like /usr/lib/udev/hwdb.d/60-sensor.hwdb

Testing is done with udevadm

udevadm test /sys/class/power_supply/BAT0

Hard loading

sudo systemd-hwdb update --strict || echo 'could not parse succesfully'
sudo udevadm trigger -v -p /sys/class/power_supply/BAT0

udevadm info -q all /sys/class/power_supply/BAT0
  • multi battery laptop, we should also allow match on "BAT*"
  • systemd PR for hwdb.d/parse_hwdb.py ?!

To add local entries, create a new file /etc/udev/hwdb.d/61-battery-local.hwdb

systemd-hwdb update
udevadm trigger -v -p DEVNAME=/dev/iio:deviceXXX
[docked]
start=50
stop=80

[travel]
start=100
end=100

[conservative]
start=20
end=60

/etc/upower/battery.d/20-lenovo

[docked]
start=30
end=90
dmi=T14sGen1 & T14S

Multiple batteries

[lenovo-bat0]
start=30
end=90
dmi=Lenovo
battery=BAT0

[lenovo-bat1]
start=50
end=90
dmi=Lenovo
battery=BAT1

Where dmi is a glob match on /sys/class/dmi/id/modalias so *T14sGen1*

battery is an entry in /sys/class/power_supply

DBus API

a{s} of battery limit profiles

  • Enable()
  • Supported Property?
  • Start Property
  • End Property

Caveats

  • Not all laptops/hardware supports the same settings so setting on 80 might be 90.

Enum

To not show too many profiles at once we should maybe just support an Enum of modes and every profile has a mode entry and in theory we could "extend" this in the future.

  • low power
  • docked
  • travel
  • conservative?

Steamdeck

https://0x0.st/HGAi.sh

Supports it through a non-standard knob max_battery_charge_level, kernel source and driver code.

  • how do I write a proper driver which uses charge_control_end_threshold
  • how do other drivers do this?
  • how does this get to power_supply?
  • how is the power_supply class created?

Framework

Forum Post about the EC with charge limit mention Blog post about EC and charge limit Official framework EC code Charge limit code? Charge controller chip Datasheet

Setting min charge threshold

  • Contact dhowett about mainlining the kernel driver

No min. percentage available Does it require just setting SYSTEM_BBRAM_IDX_CHG_MIN to support? Does hardware understand that? seems _MIN is totally not supported?

The embedded controller is a MEC1701, but what is the charge control chip?

Kernel Driver

Some patches have been submitted and merged to support the Framework cros_ec LPC driver. However Framework extended the Chromebook? EC code with charge control which is not merged into the kernel

So our kernel driver should use the EC controller and obtain a reference to it somehow, a driver that interacts with the chromeOS EC is

drivers/power/supply/cros_usbpd-charger.c

See for example a function which calls an EC command:

static int cros_usbpd_charger_ec_command(struct charger_data *charger,

For a charge limit driver we likely need to write a driver similiar to msi-ec.c in drivers/platform/x86, something like drivers/platform/x86/framework-ec.c

Questions:

  • How do we bind the EC controller? And do we need too?
  • It's a module_platform_driver, how does that determine when it needs to be loaded or is this some DeviceTree thing? The cros_usbpd driver does it like this, but how does that work?
static int cros_usbpd_charger_probe(struct platform_device *pd)
{
	struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent);
	struct cros_ec_device *ec_device = ec_dev->ec_dev;

wmi_ec uses ec_read which in turn calls acpi_ec_read. The driver binds based on DMI strings.

  • What should the framework-ec driver use?

Mainline OpenRazer power bits so upower works out of the box

A user made a bug report to support openrazer's sysfs attributes for charging/battery readout. This driver sadly exports custom sysfs attributes while it should implement a power_supply such as the logitech hid-logitech-hidpp.c driver which upower can automatically pick up

Charging bits are read here

  • Obtain hardware with an USB dongle, bluetooth might work out of the box?
  • How does one implement a power_supply driver?
  • Contact upstream about mainlining, note that the driver exposes far more stuff over sysfs which likely can't be mainlined nor do I have interest in.

Battery Calibration

After Charge limits we should consider working on battery calibration. To inhibit the system, we can use a systemd dbus call just like cc-color-calibrate does in gnome-control-center.

UPower instead should probably talk to systemd to to inhibit and it works as following:

UPower adds:

  • BAT0->Calibrate()
  • BAT0->IsCalibrating = bool

User calls BAT0->Calibrate() We set IsCalibrating = true We inhibit the current session https://www.freedesktop.org/wiki/Software/systemd/inhibit/ We disallow changing the charge limits We disable charge limits We 'full-discharge' to /sys/class/power_supply/BAT0/charge_behaviour We keep track of where we are, so discharge X% => 0% and then 0% => 100% is a full calibration Once completed we set isCalibrating to False.