Skip to content
Snippets Groups Projects
Commit 00306aad authored by Sjoerd Simons's avatar Sjoerd Simons
Browse files

WIP

parent 7b6649da
Branches
Tags
No related merge requests found
......@@ -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,
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 &&
info->energy_full_design_uwh != -EINVAL) {
struct bq27xxx_dm_buf qmax = BQ27XXX_DM_BUF(di, BQ27XXX_DM_QMAX0);
if (info->charge_full_design_uah != -EINVAL) {
struct bq27xxx_dm_buf *bd;
int updated;
bq27xxx_battery_read_dm_block(di, &bd);
bq27xxx_battery_read_dm_block(di, &qmax);
bd = bq27xxx_battery_cache_get_dm_buf (di, &cache,
BQ27XXX_DM_DESIGN_CAPACITY)
/* assume design energy & capacity are in same block */
bq27xxx_battery_update_dm_block(di, &bd,
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);
bq27xxx_battery_write_dm_block(di, &qmax);
if (di->dm_regs[BQ27XXX_DM_DESIGN_ENERGY].subclass_id != INVALID_SUBCLASS_ID)
}
/* TODO update cycle threshold! to 90 of full design ?*/
/* Reset cycle count ? */
}
if (info->energy_full_design_uwh != -EINVAL
&& di->dm_regs[BQ27XXX_DM_DESIGN_ENERGY].subclass_id != INVALID_SUBCLASS_ID) {
struct bq27xxx_dm_buf *be;
be = bq27xxx_battery_cache_get_dm_buf (di, &cache,
BQ27XXX_DM_DESIGN_ENERGY);
bq27xxx_battery_update_dm_block(di, &bd,
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 */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment