Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bogus battery time left (nine hundred hours) – POWER_SUPPLY_TIME_TO_EMPTY_NOW taken as minutes when it is seconds: driver compatibility? #521

Open
nabijaczleweli opened this issue Feb 4, 2024 · 1 comment

Comments

@nabijaczleweli
Copy link
Contributor

nabijaczleweli commented Feb 4, 2024

I have a Google Hana device with a battery which is compatible = "sbs,sbs-battery". This yields a sysfs entry as /sys/class/power_supply/sbs-6-000b:

POWER_SUPPLY_NAME=sbs-6-000b
POWER_SUPPLY_TYPE=Battery
POWER_SUPPLY_STATUS=Discharging
POWER_SUPPLY_CAPACITY_LEVEL=Normal
POWER_SUPPLY_HEALTH=Unknown
POWER_SUPPLY_PRESENT=1
POWER_SUPPLY_TECHNOLOGY=Li-poly
POWER_SUPPLY_CYCLE_COUNT=7
POWER_SUPPLY_VOLTAGE_NOW=11810000
POWER_SUPPLY_CURRENT_NOW=-202000
POWER_SUPPLY_CURRENT_AVG=-170000
POWER_SUPPLY_CAPACITY=71
POWER_SUPPLY_CAPACITY_ERROR_MARGIN=1
POWER_SUPPLY_TEMP=272
POWER_SUPPLY_TIME_TO_EMPTY_NOW=48300
POWER_SUPPLY_TIME_TO_EMPTY_AVG=55140
POWER_SUPPLY_TIME_TO_FULL_AVG=3932100
POWER_SUPPLY_SERIAL_NUMBER=049a
POWER_SUPPLY_VOLTAGE_MIN_DESIGN=11250000
POWER_SUPPLY_VOLTAGE_MAX_DESIGN=11250000
POWER_SUPPLY_ENERGY_NOW=28930000
POWER_SUPPLY_ENERGY_FULL=41760000
POWER_SUPPLY_ENERGY_FULL_DESIGN=42000000
POWER_SUPPLY_CHARGE_NOW=2603000
POWER_SUPPLY_CHARGE_FULL=3648000
POWER_SUPPLY_CHARGE_FULL_DESIGN=3735000
POWER_SUPPLY_CONSTANT_CHARGE_CURRENT_MAX=1839000
POWER_SUPPLY_CONSTANT_CHARGE_VOLTAGE_MAX=12900000
POWER_SUPPLY_MANUFACTURE_YEAR=2019
POWER_SUPPLY_MANUFACTURE_MONTH=7
POWER_SUPPLY_MANUFACTURE_DAY=29
POWER_SUPPLY_MANUFACTURER=SMP
POWER_SUPPLY_MODEL_NAME=L17M3PB0

But attaching i3status to it gives results of "BAT 69.56% 962:00", "974:00".
It is a big battery and it is discharging at just 1.94W, but hundreds of hours is, well.

A quick grep-around shows that i3status parses POWER_SUPPLY_TIME_TO_EMPTY_NOW as batt_info->seconds_remaining = abs(atoi(walk + 1)) * 60;.

drivers/power/supply/sbs-battery.c in linux 6.6.11 shows

