OnePlus 8T (kebab): OPLUS charging driver causes USB disconnects when battery is full
<!--INSTRUCTIONS What not to report - Bugs in unofficial builds or anything not downloaded from our official portal - Missing Builds - Problems with the website - Asking for device support - Feature requests If you need help please see https://www.lineageos.org/community/ Anything between <!- - and - -> won't be shown when your issue is created.--> ## Expected Behavior When the battery is fully charged while connected via USB, the USB data connection (ADB, MTP, etc.) should remain stable. The charging driver should disable charging once and enter a maintenance/trickle state without affecting the USB data path. ## Current Behavior When the battery reaches 100%, the USB connection drops repeatedly, causing ADB and MTP disconnections. The USB event log shows **30+ disconnects over 3 days**, with some periods showing rapid flapping (3 disconnects within 5 seconds). **Root cause identified in kernel source:** The OPLUS charging driver (`oplus_chg`) enters an infinite loop when the battery is full: 1. `oplus_chg_update_work` fires every **5 seconds** (defined by `OPLUS_CHG_UPDATE_INTERVAL_SEC` in `oplus_charger.c:106`) 2. Calls `oplus_chg_check_status_full()` which always evaluates true once `charging_state == CHARGING_STATUS_FULL` 3. Calls `oplus_chg_full_action()` **unconditionally every poll** - no guard for "already processed" 4. This calls `oplus_chg_voter_charging_stop()` -\> `oplus_chg_turn_off_charging()` -\> `mp2650_disable_charging()` 5. `mp2650_disable_charging()` writes to MP2650 REG08 via I2C **every time** without checking if charging is already disabled 6. The repeated I2C writes to the charge-enable register cause the MP2650 to re-evaluate its input source, triggering Type-C CC line state changes 7. The PM8150B charger reports `typec_state_change_irq_handler` with mode flapping between 7 and 8 8. This causes the DWC3 USB controller to reset, dropping the USB connection **Kernel log evidence (repeats every \~5 seconds non-stop when battery is full):** ``` [OPLUS_CHG][oplus_chg_check_status_full]is_batt_full: 0, chip->charging_state= 2 [OPLUS_CHG][oplus_chg_full_action][BATTERY] Battery full !! [OPLUS_CHG][mp2650_charging_current_write_fast]set charge current = 1100 [OPLUS_CHG][mp2650_charging_current_write_fast]set charge current = 500 [OPLUS_CHG][mp2650_disable_charging] mp2650_disable_charging ``` **Type-C state flapping (correlated with the above):** ``` pm8150b_charger: typec_state_change_irq_handler: Couldn't find wireless psy typec mode is 7 typec mode is 8 (alternating rapidly) ``` **USB disconnect events from `dumpsys usb` (sample):** ``` 03-24 11:29:48:507 USB UEVENT: USB_STATE=DISCONNECTED 03-24 11:29:50:563 USB UEVENT: USB_STATE=CONNECTED 03-24 11:29:51:068 USB UEVENT: USB_STATE=DISCONNECTED 03-24 11:29:53:126 USB UEVENT: USB_STATE=CONNECTED 03-24 11:29:53:755 USB UEVENT: USB_STATE=DISCONNECTED ``` ## Possible Solution Two changes in the kernel source ([LineageOS/android_kernel_oneplus_sm8250](https://github.com/LineageOS/android_kernel_oneplus_sm8250)): **Fix 1 - `drivers/power/oplus/oplus_charger.c` : `oplus_chg_full_action()`** Add an early return when the full state has already been processed, so the redundant charging_stop/disable_charging chain doesn't fire every 5 seconds: ```c static void oplus_chg_full_action(struct oplus_chg_chip *chip) { /* Already processed full state - only re-check recharge threshold */ if (chip->batt_full == true && chip->charging_state == CHARGING_STATUS_FULL) { oplus_chg_check_rechg_status(chip); return; } // ... rest of existing function unchanged } ``` **Fix 2 - `drivers/power/oplus/charger_ic/oplus_mp2650.c` : `mp2650_disable_charging()`** Add a guard to skip the I2C write if charging is already disabled (defense-in-depth): ```c int mp2650_disable_charging(void) { // ... existing null/suspended checks ... /* Skip redundant I2C write if charging is already disabled */ if (mp2650_check_charging_enable() == 0) return 0; // ... existing I2C write to REG08 ... } ``` Both fixes preserve the recharge logic (`oplus_chg_check_rechg_status` still runs) so charging resumes normally when battery drops below `recharge_soc` (98%). **Related issue:** #9394 (same device, same USB instability symptom, but without root cause identification) ## Device information <!--/codename redfin /version lineage-20 /date 2023-03-22 /kernel Linux localhost 4.19.261-ga3e87045cf37 #1 Wed Mar 22 06:26:12 UTC 2023 /baseband g7250-00247.1-230113-B-9488784 /mods Google Apps, microG--> /codename kebab /version lineage-23.2 /date 2026-03-20 /kernel Linux localhost 4.19.325-cip128-st12-perf-g0970a5d23405 #1 SMP PREEMPT Fri Mar 20 07:54:53 UTC 2026 /baseband Q_V1_P14 /mods none ## Steps to Reproduce 1. Connect OnePlus 8T (kebab) to a computer via USB cable 2. Enable USB debugging (ADB) or file transfer (MTP) 3. Wait for the battery to charge to 100% 4. Observe that ADB/MTP connection drops and may reconnect intermittently 5. Run `adb shell su -c "dmesg | grep mp2650_disable_charging"` to confirm the charging disable loop is firing every \~5 seconds <!--- reproduce this bug. Include code to reproduce, if relevant--> <!--THIS SECTION IS MANDATORY. If it is not filled out correctly, your issue will be marked as invalid.--> <!--/codename redfin /version lineage-20 /date 2023-03-22 /kernel Linux localhost 4.19.261-ga3e87045cf37 #1 Wed Mar 22 06:26:12 UTC 2023 /baseband g7250-00247.1-230113-B-9488784 /mods Google Apps, microG--> /codename kebab /version lineage-23.2 /date 2026-03-20 /kernel Linux localhost 4.19.325-cip128-st12-perf-g0970a5d23405 #1 SMP PREEMPT Fri Mar 20 07:54:53 UTC 2026 /baseband Q_V1_P14 /mods none /device /version /date /kernel /baseband /mods <!--Replace the following line with "I have read the directions"--> I have not read the directions.
issue