From 77d641baa3c8e18a1056bec6c64c6103c1a17b1e Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Mon, 8 Nov 2021 17:27:05 +0100 Subject: power: supply: core: add POWER_SUPPLY_HEALTH_NO_BATTERY Some chargers can keep the system powered from the mains even when no battery is present. It this case none of the currently defined health statuses applies. Add a new status to report that no battery is present. Suggested-by: Sebastian Reichel Signed-off-by: Luca Ceresoli Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_sysfs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index c3d7cbcd4fad..6ac88fbee3cb 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -106,6 +106,7 @@ static const char * const POWER_SUPPLY_HEALTH_TEXT[] = { [POWER_SUPPLY_HEALTH_WARM] = "Warm", [POWER_SUPPLY_HEALTH_COOL] = "Cool", [POWER_SUPPLY_HEALTH_HOT] = "Hot", + [POWER_SUPPLY_HEALTH_NO_BATTERY] = "No battery", }; static const char * const POWER_SUPPLY_TECHNOLOGY_TEXT[] = { -- cgit v1.2.3-59-g8ed1b From 715ecbc10d6a77cce1c3bec8ba10e59be5233b4f Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Mon, 8 Nov 2021 17:27:06 +0100 Subject: power: supply: max77976: add Maxim MAX77976 charger driver Add support for the MAX77976 3.5/5.5A 1-Cell Li+ Battery Charger. This is a simple implementation enough to be used as a simple battery charger without OTG and boost. Signed-off-by: Luca Ceresoli Signed-off-by: Sebastian Reichel --- MAINTAINERS | 1 + drivers/power/supply/Kconfig | 12 + drivers/power/supply/Makefile | 1 + drivers/power/supply/max77976_charger.c | 509 ++++++++++++++++++++++++++++++++ 4 files changed, 523 insertions(+) create mode 100644 drivers/power/supply/max77976_charger.c (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index b2347950360e..96f748c09b62 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11584,6 +11584,7 @@ MAXIM MAX77976 BATTERY CHARGER M: Luca Ceresoli S: Supported F: Documentation/devicetree/bindings/power/supply/maxim,max77976.yaml +F: drivers/power/supply/max77976_charger.c MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS M: Krzysztof Kozlowski diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 5cf5bb56d2e3..b366e2fd8e97 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -557,6 +557,18 @@ config CHARGER_MAX77693 help Say Y to enable support for the Maxim MAX77693 battery charger. +config CHARGER_MAX77976 + tristate "Maxim MAX77976 battery charger driver" + depends on I2C + select REGMAP_I2C + help + The Maxim MAX77976 is a 19 Vin, 5.5A 1-Cell Li+ Battery Charger + USB OTG support. It has an I2C interface for configuration. + + Say Y to enable support for the Maxim MAX77976 battery charger. + This driver can also be built as a module. If so, the module will be + called max77976_charger. + config CHARGER_MAX8997 tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver" depends on MFD_MAX8997 && REGULATOR_MAX8997 diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 4e55a11aab79..2c1b264b2046 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o obj-$(CONFIG_CHARGER_DETECTOR_MAX14656) += max14656_charger_detector.o obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o +obj-$(CONFIG_CHARGER_MAX77976) += max77976_charger.o obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o obj-$(CONFIG_CHARGER_MP2629) += mp2629_charger.o diff --git a/drivers/power/supply/max77976_charger.c b/drivers/power/supply/max77976_charger.c new file mode 100644 index 000000000000..8b6c8cfa7503 --- /dev/null +++ b/drivers/power/supply/max77976_charger.c @@ -0,0 +1,509 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * max77976_charger.c - Driver for the Maxim MAX77976 battery charger + * + * Copyright (C) 2021 Luca Ceresoli + * Author: Luca Ceresoli + */ + +#include +#include +#include +#include + +#define MAX77976_DRIVER_NAME "max77976-charger" +#define MAX77976_CHIP_ID 0x76 + +static const char *max77976_manufacturer = "Maxim Integrated"; +static const char *max77976_model = "MAX77976"; + +/* -------------------------------------------------------------------------- + * Register map + */ + +#define MAX77976_REG_CHIP_ID 0x00 +#define MAX77976_REG_CHIP_REVISION 0x01 +#define MAX77976_REG_CHG_INT_OK 0x12 +#define MAX77976_REG_CHG_DETAILS_01 0x14 +#define MAX77976_REG_CHG_CNFG_00 0x16 +#define MAX77976_REG_CHG_CNFG_02 0x18 +#define MAX77976_REG_CHG_CNFG_06 0x1c +#define MAX77976_REG_CHG_CNFG_09 0x1f + +/* CHG_DETAILS_01.CHG_DTLS values */ +enum max77976_charging_state { + MAX77976_CHARGING_PREQUALIFICATION = 0x0, + MAX77976_CHARGING_FAST_CONST_CURRENT, + MAX77976_CHARGING_FAST_CONST_VOLTAGE, + MAX77976_CHARGING_TOP_OFF, + MAX77976_CHARGING_DONE, + MAX77976_CHARGING_RESERVED_05, + MAX77976_CHARGING_TIMER_FAULT, + MAX77976_CHARGING_SUSPENDED_QBATT_OFF, + MAX77976_CHARGING_OFF, + MAX77976_CHARGING_RESERVED_09, + MAX77976_CHARGING_THERMAL_SHUTDOWN, + MAX77976_CHARGING_WATCHDOG_EXPIRED, + MAX77976_CHARGING_SUSPENDED_JEITA, + MAX77976_CHARGING_SUSPENDED_THM_REMOVAL, + MAX77976_CHARGING_SUSPENDED_PIN, + MAX77976_CHARGING_RESERVED_0F, +}; + +/* CHG_DETAILS_01.BAT_DTLS values */ +enum max77976_battery_state { + MAX77976_BATTERY_BATTERY_REMOVAL = 0x0, + MAX77976_BATTERY_PREQUALIFICATION, + MAX77976_BATTERY_TIMER_FAULT, + MAX77976_BATTERY_REGULAR_VOLTAGE, + MAX77976_BATTERY_LOW_VOLTAGE, + MAX77976_BATTERY_OVERVOLTAGE, + MAX77976_BATTERY_RESERVED, + MAX77976_BATTERY_BATTERY_ONLY, // No valid adapter is present +}; + +/* CHG_CNFG_00.MODE values */ +enum max77976_mode { + MAX77976_MODE_CHARGER_BUCK = 0x5, + MAX77976_MODE_BOOST = 0x9, +}; + +/* CHG_CNFG_02.CHG_CC: charge current limit, 100..5500 mA, 50 mA steps */ +#define MAX77976_CHG_CC_STEP 50000U +#define MAX77976_CHG_CC_MIN 100000U +#define MAX77976_CHG_CC_MAX 5500000U + +/* CHG_CNFG_09.CHGIN_ILIM: input current limit, 100..3200 mA, 100 mA steps */ +#define MAX77976_CHGIN_ILIM_STEP 100000U +#define MAX77976_CHGIN_ILIM_MIN 100000U +#define MAX77976_CHGIN_ILIM_MAX 3200000U + +enum max77976_field_idx { + VERSION, REVISION, /* CHIP_REVISION */ + CHGIN_OK, /* CHG_INT_OK */ + BAT_DTLS, CHG_DTLS, /* CHG_DETAILS_01 */ + MODE, /* CHG_CNFG_00 */ + CHG_CC, /* CHG_CNFG_02 */ + CHGPROT, /* CHG_CNFG_06 */ + CHGIN_ILIM, /* CHG_CNFG_09 */ + MAX77976_N_REGMAP_FIELDS +}; + +static const struct reg_field max77976_reg_field[MAX77976_N_REGMAP_FIELDS] = { + [VERSION] = REG_FIELD(MAX77976_REG_CHIP_REVISION, 4, 7), + [REVISION] = REG_FIELD(MAX77976_REG_CHIP_REVISION, 0, 3), + [CHGIN_OK] = REG_FIELD(MAX77976_REG_CHG_INT_OK, 6, 6), + [CHG_DTLS] = REG_FIELD(MAX77976_REG_CHG_DETAILS_01, 0, 3), + [BAT_DTLS] = REG_FIELD(MAX77976_REG_CHG_DETAILS_01, 4, 6), + [MODE] = REG_FIELD(MAX77976_REG_CHG_CNFG_00, 0, 3), + [CHG_CC] = REG_FIELD(MAX77976_REG_CHG_CNFG_02, 0, 6), + [CHGPROT] = REG_FIELD(MAX77976_REG_CHG_CNFG_06, 2, 3), + [CHGIN_ILIM] = REG_FIELD(MAX77976_REG_CHG_CNFG_09, 0, 5), +}; + +static const struct regmap_config max77976_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x24, +}; + +/* -------------------------------------------------------------------------- + * Data structures + */ + +struct max77976 { + struct i2c_client *client; + struct regmap *regmap; + struct regmap_field *rfield[MAX77976_N_REGMAP_FIELDS]; +}; + +/* -------------------------------------------------------------------------- + * power_supply properties + */ + +static int max77976_get_status(struct max77976 *chg, int *val) +{ + unsigned int regval; + int err; + + err = regmap_field_read(chg->rfield[CHG_DTLS], ®val); + if (err < 0) + return err; + + switch (regval) { + case MAX77976_CHARGING_PREQUALIFICATION: + case MAX77976_CHARGING_FAST_CONST_CURRENT: + case MAX77976_CHARGING_FAST_CONST_VOLTAGE: + case MAX77976_CHARGING_TOP_OFF: + *val = POWER_SUPPLY_STATUS_CHARGING; + break; + case MAX77976_CHARGING_DONE: + *val = POWER_SUPPLY_STATUS_FULL; + break; + case MAX77976_CHARGING_TIMER_FAULT: + case MAX77976_CHARGING_SUSPENDED_QBATT_OFF: + case MAX77976_CHARGING_SUSPENDED_JEITA: + case MAX77976_CHARGING_SUSPENDED_THM_REMOVAL: + case MAX77976_CHARGING_SUSPENDED_PIN: + *val = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + case MAX77976_CHARGING_OFF: + case MAX77976_CHARGING_THERMAL_SHUTDOWN: + case MAX77976_CHARGING_WATCHDOG_EXPIRED: + *val = POWER_SUPPLY_STATUS_DISCHARGING; + break; + default: + *val = POWER_SUPPLY_STATUS_UNKNOWN; + } + + return 0; +} + +static int max77976_get_charge_type(struct max77976 *chg, int *val) +{ + unsigned int regval; + int err; + + err = regmap_field_read(chg->rfield[CHG_DTLS], ®val); + if (err < 0) + return err; + + switch (regval) { + case MAX77976_CHARGING_PREQUALIFICATION: + *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + break; + case MAX77976_CHARGING_FAST_CONST_CURRENT: + case MAX77976_CHARGING_FAST_CONST_VOLTAGE: + *val = POWER_SUPPLY_CHARGE_TYPE_FAST; + break; + case MAX77976_CHARGING_TOP_OFF: + *val = POWER_SUPPLY_CHARGE_TYPE_STANDARD; + break; + case MAX77976_CHARGING_DONE: + case MAX77976_CHARGING_TIMER_FAULT: + case MAX77976_CHARGING_SUSPENDED_QBATT_OFF: + case MAX77976_CHARGING_OFF: + case MAX77976_CHARGING_THERMAL_SHUTDOWN: + case MAX77976_CHARGING_WATCHDOG_EXPIRED: + case MAX77976_CHARGING_SUSPENDED_JEITA: + case MAX77976_CHARGING_SUSPENDED_THM_REMOVAL: + case MAX77976_CHARGING_SUSPENDED_PIN: + *val = POWER_SUPPLY_CHARGE_TYPE_NONE; + break; + default: + *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; + } + + return 0; +} + +static int max77976_get_health(struct max77976 *chg, int *val) +{ + unsigned int regval; + int err; + + err = regmap_field_read(chg->rfield[BAT_DTLS], ®val); + if (err < 0) + return err; + + switch (regval) { + case MAX77976_BATTERY_BATTERY_REMOVAL: + *val = POWER_SUPPLY_HEALTH_NO_BATTERY; + break; + case MAX77976_BATTERY_LOW_VOLTAGE: + case MAX77976_BATTERY_REGULAR_VOLTAGE: + *val = POWER_SUPPLY_HEALTH_GOOD; + break; + case MAX77976_BATTERY_TIMER_FAULT: + *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; + break; + case MAX77976_BATTERY_OVERVOLTAGE: + *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + break; + case MAX77976_BATTERY_PREQUALIFICATION: + case MAX77976_BATTERY_BATTERY_ONLY: + *val = POWER_SUPPLY_HEALTH_UNKNOWN; + break; + default: + *val = POWER_SUPPLY_HEALTH_UNKNOWN; + } + + return 0; +} + +static int max77976_get_online(struct max77976 *chg, int *val) +{ + unsigned int regval; + int err; + + err = regmap_field_read(chg->rfield[CHGIN_OK], ®val); + if (err < 0) + return err; + + *val = (regval ? 1 : 0); + + return 0; +} + +static int max77976_get_integer(struct max77976 *chg, enum max77976_field_idx fidx, + unsigned int clamp_min, unsigned int clamp_max, + unsigned int mult, int *val) +{ + unsigned int regval; + int err; + + err = regmap_field_read(chg->rfield[fidx], ®val); + if (err < 0) + return err; + + *val = clamp_val(regval * mult, clamp_min, clamp_max); + + return 0; +} + +static int max77976_set_integer(struct max77976 *chg, enum max77976_field_idx fidx, + unsigned int clamp_min, unsigned int clamp_max, + unsigned int div, int val) +{ + unsigned int regval; + + regval = clamp_val(val, clamp_min, clamp_max) / div; + + return regmap_field_write(chg->rfield[fidx], regval); +} + +static int max77976_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct max77976 *chg = power_supply_get_drvdata(psy); + int err = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + err = max77976_get_status(chg, &val->intval); + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + err = max77976_get_charge_type(chg, &val->intval); + break; + case POWER_SUPPLY_PROP_HEALTH: + err = max77976_get_health(chg, &val->intval); + break; + case POWER_SUPPLY_PROP_ONLINE: + err = max77976_get_online(chg, &val->intval); + break; + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX: + val->intval = MAX77976_CHG_CC_MAX; + break; + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: + err = max77976_get_integer(chg, CHG_CC, + MAX77976_CHG_CC_MIN, + MAX77976_CHG_CC_MAX, + MAX77976_CHG_CC_STEP, + &val->intval); + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + err = max77976_get_integer(chg, CHGIN_ILIM, + MAX77976_CHGIN_ILIM_MIN, + MAX77976_CHGIN_ILIM_MAX, + MAX77976_CHGIN_ILIM_STEP, + &val->intval); + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = max77976_model; + break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = max77976_manufacturer; + break; + default: + err = -EINVAL; + } + + return err; +} + +static int max77976_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct max77976 *chg = power_supply_get_drvdata(psy); + int err = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: + err = max77976_set_integer(chg, CHG_CC, + MAX77976_CHG_CC_MIN, + MAX77976_CHG_CC_MAX, + MAX77976_CHG_CC_STEP, + val->intval); + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + err = max77976_set_integer(chg, CHGIN_ILIM, + MAX77976_CHGIN_ILIM_MIN, + MAX77976_CHGIN_ILIM_MAX, + MAX77976_CHGIN_ILIM_STEP, + val->intval); + break; + default: + err = -EINVAL; + } + + return err; +}; + +static int max77976_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + return true; + default: + return false; + } +} + +static enum power_supply_property max77976_psy_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, + POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +static const struct power_supply_desc max77976_psy_desc = { + .name = MAX77976_DRIVER_NAME, + .type = POWER_SUPPLY_TYPE_USB, + .properties = max77976_psy_props, + .num_properties = ARRAY_SIZE(max77976_psy_props), + .get_property = max77976_get_property, + .set_property = max77976_set_property, + .property_is_writeable = max77976_property_is_writeable, +}; + +/* -------------------------------------------------------------------------- + * Entry point + */ + +static int max77976_detect(struct max77976 *chg) +{ + struct device *dev = &chg->client->dev; + unsigned int id, ver, rev; + int err; + + err = regmap_read(chg->regmap, MAX77976_REG_CHIP_ID, &id); + if (err) + return dev_err_probe(dev, err, "cannot read chip ID\n"); + + if (id != MAX77976_CHIP_ID) + return dev_err_probe(dev, -ENXIO, "unknown model ID 0x%02x\n", id); + + err = regmap_field_read(chg->rfield[VERSION], &ver); + if (!err) + err = regmap_field_read(chg->rfield[REVISION], &rev); + if (err) + return dev_err_probe(dev, -ENXIO, "cannot read version/revision\n"); + + dev_info(dev, "detected model MAX779%02x ver %u rev %u", id, ver, rev); + + return 0; +} + +static int max77976_configure(struct max77976 *chg) +{ + struct device *dev = &chg->client->dev; + int err; + + /* Magic value to unlock writing to some registers */ + err = regmap_field_write(chg->rfield[CHGPROT], 0x3); + if (err) + goto err; + + /* + * Mode 5 = Charger ON, OTG OFF, buck ON, boost OFF. + * Other modes are not implemented by this driver. + */ + err = regmap_field_write(chg->rfield[MODE], MAX77976_MODE_CHARGER_BUCK); + if (err) + goto err; + + return 0; + +err: + return dev_err_probe(dev, err, "error while configuring"); +} + +static int max77976_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct power_supply_config psy_cfg = {}; + struct power_supply *psy; + struct max77976 *chg; + int err; + int i; + + chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL); + if (!chg) + return -ENOMEM; + + i2c_set_clientdata(client, chg); + psy_cfg.drv_data = chg; + chg->client = client; + + chg->regmap = devm_regmap_init_i2c(client, &max77976_regmap_config); + if (IS_ERR(chg->regmap)) + return dev_err_probe(dev, PTR_ERR(chg->regmap), + "cannot allocate regmap\n"); + + for (i = 0; i < MAX77976_N_REGMAP_FIELDS; i++) { + chg->rfield[i] = devm_regmap_field_alloc(dev, chg->regmap, + max77976_reg_field[i]); + if (IS_ERR(chg->rfield[i])) + return dev_err_probe(dev, PTR_ERR(chg->rfield[i]), + "cannot allocate regmap field\n"); + } + + err = max77976_detect(chg); + if (err) + return err; + + err = max77976_configure(chg); + if (err) + return err; + + psy = devm_power_supply_register_no_ws(dev, &max77976_psy_desc, &psy_cfg); + if (IS_ERR(psy)) + return dev_err_probe(dev, PTR_ERR(psy), "cannot register\n"); + + return 0; +} + +static const struct i2c_device_id max77976_i2c_id[] = { + { MAX77976_DRIVER_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, max77976_i2c_id); + +static const struct of_device_id max77976_of_id[] = { + { .compatible = "maxim,max77976" }, + { }, +}; +MODULE_DEVICE_TABLE(of, max77976_of_id); + +static struct i2c_driver max77976_driver = { + .driver = { + .name = MAX77976_DRIVER_NAME, + .of_match_table = max77976_of_id, + }, + .probe_new = max77976_probe, + .id_table = max77976_i2c_id, +}; +module_i2c_driver(max77976_driver); + +MODULE_AUTHOR("Luca Ceresoli "); +MODULE_DESCRIPTION("Maxim MAX77976 charger driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From a4585ba2050f460f749bbaf2b67bd56c41e30283 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Nov 2021 00:02:33 +0100 Subject: power: supply: core: Use library interpolation The power supply core appears to contain two open coded linear interpolations. Use the kernel fixpoint arithmetic interpolation library function instead. Cc: Chunyan Zhang Signed-off-by: Linus Walleij Reviewed-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_core.c | 61 ++++++++++++++++---------------- 1 file changed, 31 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index fc12a4f407f4..2907b84ceea9 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "power_supply.h" /* exported for the APM Power driver, APM emulation */ @@ -783,26 +784,25 @@ EXPORT_SYMBOL_GPL(power_supply_put_battery_info); int power_supply_temp2resist_simple(struct power_supply_resistance_temp_table *table, int table_len, int temp) { - int i, resist; + int i, high, low; - for (i = 0; i < table_len; i++) + /* Break loop at table_len - 1 because that is the highest index */ + for (i = 0; i < table_len - 1; i++) if (temp > table[i].temp) break; - if (i > 0 && i < table_len) { - int tmp; - - tmp = (table[i - 1].resistance - table[i].resistance) * - (temp - table[i].temp); - tmp /= table[i - 1].temp - table[i].temp; - resist = tmp + table[i].resistance; - } else if (i == 0) { - resist = table[0].resistance; - } else { - resist = table[table_len - 1].resistance; - } - - return resist; + /* The library function will deal with high == low */ + if ((i == 0) || (i == (table_len - 1))) + high = i; + else + high = i - 1; + low = i; + + return fixp_linear_interpolate(table[low].temp, + table[low].resistance, + table[high].temp, + table[high].resistance, + temp); } EXPORT_SYMBOL_GPL(power_supply_temp2resist_simple); @@ -821,24 +821,25 @@ EXPORT_SYMBOL_GPL(power_supply_temp2resist_simple); int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table, int table_len, int ocv) { - int i, cap, tmp; + int i, high, low; - for (i = 0; i < table_len; i++) + /* Break loop at table_len - 1 because that is the highest index */ + for (i = 0; i < table_len - 1; i++) if (ocv > table[i].ocv) break; - if (i > 0 && i < table_len) { - tmp = (table[i - 1].capacity - table[i].capacity) * - (ocv - table[i].ocv); - tmp /= table[i - 1].ocv - table[i].ocv; - cap = tmp + table[i].capacity; - } else if (i == 0) { - cap = table[0].capacity; - } else { - cap = table[table_len - 1].capacity; - } - - return cap; + /* The library function will deal with high == low */ + if ((i == 0) || (i == (table_len - 1))) + high = i - 1; + else + high = i; /* i.e. i == 0 */ + low = i; + + return fixp_linear_interpolate(table[low].ocv, + table[low].capacity, + table[high].ocv, + table[high].capacity, + ocv); } EXPORT_SYMBOL_GPL(power_supply_ocv2cap_simple); -- cgit v1.2.3-59-g8ed1b From 59f1b854706d4d6830a3ed0f6b535a2ba5d425a6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:11 +0100 Subject: power: supply: ab8500: Use core battery parser This deploys the core battery DT parser to read the basic properties of the battery. We only use very little of it as we start out, but we will improve as we go along. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 3 +-- drivers/power/supply/ab8500_bmdata.c | 31 ++++++++++++------------------- drivers/power/supply/ab8500_charger.c | 16 +++++++++++----- 3 files changed, 24 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index d11405b7ee1a..33c7e15f5d96 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -570,8 +570,7 @@ int ab8500_fg_inst_curr_start(struct ab8500_fg *di); int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res); int ab8500_fg_inst_curr_started(struct ab8500_fg *di); int ab8500_fg_inst_curr_done(struct ab8500_fg *di); -int ab8500_bm_of_probe(struct device *dev, - struct device_node *np, +int ab8500_bm_of_probe(struct power_supply *psy, struct ab8500_bm_data *bm); extern struct platform_driver ab8500_fg_driver; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index bfc1245d7912..a515dfad4c3f 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -488,29 +488,22 @@ struct ab8500_bm_data ab8500_bm_data = { .n_chg_in_curr = ARRAY_SIZE(ab8500_charge_input_curr_map), }; -int ab8500_bm_of_probe(struct device *dev, - struct device_node *np, +int ab8500_bm_of_probe(struct power_supply *psy, struct ab8500_bm_data *bm) { const struct batres_vs_temp *tmp_batres_tbl; - struct device_node *battery_node; - const char *btech; + struct power_supply_battery_info info; + struct device *dev = &psy->dev; + int ret; int i; - battery_node = of_parse_phandle(np, "monitored-battery", 0); - if (!battery_node) { - dev_err(dev, "battery node or reference missing\n"); - return -EINVAL; + ret = power_supply_get_battery_info(psy, &info); + if (ret) { + dev_err(dev, "cannot retrieve battery info\n"); + return ret; } - btech = of_get_property(battery_node, "stericsson,battery-type", NULL); - if (!btech) { - dev_warn(dev, "missing property battery-name/type\n"); - of_node_put(battery_node); - return -EINVAL; - } - - if (strncmp(btech, "LION", 4) == 0) { + if (info.technology == POWER_SUPPLY_TECHNOLOGY_LION) { bm->no_maintenance = true; bm->chg_unknown_bat = true; bm->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600; @@ -520,8 +513,8 @@ int ab8500_bm_of_probe(struct device *dev, bm->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200; } - if (of_property_read_bool(battery_node, "thermistor-on-batctrl")) { - if (strncmp(btech, "LION", 4) == 0) + if (of_property_read_bool(psy->of_node, "thermistor-on-batctrl")) { + if (info.technology == POWER_SUPPLY_TECHNOLOGY_LION) tmp_batres_tbl = temp_to_batres_tbl_9100; else tmp_batres_tbl = temp_to_batres_tbl_thermistor; @@ -536,7 +529,7 @@ int ab8500_bm_of_probe(struct device *dev, for (i = 0; i < bm->n_btypes; ++i) bm->bat_type[i].batres_tbl = tmp_batres_tbl; - of_node_put(battery_node); + power_supply_put_battery_info(psy, &info); return 0; } diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index 15eadaf46f14..59ca9c0b8012 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -3413,11 +3413,6 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->bm = &ab8500_bm_data; - ret = ab8500_bm_of_probe(dev, np, di->bm); - if (ret) { - dev_err(dev, "failed to get battery information\n"); - return ret; - } di->autopower_cfg = of_property_read_bool(np, "autopower_cfg"); /* get parent data */ @@ -3490,9 +3485,11 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->invalid_charger_detect_state = 0; /* AC and USB supply config */ + ac_psy_cfg.of_node = np; ac_psy_cfg.supplied_to = supply_interface; ac_psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); ac_psy_cfg.drv_data = &di->ac_chg; + usb_psy_cfg.of_node = np; usb_psy_cfg.supplied_to = supply_interface; usb_psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); usb_psy_cfg.drv_data = &di->usb_chg; @@ -3610,6 +3607,15 @@ static int ab8500_charger_probe(struct platform_device *pdev) return PTR_ERR(di->usb_chg.psy); } + /* + * Check what battery we have, since we always have the USB + * psy, use that as a handle. + */ + ret = ab8500_bm_of_probe(di->usb_chg.psy, di->bm); + if (ret) + return dev_err_probe(dev, ret, + "failed to get battery information\n"); + /* Identify the connected charger types during startup */ charger_status = ab8500_charger_detect_chargers(di, true); if (charger_status & AC_PW_CONN) { -- cgit v1.2.3-59-g8ed1b From 3aca6ecdab44b30e812001ab4de19b79001a3fbd Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:12 +0100 Subject: power: supply: ab8500: Sink current tables into charger code The two tables for input and output current translation from register values does not need to be passed around from the battery manager data. Just push it down into the charger code where it is used, like other tables in that code. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 8 -------- drivers/power/supply/ab8500_bmdata.c | 22 -------------------- drivers/power/supply/ab8500_charger.c | 38 +++++++++++++++++++++++------------ 3 files changed, 25 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index 33c7e15f5d96..bcb054810290 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -484,10 +484,6 @@ struct ab8500_bm_charger_parameters { * @interval_not_charging charge alg cycle period time when not charging (sec) * @temp_hysteresis temperature hysteresis * @gnd_lift_resistance Battery ground to phone ground resistance (mOhm) - * @n_chg_out_curr number of elements in array chg_output_curr - * @n_chg_in_curr number of elements in array chg_input_curr - * @chg_output_curr charger output current level map - * @chg_input_curr charger input current level map * @maxi maximization parameters * @cap_levels capacity in percent for the different capacity levels * @bat_type table of supported battery types @@ -519,10 +515,6 @@ struct ab8500_bm_data { int interval_not_charging; int temp_hysteresis; int gnd_lift_resistance; - int n_chg_out_curr; - int n_chg_in_curr; - int *chg_output_curr; - int *chg_input_curr; const struct ab8500_maxim_parameters *maxi; const struct ab8500_bm_capacity_levels *cap_levels; struct ab8500_battery_type *bat_type; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index a515dfad4c3f..6f6865c46926 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -436,24 +436,6 @@ static const struct ab8500_bm_charger_parameters chg = { .ac_curr_max = 1500, }; -/* - * This array maps the raw hex value to charger output current used by the - * AB8500 values - */ -static int ab8500_charge_output_curr_map[] = { - 100, 200, 300, 400, 500, 600, 700, 800, - 900, 1000, 1100, 1200, 1300, 1400, 1500, 1500, -}; - -/* - * This array maps the raw hex value to charger input current used by the - * AB8500 values - */ -static int ab8500_charge_input_curr_map[] = { - 50, 98, 193, 290, 380, 450, 500, 600, - 700, 800, 900, 1000, 1100, 1300, 1400, 1500, -}; - struct ab8500_bm_data ab8500_bm_data = { .temp_under = 3, .temp_low = 8, @@ -479,13 +461,9 @@ struct ab8500_bm_data ab8500_bm_data = { .interval_not_charging = 120, .temp_hysteresis = 3, .gnd_lift_resistance = 34, - .chg_output_curr = ab8500_charge_output_curr_map, - .n_chg_out_curr = ARRAY_SIZE(ab8500_charge_output_curr_map), .maxi = &ab8500_maxi_params, .chg_params = &chg, .fg_params = &fg, - .chg_input_curr = ab8500_charge_input_curr_map, - .n_chg_in_curr = ARRAY_SIZE(ab8500_charge_input_curr_map), }; int ab8500_bm_of_probe(struct power_supply *psy, diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index 59ca9c0b8012..32c2046ea6bb 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -1025,21 +1025,33 @@ static int ab8500_voltage_to_regval(int voltage) return -1; } +/* This array maps the raw register value to charger input current */ +static int ab8500_charge_input_curr_map[] = { + 50, 98, 193, 290, 380, 450, 500, 600, + 700, 800, 900, 1000, 1100, 1300, 1400, 1500, +}; + +/* This array maps the raw register value to charger output current */ +static int ab8500_charge_output_curr_map[] = { + 100, 200, 300, 400, 500, 600, 700, 800, + 900, 1000, 1100, 1200, 1300, 1400, 1500, 1500, +}; + static int ab8500_current_to_regval(struct ab8500_charger *di, int curr) { int i; - if (curr < di->bm->chg_output_curr[0]) + if (curr < ab8500_charge_output_curr_map[0]) return 0; - for (i = 0; i < di->bm->n_chg_out_curr; i++) { - if (curr < di->bm->chg_output_curr[i]) + for (i = 0; i < ARRAY_SIZE(ab8500_charge_output_curr_map); i++) { + if (curr < ab8500_charge_output_curr_map[i]) return i - 1; } /* If not last element, return error */ - i = di->bm->n_chg_out_curr - 1; - if (curr == di->bm->chg_output_curr[i]) + i = ARRAY_SIZE(ab8500_charge_output_curr_map) - 1; + if (curr == ab8500_charge_output_curr_map[i]) return i; else return -1; @@ -1049,17 +1061,17 @@ static int ab8500_vbus_in_curr_to_regval(struct ab8500_charger *di, int curr) { int i; - if (curr < di->bm->chg_input_curr[0]) + if (curr < ab8500_charge_input_curr_map[0]) return 0; - for (i = 0; i < di->bm->n_chg_in_curr; i++) { - if (curr < di->bm->chg_input_curr[i]) + for (i = 0; i < ARRAY_SIZE(ab8500_charge_input_curr_map); i++) { + if (curr < ab8500_charge_input_curr_map[i]) return i - 1; } /* If not last element, return error */ - i = di->bm->n_chg_in_curr - 1; - if (curr == di->bm->chg_input_curr[i]) + i = ARRAY_SIZE(ab8500_charge_input_curr_map) - 1; + if (curr == ab8500_charge_input_curr_map[i]) return i; else return -1; @@ -2673,7 +2685,7 @@ static void ab8500_charger_vbus_drop_end_work(struct work_struct *work) return; } - curr = di->bm->chg_input_curr[ + curr = ab8500_charge_input_curr_map[ reg_value >> AUTO_VBUS_IN_CURR_LIM_SHIFT]; if (di->max_usb_in_curr.calculated_max != curr) { @@ -3503,7 +3515,7 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->ac_chg.max_out_volt = ab8500_charger_voltage_map[ ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; di->ac_chg.max_out_curr = - di->bm->chg_output_curr[di->bm->n_chg_out_curr - 1]; + ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1]; di->ac_chg.wdt_refresh = CHG_WD_INTERVAL; /* * The AB8505 only supports USB charging. If we are not the @@ -3524,7 +3536,7 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->usb_chg.max_out_volt = ab8500_charger_voltage_map[ ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; di->usb_chg.max_out_curr = - di->bm->chg_output_curr[di->bm->n_chg_out_curr - 1]; + ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1]; di->usb_chg.wdt_refresh = CHG_WD_INTERVAL; di->usb_chg.external = false; di->usb_state.usb_current = -1; -- cgit v1.2.3-59-g8ed1b From 6252c706cdb003da0046ced1a088b9f31af1fd9b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:13 +0100 Subject: power: supply: ab8500: Standardize operating temperature Instead of storing the temperature limits in our custom struct struct ab8500_bm_data, make struct power_supply_battery_info a member of this and store the min and max temperatures inside that struct as the temp_min/temp_max and temp_alert_min/temp_alert_max respectively. The values can be assigned from the device tree, but if not present will be set to the same defaults as are currently in the code. This way we start to move over to using struct power_supply_battery_info and make it possible to move the data over to the device tree and we will move piece by piece toward using the standard info struct. Temperature hysteresis is currently not supported by the standard struct but we move the assignment here as well so that we have all parameterization in one spot. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 12 ++++------ drivers/power/supply/ab8500_bmdata.c | 43 +++++++++++++++++++++++++--------- drivers/power/supply/ab8500_chargalg.c | 20 +++++++++------- drivers/power/supply/ab8500_charger.c | 1 + 4 files changed, 48 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index bcb054810290..fe783610bc54 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -460,10 +460,7 @@ struct ab8500_bm_charger_parameters { /** * struct ab8500_bm_data - ab8500 battery management data - * @temp_under under this temp, charging is stopped - * @temp_low between this temp and temp_under charging is reduced - * @temp_high between this temp and temp_over charging is reduced - * @temp_over over this temp, charging is stopped + * @bi battery info from device tree * @temp_now present battery temperature * @temp_interval_chg temperature measurement interval in s when charging * @temp_interval_nochg temperature measurement interval in s when not charging @@ -491,10 +488,7 @@ struct ab8500_bm_charger_parameters { * @fg_params fuel gauge parameters */ struct ab8500_bm_data { - int temp_under; - int temp_low; - int temp_high; - int temp_over; + struct power_supply_battery_info bi; int temp_now; int temp_interval_chg; int temp_interval_nochg; @@ -564,6 +558,8 @@ int ab8500_fg_inst_curr_started(struct ab8500_fg *di); int ab8500_fg_inst_curr_done(struct ab8500_fg *di); int ab8500_bm_of_probe(struct power_supply *psy, struct ab8500_bm_data *bm); +void ab8500_bm_of_remove(struct power_supply *psy, + struct ab8500_bm_data *bm); extern struct platform_driver ab8500_fg_driver; extern struct platform_driver ab8500_btemp_driver; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 6f6865c46926..41561b6adfd3 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -5,6 +5,17 @@ #include "ab8500-bm.h" +/* Default: under this temperature, charging is stopped */ +#define AB8500_TEMP_UNDER 3 +/* Default: between this temp and AB8500_TEMP_UNDER charging is reduced */ +#define AB8500_TEMP_LOW 8 +/* Default: between this temp and AB8500_TEMP_OVER charging is reduced */ +#define AB8500_TEMP_HIGH 43 +/* Default: over this temp, charging is stopped */ +#define AB8500_TEMP_OVER 48 +/* Default: temperature hysteresis */ +#define AB8500_TEMP_HYSTERESIS 3 + /* * These are the defined batteries that uses a NTC and ID resistor placed * inside of the battery pack. @@ -437,10 +448,6 @@ static const struct ab8500_bm_charger_parameters chg = { }; struct ab8500_bm_data ab8500_bm_data = { - .temp_under = 3, - .temp_low = 8, - .temp_high = 43, - .temp_over = 48, .main_safety_tmr_h = 4, .temp_interval_chg = 20, .temp_interval_nochg = 120, @@ -459,7 +466,6 @@ struct ab8500_bm_data ab8500_bm_data = { .batt_id = 0, .interval_charging = 5, .interval_not_charging = 120, - .temp_hysteresis = 3, .gnd_lift_resistance = 34, .maxi = &ab8500_maxi_params, .chg_params = &chg, @@ -470,18 +476,29 @@ int ab8500_bm_of_probe(struct power_supply *psy, struct ab8500_bm_data *bm) { const struct batres_vs_temp *tmp_batres_tbl; - struct power_supply_battery_info info; + struct power_supply_battery_info *bi = &bm->bi; struct device *dev = &psy->dev; int ret; int i; - ret = power_supply_get_battery_info(psy, &info); + ret = power_supply_get_battery_info(psy, bi); if (ret) { dev_err(dev, "cannot retrieve battery info\n"); return ret; } - if (info.technology == POWER_SUPPLY_TECHNOLOGY_LION) { + if (bi->temp_min == INT_MIN) + bi->temp_min = AB8500_TEMP_UNDER; + if (bi->temp_max == INT_MAX) + bi->temp_max = AB8500_TEMP_OVER; + if (bi->temp_alert_min == INT_MIN) + bi->temp_alert_min = AB8500_TEMP_LOW; + if (bi->temp_alert_max == INT_MAX) + bi->temp_alert_max = AB8500_TEMP_HIGH; + bm->temp_hysteresis = AB8500_TEMP_HYSTERESIS; + + + if (bi->technology == POWER_SUPPLY_TECHNOLOGY_LION) { bm->no_maintenance = true; bm->chg_unknown_bat = true; bm->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600; @@ -492,7 +509,7 @@ int ab8500_bm_of_probe(struct power_supply *psy, } if (of_property_read_bool(psy->of_node, "thermistor-on-batctrl")) { - if (info.technology == POWER_SUPPLY_TECHNOLOGY_LION) + if (bi->technology == POWER_SUPPLY_TECHNOLOGY_LION) tmp_batres_tbl = temp_to_batres_tbl_9100; else tmp_batres_tbl = temp_to_batres_tbl_thermistor; @@ -507,7 +524,11 @@ int ab8500_bm_of_probe(struct power_supply *psy, for (i = 0; i < bm->n_btypes; ++i) bm->bat_type[i].batres_tbl = tmp_batres_tbl; - power_supply_put_battery_info(psy, &info); - return 0; } + +void ab8500_bm_of_remove(struct power_supply *psy, + struct ab8500_bm_data *bm) +{ + power_supply_put_battery_info(psy, &bm->bi); +} diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index ff4b26b1ceca..9196434393e8 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -722,27 +722,29 @@ static void ab8500_chargalg_start_charging(struct ab8500_chargalg *di, */ static void ab8500_chargalg_check_temp(struct ab8500_chargalg *di) { - if (di->batt_data.temp > (di->bm->temp_low + di->t_hyst_norm) && - di->batt_data.temp < (di->bm->temp_high - di->t_hyst_norm)) { + struct power_supply_battery_info *bi = &di->bm->bi; + + if (di->batt_data.temp > (bi->temp_alert_min + di->t_hyst_norm) && + di->batt_data.temp < (bi->temp_alert_max - di->t_hyst_norm)) { /* Temp OK! */ di->events.btemp_underover = false; di->events.btemp_lowhigh = false; di->t_hyst_norm = 0; di->t_hyst_lowhigh = 0; } else { - if (((di->batt_data.temp >= di->bm->temp_high) && + if (((di->batt_data.temp >= bi->temp_alert_max) && (di->batt_data.temp < - (di->bm->temp_over - di->t_hyst_lowhigh))) || + (bi->temp_max - di->t_hyst_lowhigh))) || ((di->batt_data.temp > - (di->bm->temp_under + di->t_hyst_lowhigh)) && - (di->batt_data.temp <= di->bm->temp_low))) { + (bi->temp_min + di->t_hyst_lowhigh)) && + (di->batt_data.temp <= bi->temp_alert_min))) { /* TEMP minor!!!!! */ di->events.btemp_underover = false; di->events.btemp_lowhigh = true; di->t_hyst_norm = di->bm->temp_hysteresis; di->t_hyst_lowhigh = 0; - } else if (di->batt_data.temp <= di->bm->temp_under || - di->batt_data.temp >= di->bm->temp_over) { + } else if (di->batt_data.temp <= bi->temp_min || + di->batt_data.temp >= bi->temp_max) { /* TEMP major!!!!! */ di->events.btemp_underover = true; di->events.btemp_lowhigh = false; @@ -1722,7 +1724,7 @@ static int ab8500_chargalg_get_property(struct power_supply *psy, if (di->events.batt_ovv) { val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; } else if (di->events.btemp_underover) { - if (di->batt_data.temp <= di->bm->temp_under) + if (di->batt_data.temp <= di->bm->bi.temp_min) val->intval = POWER_SUPPLY_HEALTH_COLD; else val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index 32c2046ea6bb..7a151cd97399 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -3709,6 +3709,7 @@ static int ab8500_charger_remove(struct platform_device *pdev) component_master_del(&pdev->dev, &ab8500_charger_comp_ops); usb_unregister_notifier(di->usb_phy, &di->nb); + ab8500_bm_of_remove(di->usb_chg.psy, di->bm); usb_put_phy(di->usb_phy); if (!di->ac_chg.enabled) blocking_notifier_chain_unregister( -- cgit v1.2.3-59-g8ed1b From d8d26ac12e182f2e7f2697b09fabe817b4238c2c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:14 +0100 Subject: power: supply: ab8500: Drop unused battery types The code tries to detect a lot of battery variants on the reference designs, but we are not using the reference designs in practice, we are using real products such as Samsung Phones. The reference design with no battery plugged in will be detected as a LIPO battery with a thermistor on the batctrl pin so we will assume this and later on we can support other types through the device tree if we want, just like the products do. Drop the tables for external thermistor, only keep the internal thermistor tables that we will use as default. We can delete the assignment of the temperature to resistance table since the default will be the only and correct option. Also get rid of some unused variables and unused exports. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_bmdata.c | 180 +---------------------------------- 1 file changed, 1 insertion(+), 179 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 41561b6adfd3..8235c984e724 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -39,10 +39,6 @@ const struct ab8500_res_to_temp ab8500_temp_tbl_a_thermistor[] = { {60, 13437}, {65, 12500}, }; -EXPORT_SYMBOL(ab8500_temp_tbl_a_thermistor); - -const int ab8500_temp_tbl_a_size = ARRAY_SIZE(ab8500_temp_tbl_a_thermistor); -EXPORT_SYMBOL(ab8500_temp_tbl_a_size); const struct ab8500_res_to_temp ab8500_temp_tbl_b_thermistor[] = { {-5, 200000}, @@ -61,10 +57,6 @@ const struct ab8500_res_to_temp ab8500_temp_tbl_b_thermistor[] = { {60, 85461}, {65, 82869}, }; -EXPORT_SYMBOL(ab8500_temp_tbl_b_thermistor); - -const int ab8500_temp_tbl_b_size = ARRAY_SIZE(ab8500_temp_tbl_b_thermistor); -EXPORT_SYMBOL(ab8500_temp_tbl_b_size); static const struct ab8500_v_to_cap cap_tbl_a_thermistor[] = { {4171, 100}, @@ -175,31 +167,6 @@ static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { {-20, 595}, }; -/* - * Note that the batres_vs_temp table must be strictly sorted by falling - * temperature values to work. - */ -static const struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = { - { 60, 300}, - { 30, 300}, - { 20, 300}, - { 10, 300}, - { 00, 300}, - {-10, 300}, - {-20, 300}, -}; - -/* battery resistance table for LI ION 9100 battery */ -static const struct batres_vs_temp temp_to_batres_tbl_9100[] = { - { 60, 180}, - { 30, 180}, - { 20, 180}, - { 10, 180}, - { 00, 180}, - {-10, 180}, - {-20, 180}, -}; - static struct ab8500_battery_type bat_type_thermistor[] = { [BATTERY_UNKNOWN] = { /* First element always represent the UNKNOWN battery */ @@ -286,123 +253,6 @@ static struct ab8500_battery_type bat_type_thermistor[] = { }, }; -static struct ab8500_battery_type bat_type_ext_thermistor[] = { - [BATTERY_UNKNOWN] = { - /* First element always represent the UNKNOWN battery */ - .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN, - .resis_high = 0, - .resis_low = 0, - .battery_resistance = 300, - .charge_full_design = 612, - .nominal_voltage = 3700, - .termination_vol = 4050, - .termination_curr = 200, - .recharge_cap = 95, - .normal_cur_lvl = 400, - .normal_vol_lvl = 4100, - .maint_a_cur_lvl = 400, - .maint_a_vol_lvl = 4050, - .maint_a_chg_timer_h = 60, - .maint_b_cur_lvl = 400, - .maint_b_vol_lvl = 4000, - .maint_b_chg_timer_h = 200, - .low_high_cur_lvl = 300, - .low_high_vol_lvl = 4000, - .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), - .r_to_t_tbl = temp_tbl, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), - .v_to_cap_tbl = cap_tbl, - .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), - .batres_tbl = temp_to_batres_tbl_thermistor, - }, -/* - * These are the batteries that doesn't have an internal NTC resistor to measure - * its temperature. The temperature in this case is measure with a NTC placed - * near the battery but on the PCB. - */ - { - .name = POWER_SUPPLY_TECHNOLOGY_LIPO, - .resis_high = 76000, - .resis_low = 53000, - .battery_resistance = 300, - .charge_full_design = 900, - .nominal_voltage = 3700, - .termination_vol = 4150, - .termination_curr = 100, - .recharge_cap = 95, - .normal_cur_lvl = 700, - .normal_vol_lvl = 4200, - .maint_a_cur_lvl = 600, - .maint_a_vol_lvl = 4150, - .maint_a_chg_timer_h = 60, - .maint_b_cur_lvl = 600, - .maint_b_vol_lvl = 4100, - .maint_b_chg_timer_h = 200, - .low_high_cur_lvl = 300, - .low_high_vol_lvl = 4000, - .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), - .r_to_t_tbl = temp_tbl, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), - .v_to_cap_tbl = cap_tbl, - .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), - .batres_tbl = temp_to_batres_tbl_thermistor, - }, - { - .name = POWER_SUPPLY_TECHNOLOGY_LION, - .resis_high = 30000, - .resis_low = 10000, - .battery_resistance = 300, - .charge_full_design = 950, - .nominal_voltage = 3700, - .termination_vol = 4150, - .termination_curr = 100, - .recharge_cap = 95, - .normal_cur_lvl = 700, - .normal_vol_lvl = 4200, - .maint_a_cur_lvl = 600, - .maint_a_vol_lvl = 4150, - .maint_a_chg_timer_h = 60, - .maint_b_cur_lvl = 600, - .maint_b_vol_lvl = 4100, - .maint_b_chg_timer_h = 200, - .low_high_cur_lvl = 300, - .low_high_vol_lvl = 4000, - .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), - .r_to_t_tbl = temp_tbl, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), - .v_to_cap_tbl = cap_tbl, - .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), - .batres_tbl = temp_to_batres_tbl_thermistor, - }, - { - .name = POWER_SUPPLY_TECHNOLOGY_LION, - .resis_high = 95000, - .resis_low = 76001, - .battery_resistance = 300, - .charge_full_design = 950, - .nominal_voltage = 3700, - .termination_vol = 4150, - .termination_curr = 100, - .recharge_cap = 95, - .normal_cur_lvl = 700, - .normal_vol_lvl = 4200, - .maint_a_cur_lvl = 600, - .maint_a_vol_lvl = 4150, - .maint_a_chg_timer_h = 60, - .maint_b_cur_lvl = 600, - .maint_b_vol_lvl = 4100, - .maint_b_chg_timer_h = 200, - .low_high_cur_lvl = 300, - .low_high_vol_lvl = 4000, - .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), - .r_to_t_tbl = temp_tbl, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), - .v_to_cap_tbl = cap_tbl, - .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), - .batres_tbl = temp_to_batres_tbl_thermistor, - }, -}; - static const struct ab8500_bm_capacity_levels cap_levels = { .critical = 2, .low = 10, @@ -447,6 +297,7 @@ static const struct ab8500_bm_charger_parameters chg = { .ac_curr_max = 1500, }; +/* This is referenced directly in the charger code */ struct ab8500_bm_data ab8500_bm_data = { .main_safety_tmr_h = 4, .temp_interval_chg = 20, @@ -475,11 +326,9 @@ struct ab8500_bm_data ab8500_bm_data = { int ab8500_bm_of_probe(struct power_supply *psy, struct ab8500_bm_data *bm) { - const struct batres_vs_temp *tmp_batres_tbl; struct power_supply_battery_info *bi = &bm->bi; struct device *dev = &psy->dev; int ret; - int i; ret = power_supply_get_battery_info(psy, bi); if (ret) { @@ -497,33 +346,6 @@ int ab8500_bm_of_probe(struct power_supply *psy, bi->temp_alert_max = AB8500_TEMP_HIGH; bm->temp_hysteresis = AB8500_TEMP_HYSTERESIS; - - if (bi->technology == POWER_SUPPLY_TECHNOLOGY_LION) { - bm->no_maintenance = true; - bm->chg_unknown_bat = true; - bm->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600; - bm->bat_type[BATTERY_UNKNOWN].termination_vol = 4150; - bm->bat_type[BATTERY_UNKNOWN].recharge_cap = 95; - bm->bat_type[BATTERY_UNKNOWN].normal_cur_lvl = 520; - bm->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200; - } - - if (of_property_read_bool(psy->of_node, "thermistor-on-batctrl")) { - if (bi->technology == POWER_SUPPLY_TECHNOLOGY_LION) - tmp_batres_tbl = temp_to_batres_tbl_9100; - else - tmp_batres_tbl = temp_to_batres_tbl_thermistor; - } else { - bm->n_btypes = 4; - bm->bat_type = bat_type_ext_thermistor; - bm->adc_therm = AB8500_ADC_THERM_BATTEMP; - tmp_batres_tbl = temp_to_batres_tbl_ext_thermistor; - } - - /* select the battery resolution table */ - for (i = 0; i < bm->n_btypes; ++i) - bm->bat_type[i].batres_tbl = tmp_batres_tbl; - return 0; } -- cgit v1.2.3-59-g8ed1b From e5dff305ab5c539320f1e30db44604e9977c3504 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:15 +0100 Subject: power: supply: ab8500: Use only one battery type The code was going through hoops and loops to detect what battery is connected and check the resistance for this battery etc. Skip this trouble: we will support one battery (currently "unknown") then we will find the connected battery in the device tree using a compatible string. The battery resistance may be used to double-check that the right battery is connected. Convert the array of battery types into one battery type so we can next move over the properties of this one type into the standard struct power_supply_battery_info. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 4 - drivers/power/supply/ab8500_bmdata.c | 203 +++++---------------------------- drivers/power/supply/ab8500_btemp.c | 61 +++++----- drivers/power/supply/ab8500_chargalg.c | 51 ++++----- drivers/power/supply/ab8500_fg.c | 17 +-- 5 files changed, 85 insertions(+), 251 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index fe783610bc54..99ada7f08ec7 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -475,8 +475,6 @@ struct ab8500_bm_charger_parameters { * @enable_overshoot flag to enable VBAT overshoot control * @auto_trig flag to enable auto adc trigger * @fg_res resistance of FG resistor in 0.1mOhm - * @n_btypes number of elements in array bat_type - * @batt_id index of the identified battery in array bat_type * @interval_charging charge alg cycle period time when charging (sec) * @interval_not_charging charge alg cycle period time when not charging (sec) * @temp_hysteresis temperature hysteresis @@ -503,8 +501,6 @@ struct ab8500_bm_data { bool auto_trig; enum ab8500_adc_therm adc_therm; int fg_res; - int n_btypes; - int batt_id; int interval_charging; int interval_not_charging; int temp_hysteresis; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 8235c984e724..5db13b026d81 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -16,94 +16,6 @@ /* Default: temperature hysteresis */ #define AB8500_TEMP_HYSTERESIS 3 -/* - * These are the defined batteries that uses a NTC and ID resistor placed - * inside of the battery pack. - * Note that the res_to_temp table must be strictly sorted by falling resistance - * values to work. - */ -const struct ab8500_res_to_temp ab8500_temp_tbl_a_thermistor[] = { - {-5, 53407}, - { 0, 48594}, - { 5, 43804}, - {10, 39188}, - {15, 34870}, - {20, 30933}, - {25, 27422}, - {30, 24347}, - {35, 21694}, - {40, 19431}, - {45, 17517}, - {50, 15908}, - {55, 14561}, - {60, 13437}, - {65, 12500}, -}; - -const struct ab8500_res_to_temp ab8500_temp_tbl_b_thermistor[] = { - {-5, 200000}, - { 0, 159024}, - { 5, 151921}, - {10, 144300}, - {15, 136424}, - {20, 128565}, - {25, 120978}, - {30, 113875}, - {35, 107397}, - {40, 101629}, - {45, 96592}, - {50, 92253}, - {55, 88569}, - {60, 85461}, - {65, 82869}, -}; - -static const struct ab8500_v_to_cap cap_tbl_a_thermistor[] = { - {4171, 100}, - {4114, 95}, - {4009, 83}, - {3947, 74}, - {3907, 67}, - {3863, 59}, - {3830, 56}, - {3813, 53}, - {3791, 46}, - {3771, 33}, - {3754, 25}, - {3735, 20}, - {3717, 17}, - {3681, 13}, - {3664, 8}, - {3651, 6}, - {3635, 5}, - {3560, 3}, - {3408, 1}, - {3247, 0}, -}; - -static const struct ab8500_v_to_cap cap_tbl_b_thermistor[] = { - {4161, 100}, - {4124, 98}, - {4044, 90}, - {4003, 85}, - {3966, 80}, - {3933, 75}, - {3888, 67}, - {3849, 60}, - {3813, 55}, - {3787, 47}, - {3772, 30}, - {3751, 25}, - {3718, 20}, - {3681, 16}, - {3660, 14}, - {3589, 10}, - {3546, 7}, - {3495, 4}, - {3404, 2}, - {3250, 0}, -}; - static const struct ab8500_v_to_cap cap_tbl[] = { {4186, 100}, {4163, 99}, @@ -167,90 +79,33 @@ static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { {-20, 595}, }; -static struct ab8500_battery_type bat_type_thermistor[] = { - [BATTERY_UNKNOWN] = { - /* First element always represent the UNKNOWN battery */ - .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN, - .resis_high = 0, - .resis_low = 0, - .battery_resistance = 300, - .charge_full_design = 612, - .nominal_voltage = 3700, - .termination_vol = 4050, - .termination_curr = 200, - .recharge_cap = 95, - .normal_cur_lvl = 400, - .normal_vol_lvl = 4100, - .maint_a_cur_lvl = 400, - .maint_a_vol_lvl = 4050, - .maint_a_chg_timer_h = 60, - .maint_b_cur_lvl = 400, - .maint_b_vol_lvl = 4000, - .maint_b_chg_timer_h = 200, - .low_high_cur_lvl = 300, - .low_high_vol_lvl = 4000, - .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), - .r_to_t_tbl = temp_tbl, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), - .v_to_cap_tbl = cap_tbl, - .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), - .batres_tbl = temp_to_batres_tbl_thermistor, - }, - { - .name = POWER_SUPPLY_TECHNOLOGY_LIPO, - .resis_high = 53407, - .resis_low = 12500, - .battery_resistance = 300, - .charge_full_design = 900, - .nominal_voltage = 3600, - .termination_vol = 4150, - .termination_curr = 80, - .recharge_cap = 95, - .normal_cur_lvl = 700, - .normal_vol_lvl = 4200, - .maint_a_cur_lvl = 600, - .maint_a_vol_lvl = 4150, - .maint_a_chg_timer_h = 60, - .maint_b_cur_lvl = 600, - .maint_b_vol_lvl = 4100, - .maint_b_chg_timer_h = 200, - .low_high_cur_lvl = 300, - .low_high_vol_lvl = 4000, - .n_temp_tbl_elements = ARRAY_SIZE(ab8500_temp_tbl_a_thermistor), - .r_to_t_tbl = ab8500_temp_tbl_a_thermistor, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_a_thermistor), - .v_to_cap_tbl = cap_tbl_a_thermistor, - .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), - .batres_tbl = temp_to_batres_tbl_thermistor, - - }, - { - .name = POWER_SUPPLY_TECHNOLOGY_LIPO, - .resis_high = 200000, - .resis_low = 82869, - .battery_resistance = 300, - .charge_full_design = 900, - .nominal_voltage = 3600, - .termination_vol = 4150, - .termination_curr = 80, - .recharge_cap = 95, - .normal_cur_lvl = 700, - .normal_vol_lvl = 4200, - .maint_a_cur_lvl = 600, - .maint_a_vol_lvl = 4150, - .maint_a_chg_timer_h = 60, - .maint_b_cur_lvl = 600, - .maint_b_vol_lvl = 4100, - .maint_b_chg_timer_h = 200, - .low_high_cur_lvl = 300, - .low_high_vol_lvl = 4000, - .n_temp_tbl_elements = ARRAY_SIZE(ab8500_temp_tbl_b_thermistor), - .r_to_t_tbl = ab8500_temp_tbl_b_thermistor, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_b_thermistor), - .v_to_cap_tbl = cap_tbl_b_thermistor, - .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), - .batres_tbl = temp_to_batres_tbl_thermistor, - }, +/* Default battery type for reference designs is the unknown type */ +static struct ab8500_battery_type bat_type_thermistor_unknown = { + .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN, + .resis_high = 0, + .resis_low = 0, + .battery_resistance = 300, + .charge_full_design = 612, + .nominal_voltage = 3700, + .termination_vol = 4050, + .termination_curr = 200, + .recharge_cap = 95, + .normal_cur_lvl = 400, + .normal_vol_lvl = 4100, + .maint_a_cur_lvl = 400, + .maint_a_vol_lvl = 4050, + .maint_a_chg_timer_h = 60, + .maint_b_cur_lvl = 400, + .maint_b_vol_lvl = 4000, + .maint_b_chg_timer_h = 200, + .low_high_cur_lvl = 300, + .low_high_vol_lvl = 4000, + .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), + .r_to_t_tbl = temp_tbl, + .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), + .v_to_cap_tbl = cap_tbl, + .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), + .batres_tbl = temp_to_batres_tbl_thermistor, }; static const struct ab8500_bm_capacity_levels cap_levels = { @@ -312,9 +167,7 @@ struct ab8500_bm_data ab8500_bm_data = { .enable_overshoot = false, .fg_res = 100, .cap_levels = &cap_levels, - .bat_type = bat_type_thermistor, - .n_btypes = ARRAY_SIZE(bat_type_thermistor), - .batt_id = 0, + .bat_type = &bat_type_thermistor_unknown, .interval_charging = 5, .interval_not_charging = 120, .gnd_lift_resistance = 34, diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c index b6c9111d77d7..fbb58074efab 100644 --- a/drivers/power/supply/ab8500_btemp.c +++ b/drivers/power/supply/ab8500_btemp.c @@ -454,12 +454,9 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) int temp, ret; static int prev; int rbat, rntc, vntc; - u8 id; - id = di->bm->batt_id; - - if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL && - id != BATTERY_UNKNOWN) { + if ((di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL) && + (di->bm->bat_type->name == POWER_SUPPLY_TECHNOLOGY_UNKNOWN)) { rbat = ab8500_btemp_get_batctrl_res(di); if (rbat < 0) { @@ -473,8 +470,8 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) } temp = ab8500_btemp_res_to_temp(di, - di->bm->bat_type[id].r_to_t_tbl, - di->bm->bat_type[id].n_temp_tbl_elements, rbat); + di->bm->bat_type->r_to_t_tbl, + di->bm->bat_type->n_temp_tbl_elements, rbat); } else { ret = iio_read_channel_processed(di->btemp_ball, &vntc); if (ret < 0) { @@ -490,8 +487,8 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) rntc = 230000 * vntc / (VTVOUT_V - vntc); temp = ab8500_btemp_res_to_temp(di, - di->bm->bat_type[id].r_to_t_tbl, - di->bm->bat_type[id].n_temp_tbl_elements, rntc); + di->bm->bat_type->r_to_t_tbl, + di->bm->bat_type->n_temp_tbl_elements, rntc); prev = temp; } dev_dbg(di->dev, "Battery temperature is %d\n", temp); @@ -512,7 +509,6 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) u8 i; di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA; - di->bm->batt_id = BATTERY_UNKNOWN; res = ab8500_btemp_get_batctrl_res(di); if (res < 0) { @@ -520,40 +516,37 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) return -ENXIO; } - /* BATTERY_UNKNOWN is defined on position 0, skip it! */ - for (i = BATTERY_UNKNOWN + 1; i < di->bm->n_btypes; i++) { - if ((res <= di->bm->bat_type[i].resis_high) && - (res >= di->bm->bat_type[i].resis_low)) { - dev_dbg(di->dev, "Battery detected on %s" - " low %d < res %d < high: %d" - " index: %d\n", - di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL ? - "BATCTRL" : "BATTEMP", - di->bm->bat_type[i].resis_low, res, - di->bm->bat_type[i].resis_high, i); - - di->bm->batt_id = i; - break; - } - } - - if (di->bm->batt_id == BATTERY_UNKNOWN) { + if ((res <= di->bm->bat_type->resis_high) && + (res >= di->bm->bat_type->resis_low)) { + dev_info(di->dev, "Battery detected on %s" + " low %d < res %d < high: %d" + " index: %d\n", + di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL ? + "BATCTRL" : "BATTEMP", + di->bm->bat_type->resis_low, res, + di->bm->bat_type->resis_high, i); + } else { dev_warn(di->dev, "Battery identified as unknown" - ", resistance %d Ohm\n", res); + ", resistance %d Ohm\n", res); return -ENXIO; } /* * We only have to change current source if the - * detected type is Type 1. + * detected type is Type 1 (LIPO) resis_high = 53407, resis_low = 12500 + * if someone hacks this in. + * + * FIXME: make sure this is done automatically for the batteries + * that need it. */ - if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL && - di->bm->batt_id == 1) { + if ((di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL) && + (di->bm->bat_type->name == POWER_SUPPLY_TECHNOLOGY_LIPO) && + (res <= 53407) && (res >= 12500)) { dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n"); di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA; } - return di->bm->batt_id; + return 0; } /** @@ -814,7 +807,7 @@ static int ab8500_btemp_get_property(struct power_supply *psy, val->intval = 1; break; case POWER_SUPPLY_PROP_TECHNOLOGY: - val->intval = di->bm->bat_type[di->bm->batt_id].name; + val->intval = di->bm->bat_type->name; break; case POWER_SUPPLY_PROP_TEMP: val->intval = ab8500_btemp_get_temp(di); diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index 9196434393e8..a5ccfb0aa9f4 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -356,13 +356,13 @@ static int ab8500_chargalg_check_charger_enable(struct ab8500_chargalg *di) if (di->chg_info.charger_type & USB_CHG) { return di->usb_chg->ops.check_enable(di->usb_chg, - di->bm->bat_type[di->bm->batt_id].normal_vol_lvl, - di->bm->bat_type[di->bm->batt_id].normal_cur_lvl); + di->bm->bat_type->normal_vol_lvl, + di->bm->bat_type->normal_cur_lvl); } else if ((di->chg_info.charger_type & AC_CHG) && !(di->ac_chg->external)) { return di->ac_chg->ops.check_enable(di->ac_chg, - di->bm->bat_type[di->bm->batt_id].normal_vol_lvl, - di->bm->bat_type[di->bm->batt_id].normal_cur_lvl); + di->bm->bat_type->normal_vol_lvl, + di->bm->bat_type->normal_cur_lvl); } return 0; } @@ -793,10 +793,10 @@ static void ab8500_chargalg_end_of_charge(struct ab8500_chargalg *di) if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING && di->charge_state == STATE_NORMAL && !di->maintenance_chg && (di->batt_data.volt >= - di->bm->bat_type[di->bm->batt_id].termination_vol || + di->bm->bat_type->termination_vol || di->events.usb_cv_active || di->events.ac_cv_active) && di->batt_data.avg_curr < - di->bm->bat_type[di->bm->batt_id].termination_curr && + di->bm->bat_type->termination_curr && di->batt_data.avg_curr > 0) { if (++di->eoc_cnt >= EOC_COND_CNT) { di->eoc_cnt = 0; @@ -819,9 +819,9 @@ static void ab8500_chargalg_end_of_charge(struct ab8500_chargalg *di) static void init_maxim_chg_curr(struct ab8500_chargalg *di) { di->ccm.original_iset = - di->bm->bat_type[di->bm->batt_id].normal_cur_lvl; + di->bm->bat_type->normal_cur_lvl; di->ccm.current_iset = - di->bm->bat_type[di->bm->batt_id].normal_cur_lvl; + di->bm->bat_type->normal_cur_lvl; di->ccm.test_delta_i = di->bm->maxi->charger_curr_step; di->ccm.max_current = di->bm->maxi->chg_curr; di->ccm.condition_cnt = di->bm->maxi->wait_cycles; @@ -924,7 +924,7 @@ static void handle_maxim_chg_curr(struct ab8500_chargalg *di) break; case MAXIM_RET_IBAT_TOO_HIGH: result = ab8500_chargalg_update_chg_curr(di, - di->bm->bat_type[di->bm->batt_id].normal_cur_lvl); + di->bm->bat_type->normal_cur_lvl); if (result) dev_err(di->dev, "failed to set chg curr\n"); break; @@ -1505,13 +1505,12 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) if (di->curr_status.curr_step == CHARGALG_CURR_STEP_LOW) ab8500_chargalg_stop_charging(di); else { - curr_step_lvl = di->bm->bat_type[ - di->bm->batt_id].normal_cur_lvl + curr_step_lvl = di->bm->bat_type->normal_cur_lvl * di->curr_status.curr_step / CHARGALG_CURR_STEP_HIGH; ab8500_chargalg_start_charging(di, - di->bm->bat_type[di->bm->batt_id] - .normal_vol_lvl, curr_step_lvl); + di->bm->bat_type->normal_vol_lvl, + curr_step_lvl); } ab8500_chargalg_state_to(di, STATE_NORMAL); @@ -1546,20 +1545,17 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) case STATE_WAIT_FOR_RECHARGE: if (di->batt_data.percent <= - di->bm->bat_type[di->bm->batt_id].recharge_cap) + di->bm->bat_type->recharge_cap) ab8500_chargalg_state_to(di, STATE_NORMAL_INIT); break; case STATE_MAINTENANCE_A_INIT: ab8500_chargalg_stop_safety_timer(di); ab8500_chargalg_start_maintenance_timer(di, - di->bm->bat_type[ - di->bm->batt_id].maint_a_chg_timer_h); + di->bm->bat_type->maint_a_chg_timer_h); ab8500_chargalg_start_charging(di, - di->bm->bat_type[ - di->bm->batt_id].maint_a_vol_lvl, - di->bm->bat_type[ - di->bm->batt_id].maint_a_cur_lvl); + di->bm->bat_type->maint_a_vol_lvl, + di->bm->bat_type->maint_a_cur_lvl); ab8500_chargalg_state_to(di, STATE_MAINTENANCE_A); power_supply_changed(di->chargalg_psy); fallthrough; @@ -1573,13 +1569,10 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) case STATE_MAINTENANCE_B_INIT: ab8500_chargalg_start_maintenance_timer(di, - di->bm->bat_type[ - di->bm->batt_id].maint_b_chg_timer_h); + di->bm->bat_type->maint_b_chg_timer_h); ab8500_chargalg_start_charging(di, - di->bm->bat_type[ - di->bm->batt_id].maint_b_vol_lvl, - di->bm->bat_type[ - di->bm->batt_id].maint_b_cur_lvl); + di->bm->bat_type->maint_b_vol_lvl, + di->bm->bat_type->maint_b_cur_lvl); ab8500_chargalg_state_to(di, STATE_MAINTENANCE_B); power_supply_changed(di->chargalg_psy); fallthrough; @@ -1593,10 +1586,8 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) case STATE_TEMP_LOWHIGH_INIT: ab8500_chargalg_start_charging(di, - di->bm->bat_type[ - di->bm->batt_id].low_high_vol_lvl, - di->bm->bat_type[ - di->bm->batt_id].low_high_cur_lvl); + di->bm->bat_type->low_high_vol_lvl, + di->bm->bat_type->low_high_cur_lvl); ab8500_chargalg_stop_maintenance_timer(di); di->charge_status = POWER_SUPPLY_STATUS_CHARGING; ab8500_chargalg_state_to(di, STATE_TEMP_LOWHIGH); diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 05fe9724ba50..2013db0118ee 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -857,8 +857,8 @@ static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage) const struct ab8500_v_to_cap *tbl; int cap = 0; - tbl = di->bm->bat_type[di->bm->batt_id].v_to_cap_tbl; - tbl_size = di->bm->bat_type[di->bm->batt_id].n_v_cap_tbl_elements; + tbl = di->bm->bat_type->v_to_cap_tbl; + tbl_size = di->bm->bat_type->n_v_cap_tbl_elements; for (i = 0; i < tbl_size; ++i) { if (voltage > tbl[i].voltage) @@ -910,8 +910,8 @@ static int ab8500_fg_battery_resistance(struct ab8500_fg *di) const struct batres_vs_temp *tbl; int resist = 0; - tbl = di->bm->bat_type[di->bm->batt_id].batres_tbl; - tbl_size = di->bm->bat_type[di->bm->batt_id].n_batres_tbl_elements; + tbl = di->bm->bat_type->batres_tbl; + tbl_size = di->bm->bat_type->n_batres_tbl_elements; for (i = 0; i < tbl_size; ++i) { if (di->bat_temp / 10 > tbl[i].temp) @@ -2234,10 +2234,11 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) switch (ext->desc->type) { case POWER_SUPPLY_TYPE_BATTERY: if (!di->flags.batt_id_received && - di->bm->batt_id != BATTERY_UNKNOWN) { + (di->bm->bat_type->name != + POWER_SUPPLY_TECHNOLOGY_UNKNOWN)) { const struct ab8500_battery_type *b; - b = &(di->bm->bat_type[di->bm->batt_id]); + b = di->bm->bat_type; di->flags.batt_id_received = true; @@ -3078,11 +3079,11 @@ static int ab8500_fg_probe(struct platform_device *pdev) psy_cfg.drv_data = di; di->bat_cap.max_mah_design = MILLI_TO_MICRO * - di->bm->bat_type[di->bm->batt_id].charge_full_design; + di->bm->bat_type->charge_full_design; di->bat_cap.max_mah = di->bat_cap.max_mah_design; - di->vbat_nom = di->bm->bat_type[di->bm->batt_id].nominal_voltage; + di->vbat_nom = di->bm->bat_type->nominal_voltage; di->init_capacity = true; -- cgit v1.2.3-59-g8ed1b From 22be8d77c80dca59af004d4595699b2092670499 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:16 +0100 Subject: power: supply: ab8500: Standardize design capacity Now that we know that we have only one battery type to deal with we can proceed to transfer properties to struct power_supply_battery_info. The designed capacity for the battery was in a custom field of the custom battery type in mAh, transfer this to the standard charge_full_design_uah property in struct power_supply_battery_info and augment the code accordingly. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 2 -- drivers/power/supply/ab8500_bmdata.c | 5 ++++- drivers/power/supply/ab8500_fg.c | 8 ++------ 3 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index 99ada7f08ec7..a5cae9288274 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -375,7 +375,6 @@ struct ab8500_maxim_parameters { * @name: battery technology * @resis_high: battery upper resistance limit * @resis_low: battery lower resistance limit - * @charge_full_design: Maximum battery capacity in mAh * @nominal_voltage: Nominal voltage of the battery in mV * @termination_vol: max voltage upto which battery can be charged * @termination_curr battery charging termination current in mA @@ -404,7 +403,6 @@ struct ab8500_battery_type { int name; int resis_high; int resis_low; - int charge_full_design; int nominal_voltage; int termination_vol; int termination_curr; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 5db13b026d81..2d328d3007a9 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -85,7 +85,6 @@ static struct ab8500_battery_type bat_type_thermistor_unknown = { .resis_high = 0, .resis_low = 0, .battery_resistance = 300, - .charge_full_design = 612, .nominal_voltage = 3700, .termination_vol = 4050, .termination_curr = 200, @@ -189,6 +188,10 @@ int ab8500_bm_of_probe(struct power_supply *psy, return ret; } + /* Fill in defaults for any data missing from the device tree */ + if (bi->charge_full_design_uah < 0) + /* The default capacity is 612 mAh for unknown batteries */ + bi->charge_full_design_uah = 612000; if (bi->temp_min == INT_MIN) bi->temp_min = AB8500_TEMP_UNDER; if (bi->temp_max == INT_MAX) diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 2013db0118ee..4f8b3a76c565 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -38,7 +38,6 @@ #include "ab8500-bm.h" -#define MILLI_TO_MICRO 1000 #define FG_LSB_IN_MA 1627 #define QLSB_NANO_AMP_HOURS_X10 1071 #define INS_CURR_TIMEOUT (3 * HZ) @@ -2243,8 +2242,7 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) di->flags.batt_id_received = true; di->bat_cap.max_mah_design = - MILLI_TO_MICRO * - b->charge_full_design; + di->bm->bi.charge_full_design_uah; di->bat_cap.max_mah = di->bat_cap.max_mah_design; @@ -3078,9 +3076,7 @@ static int ab8500_fg_probe(struct platform_device *pdev) psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); psy_cfg.drv_data = di; - di->bat_cap.max_mah_design = MILLI_TO_MICRO * - di->bm->bat_type->charge_full_design; - + di->bat_cap.max_mah_design = di->bm->bi.charge_full_design_uah; di->bat_cap.max_mah = di->bat_cap.max_mah_design; di->vbat_nom = di->bm->bat_type->nominal_voltage; -- cgit v1.2.3-59-g8ed1b From 2d3559a50ad6d21552ed2434889bc568acfa2a83 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:17 +0100 Subject: power: supply: ab8500: Standardize technology The AB8500 custom battery type can be replaced by the corresponding struct power_supply_battery_info field. Remove the struct member and amend the code to use the standard property. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 2 -- drivers/power/supply/ab8500_bmdata.c | 1 - drivers/power/supply/ab8500_btemp.c | 6 +++--- drivers/power/supply/ab8500_fg.c | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index a5cae9288274..750d1a962f39 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -372,7 +372,6 @@ struct ab8500_maxim_parameters { /** * struct ab8500_battery_type - different batteries supported - * @name: battery technology * @resis_high: battery upper resistance limit * @resis_low: battery lower resistance limit * @nominal_voltage: Nominal voltage of the battery in mV @@ -400,7 +399,6 @@ struct ab8500_maxim_parameters { * @batres_tbl battery internal resistance vs temperature table */ struct ab8500_battery_type { - int name; int resis_high; int resis_low; int nominal_voltage; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 2d328d3007a9..44d7c568949f 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -81,7 +81,6 @@ static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { /* Default battery type for reference designs is the unknown type */ static struct ab8500_battery_type bat_type_thermistor_unknown = { - .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN, .resis_high = 0, .resis_low = 0, .battery_resistance = 300, diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c index fbb58074efab..20253b8a7fe9 100644 --- a/drivers/power/supply/ab8500_btemp.c +++ b/drivers/power/supply/ab8500_btemp.c @@ -456,7 +456,7 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) int rbat, rntc, vntc; if ((di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL) && - (di->bm->bat_type->name == POWER_SUPPLY_TECHNOLOGY_UNKNOWN)) { + (di->bm->bi.technology == POWER_SUPPLY_TECHNOLOGY_UNKNOWN)) { rbat = ab8500_btemp_get_batctrl_res(di); if (rbat < 0) { @@ -540,7 +540,7 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) * that need it. */ if ((di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL) && - (di->bm->bat_type->name == POWER_SUPPLY_TECHNOLOGY_LIPO) && + (di->bm->bi.technology == POWER_SUPPLY_TECHNOLOGY_LIPO) && (res <= 53407) && (res >= 12500)) { dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n"); di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA; @@ -807,7 +807,7 @@ static int ab8500_btemp_get_property(struct power_supply *psy, val->intval = 1; break; case POWER_SUPPLY_PROP_TECHNOLOGY: - val->intval = di->bm->bat_type->name; + val->intval = di->bm->bi.technology; break; case POWER_SUPPLY_PROP_TEMP: val->intval = ab8500_btemp_get_temp(di); diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 4f8b3a76c565..c6237c4f4721 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -2233,7 +2233,7 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) switch (ext->desc->type) { case POWER_SUPPLY_TYPE_BATTERY: if (!di->flags.batt_id_received && - (di->bm->bat_type->name != + (di->bm->bi.technology != POWER_SUPPLY_TECHNOLOGY_UNKNOWN)) { const struct ab8500_battery_type *b; -- cgit v1.2.3-59-g8ed1b From 2a5f41830aadc2d7f4145eae49381133da5df2a3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:18 +0100 Subject: power: supply: ab8500: Standardize voltages The nominal voltage in this charge driver corresponds to both the voltage_min_design_uv and voltage_max_design_uv of struct power_supply_battery_info so assign both if this is undefined. The overcharge max voltage (when the charger should cut off) is migrated at the same time so we move both voltages to struct power_supply_battery_info. Adjust the code to deal directly with the microvolt values instead of converting them to millivolts. Add *_uv suffixes for clarity and to make sure we have changed all code sites using this member. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 4 ---- drivers/power/supply/ab8500_bmdata.c | 17 +++++++++++++++-- drivers/power/supply/ab8500_chargalg.c | 10 +++++----- drivers/power/supply/ab8500_fg.c | 21 +++++++++++++-------- 4 files changed, 33 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index 750d1a962f39..b21d3a99471f 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -374,8 +374,6 @@ struct ab8500_maxim_parameters { * struct ab8500_battery_type - different batteries supported * @resis_high: battery upper resistance limit * @resis_low: battery lower resistance limit - * @nominal_voltage: Nominal voltage of the battery in mV - * @termination_vol: max voltage upto which battery can be charged * @termination_curr battery charging termination current in mA * @recharge_cap battery capacity limit that will trigger a new * full charging cycle in the case where maintenan- @@ -401,8 +399,6 @@ struct ab8500_maxim_parameters { struct ab8500_battery_type { int resis_high; int resis_low; - int nominal_voltage; - int termination_vol; int termination_curr; int recharge_cap; int normal_cur_lvl; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 44d7c568949f..684cefccebd1 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -84,8 +84,6 @@ static struct ab8500_battery_type bat_type_thermistor_unknown = { .resis_high = 0, .resis_low = 0, .battery_resistance = 300, - .nominal_voltage = 3700, - .termination_vol = 4050, .termination_curr = 200, .recharge_cap = 95, .normal_cur_lvl = 400, @@ -191,6 +189,21 @@ int ab8500_bm_of_probe(struct power_supply *psy, if (bi->charge_full_design_uah < 0) /* The default capacity is 612 mAh for unknown batteries */ bi->charge_full_design_uah = 612000; + + /* + * All of these voltages need to be specified or we will simply + * fall back to safe defaults. + */ + if ((bi->voltage_min_design_uv < 0) || + (bi->voltage_max_design_uv < 0) || + (bi->overvoltage_limit_uv < 0)) { + /* Nominal voltage is 3.7V for unknown batteries */ + bi->voltage_min_design_uv = 3700000; + bi->voltage_max_design_uv = 3700000; + /* Termination voltage (overcharge limit) 4.05V */ + bi->overvoltage_limit_uv = 4050000; + } + if (bi->temp_min == INT_MIN) bi->temp_min = AB8500_TEMP_UNDER; if (bi->temp_max == INT_MAX) diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index a5ccfb0aa9f4..dd9cad63e37e 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -86,7 +86,7 @@ struct ab8500_chargalg_current_step_status { struct ab8500_chargalg_battery_data { int temp; - int volt; + int volt_uv; int avg_curr; int inst_curr; int percent; @@ -792,8 +792,8 @@ static void ab8500_chargalg_end_of_charge(struct ab8500_chargalg *di) { if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING && di->charge_state == STATE_NORMAL && - !di->maintenance_chg && (di->batt_data.volt >= - di->bm->bat_type->termination_vol || + !di->maintenance_chg && (di->batt_data.volt_uv >= + di->bm->bi.overvoltage_limit_uv || di->events.usb_cv_active || di->events.ac_cv_active) && di->batt_data.avg_curr < di->bm->bat_type->termination_curr && @@ -1160,7 +1160,7 @@ static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data) case POWER_SUPPLY_PROP_VOLTAGE_NOW: switch (ext->desc->type) { case POWER_SUPPLY_TYPE_BATTERY: - di->batt_data.volt = ret.intval / 1000; + di->batt_data.volt_uv = ret.intval; break; case POWER_SUPPLY_TYPE_MAINS: di->chg_info.ac_volt = ret.intval / 1000; @@ -1397,7 +1397,7 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) "State %s Active_chg %d Chg_status %d AC %d USB %d " "AC_online %d USB_online %d AC_CV %d USB_CV %d AC_I %d " "USB_I %d AC_Vset %d AC_Iset %d USB_Vset %d USB_Iset %d\n", - di->batt_data.volt, + di->batt_data.volt_uv, di->batt_data.avg_curr, di->batt_data.inst_curr, di->batt_data.temp, diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index c6237c4f4721..ab6141faa798 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -157,7 +157,7 @@ struct inst_curr_result_list { * @node: a list of AB8500 FGs, hence prepared for reentrance * @irq holds the CCEOC interrupt number * @vbat: Battery voltage in mV - * @vbat_nom: Nominal battery voltage in mV + * @vbat_nom_uv: Nominal battery voltage in uV * @inst_curr: Instantenous battery current in mA * @avg_curr: Average battery current in mA * @bat_temp battery temperature @@ -199,7 +199,7 @@ struct ab8500_fg { struct list_head node; int irq; int vbat; - int vbat_nom; + int vbat_nom_uv; int inst_curr; int avg_curr; int bat_temp; @@ -1013,11 +1013,16 @@ static int ab8500_fg_convert_mah_to_uwh(struct ab8500_fg *di, int cap_mah) u64 div_res; u32 div_rem; - div_res = ((u64) cap_mah) * ((u64) di->vbat_nom); - div_rem = do_div(div_res, 1000); + /* + * Capacity is in milli ampere hours (10^-3)Ah + * Nominal voltage is in microvolts (10^-6)V + * divide by 1000000 after multiplication to get to mWh + */ + div_res = ((u64) cap_mah) * ((u64) di->vbat_nom_uv); + div_rem = do_div(div_res, 1000000); /* Make sure to round upwards if necessary */ - if (div_rem >= 1000 / 2) + if (div_rem >= 1000000 / 2) div_res++; return (int) div_res; @@ -2247,7 +2252,8 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) di->bat_cap.max_mah = di->bat_cap.max_mah_design; - di->vbat_nom = b->nominal_voltage; + di->vbat_nom_uv = + di->bm->bi.voltage_max_design_uv; } if (ret.intval) @@ -3078,8 +3084,7 @@ static int ab8500_fg_probe(struct platform_device *pdev) di->bat_cap.max_mah_design = di->bm->bi.charge_full_design_uah; di->bat_cap.max_mah = di->bat_cap.max_mah_design; - - di->vbat_nom = di->bm->bat_type->nominal_voltage; + di->vbat_nom_uv = di->bm->bi.voltage_max_design_uv; di->init_capacity = true; -- cgit v1.2.3-59-g8ed1b From fc81c435a8a67c72939b44e851111b2991d5ac51 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:19 +0100 Subject: power: supply: ab8500_fg: Init battery data in bind() We were assigning some battery data state in probe() but this is insecure as it depends on the proper probe order between the components: the charger must probe first so that the battery data is populated. Move the init to the bind() call which is certain to happen after the probe of the master and all components has happened. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_fg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index ab6141faa798..daa008138b05 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -3023,6 +3023,10 @@ static int ab8500_fg_bind(struct device *dev, struct device *master, return -ENOMEM; } + di->bat_cap.max_mah_design = di->bm->bi.charge_full_design_uah; + di->bat_cap.max_mah = di->bat_cap.max_mah_design; + di->vbat_nom_uv = di->bm->bi.voltage_max_design_uv; + /* Start the coulomb counter */ ab8500_fg_coulomb_counter(di, true); /* Run the FG algorithm */ @@ -3082,10 +3086,6 @@ static int ab8500_fg_probe(struct platform_device *pdev) psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); psy_cfg.drv_data = di; - di->bat_cap.max_mah_design = di->bm->bi.charge_full_design_uah; - di->bat_cap.max_mah = di->bat_cap.max_mah_design; - di->vbat_nom_uv = di->bm->bi.voltage_max_design_uv; - di->init_capacity = true; ab8500_fg_charge_state_to(di, AB8500_FG_CHARGE_INIT); -- cgit v1.2.3-59-g8ed1b From 50425ccf2467db9f4134a60a95ef6b6a580222cb Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:20 +0100 Subject: power: supply: ab8500: Standardize internal resistance The nominal internal resistance isn't used by the AB8500 charging code, instead this resistance is measured continuously, but we anyways migrate this to the standard property in struct power_supply_battery_info. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 2 -- drivers/power/supply/ab8500_bmdata.c | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index b21d3a99471f..7e00f480756b 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -388,7 +388,6 @@ struct ab8500_maxim_parameters { * @maint_b_chg_timer_h: charge time in maintenance B state * @low_high_cur_lvl: charger current in temp low/high state in mA * @low_high_vol_lvl: charger voltage in temp low/high state in mV' - * @battery_resistance: battery inner resistance in mOhm. * @n_r_t_tbl_elements: number of elements in r_to_t_tbl * @r_to_t_tbl: table containing resistance to temp points * @n_v_cap_tbl_elements: number of elements in v_to_cap_tbl @@ -411,7 +410,6 @@ struct ab8500_battery_type { int maint_b_chg_timer_h; int low_high_cur_lvl; int low_high_vol_lvl; - int battery_resistance; int n_temp_tbl_elements; const struct ab8500_res_to_temp *r_to_t_tbl; int n_v_cap_tbl_elements; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 684cefccebd1..981003105af6 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -83,7 +83,6 @@ static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { static struct ab8500_battery_type bat_type_thermistor_unknown = { .resis_high = 0, .resis_low = 0, - .battery_resistance = 300, .termination_curr = 200, .recharge_cap = 95, .normal_cur_lvl = 400, @@ -204,6 +203,9 @@ int ab8500_bm_of_probe(struct power_supply *psy, bi->overvoltage_limit_uv = 4050000; } + if (bi->factory_internal_resistance_uohm < 0) + bi->factory_internal_resistance_uohm = 300000; + if (bi->temp_min == INT_MIN) bi->temp_min = AB8500_TEMP_UNDER; if (bi->temp_max == INT_MAX) -- cgit v1.2.3-59-g8ed1b From 9c20899da46b85ed00e6f3b935b4bd9c9b34a571 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:21 +0100 Subject: power: supply: ab8500: Standardize termination current The AB8500 custom termination current can be replaced by the corresponding struct power_supply_battery_info field. Remove the struct member and amend the code to use the standard property. Add *_ua suffix for clarity and to make sure we have changed all code sites using this member. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 2 -- drivers/power/supply/ab8500_bmdata.c | 5 ++++- drivers/power/supply/ab8500_chargalg.c | 12 ++++++------ 3 files changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index 7e00f480756b..4bc932109f63 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -374,7 +374,6 @@ struct ab8500_maxim_parameters { * struct ab8500_battery_type - different batteries supported * @resis_high: battery upper resistance limit * @resis_low: battery lower resistance limit - * @termination_curr battery charging termination current in mA * @recharge_cap battery capacity limit that will trigger a new * full charging cycle in the case where maintenan- * -ce charging has been disabled @@ -398,7 +397,6 @@ struct ab8500_maxim_parameters { struct ab8500_battery_type { int resis_high; int resis_low; - int termination_curr; int recharge_cap; int normal_cur_lvl; int normal_vol_lvl; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 981003105af6..cd1fc288314e 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -83,7 +83,6 @@ static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { static struct ab8500_battery_type bat_type_thermistor_unknown = { .resis_high = 0, .resis_low = 0, - .termination_curr = 200, .recharge_cap = 95, .normal_cur_lvl = 400, .normal_vol_lvl = 4100, @@ -203,6 +202,10 @@ int ab8500_bm_of_probe(struct power_supply *psy, bi->overvoltage_limit_uv = 4050000; } + if (bi->charge_term_current_ua) + /* Charging stops when we drop below this current */ + bi->charge_term_current_ua = 200000; + if (bi->factory_internal_resistance_uohm < 0) bi->factory_internal_resistance_uohm = 300000; diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index dd9cad63e37e..49e7167d0362 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -87,7 +87,7 @@ struct ab8500_chargalg_current_step_status { struct ab8500_chargalg_battery_data { int temp; int volt_uv; - int avg_curr; + int avg_curr_ua; int inst_curr; int percent; }; @@ -795,9 +795,9 @@ static void ab8500_chargalg_end_of_charge(struct ab8500_chargalg *di) !di->maintenance_chg && (di->batt_data.volt_uv >= di->bm->bi.overvoltage_limit_uv || di->events.usb_cv_active || di->events.ac_cv_active) && - di->batt_data.avg_curr < - di->bm->bat_type->termination_curr && - di->batt_data.avg_curr > 0) { + di->batt_data.avg_curr_ua < + di->bm->bi.charge_term_current_ua && + di->batt_data.avg_curr_ua > 0) { if (++di->eoc_cnt >= EOC_COND_CNT) { di->eoc_cnt = 0; di->charge_status = POWER_SUPPLY_STATUS_FULL; @@ -1237,7 +1237,7 @@ static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data) case POWER_SUPPLY_PROP_CURRENT_AVG: switch (ext->desc->type) { case POWER_SUPPLY_TYPE_BATTERY: - di->batt_data.avg_curr = ret.intval / 1000; + di->batt_data.avg_curr_ua = ret.intval; break; case POWER_SUPPLY_TYPE_USB: if (ret.intval) @@ -1398,7 +1398,7 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) "AC_online %d USB_online %d AC_CV %d USB_CV %d AC_I %d " "USB_I %d AC_Vset %d AC_Iset %d USB_Vset %d USB_Iset %d\n", di->batt_data.volt_uv, - di->batt_data.avg_curr, + di->batt_data.avg_curr_ua, di->batt_data.inst_curr, di->batt_data.temp, di->batt_data.percent, -- cgit v1.2.3-59-g8ed1b From 1091ed7db0d2957e015a5650ed17ff7537c2b3f3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:22 +0100 Subject: power: supply: ab8500: Make recharge capacity a constant The recharge capacity is the hysteresis level for a charger to restart when a battery does not support maintenance charging. All products using the AB8500 have batteries supporting maintenace charging and all code has always set this to 95%. Turn it into a constant. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 4 ---- drivers/power/supply/ab8500_bmdata.c | 1 - drivers/power/supply/ab8500_chargalg.c | 10 ++++++++-- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index 4bc932109f63..58e4cb901076 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -374,9 +374,6 @@ struct ab8500_maxim_parameters { * struct ab8500_battery_type - different batteries supported * @resis_high: battery upper resistance limit * @resis_low: battery lower resistance limit - * @recharge_cap battery capacity limit that will trigger a new - * full charging cycle in the case where maintenan- - * -ce charging has been disabled * @normal_cur_lvl: charger current in normal state in mA * @normal_vol_lvl: charger voltage in normal state in mV * @maint_a_cur_lvl: charger current in maintenance A state in mA @@ -397,7 +394,6 @@ struct ab8500_maxim_parameters { struct ab8500_battery_type { int resis_high; int resis_low; - int recharge_cap; int normal_cur_lvl; int normal_vol_lvl; int maint_a_cur_lvl; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index cd1fc288314e..78182a396de7 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -83,7 +83,6 @@ static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { static struct ab8500_battery_type bat_type_thermistor_unknown = { .resis_high = 0, .resis_low = 0, - .recharge_cap = 95, .normal_cur_lvl = 400, .normal_vol_lvl = 4100, .maint_a_cur_lvl = 400, diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index 49e7167d0362..90974a8887cd 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -49,6 +49,13 @@ #define CHARGALG_CURR_STEP_LOW 0 #define CHARGALG_CURR_STEP_HIGH 100 +/* + * This is the battery capacity limit that will trigger a new + * full charging cycle in the case where maintenance charging + * has been disabled + */ +#define AB8500_RECHARGE_CAP 95 + enum ab8500_chargers { NO_CHG, AC_CHG, @@ -1544,8 +1551,7 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) fallthrough; case STATE_WAIT_FOR_RECHARGE: - if (di->batt_data.percent <= - di->bm->bat_type->recharge_cap) + if (di->batt_data.percent <= AB8500_RECHARGE_CAP) ab8500_chargalg_state_to(di, STATE_NORMAL_INIT); break; -- cgit v1.2.3-59-g8ed1b From 83e5aa77d1120fd38101f757c4aeb985e9305700 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:23 +0100 Subject: power: supply: ab8500: Standardize CC current The current used in the constant current phase of the charging exist in struct power_supply_battery_info as constant_charge_current_max_ua. Switch the custom property max_out_curr to this and consequentally change everything that relates to this value over to using microamperes rather than milliamperes so we align internal representation of current with the power core. Prefix every variable we change with *_ua to indicate the unit everywhere but also to make sure we do not miss any outlier. Drop some duplicate unused defines in a header. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 25 +-- drivers/power/supply/ab8500-chargalg.h | 4 +- drivers/power/supply/ab8500_bmdata.c | 12 +- drivers/power/supply/ab8500_chargalg.c | 194 ++++++++++----------- drivers/power/supply/ab8500_charger.c | 301 +++++++++++++++++---------------- 5 files changed, 270 insertions(+), 266 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index 58e4cb901076..c8841567dfee 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -160,13 +160,6 @@ #define BTEMP_HIGH_TH_57_1 0x02 #define BTEMP_HIGH_TH_62 0x03 -/* current is mA */ -#define USB_0P1A 100 -#define USB_0P2A 200 -#define USB_0P3A 300 -#define USB_0P4A 400 -#define USB_0P5A 500 - #define LOW_BAT_3P1V 0x20 #define LOW_BAT_2P3V 0x00 #define LOW_BAT_RESET 0x01 @@ -359,22 +352,21 @@ struct ab8500_fg_parameters { /** * struct ab8500_charger_maximization - struct used by the board config. * @use_maxi: Enable maximization for this battery type - * @maxi_chg_curr: Maximum charger current allowed + * @maxi_chg_curr_ua: Maximum charger current allowed in microampere * @maxi_wait_cycles: cycles to wait before setting charger current - * @charger_curr_step delta between two charger current settings (mA) + * @charger_curr_step_ua: delta between two charger current settings (uA) */ struct ab8500_maxim_parameters { bool ena_maxi; - int chg_curr; + int chg_curr_ua; int wait_cycles; - int charger_curr_step; + int charger_curr_step_ua; }; /** * struct ab8500_battery_type - different batteries supported * @resis_high: battery upper resistance limit * @resis_low: battery lower resistance limit - * @normal_cur_lvl: charger current in normal state in mA * @normal_vol_lvl: charger voltage in normal state in mV * @maint_a_cur_lvl: charger current in maintenance A state in mA * @maint_a_vol_lvl: charger voltage in maintenance A state in mV @@ -394,7 +386,6 @@ struct ab8500_maxim_parameters { struct ab8500_battery_type { int resis_high; int resis_low; - int normal_cur_lvl; int normal_vol_lvl; int maint_a_cur_lvl; int maint_a_vol_lvl; @@ -431,15 +422,15 @@ struct ab8500_bm_capacity_levels { /** * struct ab8500_bm_charger_parameters - Charger specific parameters * @usb_volt_max: maximum allowed USB charger voltage in mV - * @usb_curr_max: maximum allowed USB charger current in mA + * @usb_curr_max_ua: maximum allowed USB charger current in uA * @ac_volt_max: maximum allowed AC charger voltage in mV - * @ac_curr_max: maximum allowed AC charger current in mA + * @ac_curr_max_ua: maximum allowed AC charger current in uA */ struct ab8500_bm_charger_parameters { int usb_volt_max; - int usb_curr_max; + int usb_curr_max_ua; int ac_volt_max; - int ac_curr_max; + int ac_curr_max_ua; }; /** diff --git a/drivers/power/supply/ab8500-chargalg.h b/drivers/power/supply/ab8500-chargalg.h index 07e6ff50084f..8094a3c2bd3a 100644 --- a/drivers/power/supply/ab8500-chargalg.h +++ b/drivers/power/supply/ab8500-chargalg.h @@ -32,7 +32,7 @@ struct ux500_charger_ops { * @psy power supply base class * @ops ux500 charger operations * @max_out_volt maximum output charger voltage in mV - * @max_out_curr maximum output charger current in mA + * @max_out_curr_ua maximum output charger current in uA * @enabled indicates if this charger is used or not * @external external charger unit (pm2xxx) */ @@ -40,7 +40,7 @@ struct ux500_charger { struct power_supply *psy; struct ux500_charger_ops ops; int max_out_volt; - int max_out_curr; + int max_out_curr_ua; int wdt_refresh; bool enabled; bool external; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 78182a396de7..e9bbb7517e04 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -83,7 +83,6 @@ static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { static struct ab8500_battery_type bat_type_thermistor_unknown = { .resis_high = 0, .resis_low = 0, - .normal_cur_lvl = 400, .normal_vol_lvl = 4100, .maint_a_cur_lvl = 400, .maint_a_vol_lvl = 4050, @@ -133,16 +132,16 @@ static const struct ab8500_fg_parameters fg = { static const struct ab8500_maxim_parameters ab8500_maxi_params = { .ena_maxi = true, - .chg_curr = 910, + .chg_curr_ua = 910000, .wait_cycles = 10, - .charger_curr_step = 100, + .charger_curr_step_ua = 100000, }; static const struct ab8500_bm_charger_parameters chg = { .usb_volt_max = 5500, - .usb_curr_max = 1500, + .usb_curr_max_ua = 1500000, .ac_volt_max = 7500, - .ac_curr_max = 1500, + .ac_curr_max_ua = 1500000, }; /* This is referenced directly in the charger code */ @@ -201,6 +200,9 @@ int ab8500_bm_of_probe(struct power_supply *psy, bi->overvoltage_limit_uv = 4050000; } + if (bi->constant_charge_current_max_ua < 0) + bi->constant_charge_current_max_ua = 400000; + if (bi->charge_term_current_ua) /* Charging stops when we drop below this current */ bi->charge_term_current_ua = 200000; diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index 90974a8887cd..8ad3924ee496 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -46,8 +46,8 @@ /* Five minutes expressed in seconds */ #define FIVE_MINUTES_IN_SECONDS 300 -#define CHARGALG_CURR_STEP_LOW 0 -#define CHARGALG_CURR_STEP_HIGH 100 +#define CHARGALG_CURR_STEP_LOW_UA 0 +#define CHARGALG_CURR_STEP_HIGH_UA 100000 /* * This is the battery capacity limit that will trigger a new @@ -71,13 +71,13 @@ struct ab8500_chargalg_charger_info { bool usb_chg_ok; bool ac_chg_ok; int usb_volt; - int usb_curr; + int usb_curr_ua; int ac_volt; - int ac_curr; + int ac_curr_ua; int usb_vset; - int usb_iset; + int usb_iset_ua; int ac_vset; - int ac_iset; + int ac_iset_ua; }; struct ab8500_chargalg_suspension_status { @@ -88,14 +88,14 @@ struct ab8500_chargalg_suspension_status { struct ab8500_chargalg_current_step_status { bool curr_step_change; - int curr_step; + int curr_step_ua; }; struct ab8500_chargalg_battery_data { int temp; int volt_uv; int avg_curr_ua; - int inst_curr; + int inst_curr_ua; int percent; }; @@ -184,13 +184,13 @@ struct ab8500_chargalg_events { /** * struct ab8500_charge_curr_maximization - Charger maximization parameters - * @original_iset: the non optimized/maximised charger current - * @current_iset: the charging current used at this moment - * @test_delta_i: the delta between the current we want to charge and the + * @original_iset_ua: the non optimized/maximised charger current + * @current_iset_ua: the charging current used at this moment + * @test_delta_i_ua: the delta between the current we want to charge and the current that is really going into the battery * @condition_cnt: number of iterations needed before a new charger current is set - * @max_current: maximum charger current + * @max_current_ua: maximum charger current * @wait_cnt: to avoid too fast current step down in case of charger * voltage collapse, we insert this delay between step * down @@ -198,11 +198,11 @@ struct ab8500_chargalg_events { increased */ struct ab8500_charge_curr_maximization { - int original_iset; - int current_iset; - int test_delta_i; + int original_iset_ua; + int current_iset_ua; + int test_delta_i_ua; int condition_cnt; - int max_current; + int max_current_ua; int wait_cnt; u8 level; }; @@ -352,6 +352,8 @@ static void ab8500_chargalg_state_to(struct ab8500_chargalg *di, static int ab8500_chargalg_check_charger_enable(struct ab8500_chargalg *di) { + struct power_supply_battery_info *bi = &di->bm->bi; + switch (di->charge_state) { case STATE_NORMAL: case STATE_MAINTENANCE_A: @@ -364,12 +366,12 @@ static int ab8500_chargalg_check_charger_enable(struct ab8500_chargalg *di) if (di->chg_info.charger_type & USB_CHG) { return di->usb_chg->ops.check_enable(di->usb_chg, di->bm->bat_type->normal_vol_lvl, - di->bm->bat_type->normal_cur_lvl); + bi->constant_charge_current_max_ua); } else if ((di->chg_info.charger_type & AC_CHG) && !(di->ac_chg->external)) { return di->ac_chg->ops.check_enable(di->ac_chg, di->bm->bat_type->normal_vol_lvl, - di->bm->bat_type->normal_cur_lvl); + bi->constant_charge_current_max_ua); } return 0; } @@ -545,13 +547,13 @@ static int ab8500_chargalg_kick_watchdog(struct ab8500_chargalg *di) * @di: pointer to the ab8500_chargalg structure * @enable: charger on/off * @vset: requested charger output voltage - * @iset: requested charger output current + * @iset_ua: requested charger output current in microampere * * The AC charger will be turned on/off with the requested charge voltage and * current */ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, - int vset, int iset) + int vset, int iset_ua) { static int ab8500_chargalg_ex_ac_enable_toggle; @@ -561,10 +563,10 @@ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, /* Select maximum of what both the charger and the battery supports */ if (di->ac_chg->max_out_volt) vset = min(vset, di->ac_chg->max_out_volt); - if (di->ac_chg->max_out_curr) - iset = min(iset, di->ac_chg->max_out_curr); + if (di->ac_chg->max_out_curr_ua) + iset_ua = min(iset_ua, di->ac_chg->max_out_curr_ua); - di->chg_info.ac_iset = iset; + di->chg_info.ac_iset_ua = iset_ua; di->chg_info.ac_vset = vset; /* Enable external charger */ @@ -575,7 +577,7 @@ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, ab8500_chargalg_ex_ac_enable_toggle++; } - return di->ac_chg->ops.enable(di->ac_chg, enable, vset, iset); + return di->ac_chg->ops.enable(di->ac_chg, enable, vset, iset_ua); } /** @@ -583,13 +585,13 @@ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, * @di: pointer to the ab8500_chargalg structure * @enable: charger on/off * @vset: requested charger output voltage - * @iset: requested charger output current + * @iset_ua: requested charger output current in microampere * * The USB charger will be turned on/off with the requested charge voltage and * current */ static int ab8500_chargalg_usb_en(struct ab8500_chargalg *di, int enable, - int vset, int iset) + int vset, int iset_ua) { if (!di->usb_chg || !di->usb_chg->ops.enable) return -ENXIO; @@ -597,25 +599,25 @@ static int ab8500_chargalg_usb_en(struct ab8500_chargalg *di, int enable, /* Select maximum of what both the charger and the battery supports */ if (di->usb_chg->max_out_volt) vset = min(vset, di->usb_chg->max_out_volt); - if (di->usb_chg->max_out_curr) - iset = min(iset, di->usb_chg->max_out_curr); + if (di->usb_chg->max_out_curr_ua) + iset_ua = min(iset_ua, di->usb_chg->max_out_curr_ua); - di->chg_info.usb_iset = iset; + di->chg_info.usb_iset_ua = iset_ua; di->chg_info.usb_vset = vset; - return di->usb_chg->ops.enable(di->usb_chg, enable, vset, iset); + return di->usb_chg->ops.enable(di->usb_chg, enable, vset, iset_ua); } /** * ab8500_chargalg_update_chg_curr() - Update charger current * @di: pointer to the ab8500_chargalg structure - * @iset: requested charger output current + * @iset_ua: requested charger output current in microampere * * The charger output current will be updated for the charger * that is currently in use */ static int ab8500_chargalg_update_chg_curr(struct ab8500_chargalg *di, - int iset) + int iset_ua) { /* Check if charger exists and update current if charging */ if (di->ac_chg && di->ac_chg->ops.update_curr && @@ -624,24 +626,24 @@ static int ab8500_chargalg_update_chg_curr(struct ab8500_chargalg *di, * Select maximum of what both the charger * and the battery supports */ - if (di->ac_chg->max_out_curr) - iset = min(iset, di->ac_chg->max_out_curr); + if (di->ac_chg->max_out_curr_ua) + iset_ua = min(iset_ua, di->ac_chg->max_out_curr_ua); - di->chg_info.ac_iset = iset; + di->chg_info.ac_iset_ua = iset_ua; - return di->ac_chg->ops.update_curr(di->ac_chg, iset); + return di->ac_chg->ops.update_curr(di->ac_chg, iset_ua); } else if (di->usb_chg && di->usb_chg->ops.update_curr && di->chg_info.charger_type & USB_CHG) { /* * Select maximum of what both the charger * and the battery supports */ - if (di->usb_chg->max_out_curr) - iset = min(iset, di->usb_chg->max_out_curr); + if (di->usb_chg->max_out_curr_ua) + iset_ua = min(iset_ua, di->usb_chg->max_out_curr_ua); - di->chg_info.usb_iset = iset; + di->chg_info.usb_iset_ua = iset_ua; - return di->usb_chg->ops.update_curr(di->usb_chg, iset); + return di->usb_chg->ops.update_curr(di->usb_chg, iset_ua); } return -ENXIO; @@ -691,27 +693,27 @@ static void ab8500_chargalg_hold_charging(struct ab8500_chargalg *di) * ab8500_chargalg_start_charging() - Start the charger * @di: pointer to the ab8500_chargalg structure * @vset: requested charger output voltage - * @iset: requested charger output current + * @iset_ua: requested charger output current in microampere * * A charger will be enabled depending on the requested charger type that was * detected previously. */ static void ab8500_chargalg_start_charging(struct ab8500_chargalg *di, - int vset, int iset) + int vset, int iset_ua) { switch (di->chg_info.charger_type) { case AC_CHG: dev_dbg(di->dev, - "AC parameters: Vset %d, Ich %d\n", vset, iset); + "AC parameters: Vset %d, Ich %d\n", vset, iset_ua); ab8500_chargalg_usb_en(di, false, 0, 0); - ab8500_chargalg_ac_en(di, true, vset, iset); + ab8500_chargalg_ac_en(di, true, vset, iset_ua); break; case USB_CHG: dev_dbg(di->dev, - "USB parameters: Vset %d, Ich %d\n", vset, iset); + "USB parameters: Vset %d, Ich %d\n", vset, iset_ua); ab8500_chargalg_ac_en(di, false, 0, 0); - ab8500_chargalg_usb_en(di, true, vset, iset); + ab8500_chargalg_usb_en(di, true, vset, iset_ua); break; default: @@ -825,12 +827,12 @@ static void ab8500_chargalg_end_of_charge(struct ab8500_chargalg *di) static void init_maxim_chg_curr(struct ab8500_chargalg *di) { - di->ccm.original_iset = - di->bm->bat_type->normal_cur_lvl; - di->ccm.current_iset = - di->bm->bat_type->normal_cur_lvl; - di->ccm.test_delta_i = di->bm->maxi->charger_curr_step; - di->ccm.max_current = di->bm->maxi->chg_curr; + struct power_supply_battery_info *bi = &di->bm->bi; + + di->ccm.original_iset_ua = bi->constant_charge_current_max_ua; + di->ccm.current_iset_ua = bi->constant_charge_current_max_ua; + di->ccm.test_delta_i_ua = di->bm->maxi->charger_curr_step_ua; + di->ccm.max_current_ua = di->bm->maxi->chg_curr_ua; di->ccm.condition_cnt = di->bm->maxi->wait_cycles; di->ccm.level = 0; } @@ -846,12 +848,12 @@ static void init_maxim_chg_curr(struct ab8500_chargalg *di) */ static enum maxim_ret ab8500_chargalg_chg_curr_maxim(struct ab8500_chargalg *di) { - int delta_i; + int delta_i_ua; if (!di->bm->maxi->ena_maxi) return MAXIM_RET_NOACTION; - delta_i = di->ccm.original_iset - di->batt_data.inst_curr; + delta_i_ua = di->ccm.original_iset_ua - di->batt_data.inst_curr_ua; if (di->events.vbus_collapsed) { dev_dbg(di->dev, "Charger voltage has collapsed %d\n", @@ -860,9 +862,9 @@ static enum maxim_ret ab8500_chargalg_chg_curr_maxim(struct ab8500_chargalg *di) dev_dbg(di->dev, "lowering current\n"); di->ccm.wait_cnt++; di->ccm.condition_cnt = di->bm->maxi->wait_cycles; - di->ccm.max_current = - di->ccm.current_iset - di->ccm.test_delta_i; - di->ccm.current_iset = di->ccm.max_current; + di->ccm.max_current_ua = + di->ccm.current_iset_ua - di->ccm.test_delta_i_ua; + di->ccm.current_iset_ua = di->ccm.max_current_ua; di->ccm.level--; return MAXIM_RET_CHANGE; } else { @@ -875,36 +877,36 @@ static enum maxim_ret ab8500_chargalg_chg_curr_maxim(struct ab8500_chargalg *di) di->ccm.wait_cnt = 0; - if (di->batt_data.inst_curr > di->ccm.original_iset) { - dev_dbg(di->dev, " Maximization Ibat (%dmA) too high" - " (limit %dmA) (current iset: %dmA)!\n", - di->batt_data.inst_curr, di->ccm.original_iset, - di->ccm.current_iset); + if (di->batt_data.inst_curr_ua > di->ccm.original_iset_ua) { + dev_dbg(di->dev, " Maximization Ibat (%duA) too high" + " (limit %duA) (current iset: %duA)!\n", + di->batt_data.inst_curr_ua, di->ccm.original_iset_ua, + di->ccm.current_iset_ua); - if (di->ccm.current_iset == di->ccm.original_iset) + if (di->ccm.current_iset_ua == di->ccm.original_iset_ua) return MAXIM_RET_NOACTION; di->ccm.condition_cnt = di->bm->maxi->wait_cycles; - di->ccm.current_iset = di->ccm.original_iset; + di->ccm.current_iset_ua = di->ccm.original_iset_ua; di->ccm.level = 0; return MAXIM_RET_IBAT_TOO_HIGH; } - if (delta_i > di->ccm.test_delta_i && - (di->ccm.current_iset + di->ccm.test_delta_i) < - di->ccm.max_current) { + if (delta_i_ua > di->ccm.test_delta_i_ua && + (di->ccm.current_iset_ua + di->ccm.test_delta_i_ua) < + di->ccm.max_current_ua) { if (di->ccm.condition_cnt-- == 0) { /* Increse the iset with cco.test_delta_i */ di->ccm.condition_cnt = di->bm->maxi->wait_cycles; - di->ccm.current_iset += di->ccm.test_delta_i; + di->ccm.current_iset_ua += di->ccm.test_delta_i_ua; di->ccm.level++; dev_dbg(di->dev, " Maximization needed, increase" - " with %d mA to %dmA (Optimal ibat: %d)" + " with %d uA to %duA (Optimal ibat: %d uA)" " Level %d\n", - di->ccm.test_delta_i, - di->ccm.current_iset, - di->ccm.original_iset, + di->ccm.test_delta_i_ua, + di->ccm.current_iset_ua, + di->ccm.original_iset_ua, di->ccm.level); return MAXIM_RET_CHANGE; } else { @@ -918,6 +920,7 @@ static enum maxim_ret ab8500_chargalg_chg_curr_maxim(struct ab8500_chargalg *di) static void handle_maxim_chg_curr(struct ab8500_chargalg *di) { + struct power_supply_battery_info *bi = &di->bm->bi; enum maxim_ret ret; int result; @@ -925,13 +928,13 @@ static void handle_maxim_chg_curr(struct ab8500_chargalg *di) switch (ret) { case MAXIM_RET_CHANGE: result = ab8500_chargalg_update_chg_curr(di, - di->ccm.current_iset); + di->ccm.current_iset_ua); if (result) dev_err(di->dev, "failed to set chg curr\n"); break; case MAXIM_RET_IBAT_TOO_HIGH: result = ab8500_chargalg_update_chg_curr(di, - di->bm->bat_type->normal_cur_lvl); + bi->constant_charge_current_max_ua); if (result) dev_err(di->dev, "failed to set chg curr\n"); break; @@ -1226,15 +1229,13 @@ static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data) case POWER_SUPPLY_PROP_CURRENT_NOW: switch (ext->desc->type) { case POWER_SUPPLY_TYPE_MAINS: - di->chg_info.ac_curr = - ret.intval / 1000; - break; + di->chg_info.ac_curr_ua = ret.intval; + break; case POWER_SUPPLY_TYPE_USB: - di->chg_info.usb_curr = - ret.intval / 1000; + di->chg_info.usb_curr_ua = ret.intval; break; case POWER_SUPPLY_TYPE_BATTERY: - di->batt_data.inst_curr = ret.intval / 1000; + di->batt_data.inst_curr_ua = ret.intval; break; default: break; @@ -1298,9 +1299,10 @@ static void ab8500_chargalg_external_power_changed(struct power_supply *psy) */ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) { + struct power_supply_battery_info *bi = &di->bm->bi; int charger_status; int ret; - int curr_step_lvl; + int curr_step_lvl_ua; /* Collect data from all power_supply class devices */ class_for_each_device(power_supply_class, NULL, @@ -1406,7 +1408,7 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) "USB_I %d AC_Vset %d AC_Iset %d USB_Vset %d USB_Iset %d\n", di->batt_data.volt_uv, di->batt_data.avg_curr_ua, - di->batt_data.inst_curr, + di->batt_data.inst_curr_ua, di->batt_data.temp, di->batt_data.percent, di->maintenance_chg, @@ -1419,12 +1421,12 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) di->chg_info.online_chg & USB_CHG, di->events.ac_cv_active, di->events.usb_cv_active, - di->chg_info.ac_curr, - di->chg_info.usb_curr, + di->chg_info.ac_curr_ua, + di->chg_info.usb_curr_ua, di->chg_info.ac_vset, - di->chg_info.ac_iset, + di->chg_info.ac_iset_ua, di->chg_info.usb_vset, - di->chg_info.usb_iset); + di->chg_info.usb_iset_ua); switch (di->charge_state) { case STATE_HANDHELD_INIT: @@ -1509,15 +1511,15 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) break; case STATE_NORMAL_INIT: - if (di->curr_status.curr_step == CHARGALG_CURR_STEP_LOW) + if (di->curr_status.curr_step_ua == CHARGALG_CURR_STEP_LOW_UA) ab8500_chargalg_stop_charging(di); else { - curr_step_lvl = di->bm->bat_type->normal_cur_lvl - * di->curr_status.curr_step - / CHARGALG_CURR_STEP_HIGH; + curr_step_lvl_ua = bi->constant_charge_current_max_ua + * di->curr_status.curr_step_ua + / CHARGALG_CURR_STEP_HIGH_UA; ab8500_chargalg_start_charging(di, di->bm->bat_type->normal_vol_lvl, - curr_step_lvl); + curr_step_lvl_ua); } ab8500_chargalg_state_to(di, STATE_NORMAL); @@ -1743,7 +1745,7 @@ static int ab8500_chargalg_get_property(struct power_supply *psy, static ssize_t ab8500_chargalg_curr_step_show(struct ab8500_chargalg *di, char *buf) { - return sprintf(buf, "%d\n", di->curr_status.curr_step); + return sprintf(buf, "%d\n", di->curr_status.curr_step_ua); } static ssize_t ab8500_chargalg_curr_step_store(struct ab8500_chargalg *di, @@ -1756,9 +1758,9 @@ static ssize_t ab8500_chargalg_curr_step_store(struct ab8500_chargalg *di, if (ret < 0) return ret; - di->curr_status.curr_step = param; - if (di->curr_status.curr_step >= CHARGALG_CURR_STEP_LOW && - di->curr_status.curr_step <= CHARGALG_CURR_STEP_HIGH) { + di->curr_status.curr_step_ua = param; + if (di->curr_status.curr_step_ua >= CHARGALG_CURR_STEP_LOW_UA && + di->curr_status.curr_step_ua <= CHARGALG_CURR_STEP_HIGH_UA) { di->curr_status.curr_step_change = true; queue_work(di->chargalg_wq, &di->chargalg_work); } else @@ -2055,7 +2057,7 @@ static int ab8500_chargalg_probe(struct platform_device *pdev) dev_err(di->dev, "failed to create sysfs entry\n"); return ret; } - di->curr_status.curr_step = CHARGALG_CURR_STEP_HIGH; + di->curr_status.curr_step_ua = CHARGALG_CURR_STEP_HIGH_UA; dev_info(di->dev, "probe success\n"); return component_add(dev, &ab8500_chargalg_component_ops); diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index 7a151cd97399..e66091f3f606 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -145,23 +145,23 @@ enum ab8500_usb_state { AB8500_BM_USB_STATE_MAX, }; -/* VBUS input current limits supported in AB8500 in mA */ -#define USB_CH_IP_CUR_LVL_0P05 50 -#define USB_CH_IP_CUR_LVL_0P09 98 -#define USB_CH_IP_CUR_LVL_0P19 193 -#define USB_CH_IP_CUR_LVL_0P29 290 -#define USB_CH_IP_CUR_LVL_0P38 380 -#define USB_CH_IP_CUR_LVL_0P45 450 -#define USB_CH_IP_CUR_LVL_0P5 500 -#define USB_CH_IP_CUR_LVL_0P6 600 -#define USB_CH_IP_CUR_LVL_0P7 700 -#define USB_CH_IP_CUR_LVL_0P8 800 -#define USB_CH_IP_CUR_LVL_0P9 900 -#define USB_CH_IP_CUR_LVL_1P0 1000 -#define USB_CH_IP_CUR_LVL_1P1 1100 -#define USB_CH_IP_CUR_LVL_1P3 1300 -#define USB_CH_IP_CUR_LVL_1P4 1400 -#define USB_CH_IP_CUR_LVL_1P5 1500 +/* VBUS input current limits supported in AB8500 in uA */ +#define USB_CH_IP_CUR_LVL_0P05 50000 +#define USB_CH_IP_CUR_LVL_0P09 98000 +#define USB_CH_IP_CUR_LVL_0P19 193000 +#define USB_CH_IP_CUR_LVL_0P29 290000 +#define USB_CH_IP_CUR_LVL_0P38 380000 +#define USB_CH_IP_CUR_LVL_0P45 450000 +#define USB_CH_IP_CUR_LVL_0P5 500000 +#define USB_CH_IP_CUR_LVL_0P6 600000 +#define USB_CH_IP_CUR_LVL_0P7 700000 +#define USB_CH_IP_CUR_LVL_0P8 800000 +#define USB_CH_IP_CUR_LVL_0P9 900000 +#define USB_CH_IP_CUR_LVL_1P0 1000000 +#define USB_CH_IP_CUR_LVL_1P1 1100000 +#define USB_CH_IP_CUR_LVL_1P3 1300000 +#define USB_CH_IP_CUR_LVL_1P4 1400000 +#define USB_CH_IP_CUR_LVL_1P5 1500000 #define VBAT_TRESH_IP_CUR_RED 3800 @@ -186,7 +186,7 @@ struct ab8500_charger_info { int charger_voltage; int cv_active; bool wd_expired; - int charger_current; + int charger_current_ua; }; struct ab8500_charger_event_flags { @@ -201,17 +201,17 @@ struct ab8500_charger_event_flags { }; struct ab8500_charger_usb_state { - int usb_current; - int usb_current_tmp; + int usb_current_ua; + int usb_current_tmp_ua; enum ab8500_usb_state state; enum ab8500_usb_state state_tmp; spinlock_t usb_lock; }; struct ab8500_charger_max_usb_in_curr { - int usb_type_max; - int set_max; - int calculated_max; + int usb_type_max_ua; + int set_max_ua; + int calculated_max_ua; }; /** @@ -552,7 +552,7 @@ static int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di) * @di: pointer to the ab8500_charger structure * * This function returns the usb charger current. - * Returns usb current (on success) and error code on failure + * Returns usb current in microamperes (on success) and error code on failure */ static int ab8500_charger_get_usb_current(struct ab8500_charger *di) { @@ -566,7 +566,8 @@ static int ab8500_charger_get_usb_current(struct ab8500_charger *di) } else { ich = 0; } - return ich; + /* Return microamperes */ + return ich * 1000; } /** @@ -574,7 +575,7 @@ static int ab8500_charger_get_usb_current(struct ab8500_charger *di) * @di: pointer to the ab8500_charger structure * * This function returns the ac charger current. - * Returns ac current (on success) and error code on failure. + * Returns ac current in microamperes (on success) and error code on failure. */ static int ab8500_charger_get_ac_current(struct ab8500_charger *di) { @@ -588,7 +589,8 @@ static int ab8500_charger_get_ac_current(struct ab8500_charger *di) } else { ich = 0; } - return ich; + /* Return microamperes */ + return ich * 1000; } /** @@ -711,19 +713,19 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, case USB_STAT_STD_HOST_C_S: dev_dbg(di->dev, "USB Type - Standard host is " "detected through USB driver\n"); - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; di->is_aca_rid = 0; break; case USB_STAT_HOST_CHG_HS_CHIRP: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; di->is_aca_rid = 0; break; case USB_STAT_HOST_CHG_HS: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; di->is_aca_rid = 0; break; case USB_STAT_ACA_RID_C_HS: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P9; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P9; di->is_aca_rid = 0; break; case USB_STAT_ACA_RID_A: @@ -732,7 +734,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, * can consume (900mA). Closest level is 500mA */ dev_dbg(di->dev, "USB_STAT_ACA_RID_A detected\n"); - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; di->is_aca_rid = 1; break; case USB_STAT_ACA_RID_B: @@ -740,36 +742,36 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, * Dedicated charger level minus 120mA (20mA for ACA and * 100mA for potential accessory). Closest level is 1300mA */ - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_1P3; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_1P3; dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status, - di->max_usb_in_curr.usb_type_max); + di->max_usb_in_curr.usb_type_max_ua); di->is_aca_rid = 1; break; case USB_STAT_HOST_CHG_NM: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; di->is_aca_rid = 0; break; case USB_STAT_DEDICATED_CHG: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_1P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_1P5; di->is_aca_rid = 0; break; case USB_STAT_ACA_RID_C_HS_CHIRP: case USB_STAT_ACA_RID_C_NM: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_1P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_1P5; di->is_aca_rid = 1; break; case USB_STAT_NOT_CONFIGURED: if (di->vbus_detected) { di->usb_device_is_unrecognised = true; dev_dbg(di->dev, "USB Type - Legacy charger.\n"); - di->max_usb_in_curr.usb_type_max = + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_1P5; break; } fallthrough; case USB_STAT_HM_IDGND: dev_err(di->dev, "USB Type - Charging not allowed\n"); - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P05; ret = -ENXIO; break; case USB_STAT_RESERVED: @@ -781,11 +783,11 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, break; } else { dev_dbg(di->dev, "USB Type - Charging not allowed\n"); - di->max_usb_in_curr.usb_type_max = + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P05; dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status, - di->max_usb_in_curr.usb_type_max); + di->max_usb_in_curr.usb_type_max_ua); ret = -ENXIO; break; } @@ -793,25 +795,25 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, case USB_STAT_CARKIT_2: case USB_STAT_ACA_DOCK_CHARGER: case USB_STAT_CHARGER_LINE_1: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status, - di->max_usb_in_curr.usb_type_max); + di->max_usb_in_curr.usb_type_max_ua); break; case USB_STAT_NOT_VALID_LINK: dev_err(di->dev, "USB Type invalid - try charging anyway\n"); - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; break; default: dev_err(di->dev, "USB Type - Unknown\n"); - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P05; ret = -ENXIO; break; } - di->max_usb_in_curr.set_max = di->max_usb_in_curr.usb_type_max; + di->max_usb_in_curr.set_max_ua = di->max_usb_in_curr.usb_type_max_ua; dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", - link_status, di->max_usb_in_curr.set_max); + link_status, di->max_usb_in_curr.set_max_ua); return ret; } @@ -1027,51 +1029,51 @@ static int ab8500_voltage_to_regval(int voltage) /* This array maps the raw register value to charger input current */ static int ab8500_charge_input_curr_map[] = { - 50, 98, 193, 290, 380, 450, 500, 600, - 700, 800, 900, 1000, 1100, 1300, 1400, 1500, + 50000, 98000, 193000, 290000, 380000, 450000, 500000, 600000, + 700000, 800000, 900000, 1000000, 1100000, 1300000, 1400000, 1500000, }; /* This array maps the raw register value to charger output current */ static int ab8500_charge_output_curr_map[] = { - 100, 200, 300, 400, 500, 600, 700, 800, - 900, 1000, 1100, 1200, 1300, 1400, 1500, 1500, + 100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, + 900000, 1000000, 1100000, 1200000, 1300000, 1400000, 1500000, 1500000, }; -static int ab8500_current_to_regval(struct ab8500_charger *di, int curr) +static int ab8500_current_to_regval(struct ab8500_charger *di, int curr_ua) { int i; - if (curr < ab8500_charge_output_curr_map[0]) + if (curr_ua < ab8500_charge_output_curr_map[0]) return 0; for (i = 0; i < ARRAY_SIZE(ab8500_charge_output_curr_map); i++) { - if (curr < ab8500_charge_output_curr_map[i]) + if (curr_ua < ab8500_charge_output_curr_map[i]) return i - 1; } /* If not last element, return error */ i = ARRAY_SIZE(ab8500_charge_output_curr_map) - 1; - if (curr == ab8500_charge_output_curr_map[i]) + if (curr_ua == ab8500_charge_output_curr_map[i]) return i; else return -1; } -static int ab8500_vbus_in_curr_to_regval(struct ab8500_charger *di, int curr) +static int ab8500_vbus_in_curr_to_regval(struct ab8500_charger *di, int curr_ua) { int i; - if (curr < ab8500_charge_input_curr_map[0]) + if (curr_ua < ab8500_charge_input_curr_map[0]) return 0; for (i = 0; i < ARRAY_SIZE(ab8500_charge_input_curr_map); i++) { - if (curr < ab8500_charge_input_curr_map[i]) + if (curr_ua < ab8500_charge_input_curr_map[i]) return i - 1; } /* If not last element, return error */ i = ARRAY_SIZE(ab8500_charge_input_curr_map) - 1; - if (curr == ab8500_charge_input_curr_map[i]) + if (curr_ua == ab8500_charge_input_curr_map[i]) return i; else return -1; @@ -1082,35 +1084,35 @@ static int ab8500_vbus_in_curr_to_regval(struct ab8500_charger *di, int curr) * @di: pointer to the ab8500_charger structre * * The usb stack provides the maximum current that can be drawn from - * the standard usb host. This will be in mA. - * This function converts current in mA to a value that can be written + * the standard usb host. This will be in uA. + * This function converts current in uA to a value that can be written * to the register. Returns -1 if charging is not allowed */ static int ab8500_charger_get_usb_cur(struct ab8500_charger *di) { int ret = 0; - switch (di->usb_state.usb_current) { - case 100: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P09; + switch (di->usb_state.usb_current_ua) { + case 100000: + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P09; break; - case 200: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P19; + case 200000: + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P19; break; - case 300: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P29; + case 300000: + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P29; break; - case 400: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P38; + case 400000: + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P38; break; - case 500: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; + case 500000: + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; break; default: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P05; ret = -EPERM; break; } - di->max_usb_in_curr.set_max = di->max_usb_in_curr.usb_type_max; + di->max_usb_in_curr.set_max_ua = di->max_usb_in_curr.usb_type_max_ua; return ret; } @@ -1135,7 +1137,7 @@ static bool ab8500_charger_check_continue_stepping(struct ab8500_charger *di, /** * ab8500_charger_set_current() - set charger current * @di: pointer to the ab8500_charger structure - * @ich: charger current, in mA + * @ich_ua: charger current, in uA * @reg: select what charger register to set * * Set charger current. @@ -1146,7 +1148,7 @@ static bool ab8500_charger_check_continue_stepping(struct ab8500_charger *di, * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_set_current(struct ab8500_charger *di, - int ich, int reg) + int ich_ua, int reg) { int ret = 0; int curr_index, prev_curr_index, shift_value, i; @@ -1167,7 +1169,7 @@ static int ab8500_charger_set_current(struct ab8500_charger *di, case AB8500_MCH_IPT_CURLVL_REG: shift_value = MAIN_CH_INPUT_CURR_SHIFT; prev_curr_index = (reg_value >> shift_value); - curr_index = ab8500_current_to_regval(di, ich); + curr_index = ab8500_current_to_regval(di, ich_ua); step_udelay = STEP_UDELAY; if (!di->ac.charger_connected) no_stepping = true; @@ -1175,7 +1177,7 @@ static int ab8500_charger_set_current(struct ab8500_charger *di, case AB8500_USBCH_IPT_CRNTLVL_REG: shift_value = VBUS_IN_CURR_LIM_SHIFT; prev_curr_index = (reg_value >> shift_value); - curr_index = ab8500_vbus_in_curr_to_regval(di, ich); + curr_index = ab8500_vbus_in_curr_to_regval(di, ich_ua); step_udelay = STEP_UDELAY * 100; if (!di->usb.charger_connected) @@ -1184,7 +1186,7 @@ static int ab8500_charger_set_current(struct ab8500_charger *di, case AB8500_CH_OPT_CRNTLVL_REG: shift_value = 0; prev_curr_index = (reg_value >> shift_value); - curr_index = ab8500_current_to_regval(di, ich); + curr_index = ab8500_current_to_regval(di, ich_ua); step_udelay = STEP_UDELAY; if (curr_index && (curr_index - prev_curr_index) > 1) step_udelay *= 100; @@ -1213,8 +1215,8 @@ static int ab8500_charger_set_current(struct ab8500_charger *di, goto exit_set_current; } - dev_dbg(di->dev, "%s set charger current: %d mA for reg: 0x%02x\n", - __func__, ich, reg); + dev_dbg(di->dev, "%s set charger current: %d uA for reg: 0x%02x\n", + __func__, ich_ua, reg); if (no_stepping) { ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, @@ -1261,31 +1263,31 @@ exit_set_current: /** * ab8500_charger_set_vbus_in_curr() - set VBUS input current limit * @di: pointer to the ab8500_charger structure - * @ich_in: charger input current limit + * @ich_in_ua: charger input current limit in microampere * * Sets the current that can be drawn from the USB host * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, - int ich_in) + int ich_in_ua) { int min_value; int ret; /* We should always use to lowest current limit */ - min_value = min(di->bm->chg_params->usb_curr_max, ich_in); - if (di->max_usb_in_curr.set_max > 0) - min_value = min(di->max_usb_in_curr.set_max, min_value); + min_value = min(di->bm->chg_params->usb_curr_max_ua, ich_in_ua); + if (di->max_usb_in_curr.set_max_ua > 0) + min_value = min(di->max_usb_in_curr.set_max_ua, min_value); - if (di->usb_state.usb_current >= 0) - min_value = min(di->usb_state.usb_current, min_value); + if (di->usb_state.usb_current_ua >= 0) + min_value = min(di->usb_state.usb_current_ua, min_value); switch (min_value) { - case 100: + case 100000: if (di->vbat < VBAT_TRESH_IP_CUR_RED) min_value = USB_CH_IP_CUR_LVL_0P05; break; - case 500: + case 500000: if (di->vbat < VBAT_TRESH_IP_CUR_RED) min_value = USB_CH_IP_CUR_LVL_0P45; break; @@ -1293,7 +1295,7 @@ static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, break; } - dev_info(di->dev, "VBUS input current limit set to %d mA\n", min_value); + dev_info(di->dev, "VBUS input current limit set to %d uA\n", min_value); mutex_lock(&di->usb_ipt_crnt_lock); ret = ab8500_charger_set_current(di, min_value, @@ -1306,30 +1308,30 @@ static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, /** * ab8500_charger_set_main_in_curr() - set main charger input current * @di: pointer to the ab8500_charger structure - * @ich_in: input charger current, in mA + * @ich_in_ua: input charger current, in uA * * Set main charger input current. * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_set_main_in_curr(struct ab8500_charger *di, - int ich_in) + int ich_in_ua) { - return ab8500_charger_set_current(di, ich_in, + return ab8500_charger_set_current(di, ich_in_ua, AB8500_MCH_IPT_CURLVL_REG); } /** * ab8500_charger_set_output_curr() - set charger output current * @di: pointer to the ab8500_charger structure - * @ich_out: output charger current, in mA + * @ich_out_ua: output charger current, in uA * * Set charger output current. * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_set_output_curr(struct ab8500_charger *di, - int ich_out) + int ich_out_ua) { - return ab8500_charger_set_current(di, ich_out, + return ab8500_charger_set_current(di, ich_out_ua, AB8500_CH_OPT_CRNTLVL_REG); } @@ -1381,13 +1383,13 @@ static int ab8500_charger_led_en(struct ab8500_charger *di, int on) * @di: pointer to the ab8500_charger structure * @enable: enable/disable flag * @vset: charging voltage - * @iset: charging current + * @iset_ua: charging current in microampere * * Enable/Disable AC/Mains charging and turns on/off the charging led * respectively. **/ static int ab8500_charger_ac_en(struct ux500_charger *charger, - int enable, int vset, int iset) + int enable, int vset, int iset_ua) { int ret; int volt_index; @@ -1405,7 +1407,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, } /* Enable AC charging */ - dev_dbg(di->dev, "Enable AC: %dmV %dmA\n", vset, iset); + dev_dbg(di->dev, "Enable AC: %dmV %duA\n", vset, iset_ua); /* * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts @@ -1428,9 +1430,9 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, /* Check if the requested voltage or current is valid */ volt_index = ab8500_voltage_to_regval(vset); - curr_index = ab8500_current_to_regval(di, iset); + curr_index = ab8500_current_to_regval(di, iset_ua); input_curr_index = ab8500_current_to_regval(di, - di->bm->chg_params->ac_curr_max); + di->bm->chg_params->ac_curr_max_ua); if (volt_index < 0 || curr_index < 0 || input_curr_index < 0) { dev_err(di->dev, "Charger voltage or current too high, " @@ -1447,14 +1449,14 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, } /* MainChInputCurr: current that can be drawn from the charger*/ ret = ab8500_charger_set_main_in_curr(di, - di->bm->chg_params->ac_curr_max); + di->bm->chg_params->ac_curr_max_ua); if (ret) { dev_err(di->dev, "%s Failed to set MainChInputCurr\n", __func__); return ret; } /* ChOutputCurentLevel: protected output current */ - ret = ab8500_charger_set_output_curr(di, iset); + ret = ab8500_charger_set_output_curr(di, iset_ua); if (ret) { dev_err(di->dev, "%s " "Failed to set ChOutputCurentLevel\n", @@ -1558,13 +1560,13 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, * @di: pointer to the ab8500_charger structure * @enable: enable/disable flag * @vset: charging voltage - * @ich_out: charger output current + * @ich_out_ua: charger output current in microampere * * Enable/Disable USB charging and turns on/off the charging led respectively. * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_usb_en(struct ux500_charger *charger, - int enable, int vset, int ich_out) + int enable, int vset, int ich_out_ua) { int ret; int volt_index; @@ -1600,11 +1602,11 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, } /* Enable USB charging */ - dev_dbg(di->dev, "Enable USB: %dmV %dmA\n", vset, ich_out); + dev_dbg(di->dev, "Enable USB: %d mV %d uA\n", vset, ich_out_ua); /* Check if the requested voltage or current is valid */ volt_index = ab8500_voltage_to_regval(vset); - curr_index = ab8500_current_to_regval(di, ich_out); + curr_index = ab8500_current_to_regval(di, ich_out_ua); if (volt_index < 0 || curr_index < 0) { dev_err(di->dev, "Charger voltage or current too high, " @@ -1645,14 +1647,14 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, /* USBChInputCurr: current that can be drawn from the usb */ ret = ab8500_charger_set_vbus_in_curr(di, - di->max_usb_in_curr.usb_type_max); + di->max_usb_in_curr.usb_type_max_ua); if (ret) { dev_err(di->dev, "setting USBChInputCurr failed\n"); return ret; } /* ChOutputCurentLevel: protected output current */ - ret = ab8500_charger_set_output_curr(di, ich_out); + ret = ab8500_charger_set_output_curr(di, ich_out_ua); if (ret) { dev_err(di->dev, "%s " "Failed to set ChOutputCurentLevel\n", @@ -1739,13 +1741,13 @@ out: * ab8500_charger_usb_check_enable() - enable usb charging * @charger: pointer to the ux500_charger structure * @vset: charging voltage - * @iset: charger output current + * @iset_ua: charger output current in microampere * * Check if the VBUS charger has been disconnected and reconnected without * AB8500 rising an interrupt. Returns 0 on success. */ static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, - int vset, int iset) + int vset, int iset_ua) { u8 usbch_ctrl1 = 0; int ret = 0; @@ -1774,7 +1776,7 @@ static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, return ret; } - ret = ab8500_charger_usb_en(&di->usb_chg, true, vset, iset); + ret = ab8500_charger_usb_en(&di->usb_chg, true, vset, iset_ua); if (ret < 0) { dev_err(di->dev, "Failed to enable VBUS charger %d\n", __LINE__); @@ -1788,13 +1790,13 @@ static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, * ab8500_charger_ac_check_enable() - enable usb charging * @charger: pointer to the ux500_charger structure * @vset: charging voltage - * @iset: charger output current + * @iset_ua: charger output current in micrompere * * Check if the AC charger has been disconnected and reconnected without * AB8500 rising an interrupt. Returns 0 on success. */ static int ab8500_charger_ac_check_enable(struct ux500_charger *charger, - int vset, int iset) + int vset, int iset_ua) { u8 mainch_ctrl1 = 0; int ret = 0; @@ -1824,7 +1826,7 @@ static int ab8500_charger_ac_check_enable(struct ux500_charger *charger, return ret; } - ret = ab8500_charger_ac_en(&di->usb_chg, true, vset, iset); + ret = ab8500_charger_ac_en(&di->usb_chg, true, vset, iset_ua); if (ret < 0) { dev_err(di->dev, "failed to enable AC charger %d\n", __LINE__); @@ -1863,13 +1865,14 @@ static int ab8500_charger_watchdog_kick(struct ux500_charger *charger) /** * ab8500_charger_update_charger_current() - update charger current - * @di: pointer to the ab8500_charger structure + * @charger: pointer to the ab8500_charger structure + * @ich_out_ua: desired output current in microampere * * Update the charger output current for the specified charger * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_update_charger_current(struct ux500_charger *charger, - int ich_out) + int ich_out_ua) { int ret; struct ab8500_charger *di; @@ -1881,7 +1884,7 @@ static int ab8500_charger_update_charger_current(struct ux500_charger *charger, else return -ENXIO; - ret = ab8500_charger_set_output_curr(di, ich_out); + ret = ab8500_charger_set_output_curr(di, ich_out_ua); if (ret) { dev_err(di->dev, "%s " "Failed to set ChOutputCurentLevel\n", @@ -1973,10 +1976,10 @@ static void ab8500_charger_check_vbat_work(struct work_struct *work) di->vbat > VBAT_TRESH_IP_CUR_RED))) { dev_dbg(di->dev, "Vbat did cross threshold, curr: %d, new: %d," - " old: %d\n", di->max_usb_in_curr.usb_type_max, + " old: %d\n", di->max_usb_in_curr.usb_type_max_ua, di->vbat, di->old_vbat); ab8500_charger_set_vbus_in_curr(di, - di->max_usb_in_curr.usb_type_max); + di->max_usb_in_curr.usb_type_max_ua); power_supply_changed(di->usb_chg.psy); } @@ -2257,7 +2260,7 @@ static void ab8500_charger_usb_link_attach_work(struct work_struct *work) /* Update maximum input current if USB enumeration is not detected */ if (!di->usb.charger_online) { ret = ab8500_charger_set_vbus_in_curr(di, - di->max_usb_in_curr.usb_type_max); + di->max_usb_in_curr.usb_type_max_ua); if (ret) return; } @@ -2419,11 +2422,11 @@ static void ab8500_charger_usb_state_changed_work(struct work_struct *work) spin_lock_irqsave(&di->usb_state.usb_lock, flags); di->usb_state.state = di->usb_state.state_tmp; - di->usb_state.usb_current = di->usb_state.usb_current_tmp; + di->usb_state.usb_current_ua = di->usb_state.usb_current_tmp_ua; spin_unlock_irqrestore(&di->usb_state.usb_lock, flags); - dev_dbg(di->dev, "%s USB state: 0x%02x mA: %d\n", - __func__, di->usb_state.state, di->usb_state.usb_current); + dev_dbg(di->dev, "%s USB state: 0x%02x uA: %d\n", + __func__, di->usb_state.state, di->usb_state.usb_current_ua); switch (di->usb_state.state) { case AB8500_BM_USB_STATE_RESET_HS: @@ -2449,7 +2452,7 @@ static void ab8500_charger_usb_state_changed_work(struct work_struct *work) if (!ab8500_charger_get_usb_cur(di)) { /* Update maximum input current */ ret = ab8500_charger_set_vbus_in_curr(di, - di->max_usb_in_curr.usb_type_max); + di->max_usb_in_curr.usb_type_max_ua); if (ret) return; @@ -2669,7 +2672,7 @@ static void ab8500_charger_vbus_drop_end_work(struct work_struct *work) { struct ab8500_charger *di = container_of(work, struct ab8500_charger, vbus_drop_end_work.work); - int ret, curr; + int ret, curr_ua; u8 reg_value; di->flags.vbus_drop_end = false; @@ -2685,30 +2688,30 @@ static void ab8500_charger_vbus_drop_end_work(struct work_struct *work) return; } - curr = ab8500_charge_input_curr_map[ + curr_ua = ab8500_charge_input_curr_map[ reg_value >> AUTO_VBUS_IN_CURR_LIM_SHIFT]; - if (di->max_usb_in_curr.calculated_max != curr) { + if (di->max_usb_in_curr.calculated_max_ua != curr_ua) { /* USB source is collapsing */ - di->max_usb_in_curr.calculated_max = curr; + di->max_usb_in_curr.calculated_max_ua = curr_ua; dev_dbg(di->dev, - "VBUS input current limiting to %d mA\n", - di->max_usb_in_curr.calculated_max); + "VBUS input current limiting to %d uA\n", + di->max_usb_in_curr.calculated_max_ua); } else { /* * USB source can not give more than this amount. * Taking more will collapse the source. */ - di->max_usb_in_curr.set_max = - di->max_usb_in_curr.calculated_max; + di->max_usb_in_curr.set_max_ua = + di->max_usb_in_curr.calculated_max_ua; dev_dbg(di->dev, - "VBUS input current limited to %d mA\n", - di->max_usb_in_curr.set_max); + "VBUS input current limited to %d uA\n", + di->max_usb_in_curr.set_max_ua); } if (di->usb.charger_connected) ab8500_charger_set_vbus_in_curr(di, - di->max_usb_in_curr.usb_type_max); + di->max_usb_in_curr.usb_type_max_ua); } /** @@ -2953,8 +2956,8 @@ static int ab8500_charger_ac_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CURRENT_NOW: ret = ab8500_charger_get_ac_current(di); if (ret >= 0) - di->ac.charger_current = ret; - val->intval = di->ac.charger_current * 1000; + di->ac.charger_current_ua = ret; + val->intval = di->ac.charger_current_ua; break; default: return -EINVAL; @@ -3021,8 +3024,8 @@ static int ab8500_charger_usb_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CURRENT_NOW: ret = ab8500_charger_get_usb_current(di); if (ret >= 0) - di->usb.charger_current = ret; - val->intval = di->usb.charger_current * 1000; + di->usb.charger_current_ua = ret; + val->intval = di->usb.charger_current_ua; break; case POWER_SUPPLY_PROP_CURRENT_AVG: /* @@ -3198,6 +3201,11 @@ static int ab8500_charger_usb_notifier_call(struct notifier_block *nb, struct ab8500_charger *di = container_of(nb, struct ab8500_charger, nb); enum ab8500_usb_state bm_usb_state; + /* + * FIXME: it appears the AB8500 PHY never sends what it should here. + * Fix the PHY driver to properly notify the desired current. + * Also broadcast microampere and not milliampere. + */ unsigned mA = *((unsigned *)power); if (event != USB_EVENT_VBUS) { @@ -3208,7 +3216,7 @@ static int ab8500_charger_usb_notifier_call(struct notifier_block *nb, /* TODO: State is fabricate here. See if charger really needs USB * state or if mA is enough */ - if ((di->usb_state.usb_current == 2) && (mA > 2)) + if ((di->usb_state.usb_current_ua == 2000) && (mA > 2)) bm_usb_state = AB8500_BM_USB_STATE_RESUME; else if (mA == 0) bm_usb_state = AB8500_BM_USB_STATE_RESET_HS; @@ -3224,7 +3232,8 @@ static int ab8500_charger_usb_notifier_call(struct notifier_block *nb, spin_lock(&di->usb_state.usb_lock); di->usb_state.state_tmp = bm_usb_state; - di->usb_state.usb_current_tmp = mA; + /* FIXME: broadcast ua instead, see above */ + di->usb_state.usb_current_tmp_ua = mA * 1000; spin_unlock(&di->usb_state.usb_lock); /* @@ -3514,7 +3523,7 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->ac_chg.ops.update_curr = &ab8500_charger_update_charger_current; di->ac_chg.max_out_volt = ab8500_charger_voltage_map[ ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; - di->ac_chg.max_out_curr = + di->ac_chg.max_out_curr_ua = ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1]; di->ac_chg.wdt_refresh = CHG_WD_INTERVAL; /* @@ -3535,11 +3544,11 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->usb_chg.ops.update_curr = &ab8500_charger_update_charger_current; di->usb_chg.max_out_volt = ab8500_charger_voltage_map[ ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; - di->usb_chg.max_out_curr = + di->usb_chg.max_out_curr_ua = ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1]; di->usb_chg.wdt_refresh = CHG_WD_INTERVAL; di->usb_chg.external = false; - di->usb_state.usb_current = -1; + di->usb_state.usb_current_ua = -1; mutex_init(&di->charger_attached_mutex); -- cgit v1.2.3-59-g8ed1b From bc6e0287140216011b99392fdf687a92707675ad Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:24 +0100 Subject: power: supply: ab8500: Standardize CV voltage The voltage used in the constant voltage phase of the charging exist in struct power_supply_battery_info as constant_charge_voltage_max_uv. Switch the custom property normal_vol_lvl to this and consequentially change everything that relates to this value over to using microvolts rather than millivolts so we align internal representation of current with the power core. Prefix every variable we change with *_uv to indicate the unit everywhere but also to make sure we do not miss any outlier. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 10 +- drivers/power/supply/ab8500-chargalg.h | 4 +- drivers/power/supply/ab8500_bmdata.c | 8 +- drivers/power/supply/ab8500_chargalg.c | 62 +++++----- drivers/power/supply/ab8500_charger.c | 218 +++++++++++++++++---------------- 5 files changed, 152 insertions(+), 150 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index c8841567dfee..febf2dea853b 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -367,7 +367,6 @@ struct ab8500_maxim_parameters { * struct ab8500_battery_type - different batteries supported * @resis_high: battery upper resistance limit * @resis_low: battery lower resistance limit - * @normal_vol_lvl: charger voltage in normal state in mV * @maint_a_cur_lvl: charger current in maintenance A state in mA * @maint_a_vol_lvl: charger voltage in maintenance A state in mV * @maint_a_chg_timer_h: charge time in maintenance A state @@ -386,7 +385,6 @@ struct ab8500_maxim_parameters { struct ab8500_battery_type { int resis_high; int resis_low; - int normal_vol_lvl; int maint_a_cur_lvl; int maint_a_vol_lvl; int maint_a_chg_timer_h; @@ -421,15 +419,15 @@ struct ab8500_bm_capacity_levels { /** * struct ab8500_bm_charger_parameters - Charger specific parameters - * @usb_volt_max: maximum allowed USB charger voltage in mV + * @usb_volt_max_uv: maximum allowed USB charger voltage in uV * @usb_curr_max_ua: maximum allowed USB charger current in uA - * @ac_volt_max: maximum allowed AC charger voltage in mV + * @ac_volt_max_uv: maximum allowed AC charger voltage in uV * @ac_curr_max_ua: maximum allowed AC charger current in uA */ struct ab8500_bm_charger_parameters { - int usb_volt_max; + int usb_volt_max_uv; int usb_curr_max_ua; - int ac_volt_max; + int ac_volt_max_uv; int ac_curr_max_ua; }; diff --git a/drivers/power/supply/ab8500-chargalg.h b/drivers/power/supply/ab8500-chargalg.h index 8094a3c2bd3a..f47a0061c36a 100644 --- a/drivers/power/supply/ab8500-chargalg.h +++ b/drivers/power/supply/ab8500-chargalg.h @@ -31,7 +31,7 @@ struct ux500_charger_ops { * struct ux500_charger - power supply ux500 charger sub class * @psy power supply base class * @ops ux500 charger operations - * @max_out_volt maximum output charger voltage in mV + * @max_out_volt_uv maximum output charger voltage in uV * @max_out_curr_ua maximum output charger current in uA * @enabled indicates if this charger is used or not * @external external charger unit (pm2xxx) @@ -39,7 +39,7 @@ struct ux500_charger_ops { struct ux500_charger { struct power_supply *psy; struct ux500_charger_ops ops; - int max_out_volt; + int max_out_volt_uv; int max_out_curr_ua; int wdt_refresh; bool enabled; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index e9bbb7517e04..ce0a5fcb3177 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -83,7 +83,6 @@ static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { static struct ab8500_battery_type bat_type_thermistor_unknown = { .resis_high = 0, .resis_low = 0, - .normal_vol_lvl = 4100, .maint_a_cur_lvl = 400, .maint_a_vol_lvl = 4050, .maint_a_chg_timer_h = 60, @@ -138,9 +137,9 @@ static const struct ab8500_maxim_parameters ab8500_maxi_params = { }; static const struct ab8500_bm_charger_parameters chg = { - .usb_volt_max = 5500, + .usb_volt_max_uv = 5500000, .usb_curr_max_ua = 1500000, - .ac_volt_max = 7500, + .ac_volt_max_uv = 7500000, .ac_curr_max_ua = 1500000, }; @@ -203,6 +202,9 @@ int ab8500_bm_of_probe(struct power_supply *psy, if (bi->constant_charge_current_max_ua < 0) bi->constant_charge_current_max_ua = 400000; + if (bi->constant_charge_voltage_max_uv < 0) + bi->constant_charge_voltage_max_uv = 4100000; + if (bi->charge_term_current_ua) /* Charging stops when we drop below this current */ bi->charge_term_current_ua = 200000; diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index 8ad3924ee496..86d740ce3a63 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -70,13 +70,13 @@ struct ab8500_chargalg_charger_info { enum ab8500_chargers charger_type; bool usb_chg_ok; bool ac_chg_ok; - int usb_volt; + int usb_volt_uv; int usb_curr_ua; - int ac_volt; + int ac_volt_uv; int ac_curr_ua; - int usb_vset; + int usb_vset_uv; int usb_iset_ua; - int ac_vset; + int ac_vset_uv; int ac_iset_ua; }; @@ -365,12 +365,12 @@ static int ab8500_chargalg_check_charger_enable(struct ab8500_chargalg *di) if (di->chg_info.charger_type & USB_CHG) { return di->usb_chg->ops.check_enable(di->usb_chg, - di->bm->bat_type->normal_vol_lvl, + bi->constant_charge_voltage_max_uv, bi->constant_charge_current_max_ua); } else if ((di->chg_info.charger_type & AC_CHG) && !(di->ac_chg->external)) { return di->ac_chg->ops.check_enable(di->ac_chg, - di->bm->bat_type->normal_vol_lvl, + bi->constant_charge_voltage_max_uv, bi->constant_charge_current_max_ua); } return 0; @@ -546,14 +546,14 @@ static int ab8500_chargalg_kick_watchdog(struct ab8500_chargalg *di) * ab8500_chargalg_ac_en() - Turn on/off the AC charger * @di: pointer to the ab8500_chargalg structure * @enable: charger on/off - * @vset: requested charger output voltage + * @vset_uv: requested charger output voltage in microvolt * @iset_ua: requested charger output current in microampere * * The AC charger will be turned on/off with the requested charge voltage and * current */ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, - int vset, int iset_ua) + int vset_uv, int iset_ua) { static int ab8500_chargalg_ex_ac_enable_toggle; @@ -561,13 +561,13 @@ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, return -ENXIO; /* Select maximum of what both the charger and the battery supports */ - if (di->ac_chg->max_out_volt) - vset = min(vset, di->ac_chg->max_out_volt); + if (di->ac_chg->max_out_volt_uv) + vset_uv = min(vset_uv, di->ac_chg->max_out_volt_uv); if (di->ac_chg->max_out_curr_ua) iset_ua = min(iset_ua, di->ac_chg->max_out_curr_ua); di->chg_info.ac_iset_ua = iset_ua; - di->chg_info.ac_vset = vset; + di->chg_info.ac_vset_uv = vset_uv; /* Enable external charger */ if (enable && di->ac_chg->external && @@ -577,35 +577,35 @@ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, ab8500_chargalg_ex_ac_enable_toggle++; } - return di->ac_chg->ops.enable(di->ac_chg, enable, vset, iset_ua); + return di->ac_chg->ops.enable(di->ac_chg, enable, vset_uv, iset_ua); } /** * ab8500_chargalg_usb_en() - Turn on/off the USB charger * @di: pointer to the ab8500_chargalg structure * @enable: charger on/off - * @vset: requested charger output voltage + * @vset_uv: requested charger output voltage in microvolt * @iset_ua: requested charger output current in microampere * * The USB charger will be turned on/off with the requested charge voltage and * current */ static int ab8500_chargalg_usb_en(struct ab8500_chargalg *di, int enable, - int vset, int iset_ua) + int vset_uv, int iset_ua) { if (!di->usb_chg || !di->usb_chg->ops.enable) return -ENXIO; /* Select maximum of what both the charger and the battery supports */ - if (di->usb_chg->max_out_volt) - vset = min(vset, di->usb_chg->max_out_volt); + if (di->usb_chg->max_out_volt_uv) + vset_uv = min(vset_uv, di->usb_chg->max_out_volt_uv); if (di->usb_chg->max_out_curr_ua) iset_ua = min(iset_ua, di->usb_chg->max_out_curr_ua); di->chg_info.usb_iset_ua = iset_ua; - di->chg_info.usb_vset = vset; + di->chg_info.usb_vset_uv = vset_uv; - return di->usb_chg->ops.enable(di->usb_chg, enable, vset, iset_ua); + return di->usb_chg->ops.enable(di->usb_chg, enable, vset_uv, iset_ua); } /** @@ -692,28 +692,28 @@ static void ab8500_chargalg_hold_charging(struct ab8500_chargalg *di) /** * ab8500_chargalg_start_charging() - Start the charger * @di: pointer to the ab8500_chargalg structure - * @vset: requested charger output voltage + * @vset_uv: requested charger output voltage in microvolt * @iset_ua: requested charger output current in microampere * * A charger will be enabled depending on the requested charger type that was * detected previously. */ static void ab8500_chargalg_start_charging(struct ab8500_chargalg *di, - int vset, int iset_ua) + int vset_uv, int iset_ua) { switch (di->chg_info.charger_type) { case AC_CHG: dev_dbg(di->dev, - "AC parameters: Vset %d, Ich %d\n", vset, iset_ua); + "AC parameters: Vset %d, Ich %d\n", vset_uv, iset_ua); ab8500_chargalg_usb_en(di, false, 0, 0); - ab8500_chargalg_ac_en(di, true, vset, iset_ua); + ab8500_chargalg_ac_en(di, true, vset_uv, iset_ua); break; case USB_CHG: dev_dbg(di->dev, - "USB parameters: Vset %d, Ich %d\n", vset, iset_ua); + "USB parameters: Vset %d, Ich %d\n", vset_uv, iset_ua); ab8500_chargalg_ac_en(di, false, 0, 0); - ab8500_chargalg_usb_en(di, true, vset, iset_ua); + ab8500_chargalg_usb_en(di, true, vset_uv, iset_ua); break; default: @@ -777,12 +777,12 @@ static void ab8500_chargalg_check_temp(struct ab8500_chargalg *di) */ static void ab8500_chargalg_check_charger_voltage(struct ab8500_chargalg *di) { - if (di->chg_info.usb_volt > di->bm->chg_params->usb_volt_max) + if (di->chg_info.usb_volt_uv > di->bm->chg_params->usb_volt_max_uv) di->chg_info.usb_chg_ok = false; else di->chg_info.usb_chg_ok = true; - if (di->chg_info.ac_volt > di->bm->chg_params->ac_volt_max) + if (di->chg_info.ac_volt_uv > di->bm->chg_params->ac_volt_max_uv) di->chg_info.ac_chg_ok = false; else di->chg_info.ac_chg_ok = true; @@ -1173,10 +1173,10 @@ static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data) di->batt_data.volt_uv = ret.intval; break; case POWER_SUPPLY_TYPE_MAINS: - di->chg_info.ac_volt = ret.intval / 1000; + di->chg_info.ac_volt_uv = ret.intval; break; case POWER_SUPPLY_TYPE_USB: - di->chg_info.usb_volt = ret.intval / 1000; + di->chg_info.usb_volt_uv = ret.intval; break; default: break; @@ -1423,9 +1423,9 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) di->events.usb_cv_active, di->chg_info.ac_curr_ua, di->chg_info.usb_curr_ua, - di->chg_info.ac_vset, + di->chg_info.ac_vset_uv, di->chg_info.ac_iset_ua, - di->chg_info.usb_vset, + di->chg_info.usb_vset_uv, di->chg_info.usb_iset_ua); switch (di->charge_state) { @@ -1518,7 +1518,7 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) * di->curr_status.curr_step_ua / CHARGALG_CURR_STEP_HIGH_UA; ab8500_chargalg_start_charging(di, - di->bm->bat_type->normal_vol_lvl, + bi->constant_charge_voltage_max_uv, curr_step_lvl_ua); } diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index e66091f3f606..db7457064a17 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -183,7 +183,7 @@ struct ab8500_charger_interrupts { struct ab8500_charger_info { int charger_connected; int charger_online; - int charger_voltage; + int charger_voltage_uv; int cv_active; bool wd_expired; int charger_current_ua; @@ -479,7 +479,7 @@ static void ab8500_charger_set_usb_connected(struct ab8500_charger *di, * ab8500_charger_get_ac_voltage() - get ac charger voltage * @di: pointer to the ab8500_charger structure * - * Returns ac charger voltage (on success) + * Returns ac charger voltage in microvolt (on success) */ static int ab8500_charger_get_ac_voltage(struct ab8500_charger *di) { @@ -493,7 +493,8 @@ static int ab8500_charger_get_ac_voltage(struct ab8500_charger *di) } else { vch = 0; } - return vch; + /* Convert to microvolt, IIO returns millivolt */ + return vch * 1000; } /** @@ -530,7 +531,7 @@ static int ab8500_charger_ac_cv(struct ab8500_charger *di) * @di: pointer to the ab8500_charger structure * * This function returns the vbus voltage. - * Returns vbus voltage (on success) + * Returns vbus voltage in microvolt (on success) */ static int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di) { @@ -544,7 +545,8 @@ static int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di) } else { vch = 0; } - return vch; + /* Convert to microvolt, IIO returns millivolt */ + return vch * 1000; } /** @@ -923,105 +925,105 @@ static int ab8500_charger_detect_usb_type(struct ab8500_charger *di) /* * This array maps the raw hex value to charger voltage used by the AB8500 - * Values taken from the UM0836 + * Values taken from the UM0836, in microvolt. */ static int ab8500_charger_voltage_map[] = { - 3500 , - 3525 , - 3550 , - 3575 , - 3600 , - 3625 , - 3650 , - 3675 , - 3700 , - 3725 , - 3750 , - 3775 , - 3800 , - 3825 , - 3850 , - 3875 , - 3900 , - 3925 , - 3950 , - 3975 , - 4000 , - 4025 , - 4050 , - 4060 , - 4070 , - 4080 , - 4090 , - 4100 , - 4110 , - 4120 , - 4130 , - 4140 , - 4150 , - 4160 , - 4170 , - 4180 , - 4190 , - 4200 , - 4210 , - 4220 , - 4230 , - 4240 , - 4250 , - 4260 , - 4270 , - 4280 , - 4290 , - 4300 , - 4310 , - 4320 , - 4330 , - 4340 , - 4350 , - 4360 , - 4370 , - 4380 , - 4390 , - 4400 , - 4410 , - 4420 , - 4430 , - 4440 , - 4450 , - 4460 , - 4470 , - 4480 , - 4490 , - 4500 , - 4510 , - 4520 , - 4530 , - 4540 , - 4550 , - 4560 , - 4570 , - 4580 , - 4590 , - 4600 , + 3500000, + 3525000, + 3550000, + 3575000, + 3600000, + 3625000, + 3650000, + 3675000, + 3700000, + 3725000, + 3750000, + 3775000, + 3800000, + 3825000, + 3850000, + 3875000, + 3900000, + 3925000, + 3950000, + 3975000, + 4000000, + 4025000, + 4050000, + 4060000, + 4070000, + 4080000, + 4090000, + 4100000, + 4110000, + 4120000, + 4130000, + 4140000, + 4150000, + 4160000, + 4170000, + 4180000, + 4190000, + 4200000, + 4210000, + 4220000, + 4230000, + 4240000, + 4250000, + 4260000, + 4270000, + 4280000, + 4290000, + 4300000, + 4310000, + 4320000, + 4330000, + 4340000, + 4350000, + 4360000, + 4370000, + 4380000, + 4390000, + 4400000, + 4410000, + 4420000, + 4430000, + 4440000, + 4450000, + 4460000, + 4470000, + 4480000, + 4490000, + 4500000, + 4510000, + 4520000, + 4530000, + 4540000, + 4550000, + 4560000, + 4570000, + 4580000, + 4590000, + 4600000, }; -static int ab8500_voltage_to_regval(int voltage) +static int ab8500_voltage_to_regval(int voltage_uv) { int i; /* Special case for voltage below 3.5V */ - if (voltage < ab8500_charger_voltage_map[0]) + if (voltage_uv < ab8500_charger_voltage_map[0]) return LOW_VOLT_REG; for (i = 1; i < ARRAY_SIZE(ab8500_charger_voltage_map); i++) { - if (voltage < ab8500_charger_voltage_map[i]) + if (voltage_uv < ab8500_charger_voltage_map[i]) return i - 1; } /* If not last element, return error */ i = ARRAY_SIZE(ab8500_charger_voltage_map) - 1; - if (voltage == ab8500_charger_voltage_map[i]) + if (voltage_uv == ab8500_charger_voltage_map[i]) return i; else return -1; @@ -1382,14 +1384,14 @@ static int ab8500_charger_led_en(struct ab8500_charger *di, int on) * ab8500_charger_ac_en() - enable or disable ac charging * @di: pointer to the ab8500_charger structure * @enable: enable/disable flag - * @vset: charging voltage + * @vset_uv: charging voltage in microvolt * @iset_ua: charging current in microampere * * Enable/Disable AC/Mains charging and turns on/off the charging led * respectively. **/ static int ab8500_charger_ac_en(struct ux500_charger *charger, - int enable, int vset, int iset_ua) + int enable, int vset_uv, int iset_ua) { int ret; int volt_index; @@ -1407,7 +1409,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, } /* Enable AC charging */ - dev_dbg(di->dev, "Enable AC: %dmV %duA\n", vset, iset_ua); + dev_dbg(di->dev, "Enable AC: %duV %duA\n", vset_uv, iset_ua); /* * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts @@ -1429,7 +1431,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, } /* Check if the requested voltage or current is valid */ - volt_index = ab8500_voltage_to_regval(vset); + volt_index = ab8500_voltage_to_regval(vset_uv); curr_index = ab8500_current_to_regval(di, iset_ua); input_curr_index = ab8500_current_to_regval(di, di->bm->chg_params->ac_curr_max_ua); @@ -1559,14 +1561,14 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, * ab8500_charger_usb_en() - enable usb charging * @di: pointer to the ab8500_charger structure * @enable: enable/disable flag - * @vset: charging voltage + * @vset_uv: charging voltage in microvolt * @ich_out_ua: charger output current in microampere * * Enable/Disable USB charging and turns on/off the charging led respectively. * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_usb_en(struct ux500_charger *charger, - int enable, int vset, int ich_out_ua) + int enable, int vset_uv, int ich_out_ua) { int ret; int volt_index; @@ -1602,10 +1604,10 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, } /* Enable USB charging */ - dev_dbg(di->dev, "Enable USB: %d mV %d uA\n", vset, ich_out_ua); + dev_dbg(di->dev, "Enable USB: %d uV %d uA\n", vset_uv, ich_out_ua); /* Check if the requested voltage or current is valid */ - volt_index = ab8500_voltage_to_regval(vset); + volt_index = ab8500_voltage_to_regval(vset_uv); curr_index = ab8500_current_to_regval(di, ich_out_ua); if (volt_index < 0 || curr_index < 0) { dev_err(di->dev, @@ -1740,14 +1742,14 @@ out: /** * ab8500_charger_usb_check_enable() - enable usb charging * @charger: pointer to the ux500_charger structure - * @vset: charging voltage + * @vset_uv: charging voltage in microvolt * @iset_ua: charger output current in microampere * * Check if the VBUS charger has been disconnected and reconnected without * AB8500 rising an interrupt. Returns 0 on success. */ static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, - int vset, int iset_ua) + int vset_uv, int iset_ua) { u8 usbch_ctrl1 = 0; int ret = 0; @@ -1776,7 +1778,7 @@ static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, return ret; } - ret = ab8500_charger_usb_en(&di->usb_chg, true, vset, iset_ua); + ret = ab8500_charger_usb_en(&di->usb_chg, true, vset_uv, iset_ua); if (ret < 0) { dev_err(di->dev, "Failed to enable VBUS charger %d\n", __LINE__); @@ -1789,14 +1791,14 @@ static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, /** * ab8500_charger_ac_check_enable() - enable usb charging * @charger: pointer to the ux500_charger structure - * @vset: charging voltage + * @vset_uv: charging voltage in microvolt * @iset_ua: charger output current in micrompere * * Check if the AC charger has been disconnected and reconnected without * AB8500 rising an interrupt. Returns 0 on success. */ static int ab8500_charger_ac_check_enable(struct ux500_charger *charger, - int vset, int iset_ua) + int vset_uv, int iset_ua) { u8 mainch_ctrl1 = 0; int ret = 0; @@ -1826,7 +1828,7 @@ static int ab8500_charger_ac_check_enable(struct ux500_charger *charger, return ret; } - ret = ab8500_charger_ac_en(&di->usb_chg, true, vset, iset_ua); + ret = ab8500_charger_ac_en(&di->usb_chg, true, vset_uv, iset_ua); if (ret < 0) { dev_err(di->dev, "failed to enable AC charger %d\n", __LINE__); @@ -2941,9 +2943,9 @@ static int ab8500_charger_ac_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_NOW: ret = ab8500_charger_get_ac_voltage(di); if (ret >= 0) - di->ac.charger_voltage = ret; + di->ac.charger_voltage_uv = ret; /* On error, use previous value */ - val->intval = di->ac.charger_voltage * 1000; + val->intval = di->ac.charger_voltage_uv; break; case POWER_SUPPLY_PROP_VOLTAGE_AVG: /* @@ -3010,8 +3012,8 @@ static int ab8500_charger_usb_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_NOW: ret = ab8500_charger_get_vbus_voltage(di); if (ret >= 0) - di->usb.charger_voltage = ret; - val->intval = di->usb.charger_voltage * 1000; + di->usb.charger_voltage_uv = ret; + val->intval = di->usb.charger_voltage_uv; break; case POWER_SUPPLY_PROP_VOLTAGE_AVG: /* @@ -3521,7 +3523,7 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->ac_chg.ops.check_enable = &ab8500_charger_ac_check_enable; di->ac_chg.ops.kick_wd = &ab8500_charger_watchdog_kick; di->ac_chg.ops.update_curr = &ab8500_charger_update_charger_current; - di->ac_chg.max_out_volt = ab8500_charger_voltage_map[ + di->ac_chg.max_out_volt_uv = ab8500_charger_voltage_map[ ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; di->ac_chg.max_out_curr_ua = ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1]; @@ -3542,7 +3544,7 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->usb_chg.ops.check_enable = &ab8500_charger_usb_check_enable; di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick; di->usb_chg.ops.update_curr = &ab8500_charger_update_charger_current; - di->usb_chg.max_out_volt = ab8500_charger_voltage_map[ + di->usb_chg.max_out_volt_uv = ab8500_charger_voltage_map[ ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; di->usb_chg.max_out_curr_ua = ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1]; -- cgit v1.2.3-59-g8ed1b From 67acb291f3b6636cc52a3f859c91c05688992a15 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:25 +0100 Subject: power: supply: ab8500: Standardize temp res lookup The lookup from battery temperature to internal resistance was using its own format. Rewrite this to use the table inside struct power_supply_battery_info:s resist_table. The supplied resistance table has to be rewritten to express the resistance in percent of the factory resistance as a side effect. We can then rely on the library function power_supply_temp2resist_simple() to interpolate the internal resistance percent from the temperature. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 15 ------------ drivers/power/supply/ab8500_bmdata.c | 31 +++++++++++++++--------- drivers/power/supply/ab8500_fg.c | 47 +++++++++++++++--------------------- 3 files changed, 38 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index febf2dea853b..af52539a7a7b 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -379,8 +379,6 @@ struct ab8500_maxim_parameters { * @r_to_t_tbl: table containing resistance to temp points * @n_v_cap_tbl_elements: number of elements in v_to_cap_tbl * @v_to_cap_tbl: Voltage to capacity (in %) table - * @n_batres_tbl_elements number of elements in the batres_tbl - * @batres_tbl battery internal resistance vs temperature table */ struct ab8500_battery_type { int resis_high; @@ -397,8 +395,6 @@ struct ab8500_battery_type { const struct ab8500_res_to_temp *r_to_t_tbl; int n_v_cap_tbl_elements; const struct ab8500_v_to_cap *v_to_cap_tbl; - int n_batres_tbl_elements; - const struct batres_vs_temp *batres_tbl; }; /** @@ -502,17 +498,6 @@ struct res_to_temp { int resist; }; -/** - * struct batres_vs_temp - defines one point in a temp vs battery internal - * resistance curve. - * @temp: battery pack temperature in Celsius - * @resist: battery internal reistance in mOhm - */ -struct batres_vs_temp { - int temp; - int resist; -}; - /* Forward declaration */ struct ab8500_fg; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index ce0a5fcb3177..1175532fe017 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -67,16 +67,17 @@ static const struct ab8500_res_to_temp temp_tbl[] = { /* * Note that the batres_vs_temp table must be strictly sorted by falling - * temperature values to work. + * temperature values to work. Factory resistance is 300 mOhm and the + * resistance values to the right are percentages of 300 mOhm. */ -static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { - { 40, 120}, - { 30, 135}, - { 20, 165}, - { 10, 230}, - { 00, 325}, - {-10, 445}, - {-20, 595}, +static struct power_supply_resistance_temp_table temp_to_batres_tbl_thermistor[] = { + { .temp = 40, .resistance = 40 /* 120 mOhm */ }, + { .temp = 30, .resistance = 45 /* 135 mOhm */ }, + { .temp = 20, .resistance = 55 /* 165 mOhm */ }, + { .temp = 10, .resistance = 77 /* 230 mOhm */ }, + { .temp = 00, .resistance = 108 /* 325 mOhm */ }, + { .temp = -10, .resistance = 158 /* 445 mOhm */ }, + { .temp = -20, .resistance = 198 /* 595 mOhm */ }, }; /* Default battery type for reference designs is the unknown type */ @@ -95,8 +96,6 @@ static struct ab8500_battery_type bat_type_thermistor_unknown = { .r_to_t_tbl = temp_tbl, .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), .v_to_cap_tbl = cap_tbl, - .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), - .batres_tbl = temp_to_batres_tbl_thermistor, }; static const struct ab8500_bm_capacity_levels cap_levels = { @@ -209,8 +208,16 @@ int ab8500_bm_of_probe(struct power_supply *psy, /* Charging stops when we drop below this current */ bi->charge_term_current_ua = 200000; - if (bi->factory_internal_resistance_uohm < 0) + /* + * Internal resistance and factory resistance are tightly coupled + * so both MUST be defined or we fall back to defaults. + */ + if ((bi->factory_internal_resistance_uohm < 0) || + !bi->resist_table) { bi->factory_internal_resistance_uohm = 300000; + bi->resist_table = temp_to_batres_tbl_thermistor; + bi->resist_table_size = ARRAY_SIZE(temp_to_batres_tbl_thermistor); + } if (bi->temp_min == INT_MIN) bi->temp_min = AB8500_TEMP_UNDER; diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index daa008138b05..96bb81e539f0 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -901,44 +901,35 @@ static int ab8500_fg_uncomp_volt_to_capacity(struct ab8500_fg *di) * @di: pointer to the ab8500_fg structure * * Returns battery inner resistance added with the fuel gauge resistor value - * to get the total resistance in the whole link from gnd to bat+ node. + * to get the total resistance in the whole link from gnd to bat+ node + * in milliohm. */ static int ab8500_fg_battery_resistance(struct ab8500_fg *di) { - int i, tbl_size; - const struct batres_vs_temp *tbl; - int resist = 0; - - tbl = di->bm->bat_type->batres_tbl; - tbl_size = di->bm->bat_type->n_batres_tbl_elements; - - for (i = 0; i < tbl_size; ++i) { - if (di->bat_temp / 10 > tbl[i].temp) - break; - } + struct power_supply_battery_info *bi = &di->bm->bi; + int resistance_percent = 0; + int resistance; - if ((i > 0) && (i < tbl_size)) { - resist = fixp_linear_interpolate( - tbl[i].temp, - tbl[i].resist, - tbl[i-1].temp, - tbl[i-1].resist, - di->bat_temp / 10); - } else if (i == 0) { - resist = tbl[0].resist; - } else { - resist = tbl[tbl_size - 1].resist; - } + resistance_percent = power_supply_temp2resist_simple(bi->resist_table, + bi->resist_table_size, + di->bat_temp / 10); + /* + * We get a percentage of factory resistance here so first get + * the factory resistance in milliohms then calculate how much + * resistance we have at this temperature. + */ + resistance = (bi->factory_internal_resistance_uohm / 1000); + resistance = resistance * resistance_percent / 100; dev_dbg(di->dev, "%s Temp: %d battery internal resistance: %d" " fg resistance %d, total: %d (mOhm)\n", - __func__, di->bat_temp, resist, di->bm->fg_res / 10, - (di->bm->fg_res / 10) + resist); + __func__, di->bat_temp, resistance, di->bm->fg_res / 10, + (di->bm->fg_res / 10) + resistance); /* fg_res variable is in 0.1mOhm */ - resist += di->bm->fg_res / 10; + resistance += di->bm->fg_res / 10; - return resist; + return resistance; } /** -- cgit v1.2.3-59-g8ed1b From 0525f34d02758b801619d5e7093003e66a7efe3c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:26 +0100 Subject: power: supply: ab8500: Standardize capacity lookup The AB8500 charger only has one capacity table with unspecified temperature, so we assume this capacity is given for 20 degrees Celsius. Convert this table to use the OCV (open circuit voltage) tables in struct power_supply_battery_ocv_table. In the process, convert the fuel gauge driver to use microvolts and microamperes so we can use the same internals as the power supply subsystem without having to multiply and divide with 1000 in a few places. Also convert high_curr_threshold and lowbat_threshold to use microamperes and microvolts as these are closely related to these changes. Drop the unused overbat_threshold member in the custom struct ab8500_fg_parameters. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 30 +--- drivers/power/supply/ab8500_bmdata.c | 63 ++++---- drivers/power/supply/ab8500_fg.c | 286 ++++++++++++++++------------------- 3 files changed, 173 insertions(+), 206 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index af52539a7a7b..57e1a8e27e51 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -196,8 +196,8 @@ enum bup_vch_sel { #define BATT_OVV_TH_3P7 0x00 #define BATT_OVV_TH_4P75 0x01 -/* A value to indicate over voltage */ -#define BATT_OVV_VALUE 4750 +/* A value to indicate over voltage (microvolts) */ +#define BATT_OVV_VALUE 4750000 /* VBUS OVV constants */ #define VBUS_OVV_SELECT_MASK 0x78 @@ -284,16 +284,6 @@ struct ab8500_res_to_temp { int resist; }; -/** - * struct ab8500_v_to_cap - Table for translating voltage to capacity - * @voltage: Voltage in mV - * @capacity: Capacity in percent - */ -struct ab8500_v_to_cap { - int voltage; - int capacity; -}; - /* Forward declaration */ struct ab8500_fg; @@ -307,10 +297,9 @@ struct ab8500_fg; * @init_total_time: Total init time during startup * @high_curr_time: Time current has to be high to go to recovery * @accu_charging: FG accumulation time while charging - * @accu_high_curr: FG accumulation time in high current mode - * @high_curr_threshold: High current threshold, in mA - * @lowbat_threshold: Low battery threshold, in mV - * @overbat_threshold: Over battery threshold, in mV + * @accu_high_curr_ua: FG accumulation time in high current mode + * @high_curr_threshold_ua: High current threshold, in uA + * @lowbat_threshold_uv: Low battery threshold, in uV * @battok_falling_th_sel0 Threshold in mV for battOk signal sel0 * Resolution in 50 mV step. * @battok_raising_th_sel1 Threshold in mV for battOk signal sel1 @@ -335,9 +324,8 @@ struct ab8500_fg_parameters { int high_curr_time; int accu_charging; int accu_high_curr; - int high_curr_threshold; - int lowbat_threshold; - int overbat_threshold; + int high_curr_threshold_ua; + int lowbat_threshold_uv; int battok_falling_th_sel0; int battok_raising_th_sel1; int user_cap_limit; @@ -377,8 +365,6 @@ struct ab8500_maxim_parameters { * @low_high_vol_lvl: charger voltage in temp low/high state in mV' * @n_r_t_tbl_elements: number of elements in r_to_t_tbl * @r_to_t_tbl: table containing resistance to temp points - * @n_v_cap_tbl_elements: number of elements in v_to_cap_tbl - * @v_to_cap_tbl: Voltage to capacity (in %) table */ struct ab8500_battery_type { int resis_high; @@ -393,8 +379,6 @@ struct ab8500_battery_type { int low_high_vol_lvl; int n_temp_tbl_elements; const struct ab8500_res_to_temp *r_to_t_tbl; - int n_v_cap_tbl_elements; - const struct ab8500_v_to_cap *v_to_cap_tbl; }; /** diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 1175532fe017..62953f9cb85a 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -16,31 +16,31 @@ /* Default: temperature hysteresis */ #define AB8500_TEMP_HYSTERESIS 3 -static const struct ab8500_v_to_cap cap_tbl[] = { - {4186, 100}, - {4163, 99}, - {4114, 95}, - {4068, 90}, - {3990, 80}, - {3926, 70}, - {3898, 65}, - {3866, 60}, - {3833, 55}, - {3812, 50}, - {3787, 40}, - {3768, 30}, - {3747, 25}, - {3730, 20}, - {3705, 15}, - {3699, 14}, - {3684, 12}, - {3672, 9}, - {3657, 7}, - {3638, 6}, - {3556, 4}, - {3424, 2}, - {3317, 1}, - {3094, 0}, +static struct power_supply_battery_ocv_table ocv_cap_tbl[] = { + { .ocv = 4186000, .capacity = 100}, + { .ocv = 4163000, .capacity = 99}, + { .ocv = 4114000, .capacity = 95}, + { .ocv = 4068000, .capacity = 90}, + { .ocv = 3990000, .capacity = 80}, + { .ocv = 3926000, .capacity = 70}, + { .ocv = 3898000, .capacity = 65}, + { .ocv = 3866000, .capacity = 60}, + { .ocv = 3833000, .capacity = 55}, + { .ocv = 3812000, .capacity = 50}, + { .ocv = 3787000, .capacity = 40}, + { .ocv = 3768000, .capacity = 30}, + { .ocv = 3747000, .capacity = 25}, + { .ocv = 3730000, .capacity = 20}, + { .ocv = 3705000, .capacity = 15}, + { .ocv = 3699000, .capacity = 14}, + { .ocv = 3684000, .capacity = 12}, + { .ocv = 3672000, .capacity = 9}, + { .ocv = 3657000, .capacity = 7}, + { .ocv = 3638000, .capacity = 6}, + { .ocv = 3556000, .capacity = 4}, + { .ocv = 3424000, .capacity = 2}, + { .ocv = 3317000, .capacity = 1}, + { .ocv = 3094000, .capacity = 0}, }; /* @@ -94,8 +94,6 @@ static struct ab8500_battery_type bat_type_thermistor_unknown = { .low_high_vol_lvl = 4000, .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), .r_to_t_tbl = temp_tbl, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), - .v_to_cap_tbl = cap_tbl, }; static const struct ab8500_bm_capacity_levels cap_levels = { @@ -115,8 +113,8 @@ static const struct ab8500_fg_parameters fg = { .high_curr_time = 60, .accu_charging = 30, .accu_high_curr = 30, - .high_curr_threshold = 50, - .lowbat_threshold = 3100, + .high_curr_threshold_ua = 50000, + .lowbat_threshold_uv = 3100000, .battok_falling_th_sel0 = 2860, .battok_raising_th_sel1 = 2860, .maint_thres = 95, @@ -219,6 +217,13 @@ int ab8500_bm_of_probe(struct power_supply *psy, bi->resist_table_size = ARRAY_SIZE(temp_to_batres_tbl_thermistor); } + if (!bi->ocv_table[0]) { + /* Default capacity table at say 25 degrees Celsius */ + bi->ocv_temp[0] = 25; + bi->ocv_table[0] = ocv_cap_tbl; + bi->ocv_table_size[0] = ARRAY_SIZE(ocv_cap_tbl); + } + if (bi->temp_min == INT_MIN) bi->temp_min = AB8500_TEMP_UNDER; if (bi->temp_max == INT_MAX) diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 96bb81e539f0..eb3e5c4ca44f 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -156,10 +156,10 @@ struct inst_curr_result_list { * @dev: Pointer to the structure device * @node: a list of AB8500 FGs, hence prepared for reentrance * @irq holds the CCEOC interrupt number - * @vbat: Battery voltage in mV + * @vbat_uv: Battery voltage in uV * @vbat_nom_uv: Nominal battery voltage in uV - * @inst_curr: Instantenous battery current in mA - * @avg_curr: Average battery current in mA + * @inst_curr_ua: Instantenous battery current in uA + * @avg_curr_ua: Average battery current in uA * @bat_temp battery temperature * @fg_samples: Number of samples used in the FG accumulation * @accu_charge: Accumulated charge from the last conversion @@ -198,10 +198,10 @@ struct ab8500_fg { struct device *dev; struct list_head node; int irq; - int vbat; + int vbat_uv; int vbat_nom_uv; - int inst_curr; - int avg_curr; + int inst_curr_ua; + int avg_curr_ua; int bat_temp; int fg_samples; int accu_charge; @@ -265,84 +265,84 @@ static enum power_supply_property ab8500_fg_props[] = { /* * This array maps the raw hex value to lowbat voltage used by the AB8500 - * Values taken from the UM0836 + * Values taken from the UM0836, in microvolts. */ static int ab8500_fg_lowbat_voltage_map[] = { - 2300 , - 2325 , - 2350 , - 2375 , - 2400 , - 2425 , - 2450 , - 2475 , - 2500 , - 2525 , - 2550 , - 2575 , - 2600 , - 2625 , - 2650 , - 2675 , - 2700 , - 2725 , - 2750 , - 2775 , - 2800 , - 2825 , - 2850 , - 2875 , - 2900 , - 2925 , - 2950 , - 2975 , - 3000 , - 3025 , - 3050 , - 3075 , - 3100 , - 3125 , - 3150 , - 3175 , - 3200 , - 3225 , - 3250 , - 3275 , - 3300 , - 3325 , - 3350 , - 3375 , - 3400 , - 3425 , - 3450 , - 3475 , - 3500 , - 3525 , - 3550 , - 3575 , - 3600 , - 3625 , - 3650 , - 3675 , - 3700 , - 3725 , - 3750 , - 3775 , - 3800 , - 3825 , - 3850 , - 3850 , + 2300000, + 2325000, + 2350000, + 2375000, + 2400000, + 2425000, + 2450000, + 2475000, + 2500000, + 2525000, + 2550000, + 2575000, + 2600000, + 2625000, + 2650000, + 2675000, + 2700000, + 2725000, + 2750000, + 2775000, + 2800000, + 2825000, + 2850000, + 2875000, + 2900000, + 2925000, + 2950000, + 2975000, + 3000000, + 3025000, + 3050000, + 3075000, + 3100000, + 3125000, + 3150000, + 3175000, + 3200000, + 3225000, + 3250000, + 3275000, + 3300000, + 3325000, + 3350000, + 3375000, + 3400000, + 3425000, + 3450000, + 3475000, + 3500000, + 3525000, + 3550000, + 3575000, + 3600000, + 3625000, + 3650000, + 3675000, + 3700000, + 3725000, + 3750000, + 3775000, + 3800000, + 3825000, + 3850000, + 3850000, }; -static u8 ab8500_volt_to_regval(int voltage) +static u8 ab8500_volt_to_regval(int voltage_uv) { int i; - if (voltage < ab8500_fg_lowbat_voltage_map[0]) + if (voltage_uv < ab8500_fg_lowbat_voltage_map[0]) return 0; for (i = 0; i < ARRAY_SIZE(ab8500_fg_lowbat_voltage_map); i++) { - if (voltage < ab8500_fg_lowbat_voltage_map[i]) + if (voltage_uv < ab8500_fg_lowbat_voltage_map[i]) return (u8) i - 1; } @@ -353,16 +353,16 @@ static u8 ab8500_volt_to_regval(int voltage) /** * ab8500_fg_is_low_curr() - Low or high current mode * @di: pointer to the ab8500_fg structure - * @curr: the current to base or our decision on + * @curr_ua: the current to base or our decision on in microampere * * Low current mode if the current consumption is below a certain threshold */ -static int ab8500_fg_is_low_curr(struct ab8500_fg *di, int curr) +static int ab8500_fg_is_low_curr(struct ab8500_fg *di, int curr_ua) { /* * We want to know if we're in low current mode */ - if (curr > -di->bm->fg_params->high_curr_threshold) + if (curr_ua > -di->bm->fg_params->high_curr_threshold_ua) return true; else return false; @@ -600,13 +600,13 @@ int ab8500_fg_inst_curr_done(struct ab8500_fg *di) /** * ab8500_fg_inst_curr_finalize() - battery instantaneous current * @di: pointer to the ab8500_fg structure - * @res: battery instantenous current(on success) + * @curr_ua: battery instantenous current in microampere (on success) * * Returns 0 or an error code * Note: This is part "two" and has to be called at earliest 250 ms * after ab8500_fg_inst_curr_start() */ -int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res) +int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *curr_ua) { u8 low, high; int val; @@ -662,14 +662,13 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res) /* * Convert to unit value in mA * Full scale input voltage is - * 63.160mV => LSB = 63.160mV/(4096*res) = 1.542mA + * 63.160mV => LSB = 63.160mV/(4096*res) = 1.542.000 uA * Given a 250ms conversion cycle time the LSB corresponds * to 107.1 nAh. Convert to current by dividing by the conversion * time in hours (250ms = 1 / (3600 * 4)h) * 107.1nAh assumes 10mOhm, but fg_res is in 0.1mOhm */ - val = (val * QLSB_NANO_AMP_HOURS_X10 * 36 * 4) / - (1000 * di->bm->fg_res); + val = (val * QLSB_NANO_AMP_HOURS_X10 * 36 * 4) / di->bm->fg_res; if (di->turn_off_fg) { dev_dbg(di->dev, "%s Disable FG\n", __func__); @@ -687,7 +686,7 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res) goto fail; } mutex_unlock(&di->cc_lock); - (*res) = val; + *curr_ua = val; return 0; fail: @@ -698,15 +697,15 @@ fail: /** * ab8500_fg_inst_curr_blocking() - battery instantaneous current * @di: pointer to the ab8500_fg structure - * @res: battery instantenous current(on success) * - * Returns 0 else error code + * Returns battery instantenous current in microampere (on success) + * else error code */ int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di) { int ret; unsigned long timeout; - int res = 0; + int curr_ua = 0; ret = ab8500_fg_inst_curr_start(di); if (ret) { @@ -729,14 +728,14 @@ int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di) } } - ret = ab8500_fg_inst_curr_finalize(di, &res); + ret = ab8500_fg_inst_curr_finalize(di, &curr_ua); if (ret) { dev_err(di->dev, "Failed to finalize fg_inst\n"); return 0; } - dev_dbg(di->dev, "%s instant current: %d", __func__, res); - return res; + dev_dbg(di->dev, "%s instant current: %d uA", __func__, curr_ua); + return curr_ua; fail: disable_irq(di->irq); mutex_unlock(&di->cc_lock); @@ -796,13 +795,12 @@ static void ab8500_fg_acc_cur_work(struct work_struct *work) (100 * di->bm->fg_res); /* - * Convert to unit value in mA + * Convert to unit value in uA * by dividing by the conversion * time in hours (= samples / (3600 * 4)h) - * and multiply with 1000 */ - di->avg_curr = (val * QLSB_NANO_AMP_HOURS_X10 * 36) / - (1000 * di->bm->fg_res * (di->fg_samples / 4)); + di->avg_curr_ua = (val * QLSB_NANO_AMP_HOURS_X10 * 36) / + (di->bm->fg_res * (di->fg_samples / 4)); di->flags.conv_done = true; @@ -824,7 +822,7 @@ exit: * ab8500_fg_bat_voltage() - get battery voltage * @di: pointer to the ab8500_fg structure * - * Returns battery voltage(on success) else error code + * Returns battery voltage in microvolts (on success) else error code */ static int ab8500_fg_bat_voltage(struct ab8500_fg *di) { @@ -839,6 +837,8 @@ static int ab8500_fg_bat_voltage(struct ab8500_fg *di) return prev; } + /* IIO returns millivolts but we want microvolts */ + vbat *= 1000; prev = vbat; return vbat; } @@ -846,41 +846,16 @@ static int ab8500_fg_bat_voltage(struct ab8500_fg *di) /** * ab8500_fg_volt_to_capacity() - Voltage based capacity * @di: pointer to the ab8500_fg structure - * @voltage: The voltage to convert to a capacity + * @voltage_uv: The voltage to convert to a capacity in microvolt * * Returns battery capacity in per mille based on voltage */ -static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage) +static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage_uv) { - int i, tbl_size; - const struct ab8500_v_to_cap *tbl; - int cap = 0; - - tbl = di->bm->bat_type->v_to_cap_tbl; - tbl_size = di->bm->bat_type->n_v_cap_tbl_elements; - - for (i = 0; i < tbl_size; ++i) { - if (voltage > tbl[i].voltage) - break; - } - - if ((i > 0) && (i < tbl_size)) { - cap = fixp_linear_interpolate( - tbl[i].voltage, - tbl[i].capacity * 10, - tbl[i-1].voltage, - tbl[i-1].capacity * 10, - voltage); - } else if (i == 0) { - cap = 1000; - } else { - cap = 0; - } - - dev_dbg(di->dev, "%s Vbat: %d, Cap: %d per mille", - __func__, voltage, cap); + struct power_supply_battery_info *bi = &di->bm->bi; - return cap; + /* Multiply by 10 because the capacity is tracked in per mille */ + return power_supply_batinfo_ocv2cap(bi, voltage_uv, di->bat_temp) * 10; } /** @@ -892,8 +867,8 @@ static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage) */ static int ab8500_fg_uncomp_volt_to_capacity(struct ab8500_fg *di) { - di->vbat = ab8500_fg_bat_voltage(di); - return ab8500_fg_volt_to_capacity(di, di->vbat); + di->vbat_uv = ab8500_fg_bat_voltage(di); + return ab8500_fg_volt_to_capacity(di, di->vbat_uv); } /** @@ -941,31 +916,34 @@ static int ab8500_fg_battery_resistance(struct ab8500_fg *di) */ static int ab8500_fg_load_comp_volt_to_capacity(struct ab8500_fg *di) { - int vbat_comp, res; + int vbat_comp_uv, res; int i = 0; - int vbat = 0; + int vbat_uv = 0; ab8500_fg_inst_curr_start(di); do { - vbat += ab8500_fg_bat_voltage(di); + vbat_uv += ab8500_fg_bat_voltage(di); i++; usleep_range(5000, 6000); } while (!ab8500_fg_inst_curr_done(di)); - ab8500_fg_inst_curr_finalize(di, &di->inst_curr); + ab8500_fg_inst_curr_finalize(di, &di->inst_curr_ua); - di->vbat = vbat / i; + di->vbat_uv = vbat_uv / i; res = ab8500_fg_battery_resistance(di); - /* Use Ohms law to get the load compensated voltage */ - vbat_comp = di->vbat - (di->inst_curr * res) / 1000; + /* + * Use Ohms law to get the load compensated voltage. + * Divide by 1000 to get from milliohms to ohms. + */ + vbat_comp_uv = di->vbat_uv - (di->inst_curr_ua * res) / 1000; - dev_dbg(di->dev, "%s Measured Vbat: %dmV,Compensated Vbat %dmV, " - "R: %dmOhm, Current: %dmA Vbat Samples: %d\n", - __func__, di->vbat, vbat_comp, res, di->inst_curr, i); + dev_dbg(di->dev, "%s Measured Vbat: %d uV,Compensated Vbat %d uV, " + "R: %d mOhm, Current: %d uA Vbat Samples: %d\n", + __func__, di->vbat_uv, vbat_comp_uv, res, di->inst_curr_ua, i); - return ab8500_fg_volt_to_capacity(di, vbat_comp); + return ab8500_fg_volt_to_capacity(di, vbat_comp_uv); } /** @@ -1052,8 +1030,8 @@ static int ab8500_fg_calc_cap_charging(struct ab8500_fg *di) ab8500_fg_convert_mah_to_permille(di, di->bat_cap.mah); /* We need to update battery voltage and inst current when charging */ - di->vbat = ab8500_fg_bat_voltage(di); - di->inst_curr = ab8500_fg_inst_curr_blocking(di); + di->vbat_uv = ab8500_fg_bat_voltage(di); + di->inst_curr_ua = ab8500_fg_inst_curr_blocking(di); return di->bat_cap.mah; } @@ -1580,9 +1558,9 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) * RECOVERY_SLEEP if time left. * If high, go to READOUT */ - di->inst_curr = ab8500_fg_inst_curr_blocking(di); + di->inst_curr_ua = ab8500_fg_inst_curr_blocking(di); - if (ab8500_fg_is_low_curr(di, di->inst_curr)) { + if (ab8500_fg_is_low_curr(di, di->inst_curr_ua)) { if (di->recovery_cnt > di->bm->fg_params->recovery_total_time) { di->fg_samples = SEC_TO_SAMPLE( @@ -1615,9 +1593,9 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) break; case AB8500_FG_DISCHARGE_READOUT: - di->inst_curr = ab8500_fg_inst_curr_blocking(di); + di->inst_curr_ua = ab8500_fg_inst_curr_blocking(di); - if (ab8500_fg_is_low_curr(di, di->inst_curr)) { + if (ab8500_fg_is_low_curr(di, di->inst_curr_ua)) { /* Detect mode change */ if (di->high_curr_mode) { di->high_curr_mode = false; @@ -1763,9 +1741,9 @@ static void ab8500_fg_algorithm(struct ab8500_fg *di) di->bat_cap.prev_mah, di->bat_cap.prev_percent, di->bat_cap.prev_level, - di->vbat, - di->inst_curr, - di->avg_curr, + di->vbat_uv, + di->inst_curr_ua, + di->avg_curr_ua, di->accu_charge, di->flags.charging, di->charge_state, @@ -1858,15 +1836,15 @@ static void ab8500_fg_check_hw_failure_work(struct work_struct *work) */ static void ab8500_fg_low_bat_work(struct work_struct *work) { - int vbat; + int vbat_uv; struct ab8500_fg *di = container_of(work, struct ab8500_fg, fg_low_bat_work.work); - vbat = ab8500_fg_bat_voltage(di); + vbat_uv = ab8500_fg_bat_voltage(di); /* Check if LOW_BAT still fulfilled */ - if (vbat < di->bm->fg_params->lowbat_threshold) { + if (vbat_uv < di->bm->fg_params->lowbat_threshold_uv) { /* Is it time to shut down? */ if (di->low_bat_cnt < 1) { di->flags.low_bat = true; @@ -2096,15 +2074,15 @@ static int ab8500_fg_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_VOLTAGE_NOW: if (di->flags.bat_ovv) - val->intval = BATT_OVV_VALUE * 1000; + val->intval = BATT_OVV_VALUE; else - val->intval = di->vbat * 1000; + val->intval = di->vbat_uv; break; case POWER_SUPPLY_PROP_CURRENT_NOW: - val->intval = di->inst_curr * 1000; + val->intval = di->inst_curr_ua; break; case POWER_SUPPLY_PROP_CURRENT_AVG: - val->intval = di->avg_curr * 1000; + val->intval = di->avg_curr_ua; break; case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: val->intval = ab8500_fg_convert_mah_to_uwh(di, @@ -2310,7 +2288,7 @@ static int ab8500_fg_init_hw_registers(struct ab8500_fg *di) AB8500_SYS_CTRL2_BLOCK, AB8500_LOW_BAT_REG, ab8500_volt_to_regval( - di->bm->fg_params->lowbat_threshold) << 1 | + di->bm->fg_params->lowbat_threshold_uv) << 1 | LOW_BAT_ENABLE); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); -- cgit v1.2.3-59-g8ed1b From 0838a3bfcd1b0c8d2ce38afcc94b81920486dabd Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Thu, 18 Nov 2021 22:02:05 +0100 Subject: power: supply: qcom_smbb: support pm8226 PM8226 (used in MSM8226) has v1 smbb hardware and works fine with the current driver. Signed-off-by: Luca Weiss Signed-off-by: Sebastian Reichel --- drivers/power/supply/qcom_smbb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/qcom_smbb.c b/drivers/power/supply/qcom_smbb.c index 84cc9fba029d..bd50124eef9f 100644 --- a/drivers/power/supply/qcom_smbb.c +++ b/drivers/power/supply/qcom_smbb.c @@ -863,8 +863,8 @@ static int smbb_charger_probe(struct platform_device *pdev) } chg->revision += 1; - if (chg->revision != 2 && chg->revision != 3) { - dev_err(&pdev->dev, "v1 hardware not supported\n"); + if (chg->revision != 1 && chg->revision != 2 && chg->revision != 3) { + dev_err(&pdev->dev, "v%d hardware not supported\n", chg->revision); return -ENODEV; } dev_info(&pdev->dev, "Initializing SMBB rev %u", chg->revision); @@ -1012,6 +1012,7 @@ static int smbb_charger_remove(struct platform_device *pdev) } static const struct of_device_id smbb_charger_id_table[] = { + { .compatible = "qcom,pm8226-charger" }, { .compatible = "qcom,pm8941-charger" }, { } }; -- cgit v1.2.3-59-g8ed1b From 9652c02428f3992129b73321fee32fe60b77c90f Mon Sep 17 00:00:00 2001 From: Angus Ainslie Date: Thu, 18 Nov 2021 08:18:45 -0800 Subject: power: bq25890: add POWER_SUPPLY_PROP_TEMP Add the POWER_SUPPLY_PROP_TEMP and a NTC 10K percent VREGN to degrees LUT. Make sure that a conversion is forced when the power supply is offline so the temperature is valid. Signed-off-by: Angus Ainslie Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq25890_charger.c | 37 +++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index 34ec186a2e9a..78da6e7a8b5b 100644 --- a/drivers/power/supply/bq25890_charger.c +++ b/drivers/power/supply/bq25890_charger.c @@ -266,6 +266,7 @@ enum bq25890_table_ids { /* lookup tables */ TBL_TREG, TBL_BOOSTI, + TBL_TSPCT, }; /* Thermal Regulation Threshold lookup table, in degrees Celsius */ @@ -280,6 +281,28 @@ static const u32 bq25890_boosti_tbl[] = { #define BQ25890_BOOSTI_TBL_SIZE ARRAY_SIZE(bq25890_boosti_tbl) +/* NTC 10K temperature lookup table in tenths of a degree */ +static const u32 bq25890_tspct_tbl[] = { + 850, 840, 830, 820, 810, 800, 790, 780, + 770, 760, 750, 740, 730, 720, 710, 700, + 690, 685, 680, 675, 670, 660, 650, 645, + 640, 630, 620, 615, 610, 600, 590, 585, + 580, 570, 565, 560, 550, 540, 535, 530, + 520, 515, 510, 500, 495, 490, 480, 475, + 470, 460, 455, 450, 440, 435, 430, 425, + 420, 410, 405, 400, 390, 385, 380, 370, + 365, 360, 355, 350, 340, 335, 330, 320, + 310, 305, 300, 290, 285, 280, 275, 270, + 260, 250, 245, 240, 230, 225, 220, 210, + 205, 200, 190, 180, 175, 170, 160, 150, + 145, 140, 130, 120, 115, 110, 100, 90, + 80, 70, 60, 50, 40, 30, 20, 10, + 0, -10, -20, -30, -40, -60, -70, -80, + -90, -10, -120, -140, -150, -170, -190, -210, +}; + +#define BQ25890_TSPCT_TBL_SIZE ARRAY_SIZE(bq25890_tspct_tbl) + struct bq25890_range { u32 min; u32 max; @@ -308,7 +331,8 @@ static const union { /* lookup tables */ [TBL_TREG] = { .lt = {bq25890_treg_tbl, BQ25890_TREG_TBL_SIZE} }, - [TBL_BOOSTI] = { .lt = {bq25890_boosti_tbl, BQ25890_BOOSTI_TBL_SIZE} } + [TBL_BOOSTI] = { .lt = {bq25890_boosti_tbl, BQ25890_BOOSTI_TBL_SIZE} }, + [TBL_TSPCT] = { .lt = {bq25890_tspct_tbl, BQ25890_TSPCT_TBL_SIZE} } }; static int bq25890_field_read(struct bq25890_device *bq, @@ -388,6 +412,7 @@ static bool bq25890_is_adc_property(enum power_supply_property psp) switch (psp) { case POWER_SUPPLY_PROP_VOLTAGE_NOW: case POWER_SUPPLY_PROP_CURRENT_NOW: + case POWER_SUPPLY_PROP_TEMP: return true; default: @@ -528,6 +553,15 @@ static int bq25890_power_supply_get_property(struct power_supply *psy, val->intval = ret * -50000; break; + case POWER_SUPPLY_PROP_TEMP: + ret = bq25890_field_read(bq, F_TSPCT); + if (ret < 0) + return ret; + + /* convert TS percentage into rough temperature */ + val->intval = bq25890_find_val(ret, TBL_TSPCT); + break; + default: return -EINVAL; } @@ -713,6 +747,7 @@ static const enum power_supply_property bq25890_power_supply_props[] = { POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_TEMP, }; static char *bq25890_charger_supplied_to[] = { -- cgit v1.2.3-59-g8ed1b From 1c1348bf056dee665760a3bd1cd30b0be7554fc2 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Mon, 20 Dec 2021 16:38:11 +0800 Subject: power: reset: mt6397: Check for null res pointer The return value of platform_get_resource() needs to be checked. To avoid use of error pointer in case that there is no suitable resource. Fixes: d28c74c10751 ("power: reset: add driver for mt6323 poweroff") Signed-off-by: Jiasheng Jiang Signed-off-by: Sebastian Reichel --- drivers/power/reset/mt6323-poweroff.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/power/reset/mt6323-poweroff.c b/drivers/power/reset/mt6323-poweroff.c index 0532803e6cbc..d90e76fcb938 100644 --- a/drivers/power/reset/mt6323-poweroff.c +++ b/drivers/power/reset/mt6323-poweroff.c @@ -57,6 +57,9 @@ static int mt6323_pwrc_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + pwrc->base = res->start; pwrc->regmap = mt6397_chip->regmap; pwrc->dev = &pdev->dev; -- cgit v1.2.3-59-g8ed1b From be2c0d5418b1f44b01154a71e4501de139d0a7c9 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 28 Dec 2021 21:43:22 +0100 Subject: power: supply: ab8500: Fix the error handling path of ab8500_charger_probe() Since the commit below, ab8500_bm_of_remove() needs to be called after a successful ab8500_bm_of_probe() call. This commit has only updated the remove function. Fix the error handling path of the probe the same way. Fixes: 6252c706cdb0 ("power: supply: ab8500: Standardize operating temperature") Signed-off-by: Christophe JAILLET Reviewed-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_charger.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index db7457064a17..ce074c018dcb 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -3665,11 +3665,13 @@ static int ab8500_charger_probe(struct platform_device *pdev) } if (!match) { dev_err(dev, "no matching components\n"); - return -ENODEV; + ret = -ENODEV; + goto remove_ab8500_bm; } if (IS_ERR(match)) { dev_err(dev, "could not create component match\n"); - return PTR_ERR(match); + ret = PTR_ERR(match); + goto remove_ab8500_bm; } /* Notifier for external charger enabling */ @@ -3710,6 +3712,8 @@ out_charger_notifier: if (!di->ac_chg.enabled) blocking_notifier_chain_unregister( &charger_notifier_list, &charger_nb); +remove_ab8500_bm: + ab8500_bm_of_remove(di->usb_chg.psy, di->bm); return ret; } -- cgit v1.2.3-59-g8ed1b From 25fd330370ac40653671f323acc7fb6db27ef6fe Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 15 Dec 2021 02:01:18 +0100 Subject: power: supply_core: Pass pointer to battery info The function to retrieve battery info (from the device tree) assumes we have a static info struct that gets populated by calling into power_supply_get_battery_info(). This is awkward since I want to support tables of static battery info by just assigning a pointer to all info based on e.g. a compatible value in the device tree. We also have a mixture of static and dynamically allocated variables here. Bite the bullet and let power_supply_get_battery_info() allocate also the memory used for the very top level struct power_supply_battery_info container. Pass pointers around and lifecycle this with the psy device just like the stuff we allocate inside it. Change all current users over. As part of the change, initializers need to be added to some previously uninitialized fields in struct power_supply_battery_info. Reviewed-By: Matti Vaittinen Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 2 +- drivers/power/supply/ab8500_bmdata.c | 7 +++--- drivers/power/supply/ab8500_btemp.c | 10 ++++++--- drivers/power/supply/ab8500_chargalg.c | 16 +++++++------- drivers/power/supply/ab8500_fg.c | 18 ++++++++------- drivers/power/supply/axp20x_battery.c | 6 ++--- drivers/power/supply/bd99954-charger.c | 24 +++++++++++--------- drivers/power/supply/bq24190_charger.c | 6 ++--- drivers/power/supply/bq2515x_charger.c | 8 +++---- drivers/power/supply/bq256xx_charger.c | 24 ++++++++++---------- drivers/power/supply/bq25980_charger.c | 6 ++--- drivers/power/supply/bq27xxx_battery.c | 38 ++++++++++++++++---------------- drivers/power/supply/cw2015_battery.c | 20 +++++++++++------ drivers/power/supply/ingenic-battery.c | 14 ++++++------ drivers/power/supply/power_supply_core.c | 19 ++++++++++++++-- drivers/power/supply/sc2731_charger.c | 8 +++---- drivers/power/supply/sc27xx_fuel_gauge.c | 22 +++++++++--------- drivers/power/supply/smb347-charger.c | 34 ++++++++++++++-------------- include/linux/power_supply.h | 2 +- 19 files changed, 157 insertions(+), 127 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index 57e1a8e27e51..56a5aaf9a27a 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -439,7 +439,7 @@ struct ab8500_bm_charger_parameters { * @fg_params fuel gauge parameters */ struct ab8500_bm_data { - struct power_supply_battery_info bi; + struct power_supply_battery_info *bi; int temp_now; int temp_interval_chg; int temp_interval_nochg; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 62953f9cb85a..7ae95f537580 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -167,15 +167,16 @@ struct ab8500_bm_data ab8500_bm_data = { int ab8500_bm_of_probe(struct power_supply *psy, struct ab8500_bm_data *bm) { - struct power_supply_battery_info *bi = &bm->bi; + struct power_supply_battery_info *bi; struct device *dev = &psy->dev; int ret; - ret = power_supply_get_battery_info(psy, bi); + ret = power_supply_get_battery_info(psy, &bm->bi); if (ret) { dev_err(dev, "cannot retrieve battery info\n"); return ret; } + bi = bm->bi; /* Fill in defaults for any data missing from the device tree */ if (bi->charge_full_design_uah < 0) @@ -240,5 +241,5 @@ int ab8500_bm_of_probe(struct power_supply *psy, void ab8500_bm_of_remove(struct power_supply *psy, struct ab8500_bm_data *bm) { - power_supply_put_battery_info(psy, &bm->bi); + power_supply_put_battery_info(psy, bm->bi); } diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c index 20253b8a7fe9..cc33c5187fbb 100644 --- a/drivers/power/supply/ab8500_btemp.c +++ b/drivers/power/supply/ab8500_btemp.c @@ -451,12 +451,13 @@ static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di, */ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) { + struct power_supply_battery_info *bi = di->bm->bi; int temp, ret; static int prev; int rbat, rntc, vntc; if ((di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL) && - (di->bm->bi.technology == POWER_SUPPLY_TECHNOLOGY_UNKNOWN)) { + (bi && (bi->technology == POWER_SUPPLY_TECHNOLOGY_UNKNOWN))) { rbat = ab8500_btemp_get_batctrl_res(di); if (rbat < 0) { @@ -540,7 +541,7 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) * that need it. */ if ((di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL) && - (di->bm->bi.technology == POWER_SUPPLY_TECHNOLOGY_LIPO) && + (di->bm->bi && (di->bm->bi->technology == POWER_SUPPLY_TECHNOLOGY_LIPO)) && (res <= 53407) && (res >= 12500)) { dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n"); di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA; @@ -807,7 +808,10 @@ static int ab8500_btemp_get_property(struct power_supply *psy, val->intval = 1; break; case POWER_SUPPLY_PROP_TECHNOLOGY: - val->intval = di->bm->bi.technology; + if (di->bm->bi) + val->intval = di->bm->bi->technology; + else + val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; break; case POWER_SUPPLY_PROP_TEMP: val->intval = ab8500_btemp_get_temp(di); diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index 86d740ce3a63..c4a2fe07126c 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -352,7 +352,7 @@ static void ab8500_chargalg_state_to(struct ab8500_chargalg *di, static int ab8500_chargalg_check_charger_enable(struct ab8500_chargalg *di) { - struct power_supply_battery_info *bi = &di->bm->bi; + struct power_supply_battery_info *bi = di->bm->bi; switch (di->charge_state) { case STATE_NORMAL: @@ -731,7 +731,7 @@ static void ab8500_chargalg_start_charging(struct ab8500_chargalg *di, */ static void ab8500_chargalg_check_temp(struct ab8500_chargalg *di) { - struct power_supply_battery_info *bi = &di->bm->bi; + struct power_supply_battery_info *bi = di->bm->bi; if (di->batt_data.temp > (bi->temp_alert_min + di->t_hyst_norm) && di->batt_data.temp < (bi->temp_alert_max - di->t_hyst_norm)) { @@ -802,10 +802,10 @@ static void ab8500_chargalg_end_of_charge(struct ab8500_chargalg *di) if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING && di->charge_state == STATE_NORMAL && !di->maintenance_chg && (di->batt_data.volt_uv >= - di->bm->bi.overvoltage_limit_uv || + di->bm->bi->overvoltage_limit_uv || di->events.usb_cv_active || di->events.ac_cv_active) && di->batt_data.avg_curr_ua < - di->bm->bi.charge_term_current_ua && + di->bm->bi->charge_term_current_ua && di->batt_data.avg_curr_ua > 0) { if (++di->eoc_cnt >= EOC_COND_CNT) { di->eoc_cnt = 0; @@ -827,7 +827,7 @@ static void ab8500_chargalg_end_of_charge(struct ab8500_chargalg *di) static void init_maxim_chg_curr(struct ab8500_chargalg *di) { - struct power_supply_battery_info *bi = &di->bm->bi; + struct power_supply_battery_info *bi = di->bm->bi; di->ccm.original_iset_ua = bi->constant_charge_current_max_ua; di->ccm.current_iset_ua = bi->constant_charge_current_max_ua; @@ -920,7 +920,7 @@ static enum maxim_ret ab8500_chargalg_chg_curr_maxim(struct ab8500_chargalg *di) static void handle_maxim_chg_curr(struct ab8500_chargalg *di) { - struct power_supply_battery_info *bi = &di->bm->bi; + struct power_supply_battery_info *bi = di->bm->bi; enum maxim_ret ret; int result; @@ -1299,7 +1299,7 @@ static void ab8500_chargalg_external_power_changed(struct power_supply *psy) */ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) { - struct power_supply_battery_info *bi = &di->bm->bi; + struct power_supply_battery_info *bi = di->bm->bi; int charger_status; int ret; int curr_step_lvl_ua; @@ -1723,7 +1723,7 @@ static int ab8500_chargalg_get_property(struct power_supply *psy, if (di->events.batt_ovv) { val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; } else if (di->events.btemp_underover) { - if (di->batt_data.temp <= di->bm->bi.temp_min) + if (di->batt_data.temp <= di->bm->bi->temp_min) val->intval = POWER_SUPPLY_HEALTH_COLD; else val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index eb3e5c4ca44f..b0919a6a6587 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -852,7 +852,7 @@ static int ab8500_fg_bat_voltage(struct ab8500_fg *di) */ static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage_uv) { - struct power_supply_battery_info *bi = &di->bm->bi; + struct power_supply_battery_info *bi = di->bm->bi; /* Multiply by 10 because the capacity is tracked in per mille */ return power_supply_batinfo_ocv2cap(bi, voltage_uv, di->bat_temp) * 10; @@ -881,7 +881,7 @@ static int ab8500_fg_uncomp_volt_to_capacity(struct ab8500_fg *di) */ static int ab8500_fg_battery_resistance(struct ab8500_fg *di) { - struct power_supply_battery_info *bi = &di->bm->bi; + struct power_supply_battery_info *bi = di->bm->bi; int resistance_percent = 0; int resistance; @@ -2140,11 +2140,13 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) struct power_supply *ext = dev_get_drvdata(dev); const char **supplicants = (const char **)ext->supplied_to; struct ab8500_fg *di; + struct power_supply_battery_info *bi; union power_supply_propval ret; int j; psy = (struct power_supply *)data; di = power_supply_get_drvdata(psy); + bi = di->bm->bi; /* * For all psy where the name of your driver @@ -2207,8 +2209,8 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) switch (ext->desc->type) { case POWER_SUPPLY_TYPE_BATTERY: if (!di->flags.batt_id_received && - (di->bm->bi.technology != - POWER_SUPPLY_TECHNOLOGY_UNKNOWN)) { + (bi && (bi->technology != + POWER_SUPPLY_TECHNOLOGY_UNKNOWN))) { const struct ab8500_battery_type *b; b = di->bm->bat_type; @@ -2216,13 +2218,13 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) di->flags.batt_id_received = true; di->bat_cap.max_mah_design = - di->bm->bi.charge_full_design_uah; + di->bm->bi->charge_full_design_uah; di->bat_cap.max_mah = di->bat_cap.max_mah_design; di->vbat_nom_uv = - di->bm->bi.voltage_max_design_uv; + di->bm->bi->voltage_max_design_uv; } if (ret.intval) @@ -2992,9 +2994,9 @@ static int ab8500_fg_bind(struct device *dev, struct device *master, return -ENOMEM; } - di->bat_cap.max_mah_design = di->bm->bi.charge_full_design_uah; + di->bat_cap.max_mah_design = di->bm->bi->charge_full_design_uah; di->bat_cap.max_mah = di->bat_cap.max_mah_design; - di->vbat_nom_uv = di->bm->bi.voltage_max_design_uv; + di->vbat_nom_uv = di->bm->bi->voltage_max_design_uv; /* Start the coulomb counter */ ab8500_fg_coulomb_counter(di, true); diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c index 18a9db0df4b1..5d197141f476 100644 --- a/drivers/power/supply/axp20x_battery.c +++ b/drivers/power/supply/axp20x_battery.c @@ -561,7 +561,7 @@ static int axp20x_power_probe(struct platform_device *pdev) { struct axp20x_batt_ps *axp20x_batt; struct power_supply_config psy_cfg = {}; - struct power_supply_battery_info info; + struct power_supply_battery_info *info; struct device *dev = &pdev->dev; if (!of_device_is_available(pdev->dev.of_node)) @@ -615,8 +615,8 @@ static int axp20x_power_probe(struct platform_device *pdev) } if (!power_supply_get_battery_info(axp20x_batt->batt, &info)) { - int vmin = info.voltage_min_design_uv; - int ccc = info.constant_charge_current_max_ua; + int vmin = info->voltage_min_design_uv; + int ccc = info->constant_charge_current_max_ua; if (vmin > 0 && axp20x_set_voltage_min_design(axp20x_batt, vmin)) diff --git a/drivers/power/supply/bd99954-charger.c b/drivers/power/supply/bd99954-charger.c index ffd8bfa08179..96e93e1b8094 100644 --- a/drivers/power/supply/bd99954-charger.c +++ b/drivers/power/supply/bd99954-charger.c @@ -882,7 +882,7 @@ struct dt_init { static int bd9995x_fw_probe(struct bd9995x_device *bd) { int ret; - struct power_supply_battery_info info; + struct power_supply_battery_info *info; u32 property; int i; int regval; @@ -891,49 +891,41 @@ static int bd9995x_fw_probe(struct bd9995x_device *bd) struct battery_init battery_inits[] = { { .name = "trickle-charging current", - .info_data = &info.tricklecharge_current_ua, .range = &charging_current_ranges[0], .ranges = 2, .data = &init->itrich_set, }, { .name = "pre-charging current", - .info_data = &info.precharge_current_ua, .range = &charging_current_ranges[0], .ranges = 2, .data = &init->iprech_set, }, { .name = "pre-to-trickle charge voltage threshold", - .info_data = &info.precharge_voltage_max_uv, .range = &trickle_to_pre_threshold_ranges[0], .ranges = 2, .data = &init->vprechg_th_set, }, { .name = "charging termination current", - .info_data = &info.charge_term_current_ua, .range = &charging_current_ranges[0], .ranges = 2, .data = &init->iterm_set, }, { .name = "charging re-start voltage", - .info_data = &info.charge_restart_voltage_uv, .range = &charge_voltage_regulation_ranges[0], .ranges = 2, .data = &init->vrechg_set, }, { .name = "battery overvoltage limit", - .info_data = &info.overvoltage_limit_uv, .range = &charge_voltage_regulation_ranges[0], .ranges = 2, .data = &init->vbatovp_set, }, { .name = "fast-charging max current", - .info_data = &info.constant_charge_current_max_ua, .range = &fast_charge_current_ranges[0], .ranges = 1, .data = &init->ichg_set, }, { .name = "fast-charging voltage", - .info_data = &info.constant_charge_voltage_max_uv, .range = &charge_voltage_regulation_ranges[0], .ranges = 2, .data = &init->vfastchg_reg_set1, @@ -966,6 +958,16 @@ static int bd9995x_fw_probe(struct bd9995x_device *bd) if (ret < 0) return ret; + /* Put pointers to the generic battery info */ + battery_inits[0].info_data = &info->tricklecharge_current_ua; + battery_inits[1].info_data = &info->precharge_current_ua; + battery_inits[2].info_data = &info->precharge_voltage_max_uv; + battery_inits[3].info_data = &info->charge_term_current_ua; + battery_inits[4].info_data = &info->charge_restart_voltage_uv; + battery_inits[5].info_data = &info->overvoltage_limit_uv; + battery_inits[6].info_data = &info->constant_charge_current_max_ua; + battery_inits[7].info_data = &info->constant_charge_voltage_max_uv; + for (i = 0; i < ARRAY_SIZE(battery_inits); i++) { int val = *battery_inits[i].info_data; const struct linear_range *range = battery_inits[i].range; @@ -980,7 +982,7 @@ static int bd9995x_fw_probe(struct bd9995x_device *bd) dev_err(bd->dev, "Unsupported value for %s\n", battery_inits[i].name); - power_supply_put_battery_info(bd->charger, &info); + power_supply_put_battery_info(bd->charger, info); return -EINVAL; } if (!found) { @@ -991,7 +993,7 @@ static int bd9995x_fw_probe(struct bd9995x_device *bd) *(battery_inits[i].data) = regval; } - power_supply_put_battery_info(bd->charger, &info); + power_supply_put_battery_info(bd->charger, info); for (i = 0; i < ARRAY_SIZE(props); i++) { ret = device_property_read_u32(bd->dev, props[i].prop, diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index 35ff0c8fe96f..06c34b09349c 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -1670,7 +1670,7 @@ static int bq24190_hw_init(struct bq24190_dev_info *bdi) static int bq24190_get_config(struct bq24190_dev_info *bdi) { const char * const s = "ti,system-minimum-microvolt"; - struct power_supply_battery_info info = {}; + struct power_supply_battery_info *info; int v; if (device_property_read_u32(bdi->dev, s, &v) == 0) { @@ -1684,7 +1684,7 @@ static int bq24190_get_config(struct bq24190_dev_info *bdi) if (bdi->dev->of_node && !power_supply_get_battery_info(bdi->charger, &info)) { - v = info.precharge_current_ua / 1000; + v = info->precharge_current_ua / 1000; if (v >= BQ24190_REG_PCTCC_IPRECHG_MIN && v <= BQ24190_REG_PCTCC_IPRECHG_MAX) bdi->iprechg = v; @@ -1692,7 +1692,7 @@ static int bq24190_get_config(struct bq24190_dev_info *bdi) dev_warn(bdi->dev, "invalid value for battery:precharge-current-microamp: %d\n", v); - v = info.charge_term_current_ua / 1000; + v = info->charge_term_current_ua / 1000; if (v >= BQ24190_REG_PCTCC_ITERM_MIN && v <= BQ24190_REG_PCTCC_ITERM_MAX) bdi->iterm = v; diff --git a/drivers/power/supply/bq2515x_charger.c b/drivers/power/supply/bq2515x_charger.c index 374b112f712a..4f76ad9c2f18 100644 --- a/drivers/power/supply/bq2515x_charger.c +++ b/drivers/power/supply/bq2515x_charger.c @@ -945,7 +945,7 @@ static int bq2515x_power_supply_register(struct bq2515x_device *bq2515x, static int bq2515x_hw_init(struct bq2515x_device *bq2515x) { int ret; - struct power_supply_battery_info bat_info = { }; + struct power_supply_battery_info *bat_info; ret = bq2515x_disable_watchdog_timers(bq2515x); if (ret) @@ -969,13 +969,13 @@ static int bq2515x_hw_init(struct bq2515x_device *bq2515x) } else { bq2515x->init_data.ichg = - bat_info.constant_charge_current_max_ua; + bat_info->constant_charge_current_max_ua; bq2515x->init_data.vbatreg = - bat_info.constant_charge_voltage_max_uv; + bat_info->constant_charge_voltage_max_uv; bq2515x->init_data.iprechg = - bat_info.precharge_current_ua; + bat_info->precharge_current_ua; } ret = bq2515x_set_const_charge_current(bq2515x, diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c index f501ecd49202..b274942dc46a 100644 --- a/drivers/power/supply/bq256xx_charger.c +++ b/drivers/power/supply/bq256xx_charger.c @@ -1504,7 +1504,7 @@ static int bq256xx_power_supply_init(struct bq256xx_device *bq, static int bq256xx_hw_init(struct bq256xx_device *bq) { - struct power_supply_battery_info bat_info = { }; + struct power_supply_battery_info *bat_info; int wd_reg_val = BQ256XX_WATCHDOG_DIS; int ret = 0; int i; @@ -1526,16 +1526,16 @@ static int bq256xx_hw_init(struct bq256xx_device *bq) if (ret) { dev_warn(bq->dev, "battery info missing, default values will be applied\n"); - bat_info.constant_charge_current_max_ua = + bat_info->constant_charge_current_max_ua = bq->chip_info->bq256xx_def_ichg; - bat_info.constant_charge_voltage_max_uv = + bat_info->constant_charge_voltage_max_uv = bq->chip_info->bq256xx_def_vbatreg; - bat_info.precharge_current_ua = + bat_info->precharge_current_ua = bq->chip_info->bq256xx_def_iprechg; - bat_info.charge_term_current_ua = + bat_info->charge_term_current_ua = bq->chip_info->bq256xx_def_iterm; bq->init_data.ichg_max = @@ -1545,10 +1545,10 @@ static int bq256xx_hw_init(struct bq256xx_device *bq) bq->chip_info->bq256xx_max_vbatreg; } else { bq->init_data.ichg_max = - bat_info.constant_charge_current_max_ua; + bat_info->constant_charge_current_max_ua; bq->init_data.vbatreg_max = - bat_info.constant_charge_voltage_max_uv; + bat_info->constant_charge_voltage_max_uv; } ret = bq->chip_info->bq256xx_set_vindpm(bq, bq->init_data.vindpm); @@ -1560,26 +1560,26 @@ static int bq256xx_hw_init(struct bq256xx_device *bq) return ret; ret = bq->chip_info->bq256xx_set_ichg(bq, - bat_info.constant_charge_current_max_ua); + bat_info->constant_charge_current_max_ua); if (ret) return ret; ret = bq->chip_info->bq256xx_set_iprechg(bq, - bat_info.precharge_current_ua); + bat_info->precharge_current_ua); if (ret) return ret; ret = bq->chip_info->bq256xx_set_vbatreg(bq, - bat_info.constant_charge_voltage_max_uv); + bat_info->constant_charge_voltage_max_uv); if (ret) return ret; ret = bq->chip_info->bq256xx_set_iterm(bq, - bat_info.charge_term_current_ua); + bat_info->charge_term_current_ua); if (ret) return ret; - power_supply_put_battery_info(bq->charger, &bat_info); + power_supply_put_battery_info(bq->charger, bat_info); return 0; } diff --git a/drivers/power/supply/bq25980_charger.c b/drivers/power/supply/bq25980_charger.c index 0008c229fd9c..9daa6d14db4d 100644 --- a/drivers/power/supply/bq25980_charger.c +++ b/drivers/power/supply/bq25980_charger.c @@ -1079,7 +1079,7 @@ static int bq25980_power_supply_init(struct bq25980_device *bq, static int bq25980_hw_init(struct bq25980_device *bq) { - struct power_supply_battery_info bat_info = { }; + struct power_supply_battery_info *bat_info; int wd_reg_val = BQ25980_WATCHDOG_DIS; int wd_max_val = BQ25980_NUM_WD_VAL - 1; int ret = 0; @@ -1112,8 +1112,8 @@ static int bq25980_hw_init(struct bq25980_device *bq) return -EINVAL; } - bq->init_data.ichg_max = bat_info.constant_charge_current_max_ua; - bq->init_data.vreg_max = bat_info.constant_charge_voltage_max_uv; + bq->init_data.ichg_max = bat_info->constant_charge_current_max_ua; + bq->init_data.vreg_max = bat_info->constant_charge_voltage_max_uv; if (bq->state.bypass) { ret = regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_2, diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 7e5e24b585d8..72e727cd31e8 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -1474,7 +1474,7 @@ static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di, static void bq27xxx_battery_settings(struct bq27xxx_device_info *di) { - struct power_supply_battery_info info = {}; + struct power_supply_battery_info *info; unsigned int min, max; if (power_supply_get_battery_info(di->bat, &info) < 0) @@ -1485,43 +1485,43 @@ static void bq27xxx_battery_settings(struct bq27xxx_device_info *di) return; } - if (info.energy_full_design_uwh != info.charge_full_design_uah) { - if (info.energy_full_design_uwh == -EINVAL) + if (info->energy_full_design_uwh != info->charge_full_design_uah) { + if (info->energy_full_design_uwh == -EINVAL) dev_warn(di->dev, "missing battery:energy-full-design-microwatt-hours\n"); - else if (info.charge_full_design_uah == -EINVAL) + else if (info->charge_full_design_uah == -EINVAL) dev_warn(di->dev, "missing battery:charge-full-design-microamp-hours\n"); } /* assume min == 0 */ max = di->dm_regs[BQ27XXX_DM_DESIGN_ENERGY].max; - if (info.energy_full_design_uwh > max * 1000) { + if (info->energy_full_design_uwh > max * 1000) { dev_err(di->dev, "invalid battery:energy-full-design-microwatt-hours %d\n", - info.energy_full_design_uwh); - info.energy_full_design_uwh = -EINVAL; + info->energy_full_design_uwh); + info->energy_full_design_uwh = -EINVAL; } /* assume min == 0 */ max = di->dm_regs[BQ27XXX_DM_DESIGN_CAPACITY].max; - if (info.charge_full_design_uah > max * 1000) { + if (info->charge_full_design_uah > max * 1000) { dev_err(di->dev, "invalid battery:charge-full-design-microamp-hours %d\n", - info.charge_full_design_uah); - info.charge_full_design_uah = -EINVAL; + info->charge_full_design_uah); + info->charge_full_design_uah = -EINVAL; } min = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].min; max = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].max; - if ((info.voltage_min_design_uv < min * 1000 || - info.voltage_min_design_uv > max * 1000) && - info.voltage_min_design_uv != -EINVAL) { + if ((info->voltage_min_design_uv < min * 1000 || + info->voltage_min_design_uv > max * 1000) && + info->voltage_min_design_uv != -EINVAL) { dev_err(di->dev, "invalid battery:voltage-min-design-microvolt %d\n", - info.voltage_min_design_uv); - info.voltage_min_design_uv = -EINVAL; + info->voltage_min_design_uv); + info->voltage_min_design_uv = -EINVAL; } - if ((info.energy_full_design_uwh != -EINVAL && - info.charge_full_design_uah != -EINVAL) || - info.voltage_min_design_uv != -EINVAL) - bq27xxx_battery_set_config(di, &info); + if ((info->energy_full_design_uwh != -EINVAL && + info->charge_full_design_uah != -EINVAL) || + info->voltage_min_design_uv != -EINVAL) + bq27xxx_battery_set_config(di, info); } /* diff --git a/drivers/power/supply/cw2015_battery.c b/drivers/power/supply/cw2015_battery.c index 091868e9e9e8..0c87ad0dbf71 100644 --- a/drivers/power/supply/cw2015_battery.c +++ b/drivers/power/supply/cw2015_battery.c @@ -61,7 +61,7 @@ struct cw_battery { struct delayed_work battery_delay_work; struct regmap *regmap; struct power_supply *rk_bat; - struct power_supply_battery_info battery; + struct power_supply_battery_info *battery; u8 *bat_profile; bool charger_attached; @@ -505,22 +505,22 @@ static int cw_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_FULL: case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: - if (cw_bat->battery.charge_full_design_uah > 0) - val->intval = cw_bat->battery.charge_full_design_uah; + if (cw_bat->battery->charge_full_design_uah > 0) + val->intval = cw_bat->battery->charge_full_design_uah; else val->intval = 0; break; case POWER_SUPPLY_PROP_CHARGE_NOW: - val->intval = cw_bat->battery.charge_full_design_uah; + val->intval = cw_bat->battery->charge_full_design_uah; val->intval = val->intval * cw_bat->soc / 100; break; case POWER_SUPPLY_PROP_CURRENT_NOW: if (cw_battery_valid_time_to_empty(cw_bat) && - cw_bat->battery.charge_full_design_uah > 0) { + cw_bat->battery->charge_full_design_uah > 0) { /* calculate remaining capacity */ - val->intval = cw_bat->battery.charge_full_design_uah; + val->intval = cw_bat->battery->charge_full_design_uah; val->intval = val->intval * cw_bat->soc / 100; /* estimate current based on time to empty */ @@ -687,6 +687,12 @@ static int cw_bat_probe(struct i2c_client *client) ret = power_supply_get_battery_info(cw_bat->rk_bat, &cw_bat->battery); if (ret) { + /* Allocate an empty battery */ + cw_bat->battery = devm_kzalloc(&client->dev, + sizeof(cw_bat->battery), + GFP_KERNEL); + if (!cw_bat->battery) + return -ENOMEM; dev_warn(cw_bat->dev, "No monitored battery, some properties will be missing\n"); } @@ -724,7 +730,7 @@ static int cw_bat_remove(struct i2c_client *client) struct cw_battery *cw_bat = i2c_get_clientdata(client); cancel_delayed_work_sync(&cw_bat->battery_delay_work); - power_supply_put_battery_info(cw_bat->rk_bat, &cw_bat->battery); + power_supply_put_battery_info(cw_bat->rk_bat, cw_bat->battery); return 0; } diff --git a/drivers/power/supply/ingenic-battery.c b/drivers/power/supply/ingenic-battery.c index 8b18219ebe90..2e7fdfde47ec 100644 --- a/drivers/power/supply/ingenic-battery.c +++ b/drivers/power/supply/ingenic-battery.c @@ -18,7 +18,7 @@ struct ingenic_battery { struct iio_channel *channel; struct power_supply_desc desc; struct power_supply *battery; - struct power_supply_battery_info info; + struct power_supply_battery_info *info; }; static int ingenic_battery_get_property(struct power_supply *psy, @@ -26,7 +26,7 @@ static int ingenic_battery_get_property(struct power_supply *psy, union power_supply_propval *val) { struct ingenic_battery *bat = power_supply_get_drvdata(psy); - struct power_supply_battery_info *info = &bat->info; + struct power_supply_battery_info *info = bat->info; int ret; switch (psp) { @@ -80,7 +80,7 @@ static int ingenic_battery_set_scale(struct ingenic_battery *bat) if (ret != IIO_AVAIL_LIST || scale_type != IIO_VAL_FRACTIONAL_LOG2) return -EINVAL; - max_mV = bat->info.voltage_max_design_uv / 1000; + max_mV = bat->info->voltage_max_design_uv / 1000; for (i = 0; i < scale_len; i += 2) { u64 scale_mV = (max_raw * scale_raw[i]) >> scale_raw[i + 1]; @@ -156,13 +156,13 @@ static int ingenic_battery_probe(struct platform_device *pdev) dev_err(dev, "Unable to get battery info: %d\n", ret); return ret; } - if (bat->info.voltage_min_design_uv < 0) { + if (bat->info->voltage_min_design_uv < 0) { dev_err(dev, "Unable to get voltage min design\n"); - return bat->info.voltage_min_design_uv; + return bat->info->voltage_min_design_uv; } - if (bat->info.voltage_max_design_uv < 0) { + if (bat->info->voltage_max_design_uv < 0) { dev_err(dev, "Unable to get voltage max design\n"); - return bat->info.voltage_max_design_uv; + return bat->info->voltage_max_design_uv; } return ingenic_battery_set_scale(bat); diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 2907b84ceea9..fffb87dca5a0 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -564,14 +564,19 @@ EXPORT_SYMBOL_GPL(devm_power_supply_get_by_phandle); #endif /* CONFIG_OF */ int power_supply_get_battery_info(struct power_supply *psy, - struct power_supply_battery_info *info) + struct power_supply_battery_info **info_out) { struct power_supply_resistance_temp_table *resist_table; + struct power_supply_battery_info *info; struct device_node *battery_np; const char *value; int err, len, index; const __be32 *list; + info = devm_kmalloc(&psy->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + info->technology = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; info->energy_full_design_uwh = -EINVAL; info->charge_full_design_uah = -EINVAL; @@ -581,6 +586,10 @@ int power_supply_get_battery_info(struct power_supply *psy, info->charge_term_current_ua = -EINVAL; info->constant_charge_current_max_ua = -EINVAL; info->constant_charge_voltage_max_uv = -EINVAL; + info->tricklecharge_current_ua = -EINVAL; + info->precharge_voltage_max_uv = -EINVAL; + info->charge_restart_voltage_uv = -EINVAL; + info->overvoltage_limit_uv = -EINVAL; info->temp_ambient_alert_min = INT_MIN; info->temp_ambient_alert_max = INT_MAX; info->temp_alert_min = INT_MIN; @@ -728,7 +737,7 @@ int power_supply_get_battery_info(struct power_supply *psy, list = of_get_property(battery_np, "resistance-temp-table", &len); if (!list || !len) - goto out_put_node; + goto out_ret_pointer; info->resist_table_size = len / (2 * sizeof(__be32)); resist_table = info->resist_table = devm_kcalloc(&psy->dev, @@ -746,6 +755,10 @@ int power_supply_get_battery_info(struct power_supply *psy, resist_table[index].resistance = be32_to_cpu(*list++); } +out_ret_pointer: + /* Finally return the whole thing */ + *info_out = info; + out_put_node: of_node_put(battery_np); return err; @@ -764,6 +777,8 @@ void power_supply_put_battery_info(struct power_supply *psy, if (info->resist_table) devm_kfree(&psy->dev, info->resist_table); + + devm_kfree(&psy->dev, info); } EXPORT_SYMBOL_GPL(power_supply_put_battery_info); diff --git a/drivers/power/supply/sc2731_charger.c b/drivers/power/supply/sc2731_charger.c index 288b79836c13..9ac17cf7a126 100644 --- a/drivers/power/supply/sc2731_charger.c +++ b/drivers/power/supply/sc2731_charger.c @@ -368,7 +368,7 @@ static int sc2731_charger_usb_change(struct notifier_block *nb, static int sc2731_charger_hw_init(struct sc2731_charger_info *info) { - struct power_supply_battery_info bat_info = { }; + struct power_supply_battery_info *bat_info; u32 term_currrent, term_voltage, cur_val, vol_val; int ret; @@ -390,7 +390,7 @@ static int sc2731_charger_hw_init(struct sc2731_charger_info *info) cur_val = 0x2; vol_val = 0x1; } else { - term_currrent = bat_info.charge_term_current_ua / 1000; + term_currrent = bat_info->charge_term_current_ua / 1000; if (term_currrent <= 90) cur_val = 0; @@ -399,7 +399,7 @@ static int sc2731_charger_hw_init(struct sc2731_charger_info *info) else cur_val = ((term_currrent - 90) / 25) + 1; - term_voltage = bat_info.constant_charge_voltage_max_uv / 1000; + term_voltage = bat_info->constant_charge_voltage_max_uv / 1000; if (term_voltage > 4500) term_voltage = 4500; @@ -409,7 +409,7 @@ static int sc2731_charger_hw_init(struct sc2731_charger_info *info) else vol_val = 0; - power_supply_put_battery_info(info->psy_usb, &bat_info); + power_supply_put_battery_info(info->psy_usb, bat_info); } /* Set charge termination current */ diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index ae45069bd5e1..632977f84b95 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -998,7 +998,7 @@ static int sc27xx_fgu_calibration(struct sc27xx_fgu_data *data) static int sc27xx_fgu_hw_init(struct sc27xx_fgu_data *data) { - struct power_supply_battery_info info = { }; + struct power_supply_battery_info *info; struct power_supply_battery_ocv_table *table; int ret, delta_clbcnt, alarm_adc; @@ -1008,16 +1008,16 @@ static int sc27xx_fgu_hw_init(struct sc27xx_fgu_data *data) return ret; } - data->total_cap = info.charge_full_design_uah / 1000; - data->max_volt = info.constant_charge_voltage_max_uv / 1000; - data->internal_resist = info.factory_internal_resistance_uohm / 1000; - data->min_volt = info.voltage_min_design_uv; + data->total_cap = info->charge_full_design_uah / 1000; + data->max_volt = info->constant_charge_voltage_max_uv / 1000; + data->internal_resist = info->factory_internal_resistance_uohm / 1000; + data->min_volt = info->voltage_min_design_uv; /* * For SC27XX fuel gauge device, we only use one ocv-capacity * table in normal temperature 20 Celsius. */ - table = power_supply_find_ocv2cap_table(&info, 20, &data->table_len); + table = power_supply_find_ocv2cap_table(info, 20, &data->table_len); if (!table) return -EINVAL; @@ -1025,7 +1025,7 @@ static int sc27xx_fgu_hw_init(struct sc27xx_fgu_data *data) data->table_len * sizeof(*table), GFP_KERNEL); if (!data->cap_table) { - power_supply_put_battery_info(data->battery, &info); + power_supply_put_battery_info(data->battery, info); return -ENOMEM; } @@ -1035,19 +1035,19 @@ static int sc27xx_fgu_hw_init(struct sc27xx_fgu_data *data) if (!data->alarm_cap) data->alarm_cap += 1; - data->resist_table_len = info.resist_table_size; + data->resist_table_len = info->resist_table_size; if (data->resist_table_len > 0) { - data->resist_table = devm_kmemdup(data->dev, info.resist_table, + data->resist_table = devm_kmemdup(data->dev, info->resist_table, data->resist_table_len * sizeof(struct power_supply_resistance_temp_table), GFP_KERNEL); if (!data->resist_table) { - power_supply_put_battery_info(data->battery, &info); + power_supply_put_battery_info(data->battery, info); return -ENOMEM; } } - power_supply_put_battery_info(data->battery, &info); + power_supply_put_battery_info(data->battery, info); ret = sc27xx_fgu_calibration(data); if (ret) diff --git a/drivers/power/supply/smb347-charger.c b/drivers/power/supply/smb347-charger.c index 753944e774c4..d56e469043bb 100644 --- a/drivers/power/supply/smb347-charger.c +++ b/drivers/power/supply/smb347-charger.c @@ -1281,7 +1281,7 @@ static void smb347_dt_parse_dev_info(struct smb347_charger *smb) static int smb347_get_battery_info(struct smb347_charger *smb) { - struct power_supply_battery_info info = {}; + struct power_supply_battery_info *info; struct power_supply *supply; int err; @@ -1296,29 +1296,29 @@ static int smb347_get_battery_info(struct smb347_charger *smb) if (err) return err; - if (info.constant_charge_current_max_ua != -EINVAL) - smb->max_charge_current = info.constant_charge_current_max_ua; + if (info->constant_charge_current_max_ua != -EINVAL) + smb->max_charge_current = info->constant_charge_current_max_ua; - if (info.constant_charge_voltage_max_uv != -EINVAL) - smb->max_charge_voltage = info.constant_charge_voltage_max_uv; + if (info->constant_charge_voltage_max_uv != -EINVAL) + smb->max_charge_voltage = info->constant_charge_voltage_max_uv; - if (info.precharge_current_ua != -EINVAL) - smb->pre_charge_current = info.precharge_current_ua; + if (info->precharge_current_ua != -EINVAL) + smb->pre_charge_current = info->precharge_current_ua; - if (info.charge_term_current_ua != -EINVAL) - smb->termination_current = info.charge_term_current_ua; + if (info->charge_term_current_ua != -EINVAL) + smb->termination_current = info->charge_term_current_ua; - if (info.temp_alert_min != INT_MIN) - smb->soft_cold_temp_limit = info.temp_alert_min; + if (info->temp_alert_min != INT_MIN) + smb->soft_cold_temp_limit = info->temp_alert_min; - if (info.temp_alert_max != INT_MAX) - smb->soft_hot_temp_limit = info.temp_alert_max; + if (info->temp_alert_max != INT_MAX) + smb->soft_hot_temp_limit = info->temp_alert_max; - if (info.temp_min != INT_MIN) - smb->hard_cold_temp_limit = info.temp_min; + if (info->temp_min != INT_MIN) + smb->hard_cold_temp_limit = info->temp_min; - if (info.temp_max != INT_MAX) - smb->hard_hot_temp_limit = info.temp_max; + if (info->temp_max != INT_MAX) + smb->hard_hot_temp_limit = info->temp_max; /* Suspend when battery temperature is outside hard limits */ if (smb->hard_cold_temp_limit != SMB3XX_TEMP_USE_DEFAULT || diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index f6e94eae4f28..86b4d5c4dab9 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -575,7 +575,7 @@ devm_power_supply_get_by_phandle(struct device *dev, const char *property) #endif /* CONFIG_OF */ extern int power_supply_get_battery_info(struct power_supply *psy, - struct power_supply_battery_info *info); + struct power_supply_battery_info **info_out); extern void power_supply_put_battery_info(struct power_supply *psy, struct power_supply_battery_info *info); extern int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table, -- cgit v1.2.3-59-g8ed1b