static void  sbs_unit_adjustment(struct i2c_client *client,
        enum power_supply_property psp, union power_supply_propval *val)
{
#define BASE_UNIT_CONVERSION            1000
#define BATTERY_MODE_CAP_MULT_WATT      (10 * BASE_UNIT_CONVERSION)
#define TIME_UNIT_CONVERSION            60
#define TEMP_KELVIN_TO_CELSIUS          2731
// ...
        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
        case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
                /* sbs provides time to empty and time to full in minutes.
                 * Convert to seconds
                 */
                val->intval *= TIME_UNIT_CONVERSION;
                break;

and being off factor of 60 would put it at around 15.7h, which I'd be willing to buy (this is a Lenovo 300e Chromebook 2nd Gen MTK; I also have a Lenovo 300e Chromebook 2nd Gen, which is a similar Intel platform, and it gets around that when it hits <2W).

Additional survey of the non-staging results I got for grep -rI TIME_TO_EMPTY_NOW shows:

        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: {
                        int percent = twl4030_madc_bat_voltscale(bat,
                                        twl4030_madc_bat_get_voltage(bat));
                        /* in mAh */
                        int chg = (percent * (bat->pdata->capacity/1000))/100;

                        /* assume discharge with 400 mA (ca. 1.5W) */
                        val->intval = (3600l * chg) / 400;
                        break;
drivers/power/supply/twl4030_madc_battery.c lines 110-162/272 byte 4435/7515 59%  (press RETURN)

(idk)

static int rn5t618_battery_tte(struct rn5t618_power_info *info,
                               union power_supply_propval *val)
{
        u16 res;
        int ret;

        ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_EMPTY_H, &res);
        if (ret)
                return ret;

        if (res == 65535)
                return -ENODATA;

        val->intval = res * 60;

        return 0;
}
drivers/power/supply/rn5t618_power.c lines 226-278/828 byte 6289/19922 32%  (press RETURN)

(EMPTY_H * 60 => minutes)

        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
                ret = regmap_read(map, MAX17042_TTE, &data);
                if (ret < 0)
                        return ret;

                val->intval = data * 5625 / 1000;
                break;
drivers/power/supply/max17042_battery.c lines 380-432/1225 byte 10904/33247 33%  (press RETURN)

(no clue)

        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
                val->intval = di->life_sec;
                break;
drivers/power/supply/ds2760_battery.c lines 524-576/808 byte 16594/22502 74%  (press RETURN)

(seconds)

        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
                if (cw_battery_valid_time_to_empty(cw_bat))
                        val->intval = cw_bat->time_to_empty;
                else
                        val->intval = 0;
                break;
drivers/power/supply/cw2015_battery.c lines 445-497/759 byte 12373/19482 64%  (press RETURN)

(time_to_empty is unannotated – no clue)

        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
                ret = bq27xxx_simple_value(di->cache.time_to_empty, val);
                break;
drivers/power/supply/bq27xxx_battery.c lines 1990-2042/2167 byte 58542/62305 94%  (press RETURN)
/*
 * Read a time register.
 * Return < 0 if something fails.
 */
static int bq27xxx_battery_read_time(struct bq27xxx_device_info *di, u8 reg)
{
        int tval;

        tval = bq27xxx_read(di, reg, false);
        if (tval < 0) {
                dev_dbg(di->dev, "error reading time register %02x: %d\n",
                        reg, tval);
                return tval;
        }

        if (tval == 65535)
                return -ENODATA;

        return tval * 60;
}

(no clue)

        /* time */

        info->units = APM_UNITS_MINS;

        if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
                if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) ||
                                !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full))
                        info->time = time_to_full.intval / 60;
                else
                        info->time = calculate_time(status.intval);
        } else {
                if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) ||
                              !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty))
                        info->time = time_to_empty.intval / 60;
                else
                        info->time = calculate_time(status.intval);
        }
drivers/power/supply/apm_power.c lines 301-353/376 byte 9902/10386 95%  (press RETURN)

(labelled as minutes, divides by 60 so can only be minutes really)

or, tabularly:

seconds minutes idk
sbs-battery rn5t618_power twl4030_madc_battery
ds2760_battery apm_power max17042_battery
cw2015_battery
bq27xxx_battery

which is an even split (with ~100% of x86 platforms using the APM driver and ~100% of ARM platforms using the SBS driver 🙈).

So i3status's scaling produces obviously-incorrect results by a factor of 60.

@nabijaczleweli
Copy link
Contributor Author

nabijaczleweli commented Feb 4, 2024

I was also just quoted "CHR 1032:15" (also unlikely given it's charging at 22W).

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

No branches or pull requests

1 participant