From 70c7d40a8b1ef5dbc84654b22a6f6daf58364f19 Mon Sep 17 00:00:00 2001 From: Rakesh Kota Date: Tue, 30 Aug 2022 23:14:14 +0530 Subject: [PATCH] power: supply: bq27xxx: update the resistance table Add support to update battery calibrated resistance values into the BQ27XXX's internal NVM memory, when config (CONFIG_BATTERY_BQ27XXX_RESIST_TABLE_UPDATES_NVM) is enabled. With this change, update bq27xx_parse_dt function to return error code when number of elements does not match with the fixed resistance array length. Change-Id: Ibbb0e4543b410a319343c625e43727207e739c0b Signed-off-by: Rakesh Kota Signed-off-by: Monish Chunara --- drivers/power/supply/Kconfig | 12 +++ drivers/power/supply/bq27xxx_battery.c | 87 +++++++++++++++++++++- drivers/power/supply/bq27xxx_battery_i2c.c | 45 +++++++++++ include/linux/power/bq27xxx_battery.h | 6 ++ 4 files changed, 146 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 9af27a694527..97846f3794a1 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -295,6 +295,18 @@ config BATTERY_BQ27XXX_DT_UPDATES_NVM general-purpose kernels, as this can cause misconfiguration of a smart battery with embedded NVM/flash. +config BATTERY_BQ27XXX_RESIST_TABLE_UPDATES_NVM + bool "BQ27xxx resistance table update of NVM/flash data memory" + depends on BATTERY_BQ27XXX_DT_UPDATES_NVM + help + Say Y here to enable devicetree monitored-battery resistance table config + and Qmax-cell0 value in the NVM/flash data memory. Only enable this option + when calibrated resistance table and Qmax-Cell0 parameters for the battery + in-use are updated in DT. If the Battery specific data is not available + in DT, then this config should not be set to Y. Not for general-purpose + kernels, as this can cause is the configuration of a smart battery with + embedded NVM/flash. + config BATTERY_DA9030 tristate "DA9030 battery driver" depends on PMIC_DA903X diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 22b0df606136..ca4f7d26684b 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -866,7 +866,25 @@ enum bq27xxx_dm_reg_id { BQ27XXX_DM_DESIGN_CAPACITY = 0, BQ27XXX_DM_DESIGN_ENERGY, BQ27XXX_DM_TERMINATE_VOLTAGE, +#ifdef CONFIG_BATTERY_BQ27XXX_RESIST_TABLE_UPDATES_NVM BQ27XXX_DM_TAPER_RATE, + BQ27XXX_DM_QMAX, + BQ27XXX_RAM_R_A0_0, + BQ27XXX_RAM_R_A0_1, + BQ27XXX_RAM_R_A0_2, + BQ27XXX_RAM_R_A0_3, + BQ27XXX_RAM_R_A0_4, + BQ27XXX_RAM_R_A0_5, + BQ27XXX_RAM_R_A0_6, + BQ27XXX_RAM_R_A0_7, + BQ27XXX_RAM_R_A0_8, + BQ27XXX_RAM_R_A0_9, + BQ27XXX_RAM_R_A0_10, + BQ27XXX_RAM_R_A0_11, + BQ27XXX_RAM_R_A0_12, + BQ27XXX_RAM_R_A0_13, + BQ27XXX_RAM_R_A0_14, +#endif }; #define bq27000_dm_regs NULL @@ -921,7 +939,25 @@ static struct bq27xxx_dm_reg bq27421_dm_regs[] = { [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2, 0, 8000 }, [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2, 0, 32767 }, [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2500, 3700 }, +#ifdef CONFIG_BATTERY_BQ27XXX_RESIST_TABLE_UPDATES_NVM [BQ27XXX_DM_TAPER_RATE] = { 82, 27, 2, 0, 2000 }, /* Taper rate */ + [BQ27XXX_DM_QMAX] = { 82, 0, 2, 0, 32767 }, + [BQ27XXX_RAM_R_A0_0] = { 89, 0, 2, 0, 32767 }, + [BQ27XXX_RAM_R_A0_1] = { 89, 2, 2, 0, 32767 }, + [BQ27XXX_RAM_R_A0_2] = { 89, 4, 2, 0, 32767 }, + [BQ27XXX_RAM_R_A0_3] = { 89, 6, 2, 0, 32767 }, + [BQ27XXX_RAM_R_A0_4] = { 89, 8, 2, 0, 32767 }, + [BQ27XXX_RAM_R_A0_5] = { 89, 10, 2, 0, 32767 }, + [BQ27XXX_RAM_R_A0_6] = { 89, 12, 2, 0, 32767 }, + [BQ27XXX_RAM_R_A0_7] = { 89, 14, 2, 0, 32767 }, + [BQ27XXX_RAM_R_A0_8] = { 89, 16, 2, 0, 32767 }, + [BQ27XXX_RAM_R_A0_9] = { 89, 18, 2, 0, 32767 }, + [BQ27XXX_RAM_R_A0_10] = { 89, 20, 2, 0, 32767 }, + [BQ27XXX_RAM_R_A0_11] = { 89, 22, 2, 0, 32767 }, + [BQ27XXX_RAM_R_A0_12] = { 89, 24, 2, 0, 32767 }, + [BQ27XXX_RAM_R_A0_13] = { 89, 26, 2, 0, 32767 }, + [BQ27XXX_RAM_R_A0_14] = { 89, 28, 2, 0, 32767 }, +#endif }; static struct bq27xxx_dm_reg bq27425_dm_regs[] = { @@ -1060,7 +1096,26 @@ static const char * const bq27xxx_dm_reg_name[] = { [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity", [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy", [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage", +#ifdef CONFIG_BATTERY_BQ27XXX_RESIST_TABLE_UPDATES_NVM [BQ27XXX_DM_TAPER_RATE] = "Taper-rate", + [BQ27XXX_DM_QMAX] = "QMAX-Cell", + [BQ27XXX_RAM_R_A0_0] = "R_A0_0", + [BQ27XXX_RAM_R_A0_1] = "R_A0_1", + [BQ27XXX_RAM_R_A0_2] = "R_A0_2", + [BQ27XXX_RAM_R_A0_3] = "R_A0_3", + [BQ27XXX_RAM_R_A0_4] = "R_A0_4", + [BQ27XXX_RAM_R_A0_5] = "R_A0_5", + [BQ27XXX_RAM_R_A0_6] = "R_A0_6", + [BQ27XXX_RAM_R_A0_7] = "R_A0_7", + [BQ27XXX_RAM_R_A0_8] = "R_A0_8", + [BQ27XXX_RAM_R_A0_9] = "R_A0_9", + [BQ27XXX_RAM_R_A0_10] = "R_A0_10", + [BQ27XXX_RAM_R_A0_11] = "R_A0_11", + [BQ27XXX_RAM_R_A0_12] = "R_A0_12", + [BQ27XXX_RAM_R_A0_13] = "R_A0_13", + [BQ27XXX_RAM_R_A0_14] = "R_A0_14", +#endif + }; @@ -1435,7 +1490,10 @@ static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di, 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); bool updated; - u32 taper_rate, i; +#ifdef CONFIG_BATTERY_BQ27XXX_RESIST_TABLE_UPDATES_NVM + struct bq27xxx_dm_buf rt = BQ27XXX_DM_BUF(di, BQ27XXX_RAM_R_A0_0); + u32 i, taper_rate; +#endif if (bq27xxx_battery_unseal(di) < 0) return; @@ -1443,8 +1501,7 @@ static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di, if (info->charge_full_design_uah != -EINVAL && info->energy_full_design_uwh != -EINVAL) { bq27xxx_battery_read_dm_block(di, &bd); - taper_rate = (u32)((info->charge_full_design_uah * 10) / - info->charge_term_current_ua); + /* assume design energy, taper_rate & capacity are in same block */ bq27xxx_battery_update_dm_block(di, &bd, BQ27XXX_DM_DESIGN_CAPACITY, @@ -1452,9 +1509,22 @@ static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di, bq27xxx_battery_update_dm_block(di, &bd, BQ27XXX_DM_DESIGN_ENERGY, info->energy_full_design_uwh / 1000); - /* update Taper rate based on the capacity and term current*/ + +#ifdef CONFIG_BATTERY_BQ27XXX_RESIST_TABLE_UPDATES_NVM + bq27xxx_battery_read_dm_block(di, &rt); + /* update Taper rate based on the capacity and term current */ + taper_rate = (u32)((info->charge_full_design_uah * 10) / + info->charge_term_current_ua); bq27xxx_battery_update_dm_block(di, &bd, BQ27XXX_DM_TAPER_RATE, taper_rate); + /* update the QMAX-CELL0 and resistance table */ + bq27xxx_battery_update_dm_block(di, &bd, BQ27XXX_DM_QMAX, + di->qmax_cell0); + for (i = 0 ; i < 15; i++) + bq27xxx_battery_update_dm_block(di, &rt, + (i + BQ27XXX_RAM_R_A0_0), + di->resist_table[i]); +#endif } if (info->voltage_min_design_uv != -EINVAL) { @@ -1471,10 +1541,19 @@ static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di, bq27xxx_battery_write_dm_block(di, &bd); bq27xxx_battery_write_dm_block(di, &bt); +#ifdef CONFIG_BATTERY_BQ27XXX_RESIST_TABLE_UPDATES_NVM + bq27xxx_battery_write_dm_block(di, &rt); + bq27xxx_battery_read_dm_block(di, &bd); for (i = 0; i < BQ27XXX_DM_SZ; i++) dev_dbg(di->dev, "BQ27xxx: DM_NVM[%d]: 0x%04x\n", i, bd.data[i]); + bq27xxx_battery_read_dm_block(di, &rt); + for (i = 0; i < BQ27XXX_DM_SZ; i++) + dev_dbg(di->dev, "BQ27xxx: Resisiatnce table DM_NVM[%d]:0x%04x\n", + i, rt.data[i]); +#endif + bq27xxx_battery_seal(di); if (updated && !(di->opts & BQ27XXX_O_CFGUP)) { diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index 0713a52a2510..767a188f9736 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -136,6 +136,37 @@ static int bq27xxx_battery_i2c_bulk_write(struct bq27xxx_device_info *di, return 0; } +#ifdef CONFIG_BATTERY_BQ27XXX_RESIST_TABLE_UPDATES_NVM +static int bq27xx_parse_dt(struct bq27xxx_device_info *di, + struct device *dev, + struct device_node *battery_np) +{ + int ret; + int rc; + + ret = of_property_read_u32(battery_np, "qmax-cell0", &di->qmax_cell0); + if (ret) { + dev_err(dev, "Undefined Qmax-Cell0\n"); + return ret; + } + + rc = of_property_count_elems_of_size(battery_np, "resist-table", + sizeof(u32)); + + if (rc != BQ27XXX_RESISTANCE_TABLE_LENGTH) { + dev_err(dev, "Invalid number of elements in resist-table\n"); + return -EINVAL; + } + + ret = of_property_read_u32_array(battery_np, "resist-table", + di->resist_table, BQ27XXX_RESISTANCE_TABLE_LENGTH); + if (ret) + dev_err(dev, "Undefined resistance table\n"); + + return ret; +} +#endif + static int bq27xxx_battery_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -143,6 +174,9 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client, int ret; char *name; int num; +#ifdef CONFIG_BATTERY_BQ27XXX_RESIST_TABLE_UPDATES_NVM + struct device_node *battery_np_rt; +#endif /* Get new ID for the new battery device */ mutex_lock(&battery_mutex); @@ -169,6 +203,17 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client, di->bus.read_bulk = bq27xxx_battery_i2c_bulk_read; di->bus.write_bulk = bq27xxx_battery_i2c_bulk_write; +#ifdef CONFIG_BATTERY_BQ27XXX_RESIST_TABLE_UPDATES_NVM + battery_np_rt = of_parse_phandle(client->dev.of_node, + "bat-resist-table", 0); + if (!battery_np_rt) + return -ENODEV; + ret = bq27xx_parse_dt(di, di->dev, battery_np_rt); + of_node_put(battery_np_rt); + if (ret) + return -EINVAL; +#endif + ret = bq27xxx_battery_setup(di); if (ret) goto err_failed; diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h index 7c8d65414a70..6820c15aac99 100644 --- a/include/linux/power/bq27xxx_battery.h +++ b/include/linux/power/bq27xxx_battery.h @@ -4,6 +4,8 @@ #include +#define BQ27XXX_RESISTANCE_TABLE_LENGTH 15 + enum bq27xxx_chip { BQ27000 = 1, /* bq27000, bq27200 */ BQ27010, /* bq27010, bq27210 */ @@ -78,6 +80,10 @@ struct bq27xxx_device_info { struct list_head list; struct mutex lock; u8 *regs; +#ifdef CONFIG_BATTERY_BQ27XXX_RESIST_TABLE_UPDATES_NVM + u32 qmax_cell0; + u32 resist_table[BQ27XXX_RESISTANCE_TABLE_LENGTH]; +#endif }; void bq27xxx_battery_update(struct bq27xxx_device_info *di);