Recalibrate battery after replacement in a Xperia XA2

I found this thread:

Maybe its enough to reflash the dtbo.img again to have the factory settings definition of the battery.

solely refresh dtbo is not enough, I will have to rewrite the value of /sys/class/power/bms/charge_full when boot the machine, and possibily set this value to the max of battery,and make its permission to something like 400, otherwise bms will frequently rewrite this value to the old batteryā€™s degraded full charge capacity value.

2 Likes

Hopefully it does it not. But there are other Values we must take care of like the mirrowed capacity_full and maybe others.

battery logic were hardcoded in kernelā€™s part, most of them. I donā€™t know how does XA works like. Sony have their own process of release the lock of their BMS setting somehow, otherwise it could be difficult to just swapping and recalibrate the battery, I found all of the sources from their forum, and most of them said sony doesnā€™t allow user to do this by themselves, dtbo flash only solves the problem of charge_full_designed, for charge_full, they only can be modified by magisk, or most possibily, just memory or function hijack to replace this value. My way to solve this is replace dtbo, and echo value > charge_full, and locks its permission from rewrite. From dmesg I can still see a lot of capacity learning updates message, but it doesnā€™t being applied to a locked file. The best approach probably is to modify the kernel, or doing a kernel patch, to make everything working as expected, but it really consumes too much time for testing, I gave up for a best solutionā€¦

Maybe the learning_counter must reach a certain value before write the new charge_full!?

Not quite sure, I guess this value were hardcoded and hard reseted with BMS board. I flashed back to android one time, using accubattery for calibrating, full discharge and full charge for 3 times, but the result varies quite large everytime. And tried using reset cache method for couple few times, like long press volume and power to reset the phone, all doesnā€™t help. I did using xposed to trace the value change of charge_full update last time as well. they always sending me a value of around 2000mah whereas my battery is indeed more than 4600mah even after depleted charge and so on. So i stopped testing because it really hurts the battery for these full depletes cycles.

I found some information that Emma once had the option for calibrating the battery. I connected my device, but all it offered was to flash stock Android; there was no option for battery calibration. Maybe this is related to older Xperia devices.

official ways if possible could be way better, i donā€™t have access to windows machine so donā€™t know if EMMA could have that directly or not.
The way how i locked the full_charge were coming from yet another way out is by patching this file for specific machine, see my reference link, after patches dtbo(write the correct battery info into the kernel), he patches this two methods somc_fg_gen4_restore_batt_aging_level_from_sram/somc_fg_gen4_set_batt_aging_level, basically are very small blocks of change, I didnā€™t dis-assmeble the patch
magiskboot hexpatch $DIRPATH/boot_0.img E243413968D647B9 0200805268D647B9
magiskboot hexpatch $DIRPATH/boot_0.img E00D0054A80240B9 E00D005408008052

But the main logic is pretty straight forward.
static int somc_fg_gen4_set_batt_aging_level(struct fg_dev *fg, int aging_level)
{
if (fg->max_batt_aging_level == BATT_AGING_LEVEL_NONE) {
pr_err(ā€œcannot set batt aging level because somc batterydata node does not exists\nā€);
return -EINVAL;
}

    if (aging_level < 0 || aging_level > fg->max_batt_aging_level) {
            pr_err("setting value is out of range\n");
            return -EINVAL;
    }

    if (aging_level == fg->batt_aging_level)
            return 0;

    fg->profile_load_status = PROFILE_NOT_LOADED;
    fg->requested_batt_aging_level = aging_level;
    schedule_delayed_work(&fg->profile_load_work, 0);
    return 0;

}
static void somc_fg_gen4_restore_batt_aging_level_from_sram(struct fg_dev *fg)
{
int rc;
u8 val;

    fg->batt_aging_level = 0;
    if (fg->max_batt_aging_level == BATT_AGING_LEVEL_NONE) {
            fg_dbg(fg, FG_SOMC, "batt aging level is not restored\n");
            return;
    }

    rc = fg_sram_read(fg, SOMC_AGING_LEVEL_WORD, SOMC_AGING_LEVEL_OFFSET,
                                            &val, 1, FG_IMA_DEFAULT);
    if (rc < 0) {
            pr_err("failed to read batt aging level rc=%d\n", rc);
    } else if (val > fg->max_batt_aging_level) {
            pr_err("saved batt aging level is abnormal val=%d\n", val);
    } else {
            fg->batt_aging_level = val;
    }
    fg_dbg(fg, FG_SOMC, "batt aging level = %d\n", fg->batt_aging_level);

    fg->requested_batt_aging_level = NO_REQUESTED_LEVEL;

}

I guess he directly passed 100 or 0 directly to trick the following process, but since SailfishOS looks like only cares about charge_full, so you donā€™t need to care those if simple cat and chmod works. Iā€™m looking forward to give kernel patch a try as well, but just donā€™t feeling comfortable because is hard to remove or forgot what I have changed in the future.

Ref.

if your kernel have APatch support, you can directly writting kernel patch, or directly patch methods accordingly to the fg model you use,

P.S.
Disassemble a bit.

0x0000000000000000:  E0 0D 00 54    b.eq #0x1bc
0x0000000000000004:  08 00 80 52    movz w8, #0
0x0000000000000000:  02 00 80 52    movz w2, #0
0x0000000000000004:  68 D6 47 B9    ldr  w8, [x19, #0x7d4]

Heā€™s just patched the fg->batt_aging_level to 0 probably.