Skip to content

power: supply: macsmc: add "auto-discharge" charge behaviour for CHLS - #521

Open
BoiledElectricity wants to merge 62 commits into
AsahiLinux:asahi-wipfrom
BoiledElectricity:macsmc-force-discharge-configurable
Open

power: supply: macsmc: add "auto-discharge" charge behaviour for CHLS#521
BoiledElectricity wants to merge 62 commits into
AsahiLinux:asahi-wipfrom
BoiledElectricity:macsmc-force-discharge-configurable

Conversation

@BoiledElectricity

@BoiledElectricity BoiledElectricity commented Jun 24, 2026

Copy link
Copy Markdown

Lowering the charge limit on CHLS machines always sets CHLS_FORCE_DISCHARGE, so the battery actively drains down to the limit even on AC. Per review feedback, this is now implemented as a new charge_behaviour value instead of a module parameter:

  • New auto-discharge value (enum + sysfs string + ABI doc): like auto, but actively discharge down to the charge control end threshold.
  • End-threshold writes preserve the current CHLS_FORCE_DISCHARGE bit instead of forcing it on; auto keeps its documented cap-only meaning.
  • The selection lives in the CHLS key itself: no driver state, persists across reboots, and systems upgrading from the old behaviour keep force-discharge until they explicitly write auto.

Resolves the in-code TODO. Tested on M1 MacBook Pro (j293), see comments.

jannau and others added 20 commits June 20, 2026 17:01
Apple Silicon based laptop use SPI as transport for HID. Add support for
SPI-based HID devices and and Apple keyboard and trackpad devices.
Intel based laptops using the keyboard input driver applespi use the
same HID over SPI protocol and can be supported later.

This requires SPI keyboard/mouse HID types since Apple's intenal
keyboards/trackpads use the same product id.

Signed-off-by: Janne Grunau <j@jannau.net>
Apple M2* chips have an embedded MTP processor that handles all HID
functions, and does not go over a traditional bus like SPI. The devices
still have real IDs, so add them here.

Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Hector Martin <marcan@marcan.st>
This maximum is arbitrary. Recent Apple devices have some vendor-defined
reports with 16384 here which fail to parse without this, so let's bump
it to that.

This value is used as follows:

report->size += parser->global.report_size * parser->global.report_count;

[...]

/* Total size check: Allow for possible report index byte */
if (report->size > (max_buffer_size - 1) << 3) {
	hid_err(parser->device, "report is too long\n");
	return -1;
}

All of these fields are unsigned integers, and report_count is bounded
by HID_MAX_USAGES (12288). Therefore, as long as the respective maximums
do not overflow an unsigned integer (let's say a signed integer just in
case), we're safe. This holds for 16384.

Signed-off-by: Hector Martin <marcan@marcan.st>
Apple MacBook keyboards started using HID over SPI in 2015. With the
addition of the SPI HID transport they can be supported by this driver.
Support all product ids over with the Apple SPI vendor id for now.

The Macbook Pro (M1, 13-inch, 2020) uses the same function key mapping
as other Macbook Pros with touchbar and dedicated ESC key.
Apple silicon Macbooks use the same function key mapping as the 2021 and
later Magic Keyboards.

Signed-off-by: Janne Grunau <j@jannau.net>
We use BUS_HOST for MTP HID subdevices

Signed-off-by: Hector Martin <marcan@marcan.st>
This mode is added to ease adding new xkeyboard configs for Apple
silicon Macbook keyboards. The existing ones have strange quirks [1] and
as the keyboard sends a key code for the 'fn' there is desire to use it
as additional modifier [2].

[1]: https://pagure.io/fedora-asahi/remix-bugs/issue/17
[2]: https://asahilinux.org/docs/project/help-wanted/ (Keyboard layout cleanup)

Signed-off-by: Janne Grunau <j@jannau.net>
Signed-off-by: Janne Grunau <j@jannau.net>
Signed-off-by: Janne Grunau <j@jannau.net>
Will be used for supporting MacBook trackpads connected via SPI.

Signed-off-by: Janne Grunau <j@jannau.net>
The trackpads in Macbooks beginning in 2015 are HID devices connected
over SPI. On Intel Macbooks they are currently supported by applespi.c.
This chang adds support for the trackpads on Apple Silicon Macbooks
starting in late 2020. They use a new HID over SPI transport driver.
The touch report format differs from USB/BT Magic Trackpads. It is the
same format as the type 4 format supported by bcm5974.c.

Signed-off-by: Janne Grunau <j@jannau.net>
Apple M2 devices expose the multi-touch device over the HID over
DockChannel transport, which we represent as the HOST bus type. The
report format is the same, except the legacy mouse header is gone and
there is no enable request needed.

Signed-off-by: Hector Martin <marcan@marcan.st>
The trackpad has to request multi touch reports during resume.

