diff options
-rw-r--r-- | drivers/power/max17040_battery.c | 18 | ||||
-rw-r--r-- | include/linux/max17040_battery.h | 3 |
2 files changed, 20 insertions, 1 deletions
diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c index 68322b3..895f207 100644 --- a/drivers/power/max17040_battery.c +++ b/drivers/power/max17040_battery.c @@ -139,16 +139,32 @@ static void max17040_get_vcell(struct i2c_client *client) chip->vcell = ((msb << 4) + (lsb >> 4)) * 1250; } +#define TO_FIXED(a,b) (((a) << 8) + (b)) +#define FIXED_TO_INT(x) ((int)((x) >> 8)) +#define FIXED_MULT(x,y) ((((u32)(x) * (u32)(y)) + (1 << 7)) >> 8) +#define FIXED_DIV(x,y) ((((u32)(x) << 8) + ((u32)(y) >> 1)) / (u32)(y)) + static void max17040_get_soc(struct i2c_client *client) { struct max17040_chip *chip = i2c_get_clientdata(client); u8 msb; u8 lsb; + u32 val; + u32 fmin_cap = TO_FIXED(chip->pdata->min_capacity, 0); msb = max17040_read_reg(client, MAX17040_SOC_MSB); lsb = max17040_read_reg(client, MAX17040_SOC_LSB); - chip->soc = min(msb, (u8)100); + /* convert msb.lsb to Q8.8 */ + val = TO_FIXED(msb, lsb); + if (val <= fmin_cap) { + chip->soc = 0; + return; + } + + val = FIXED_MULT(TO_FIXED(100, 0), val - fmin_cap); + val = FIXED_DIV(val, TO_FIXED(100, 0) - fmin_cap); + chip->soc = clamp(FIXED_TO_INT(val), 0, 100); } static void max17040_get_version(struct i2c_client *client) diff --git a/include/linux/max17040_battery.h b/include/linux/max17040_battery.h index 27d4018..584ffaf 100644 --- a/include/linux/max17040_battery.h +++ b/include/linux/max17040_battery.h @@ -15,6 +15,9 @@ struct max17040_platform_data { int (*charger_online)(void); int (*charger_enable)(void); bool skip_reset; + int min_capacity; /* minimum allowable capacity. The reported capacity + will be scaled from [<min_capacity>,100] to + [0,100] */ }; #endif |