Skip to content

The Type-C Rp advertisement is ignored, so a 3 A source charges at 500 mA -- and AICL, not the driver, is what bounds the request

scope: soc:msm8998 · severity: finding · confidence: proven · subsystem: power

The question — the default 500 mA input limit leaves the phone losing charge under load, so current_max gets forced. At 3 A the USB gadget dies and ssh over usb0 goes with it. Does writing current_max drop the gadget?

The answer — no, and the driver could not do it if it wanted to. smb2_set_current_limit() in drivers/power/supply/qcom_pmi8998_charger.c writes exactly one register (USBIN_CURRENT_LIMIT_CFG, value/25000). There is no APSD rerun and no DPDM handoff on that path – CMD_APSD/APSD_RERUN_BIT is only touched by smb2_status_change_work() when charger-type detection fails.

It is electrical. A host port advertising [SDP] sources 500 mA. Asking for 3 A droops VBUS until the host resets the port; the gadget goes with the port, not with the driver. The measured ceiling on this desk’s port was ~1.35 A at 4.73 V – above that, nothing more arrives and the charger’s own AICL walks the limit back down (3000000 written, 1700000 read back).

The value that works is 1500000:

current_max USB in VBUS into battery
500000 (default) 474 mA 4.96 V +15 mA
900000 856 mA 4.86 V +452 mA
1500000 1354 mA 4.73 V +915 mA
2000000 1285 mA 4.73 V +915 mA (no gain)
3000000 – – write wedged, AICL clamped to 1.7 A

At the default the battery gains +15 mA while idle; under browser load that goes negative, which is the-debug-cable-starves-the-battery and the reason a-browser-arm-runs-on-a-throttled-phone-that-is-discharging-on-the-pc-port exists. At 1500000 the same phone went 30% -> 71% during an hour of continuous video arms.

3 A is safe to request, and is what the source advertises. Measured again at 76% battery, writing 3000000: the hardware AICL settled the limit at 2.05 A, USBIN drew 1.9 A at 4.53-4.61 V, the battery took +530-870 mA under load, and there was no USB disconnect and nothing in dmesg. That is better than the 1.5 A hand-set value (1.43 A in).

An earlier ramp on this same desk saturated near 1.35 A and one 3000000 write appeared to wedge; that was a single event, was not reproduced, and should not be read as causation – the register write itself cannot drop the gadget (see above). Where a source cannot supply what it advertises, AICL walking the limit down is the designed behaviour, not a fault.

It does not survive a replug. current_max is reset by the charger’s detection path on every attach, so it has to be re-applied per session.

How it was established — a stepped ramp with a 6 s settle, reading current_now/voltage_now on the charger and current_now on bms, with ssh over wlan0 so that losing usb0 could not take the measurement with it. That last part is not optional: reach the device over wifi before touching the charger, or the experiment kills its own transport.