Signed-off-by: Janne Grunau <j@jannau.net>
On at least some SPI devices (e.g. recent Apple Silicon machines), the
Broadcom touch controller is prone to crashing. When this happens, the
STM eventually notices and resets it. It then notifies the driver via
HID report 0x60, and the driver needs to re-enable MT mode to make
things work again.

This poses an additional issue: the hidinput core will close the
low-level transport while the device is closed, which can cause us to
miss a reset notification. To fix this, override the input open/close
callbacks and send the MT enable every time the HID device is opened,
instead of only once on probe. This should increase general robustness,
even if the reset mechanism doesn't work for some reason, so it's worth
doing it for USB devices too. MTP devices are exempt since they do not
require the MT enable at all.

Signed-off-by: Hector Martin <marcan@marcan.st>
For SPI/MTP trackpads, query the dimensions via HID report instead of
hardcoding values.

TODO: Does this work for the USB/BT devices? Maybe we can get rid of the
hardcoded sizes everywhere?

Signed-off-by: Hector Martin <marcan@marcan.st>
Keyboard and trackpad of Apple Sillicon SoCs (M1, M1 Pro/Max) laptops
are are HID devices connected via SPI.

This is the same protocol as implemented by applespi.c. It was not
noticed that protocol is a transport for HID. Adding support for ACPI
based Intel MacBooks will be done in a separate commit.

How HID is mapped in this protocol is not yet fully understood.

Microsoft has a specification for HID over SPI [1] incompatible with the
transport protocol used by Apple.

[1] https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/hid-over-spi

Contains "HID: transport: spi: apple: Increase receive buffer size"

The SPI receive buffer is passed directly to hid_input_report() if it
contains a complete report. It is then passed to hid_report_raw_event()
which computes the expected report size and memsets the "missing
trailing data up to HID_MAX_BUFFER_SIZE (16K) or
hid_ll_driver.max_buffer_size (if set) to zero.

Co-developed-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Janne Grunau <j@jannau.net>
DockChannel is a simple FIFO interface used to communicate between SoC
blocks. Add a driver that represents the shared interrupt controller for
the DockChannel block, and then exposes probe and data transfer
functions that child device drivers can use to instantiate individual
FIFOs.

Signed-off-by: Hector Martin <marcan@marcan.st>
Apple M2 devices have an MTP coprocessor embedded in the SoC that
handles HID for the integrated touchpad/keyboard, and communicates
over the DockChannel interface. This driver implements this new
interface.

Signed-off-by: Hector Martin <marcan@marcan.st>
This driver can be used for coprocessors that do some background task or
communicate out-of-band, and do not do any mailbox I/O beyond the
standard RTKit initialization.

Signed-off-by: Hector Martin <marcan@marcan.st>
The SMC firmware included in macOS 27 changed the size of BCF0 key from
4 to 1 bytes. This key is used for indicating that battery state is
critically low.

Reviewed-by: Sven Peter <sven@kernel.org>
Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
@BoiledElectricity

Copy link
Copy Markdown
Author

Tested on Apple MacBook Pro 13" M1 (j293), kernel 6.19.14, on AC at 100% (this firmware uses the CHLS path, has_chls=1):

  • force_discharge=N + set 90% limit → battery just caps charging, no discharge (Full, current_now=0)
  • force_discharge=Y (default) + set 90% limit → actively discharges (Discharging, ~-360 mA)
force_discharge=N, end_threshold=90:
  status=Full  current_now=0 uA        x4 samples over 8s

force_discharge=Y, end_threshold=90:
  status=Full         current_now=0 uA
  status=Discharging  current_now=-347000 uA
  status=Discharging  current_now=-376000 uA
  status=Discharging  current_now=-361000 uA

Battery restored to 100% / default afterwards.

jannau and others added 8 commits July 24, 2026 20:51
Apple M3 Pro and Max devices are using 'gp00' keys for GPIO in addition
to 'gP00' keys. Add a second compatible to handle this keys with an
additional macsmc-gpio instance.

Signed-off-by: Janne Grunau <j@jannau.net>
Add support for SMC GPIO keys with a lower letter 'p' via the
"apple,smc-low-gpio" compatible. This adds support for a second
macsmc-gpio controller using 'gp00' keys.
These keys are used on Apple M3 Pro and Max MacBooks in the controller
for keyboard and trackpad and for the built-in DisplayPort to HDMI
converter.

Signed-off-by: Janne Grunau <j@jannau.net>
Apple M3 Pro and Max devices are using 'gp00' keys for GPIO in addition
to 'gP00' keys. These keys are handled by an additional macsmc-gpio
instance using the "apple,smc-low-gpio" compatible.

Signed-off-by: Janne Grunau <j@jannau.net>
Signed-off-by: Janne Grunau <j@jannau.net>
Signed-off-by: sofus <sofus.c@icloud.com>
Since immediate mode was enabled, unmapping a GPU VA can defer
drm_gpuvm_bo destruction until drm_gpuvm_bo_deferred_cleanup() is called.
The GEM bind and unbind paths drain that list, but Vm::drop() unmaps the
remaining user ranges without doing so.

