• Andrejus Basovas's avatar
    power: supply: axp288_fuel_gauge: Refresh all registers in one go · 394088f0
    Andrejus Basovas authored
    The I2C-bus to the XPower AXP288 is shared between the Linux kernel and
    the SoCs P-Unit. The P-Unit has a semaphore which the kernel must "lock"
    before it may use the bus and while the kernel holds the semaphore the CPU
    and GPU power-states must not be changed otherwise the system will freeze.
    
    This is a complex process, which is quite expensive. This is all done by
    iosf_mbi_block_punit_i2c_access(). To ensure that no unguarded I2C-bus
    accesses happen, iosf_mbi_block_punit_i2c_access() gets called by the
    I2C-bus-driver for every I2C transfer. Because this is so expensive it
    is allowed to call iosf_mbi_block_punit_i2c_access() in a nested
    fashion, so that higher-level code which does multiple I2C-transfers can
    call it once for a group of transfers, turning the calls done by the
    I2C-bus-driver into no-ops.
    
    Userspace power-supply API users typically will read all provided
    properties in one go, refreshing the last read values when
    power_supply_changed() is called by the driver and/or periodically
    (e.g. every 2 minutes).
    
    The reading of all properties in one go causes the P-Unit semaphore
    to quickly be taken and released multiple times in a row. Certain
    PMIC registers like AXP20X_FG_RES are even used in multiple properties
    so they get read multiple times, leading to a P-Unit take + release
    each time the register is read.
    
    As already mentioned the taking of the P-Unit semaphore is a quite
    expensive operation and it has also been reported that the
    "hammering" of the P-Unit semaphore done by the axp288_fuel_gauge
    driver can even cause stability issues with the system as a whole.
    
    Switch over to a scheme where the axp288_fuel_gauge driver keeps
    a local copy of all the registers which it uses for properties
    and make it only refresh its copy of the registers if the values
    are older then 1 minute; or when a fuel-gauge interrupt has
    triggered since the last read.
    
    This not only reduces the amount of reads, it also makes the code
    do all the reads in one go, rather then reading specific registers
    based on which property is being queried. This allows calling
    iosf_mbi_block_punit_i2c_access() once before doing all the reads,
    so that we now only take the P-Unit semaphore once per update.
    Tested-by: default avatarAndrejus Basovas <cpp@gcc.lt>
    Signed-off-by: default avatarAndrejus Basovas <cpp@gcc.lt>
    Co-developed-by: default avatarHans de Goede <hdegoede@redhat.com>
    Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
    Signed-off-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
    394088f0
Kconfig 25.1 KB