From 00306aad27c9efc2ee7bbeea91f48abae6c2aa40 Mon Sep 17 00:00:00 2001 From: Sjoerd Simons <sjoerd.simons@collabora.co.uk> Date: Tue, 30 Oct 2018 20:59:14 +0100 Subject: [PATCH] WIP --- drivers/power/supply/bq27xxx_battery.c | 181 ++++++++++++++++++------- 1 file changed, 130 insertions(+), 51 deletions(-) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index f2464ebeb2ae..94f7688fe749 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -884,6 +884,14 @@ struct bq27xxx_dm_buf { bool has_data, dirty; }; +/** + * Struct holding ding a cache of read dm_bufs + */ +#define DM_BUF_CACHE_SIZE 4; +struct bq27xxx_dm_buf_cache { + struct bq27xxx_dm_buf blocks[DM_BUF_CACHE_SIZE]; +} + #define BQ27XXX_DM_BUF(di, i) { \ .class = (di)->dm_regs[i].subclass_id, \ .block = (di)->dm_regs[i].offset / BQ27XXX_DM_SZ, \ @@ -1121,33 +1129,35 @@ static int bq27xxx_battery_read_dm_block(struct bq27xxx_device_info *di, return ret; } -static void bq27xxx_battery_update_dm_block(struct bq27xxx_device_info *di, - struct bq27xxx_dm_buf *buf, - enum bq27xxx_dm_reg_id reg_id, - unsigned int val) +static int bq27xxx_battery_update_dm_block(struct bq27xxx_device_info *di, + struct bq27xxx_dm_buf_cache *cache, + enum bq27xxx_dm_reg_id reg_id, + unsigned int val) { struct bq27xxx_dm_reg *reg = &di->dm_regs[reg_id]; const char *str = bq27xxx_dm_reg_name[reg_id]; + struct bq27xxx_dm_buf *buf = bq27xxx_battery_cache_get_dm_buf (di, cache, + reg_id); u16 *prev = bq27xxx_dm_reg_ptr(buf, reg); if (prev == NULL) { dev_warn(di->dev, "buffer does not match %s dm spec\n", str); - return; + return -1; } if (reg->bytes != 2) { dev_warn(di->dev, "%s dm spec has unsupported byte size\n", str); - return; + return -1; } if (!buf->has_data) { dev_warn(di->dev, "%s buffer has no data\n", str); - return; + return -1; } if (be16_to_cpup(prev) == val) { dev_info(di->dev, "%s has %u\n", str, val); - return; + return 0; } dev_info(di->dev, "%s had %u\n", str, be16_to_cpup(prev)); @@ -1164,15 +1174,77 @@ static void bq27xxx_battery_update_dm_block(struct bq27xxx_device_info *di, "for flash/NVM data memory" #endif "\n", str, be16_to_cpup(prev), val); - return; + return 0; } dev_info(di->dev, "update %s to %u\n", str, val); *prev = cpu_to_be16(val); buf->dirty = true; + return 1; +} + +static struct bq27xxx_dm_buf *bq27xxx_battery_cache_get_dm_buf (struct bq27xxx_device_info *di, + struct bq27xxx_dm_buf_cache *cache, + int regindex) +{ + u8 class = di->dm_regs[regindex].subclass_id; + u8 block = di->dm_regs[regindex].offset / BQ27XXX_DM_SZ,; + int i; + struct bq27xxx_dm_buf *buf; + + for (i = 0; i < DM_BUF_CACHE_SIZE; i++) { + buf = cache->blocks + i; + if (buf->class == class && buf->block == block) { + return buf; + } + + if (buf->class == 0) { + /* unallocated */ + buf->class = class; + buf->block = block; + bq27xxx_battery_read_dm_block(di, buf); + return buf; + } + } + + BUG_ON("ran out of cache space"); + return NULL; +} + +/* + * Flush cached blocked back to storage if needed; return negative on error, + * number of blocks written back on success + */ +static int bq27xxx_dm_buf *bq27xxx_battery_cache_flush (struct bq27xxx_device_info *di, + struct bq27xxx_dm_buf_cache *cache) +{ + int i; + int ret = 0; + + for (i = 0; i < DM_BUF_CACHE_SIZE; i++) { + struct bq27xxx_dm_buf *buf = cache->blocks + i; + + if (buf->class == 0) + break; + + if (buf->dirty) { + int r; + + r = bq27xxx_battery_write_dm_block (di, buf); + + if (r < 0) { + return r; + } + ret++; + } + + } + + return ret; } + static int bq27xxx_battery_cfgupdate_priv(struct bq27xxx_device_info *di, bool active) { const int limit = 100; @@ -1284,13 +1356,13 @@ static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di, } static int bq27xxx_battery_repair_bd_block (struct bq27xxx_device_info *di, - struct bq27xxx_dm_buf *bd) + struct bq27xxx_dm_buf_cache *cache) { const char *model = "bq27532"; int i; int ret; int valid = true; - struct bq27xxx_dm_buf cc = BQ27XXX_DM_BUF(di, BQ27XXX_DM_CYCLE_COUNT); + struct bq27xxx_dm_buf *bd, *cc; u8 defaults[] = { 0x3, 0x84, /* CC threshold */ 0x3, 0xe8, /* Design capacity*/ 0x1, /* Des Energy Scale */ @@ -1299,11 +1371,12 @@ static int bq27xxx_battery_repair_bd_block (struct bq27xxx_device_info *di, 'b', 'q', '2', '7', '5', '3', '2', '\0', 0x0 }; - ret = bq27xxx_battery_read_dm_block(di, bd); - if (ret < 0) { - dev_warn(di->dev, "failed to read bd block\n"); - return ret; + bd = bq27xxx_battery_cache_get_dm_buf (di, cache, + BQ27XXX_DM_DESIGN_CAPACITY) + if (bd == NULL) { + dev_warn(di->dev, "failed to get bd block\n"); + return -EINVAL; } for (i = 0; model[i] != '\0'; i++) { @@ -1329,17 +1402,14 @@ static int bq27xxx_battery_repair_bd_block (struct bq27xxx_device_info *di, } memcpy (bd->data, defaults, ARRAY_SIZE (defaults)); - bd->dirty = true; - bq27xxx_battery_write_dm_block(di,bd); - - dev_info(di->dev, "Set cycle count to 0"); - bq27xxx_battery_read_dm_block(di, &cc); - bq27xxx_battery_update_dm_block(di, &cc, + dev_info(di->dev, "Set cycle count to 0 after bd repair"); + cc = bq27xxx_battery_cache_get_dm_buf (di, cache, + BQ27XXX_DM_CYCLE_COUNT); + bq27xxx_battery_update_dm_block(di, cc, BQ27XXX_DM_CYCLE_COUNT, 0); - bq27xxx_battery_write_dm_block(di, &cc); return 1; } @@ -1347,53 +1417,62 @@ static int bq27xxx_battery_repair_bd_block (struct bq27xxx_device_info *di, static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di, struct power_supply_battery_info *info) { - struct bq27xxx_dm_buf bd = BQ27XXX_DM_BUF(di, BQ27XXX_DM_DESIGN_CAPACITY); - struct bq27xxx_dm_buf bt = BQ27XXX_DM_BUF(di, BQ27XXX_DM_TERMINATE_VOLTAGE); + struct bq27xxx_dm_buf_cache cache; bool updated; int repaired; if (bq27xxx_battery_unseal(di) < 0) return; - repaired = bq27xxx_battery_repair_bd_block(di, &bd); + repaired = bq27xxx_battery_repair_bd_block(di, &cache); + + if (info->charge_full_design_uah != -EINVAL) { + struct bq27xxx_dm_buf *bd; + int updated; + + bd = bq27xxx_battery_cache_get_dm_buf (di, &cache, + BQ27XXX_DM_DESIGN_CAPACITY) + + updated = bq27xxx_battery_update_dm_block(di, bd, + BQ27XXX_DM_DESIGN_CAPACITY, + info->charge_full_design_uah / 1000); + /* Also reset Qmax 0 */ + if (updated) { + struct bq27xxx_dm_buf *qmax; + qmax = bq27xxx_battery_cache_get_dm_buf (di, &cache, + BQ27XXX_DM_DESIGN_CAPACITY) + bq27xxx_battery_update_dm_block(di, &qmax, + BQ27XXX_DM_QMAX0, + info->charge_full_design_uah / 1000); + } - if (info->charge_full_design_uah != -EINVAL && - info->energy_full_design_uwh != -EINVAL) { - struct bq27xxx_dm_buf qmax = BQ27XXX_DM_BUF(di, BQ27XXX_DM_QMAX0); + /* TODO update cycle threshold! to 90 of full design ?*/ + /* Reset cycle count ? */ + } - bq27xxx_battery_read_dm_block(di, &bd); - bq27xxx_battery_read_dm_block(di, &qmax); + if (info->energy_full_design_uwh != -EINVAL + && di->dm_regs[BQ27XXX_DM_DESIGN_ENERGY].subclass_id != INVALID_SUBCLASS_ID) { + struct bq27xxx_dm_buf *be; - /* assume design energy & capacity are in same block */ + be = bq27xxx_battery_cache_get_dm_buf (di, &cache, + BQ27XXX_DM_DESIGN_ENERGY); bq27xxx_battery_update_dm_block(di, &bd, - BQ27XXX_DM_DESIGN_CAPACITY, - info->charge_full_design_uah / 1000); - bq27xxx_battery_update_dm_block(di, &qmax, - BQ27XXX_DM_QMAX0, - info->charge_full_design_uah / 1000); - bq27xxx_battery_write_dm_block(di, &qmax); - if (di->dm_regs[BQ27XXX_DM_DESIGN_ENERGY].subclass_id != INVALID_SUBCLASS_ID) - bq27xxx_battery_update_dm_block(di, &bd, - BQ27XXX_DM_DESIGN_ENERGY, - info->energy_full_design_uwh / 1000); + BQ27XXX_DM_DESIGN_ENERGY, + info->energy_full_design_uwh / 1000); } if (info->voltage_min_design_uv != -EINVAL) { - bool same = bd.class == bt.class && bd.block == bt.block; - if (!same) - bq27xxx_battery_read_dm_block(di, &bt); - bq27xxx_battery_update_dm_block(di, same ? &bd : &bt, + struct bq27xxx_dm_buf *bt; + bt = bq27xxx_battery_cache_get_dm_buf (di, &cache, + BQ27XXX_DM_TERMINATE_VOLTAGE); + bq27xxx_battery_update_dm_block(di, &bt, BQ27XXX_DM_TERMINATE_VOLTAGE, info->voltage_min_design_uv / 1000); } - updated = repaired || bd.dirty || bt.dirty; - - bq27xxx_battery_write_dm_block(di, &bd); - bq27xxx_battery_write_dm_block(di, &bt); - + updated = bq27xxx_battery_cache_flush (di, &cache) - if (updated && !(di->opts & BQ27XXX_O_CFGUP)) { + if (updated > 0 && !(di->opts & BQ27XXX_O_CFGUP)) { dev_info(di->dev, "Resetting due to update options"); bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_RESET, false); BQ27XXX_MSLEEP(300); /* reset time is not documented */ -- GitLab