Recalibrate battery after replacement in a Xperia XA2

NO. It’s exactly what I’m looking for. tlp commands are missing.
I’m referrring to the last message of this closed topic:

Perhaps we have to install the “tlp” package.

Informations for tlp you can find here:

https://linrunner.de/tlp/

But if this could work under SailfishOS I don’t know.

1 Like

It’s possible to install tlp from sources like described. I was able to manage that. But I cant test recalibration now because of I’m not at home at the moment.

1 Like

I have the same problems but on Sony XZ2 Compact, new original Battery but the BMS still shows the values of the old one, even after 7 complete charges/discharges:

POWER_SUPPLY_CHARGE_FULL_DESIGN=2899000
POWER_SUPPLY_CHARGE_FULL=1113000 (old Battery!!)

Only cycle count was reset directly after change the Battery:

POWER_SUPPLY_CYCLE_COUNT=1

I’m afraid I have to install Stock Android to calibrate it, but I will first wait here for a software solution.

I tested tlp yesterday evening with following result:

Error: battery charge thresholds/ discharge/recalibrate not available

So it seems that tlp is not supporting my hardware or something in kernel is missing for that feature.

My hardware for testing was X10 III with SF 4.6.0.13

Unfortunately, recalibrate option is only available for ThinkPad.

I fear that with every new kernel flashed and booted (Android Stock for calibration and then back to SFOS), the calibration data will be reset. So we really need this functionality in SFOS, and I can’t believe there are so few people experiencing problems with a de-calibrated battery after a change.

1 Like

What is this battery calibration in detail? Isn’t it enough to stop charging at a voltage, e.g. 4,2V to not overload the battery and on other side to stop discharging and shutdown the phone at e.g. 3,7 or 3,8V to take care of the battery and extend it’s lifetime? Is the calibration only for an exact display of charging percentage or has it a higher sense?

As a battery ages, it loses capacity. Along with voltage, the charging current is an important criterion. By fully discharging and recharging, the battery management system (BMS) can recalibrate the percentage classification. While partial charging and discharging may extend the battery’s lifespan, it ultimately leads to a decoupling of the classification, which can result in unpleasant events such as a sudden shutdown of the device at 10% or similar occurrences. Until proper calibration is achieved, the percentage display is inaccurate and worthless.

When not calibrated and after a battery replacement, the new battery charges relatively quickly to 100%, as indicated by the old POWER_SUPPLY_CHARGE_FULL value. If you disconnect the charger at the indicated 100%, only a fraction of the actual capacity of the new battery is charged. This is evident because the charging current is still high at the indicated 100%, indicating that calibration is necessary. If this is not done, you are effectively only using the remaining capacity of the old battery with the new battery when relying on the percentage display.

I experienced this problem also on my Sony Xperia X Compact as well, but I thought it was just a display error without investigating or following up further.

Under Android, it was the case that after the battery replacement, the correct capacity was displayed immediately. The batteries have a small circuit board with monitoring, sensor, and protection functions. It’s possible that some values are not being transmitted or reset correctly after the exchange.

That’s why I wonder where the problem lies. Was this calibration mechanism forgotten to be implemented or activated in the AOSP drivers/kernel provided by Sony, or is this function missing in (Community-Ports of) SailfishOS?

When my Jolla C2 is delivered and set up, I will flash my XZ2 Compact with the Sony stock ROM and see if that correctly calibrates the new battery and if it stays that way after SFOS is flashed back on. Maybe I can install the stock ROM on Slot B and change the bootloader without having to delete/overwrite SFOS!? I will report back.

2 Likes

I have replaced XA2s batteries several times.
I just did some full discharge/charge cycles and all was ok then.

3 Likes

I’ll do the same, @ric9k , on my testphone where I changed the battery a week ago and report what happens when ready. I’ll turn off charging/discharging limits during the test.

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.