Drain the deferred list after both teardown unmaps. Otherwise a deferred
drm_gpuvm_bo retains the imported GEM and dma-buf after its DRM file is
closed, leaving its backing pages pinned.

Fixes: 2aeee2d ("drm/asahi: Switch gpuvm to DRM_GPUVM_IMMEDIATE_MODE")
Signed-off-by: DesktopECHO <33142753+DesktopECHO@users.noreply.github.com>
Add CONFIG_VIDEO_APPLE_AVD for AVD (Apple video decoder) support.

Signed-off-by: Janne Grunau <j@jannau.net>
sofus13 and others added 9 commits July 25, 2026 22:15
Signed-off-by: sofus <sofus.c@icloud.com>
This is a hardcoded charge threshold feature present in firmware 13.0 or
newer. Userspace settings are rounded to one of the two possible
behaviors.

Since macOS Sequoia firmware, CHLS replaced CHWA and now allows an
arbitrary end charge threshold to be configured.

Prefer CHWA over CHLS since the SMC firmware from iBoot-10151.1.1
(macOS 14.0) is not compatible with our CHGLS usage. It was working
with the SMC firmware from iBoot-10151.121.1 (macOS 14.5).

Signed-off-by: Janne Grunau <j@jannau.net>
Co-developed-by: Janne Grunau <j@jannau.net>
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Janne Grunau <j@jannau.net>
The admacs seen in M3-generation SoCs (t603x, t8122) need additional
configuration writes and so are getting a new compatible chain.

Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
The admacs present on t8122 and t603x SoCs need additional writes in
order to operate correctly. The exact purpose of this register
is unknown

Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
Those get a new "HF" decimator, and an extra component
that needs to be attached

Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
Signed-off-by: Janne Grunau <j@jannau.net>
@jannau

jannau commented Aug 1, 2026

Copy link
Copy Markdown
Member

Using a module option is not a good idea. It most likely will not be accepted upstream and we do not want to carry non-upstreamable patches unless they bring clear benefits.

A possible alternative solution might be to add a charge behaviour to control this. See charge_behaviour in Documentation/ABI/testing/sysfs-class-power and add either auto-discharge or auto-inhibit-discharge. I'm not sure what what the better default is from battery health perspective. Keeping the battery full charged for a long periods is not healthy but constantly charging and discharging the battery from 80% to 100% when the laptop is powered off isn't healthy either.

It would be worth checking if the charge thresholds are now respected while the laptop is powered off now that macOS has charge thresholds in 26.4 / 26.5 and later.

Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
When lowering the charge-control end threshold on machines that use the
CHLS key, the driver unconditionally sets CHLS_FORCE_DISCHARGE, actively
draining the battery down to the limit even on AC power. Most laptop
charge-limit implementations instead just cap charging at the threshold
and let the battery drain naturally through use.

Add a new "auto-discharge" charge_behaviour value that opts into the
active discharge, and make end-threshold writes preserve the current
CHLS_FORCE_DISCHARGE bit instead of forcing it on. "auto" keeps its
documented meaning of only respecting the thresholds.

The selection lives in the CHLS key itself, so no state is kept in the
driver, it persists across reboots, and systems upgrading from the old
behaviour keep force-discharge enabled until they explicitly write
"auto". Resolves the existing TODO.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: James A DellaMorte <james.dellamorte@gmail.com>
@BoiledElectricity
BoiledElectricity force-pushed the macsmc-force-discharge-configurable branch from 0ed7acc to 922f0e1 Compare August 1, 2026 17:10
@BoiledElectricity BoiledElectricity changed the title power: supply: macsmc: make force-discharge to the charge limit configurable power: supply: macsmc: add "auto-discharge" charge behaviour for CHLS Aug 1, 2026
@BoiledElectricity

BoiledElectricity commented Aug 1, 2026

Copy link
Copy Markdown
Author

Reworked as suggested, I also rebased.

Tested on Apple MacBook Pro 13" M1 (j293), kernel 7.1.5-asahidev+, on AC at 96%, has_chls=1:

threshold=90, behaviour=auto:            status=Not charging  current_now=0 uA        (cap-only, x4 samples)
threshold=90, behaviour=auto-discharge:  status=Discharging   current_now=-330000 uA  (active drain)
threshold 90 -> 85:                      selection survives the threshold write
threshold -> 100 (CHLS=0x100):           no errors, firmware charges normally, selection retained
threshold -> 90 again:                   discharge resumes (-330 mA)

@jannau

@jannau
jannau force-pushed the asahi-wip branch 2 times, most recently from c1cb252 to 96fa2b9 Compare August 11, 2026 13:25
@jannau
jannau force-pushed the asahi-wip branch 2 times, most recently from 77cb8f2 to b02aba8 Compare August 26, 2026 09:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants