From f1b937cc86bedf94dbc3478c2c0dc79471081fff Mon Sep 17 00:00:00 2001 From: Romain Izard Date: Fri, 30 Aug 2019 15:15:56 +0200 Subject: [PATCH 01/24] power: supply: register HWMON devices with valid names With the introduction of the HWMON compatibility layer to the power supply framework in Linux 5.3, all power supply devices' names can be used directly to create HWMON devices with the same names. But HWMON has rules on allowable names that are different from those used in the power supply framework. The dash character is forbidden, as it is used by the libsensors library in userspace as a separator, whereas this character is used in the device names in more than half of the existing power supply drivers. This last case is consistent with the typical naming usage with MFD and Device Tree. This leads to warnings in the kernel log, with the format: power_supply gpio-charger: hwmon: \ 'gpio-charger' is not a valid name attribute, please fix Add a protection to power_supply_add_hwmon_sysfs() that replaces any dash in the device name with an underscore when registering with the HWMON framework. Other forbidden characters (star, slash, space, tab, newline) are not replaced, as they are not in common use. Fixes: e67d4dfc9ff1 ("power: supply: Add HWMON compatibility layer") Signed-off-by: Romain Izard Reviewed-by: Guenter Roeck Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_hwmon.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/power_supply_hwmon.c b/drivers/power/supply/power_supply_hwmon.c index 51fe60440d12..75cf861ba492 100644 --- a/drivers/power/supply/power_supply_hwmon.c +++ b/drivers/power/supply/power_supply_hwmon.c @@ -284,6 +284,7 @@ int power_supply_add_hwmon_sysfs(struct power_supply *psy) struct device *dev = &psy->dev; struct device *hwmon; int ret, i; + const char *name; if (!devres_open_group(dev, power_supply_add_hwmon_sysfs, GFP_KERNEL)) @@ -334,7 +335,19 @@ int power_supply_add_hwmon_sysfs(struct power_supply *psy) } } - hwmon = devm_hwmon_device_register_with_info(dev, psy->desc->name, + name = psy->desc->name; + if (strchr(name, '-')) { + char *new_name; + + new_name = devm_kstrdup(dev, name, GFP_KERNEL); + if (!new_name) { + ret = -ENOMEM; + goto error; + } + strreplace(new_name, '-', '_'); + name = new_name; + } + hwmon = devm_hwmon_device_register_with_info(dev, name, psyhw, &power_supply_hwmon_chip_info, NULL); From 6f3ed834717b9fcfb4993afea231937422b8ad10 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 25 Aug 2019 17:41:51 +0200 Subject: [PATCH 02/24] power: supply: axp288_fuel_gauge: Sort the DMI blacklist alphabetically The blacklist is getting big enough that it is good to have some sort of fixed order for it, sort it alphabetically. Signed-off-by: Hans de Goede Signed-off-by: Sebastian Reichel --- drivers/power/supply/axp288_fuel_gauge.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c index 44169dabb705..6db2e86098e9 100644 --- a/drivers/power/supply/axp288_fuel_gauge.c +++ b/drivers/power/supply/axp288_fuel_gauge.c @@ -674,6 +674,7 @@ intr_failed: /* * Some devices have no battery (HDMI sticks) and the axp288 battery's * detection reports one despite it not being there. + * Please keep this listed sorted alphabetically. */ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = { { @@ -696,6 +697,12 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = { DMI_EXACT_MATCH(DMI_BIOS_VERSION, "1.000"), }, }, + { + /* ECS EF20EA */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"), + }, + }, { /* Intel Cherry Trail Compute Stick, Windows version */ .matches = { @@ -719,12 +726,6 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = { DMI_MATCH(DMI_BOARD_VERSION, "V1.1"), }, }, - { - /* ECS EF20EA */ - .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"), - }, - }, {} }; From fa7da7449eb3172e9ef56ae69a1db237cb26c8df Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 25 Aug 2019 17:41:52 +0200 Subject: [PATCH 03/24] power: supply: axp288_fuel_gauge: Add Minix Neo Z83-4 to the blacklist The Minix Neo Z83-4 is another mini PC using the AXP288 PMIC where the EFI code does not disable the charger part of the PMIC causing us to report battery readings (of always 100%) to userspace even though there is no battery in this wall-outlet powered device. Add it to the blacklist to avoid the bogus battery status reporting. Signed-off-by: Hans de Goede Signed-off-by: Sebastian Reichel --- drivers/power/supply/axp288_fuel_gauge.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c index 6db2e86098e9..e1bc4e6e6f30 100644 --- a/drivers/power/supply/axp288_fuel_gauge.c +++ b/drivers/power/supply/axp288_fuel_gauge.c @@ -726,6 +726,13 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = { DMI_MATCH(DMI_BOARD_VERSION, "V1.1"), }, }, + { + /* Minix Neo Z83-4 mini PC */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MINIX"), + DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"), + } + }, {} }; From 99956a9e08251a1234434b492875b1eaff502a12 Mon Sep 17 00:00:00 2001 From: Michael Nosthoff Date: Fri, 16 Aug 2019 09:37:42 +0200 Subject: [PATCH 04/24] power: supply: sbs-battery: use correct flags field the type flag is stored in the chip->flags field not in the client->flags field. This currently leads to never using the ti specific health function as client->flags doesn't use that bit. So it's always falling back to the general one. Fixes: 76b16f4cdfb8 ("power: supply: sbs-battery: don't assume MANUFACTURER_DATA formats") Cc: Signed-off-by: Michael Nosthoff Reviewed-by: Brian Norris Reviewed-by: Enric Balletbo i Serra Signed-off-by: Sebastian Reichel --- drivers/power/supply/sbs-battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c index 048d205d7074..2e86cc1e0e35 100644 --- a/drivers/power/supply/sbs-battery.c +++ b/drivers/power/supply/sbs-battery.c @@ -620,7 +620,7 @@ static int sbs_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_PRESENT: case POWER_SUPPLY_PROP_HEALTH: - if (client->flags & SBS_FLAGS_TI_BQ20Z75) + if (chip->flags & SBS_FLAGS_TI_BQ20Z75) ret = sbs_get_ti_battery_presence_and_health(client, psp, val); else From 47c169e17bbd97a0dce44676ac10cbd317c35a11 Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Tue, 13 Aug 2019 09:13:58 +0300 Subject: [PATCH 05/24] MAINTAINERS: N900: Remove isp1704_charger.h record MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update MAINTAINERS to reflect that isp1704_charger.h file was removed. Cc: Pavel Machek Cc: linux-pm@vger.kernel.org Fixes: f5d782d46aa5 ("power: supply: isp1704: switch to gpiod API") Signed-off-by: Denis Efremov Reviewed-by: Pali Rohár Signed-off-by: Sebastian Reichel --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 783569e3c4b4..48e7b07187a5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11400,7 +11400,6 @@ NOKIA N900 POWER SUPPLY DRIVERS R: Pali Rohár F: include/linux/power/bq2415x_charger.h F: include/linux/power/bq27xxx_battery.h -F: include/linux/power/isp1704_charger.h F: drivers/power/supply/bq2415x_charger.c F: drivers/power/supply/bq27xxx_battery.c F: drivers/power/supply/bq27xxx_battery_i2c.c From fe55e770327363304c4111423e6f7ff3c650136d Mon Sep 17 00:00:00 2001 From: Michael Nosthoff Date: Fri, 16 Aug 2019 09:58:42 +0200 Subject: [PATCH 06/24] power: supply: sbs-battery: only return health when battery present when the battery is set to sbs-mode and no gpio detection is enabled "health" is always returning a value even when the battery is not present. All other fields return "not present". This leads to a scenario where the driver is constantly switching between "present" and "not present" state. This generates a lot of constant traffic on the i2c. This commit changes the response of "health" to an error when the battery is not responding leading to a consistent "not present" state. Fixes: 76b16f4cdfb8 ("power: supply: sbs-battery: don't assume MANUFACTURER_DATA formats") Cc: Signed-off-by: Michael Nosthoff Reviewed-by: Brian Norris Tested-by: Brian Norris Signed-off-by: Sebastian Reichel --- drivers/power/supply/sbs-battery.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c index 2e86cc1e0e35..f8d74e9f7931 100644 --- a/drivers/power/supply/sbs-battery.c +++ b/drivers/power/supply/sbs-battery.c @@ -314,17 +314,22 @@ static int sbs_get_battery_presence_and_health( { int ret; - if (psp == POWER_SUPPLY_PROP_PRESENT) { - /* Dummy command; if it succeeds, battery is present. */ - ret = sbs_read_word_data(client, sbs_data[REG_STATUS].addr); - if (ret < 0) - val->intval = 0; /* battery disconnected */ - else - val->intval = 1; /* battery present */ - } else { /* POWER_SUPPLY_PROP_HEALTH */ + /* Dummy command; if it succeeds, battery is present. */ + ret = sbs_read_word_data(client, sbs_data[REG_STATUS].addr); + + if (ret < 0) { /* battery not present*/ + if (psp == POWER_SUPPLY_PROP_PRESENT) { + val->intval = 0; + return 0; + } + return ret; + } + + if (psp == POWER_SUPPLY_PROP_PRESENT) + val->intval = 1; /* battery present */ + else /* POWER_SUPPLY_PROP_HEALTH */ /* SBS spec doesn't have a general health command. */ val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; - } return 0; } @@ -626,6 +631,8 @@ static int sbs_get_property(struct power_supply *psy, else ret = sbs_get_battery_presence_and_health(client, psp, val); + + /* this can only be true if no gpio is used */ if (psp == POWER_SUPPLY_PROP_PRESENT) return 0; break; From 10948061162a4bd9c54086e04dc8cd11faaf5bb5 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 5 Aug 2019 14:44:18 -0500 Subject: [PATCH 07/24] power: supply: ab8500_charger: Mark expected switch fall-through Mark switch cases where we are expecting to fall through. This patch fixes the following warning (Building: allmodconfig arm): drivers/power/supply/ab8500_charger.c:738:6: warning: this statement may fall through [-Wimplicit-fallthrough=] Signed-off-by: Gustavo A. R. Silva Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_charger.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index 30de448de802..1be75a2fed9b 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -742,6 +742,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, USB_CH_IP_CUR_LVL_1P5; break; } + /* else, fall through */ 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; From 8288022284859acbcc3cf1a073a1e2692d6c2543 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 1 Aug 2019 14:33:30 -0700 Subject: [PATCH 08/24] power: supply: Init device wakeup after device_add() We may want to use the device pointer in device_init_wakeup() with functions that expect the device to already be added with device_add(). For example, if we were to link the device initializing wakeup to something in sysfs such as a class for wakeups we'll run into an error. It looks like this code was written with the assumption that the device would be added before initializing wakeup due to the order of operations in power_supply_unregister(). Let's change the order of operations so we don't run into problems here. Fixes: 948dcf966228 ("power_supply: Prevent suspend until power supply events are processed") Cc: Greg Kroah-Hartman Cc: Tri Vo Cc: Kalesh Singh Cc: Ravi Chandra Sadineni Cc: Viresh Kumar Signed-off-by: Stephen Boyd Acked-by: Rafael J. Wysocki Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 82e84801264c..5c36c430ce8b 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -1051,14 +1051,14 @@ __power_supply_register(struct device *parent, } spin_lock_init(&psy->changed_lock); - rc = device_init_wakeup(dev, ws); - if (rc) - goto wakeup_init_failed; - rc = device_add(dev); if (rc) goto device_add_failed; + rc = device_init_wakeup(dev, ws); + if (rc) + goto wakeup_init_failed; + rc = psy_register_thermal(psy); if (rc) goto register_thermal_failed; @@ -1101,8 +1101,8 @@ register_cooler_failed: psy_unregister_thermal(psy); register_thermal_failed: device_del(dev); -device_add_failed: wakeup_init_failed: +device_add_failed: check_supplies_failed: dev_set_name_failed: put_device(dev); From 0e063317d579d0a7fca957461332b6832da69850 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 2 Sep 2019 15:00:40 +0200 Subject: [PATCH 09/24] power: reset: gpio-restart: Fix typo when gpio reset is not found Trivial patch which just corrects error message. Fixes: 371bb20d6927 ("power: Add simple gpio-restart driver") Signed-off-by: Michal Simek Signed-off-by: Sebastian Reichel --- drivers/power/reset/gpio-restart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/reset/gpio-restart.c b/drivers/power/reset/gpio-restart.c index 2880cd5ae0d2..308ca9d9d276 100644 --- a/drivers/power/reset/gpio-restart.c +++ b/drivers/power/reset/gpio-restart.c @@ -65,7 +65,7 @@ static int gpio_restart_probe(struct platform_device *pdev) gpio_restart->reset_gpio = devm_gpiod_get(&pdev->dev, NULL, open_source ? GPIOD_IN : GPIOD_OUT_LOW); if (IS_ERR(gpio_restart->reset_gpio)) { - dev_err(&pdev->dev, "Could net get reset GPIO\n"); + dev_err(&pdev->dev, "Could not get reset GPIO\n"); return PTR_ERR(gpio_restart->reset_gpio); } From 40badfa396093fe85d83a5a57711b4830e85a9e0 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 21 Jul 2019 18:03:28 +0200 Subject: [PATCH 10/24] power: supply: max17042_battery: Fix a typo in function names It is likely that 'max10742_[un]lock_model()' functions should be 'max17042_[un]lock_model()' (0 and 7 switched in 10742) Signed-off-by: Christophe JAILLET Signed-off-by: Sebastian Reichel --- drivers/power/supply/max17042_battery.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c index 64f3358eaa3c..0dfad2cf13fe 100644 --- a/drivers/power/supply/max17042_battery.c +++ b/drivers/power/supply/max17042_battery.c @@ -511,7 +511,7 @@ static inline void max17042_override_por(struct regmap *map, regmap_write(map, reg, value); } -static inline void max10742_unlock_model(struct max17042_chip *chip) +static inline void max17042_unlock_model(struct max17042_chip *chip) { struct regmap *map = chip->regmap; @@ -519,7 +519,7 @@ static inline void max10742_unlock_model(struct max17042_chip *chip) regmap_write(map, MAX17042_MLOCKReg2, MODEL_UNLOCK2); } -static inline void max10742_lock_model(struct max17042_chip *chip) +static inline void max17042_lock_model(struct max17042_chip *chip) { struct regmap *map = chip->regmap; @@ -577,7 +577,7 @@ static int max17042_init_model(struct max17042_chip *chip) if (!temp_data) return -ENOMEM; - max10742_unlock_model(chip); + max17042_unlock_model(chip); max17042_write_model_data(chip, MAX17042_MODELChrTbl, table_size); max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data, @@ -589,7 +589,7 @@ static int max17042_init_model(struct max17042_chip *chip) temp_data, table_size); - max10742_lock_model(chip); + max17042_lock_model(chip); kfree(temp_data); return ret; From 9eab9a5b4c53df850c5a7f4f48b783fac3bbffe8 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 17 Jul 2019 22:18:48 +0800 Subject: [PATCH 11/24] power: supply: ab8500: remove set but not used variables 'vbup33_vrtcn' and 'bup_vch_range' Fixes gcc '-Wunused-but-set-variable' warnings: drivers/power/supply/ab8500_charger.c: In function ab8500_charger_init_hw_registers: drivers/power/supply/ab8500_charger.c:3013:24: warning: variable vbup33_vrtcn set but not used [-Wunused-but-set-variable] drivers/power/supply/ab8500_charger.c:3013:5: warning: variable bup_vch_range set but not used [-Wunused-but-set-variable] Fixes: 4c4268dc97c4 ("power: supply: ab8500: Drop AB8540/9540 support") Reported-by: Hulk Robot Signed-off-by: YueHaibing Reviewed-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_charger.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index 1be75a2fed9b..e51d0e72beea 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -3011,7 +3011,6 @@ static int ab8500_charger_usb_get_property(struct power_supply *psy, static int ab8500_charger_init_hw_registers(struct ab8500_charger *di) { int ret = 0; - u8 bup_vch_range = 0, vbup33_vrtcn = 0; /* Setup maximum charger current and voltage for ABB cut2.0 */ if (!is_ab8500_1p1_or_earlier(di->parent)) { @@ -3112,12 +3111,6 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di) goto out; } - /* Backup battery voltage and current */ - if (di->bm->bkup_bat_v > BUP_VCH_SEL_3P1V) - bup_vch_range = BUP_VCH_RANGE; - if (di->bm->bkup_bat_v == BUP_VCH_SEL_3P3V) - vbup33_vrtcn = VBUP33_VRTCN; - ret = abx500_set_register_interruptible(di->dev, AB8500_RTC, AB8500_RTC_BACKUP_CHG_REG, From 59857e9eadceb4002b2bd601d526091e4524d610 Mon Sep 17 00:00:00 2001 From: "Matwey V. Kornilov" Date: Sat, 13 Jul 2019 18:42:48 +0300 Subject: [PATCH 12/24] power: reset: reboot-mode: Fix author email format Closing angle bracket was missing. Signed-off-by: Matwey V. Kornilov Signed-off-by: Sebastian Reichel --- drivers/power/reset/reboot-mode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c index 06ff035b57f5..b4076b10b893 100644 --- a/drivers/power/reset/reboot-mode.c +++ b/drivers/power/reset/reboot-mode.c @@ -190,6 +190,6 @@ void devm_reboot_mode_unregister(struct device *dev, } EXPORT_SYMBOL_GPL(devm_reboot_mode_unregister); -MODULE_AUTHOR("Andy Yan "); MODULE_DESCRIPTION("System reboot mode core library"); MODULE_LICENSE("GPL v2"); From 08614b407d8dffd9136c79ce6fd579be42173cc3 Mon Sep 17 00:00:00 2001 From: Fuqian Huang Date: Mon, 8 Jul 2019 20:32:51 +0800 Subject: [PATCH 13/24] power: supply: sc27xx: Introduce local variable 'struct device *dev' Introduce local variable 'struct device *dev' and use it instead of dereferencing it repeatly. Signed-off-by: Fuqian Huang Reviewed-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/supply/sc27xx_fuel_gauge.c | 47 ++++++++++++------------ 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index 24895cc3b41e..9c184d80088b 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -957,81 +957,82 @@ disable_fgu: static int sc27xx_fgu_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct power_supply_config fgu_cfg = { }; struct sc27xx_fgu_data *data; int ret, irq; - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - data->regmap = dev_get_regmap(pdev->dev.parent, NULL); + data->regmap = dev_get_regmap(dev->parent, NULL); if (!data->regmap) { - dev_err(&pdev->dev, "failed to get regmap\n"); + dev_err(dev, "failed to get regmap\n"); return -ENODEV; } - ret = device_property_read_u32(&pdev->dev, "reg", &data->base); + ret = device_property_read_u32(dev, "reg", &data->base); if (ret) { - dev_err(&pdev->dev, "failed to get fgu address\n"); + dev_err(dev, "failed to get fgu address\n"); return ret; } - data->channel = devm_iio_channel_get(&pdev->dev, "bat-temp"); + data->channel = devm_iio_channel_get(dev, "bat-temp"); if (IS_ERR(data->channel)) { - dev_err(&pdev->dev, "failed to get IIO channel\n"); + dev_err(dev, "failed to get IIO channel\n"); return PTR_ERR(data->channel); } - data->charge_chan = devm_iio_channel_get(&pdev->dev, "charge-vol"); + data->charge_chan = devm_iio_channel_get(dev, "charge-vol"); if (IS_ERR(data->charge_chan)) { - dev_err(&pdev->dev, "failed to get charge IIO channel\n"); + dev_err(dev, "failed to get charge IIO channel\n"); return PTR_ERR(data->charge_chan); } - data->gpiod = devm_gpiod_get(&pdev->dev, "bat-detect", GPIOD_IN); + data->gpiod = devm_gpiod_get(dev, "bat-detect", GPIOD_IN); if (IS_ERR(data->gpiod)) { - dev_err(&pdev->dev, "failed to get battery detection GPIO\n"); + dev_err(dev, "failed to get battery detection GPIO\n"); return PTR_ERR(data->gpiod); } ret = gpiod_get_value_cansleep(data->gpiod); if (ret < 0) { - dev_err(&pdev->dev, "failed to get gpio state\n"); + dev_err(dev, "failed to get gpio state\n"); return ret; } data->bat_present = !!ret; mutex_init(&data->lock); - data->dev = &pdev->dev; + data->dev = dev; platform_set_drvdata(pdev, data); fgu_cfg.drv_data = data; fgu_cfg.of_node = np; - data->battery = devm_power_supply_register(&pdev->dev, &sc27xx_fgu_desc, + data->battery = devm_power_supply_register(dev, &sc27xx_fgu_desc, &fgu_cfg); if (IS_ERR(data->battery)) { - dev_err(&pdev->dev, "failed to register power supply\n"); + dev_err(dev, "failed to register power supply\n"); return PTR_ERR(data->battery); } ret = sc27xx_fgu_hw_init(data); if (ret) { - dev_err(&pdev->dev, "failed to initialize fgu hardware\n"); + dev_err(dev, "failed to initialize fgu hardware\n"); return ret; } - ret = devm_add_action(&pdev->dev, sc27xx_fgu_disable, data); + ret = devm_add_action(dev, sc27xx_fgu_disable, data); if (ret) { sc27xx_fgu_disable(data); - dev_err(&pdev->dev, "failed to add fgu disable action\n"); + dev_err(dev, "failed to add fgu disable action\n"); return ret; } irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "no irq resource specified\n"); + dev_err(dev, "no irq resource specified\n"); return irq; } @@ -1046,17 +1047,17 @@ static int sc27xx_fgu_probe(struct platform_device *pdev) irq = gpiod_to_irq(data->gpiod); if (irq < 0) { - dev_err(&pdev->dev, "failed to translate GPIO to IRQ\n"); + dev_err(dev, "failed to translate GPIO to IRQ\n"); return irq; } - ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + ret = devm_request_threaded_irq(dev, irq, NULL, sc27xx_fgu_bat_detection, IRQF_ONESHOT | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, pdev->name, data); if (ret) { - dev_err(&pdev->dev, "failed to request IRQ\n"); + dev_err(dev, "failed to request IRQ\n"); return ret; } From 204205836f4d9a44c3e8825a9c14704fc5b2cdfd Mon Sep 17 00:00:00 2001 From: Fuqian Huang Date: Mon, 8 Jul 2019 20:32:59 +0800 Subject: [PATCH 14/24] power: supply: sc27xx: Replace devm_add_action() followed by failure action with devm_add_action_or_reset() devm_add_action_or_reset() is introduced as a helper function which internally calls devm_add_action(). If devm_add_action() fails then it will execute the action mentioned and return the error code. This reduce source code size (avoid writing the action twice) and reduce the likelyhood of bugs. Signed-off-by: Fuqian Huang Reviewed-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/supply/sc27xx_fuel_gauge.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index 9c184d80088b..58b2970cd359 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -1023,9 +1023,8 @@ static int sc27xx_fgu_probe(struct platform_device *pdev) return ret; } - ret = devm_add_action(dev, sc27xx_fgu_disable, data); + ret = devm_add_action_or_reset(dev, sc27xx_fgu_disable, data); if (ret) { - sc27xx_fgu_disable(data); dev_err(dev, "failed to add fgu disable action\n"); return ret; } From 5c35ba9b4743ac82613e8ff306287c8837f21f24 Mon Sep 17 00:00:00 2001 From: "Angus Ainslie (Purism)" Date: Fri, 5 Jul 2019 05:37:51 -0600 Subject: [PATCH 15/24] power: supply: bq25890_charger: Add the BQ25895 part The BQ25895 is almost identical to the BQ25890. Signed-off-by: Angus Ainslie (Purism) Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq25890_charger.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index d333f2b321b9..9d1ec8d677de 100644 --- a/drivers/power/supply/bq25890_charger.c +++ b/drivers/power/supply/bq25890_charger.c @@ -22,6 +22,7 @@ #define BQ25890_IRQ_PIN "bq25890_irq" #define BQ25890_ID 3 +#define BQ25895_ID 7 #define BQ25896_ID 0 enum bq25890_fields { @@ -171,7 +172,7 @@ static const struct reg_field bq25890_reg_fields[] = { [F_WD] = REG_FIELD(0x07, 4, 5), [F_TMR_EN] = REG_FIELD(0x07, 3, 3), [F_CHG_TMR] = REG_FIELD(0x07, 1, 2), - [F_JEITA_ISET] = REG_FIELD(0x07, 0, 0), + [F_JEITA_ISET] = REG_FIELD(0x07, 0, 0), // reserved on BQ25895 /* REG08 */ [F_BATCMP] = REG_FIELD(0x08, 5, 7), [F_VCLAMP] = REG_FIELD(0x08, 2, 4), @@ -180,7 +181,7 @@ static const struct reg_field bq25890_reg_fields[] = { [F_FORCE_ICO] = REG_FIELD(0x09, 7, 7), [F_TMR2X_EN] = REG_FIELD(0x09, 6, 6), [F_BATFET_DIS] = REG_FIELD(0x09, 5, 5), - [F_JEITA_VSET] = REG_FIELD(0x09, 4, 4), + [F_JEITA_VSET] = REG_FIELD(0x09, 4, 4), // reserved on BQ25895 [F_BATFET_DLY] = REG_FIELD(0x09, 3, 3), [F_BATFET_RST_EN] = REG_FIELD(0x09, 2, 2), [F_PUMPX_UP] = REG_FIELD(0x09, 1, 1), @@ -188,7 +189,7 @@ static const struct reg_field bq25890_reg_fields[] = { /* REG0A */ [F_BOOSTV] = REG_FIELD(0x0A, 4, 7), /* PFM_OTG_DIS 3 on BQ25896 */ - [F_BOOSTI] = REG_FIELD(0x0A, 0, 2), + [F_BOOSTI] = REG_FIELD(0x0A, 0, 2), // reserved on BQ25895 /* REG0B */ [F_VBUS_STAT] = REG_FIELD(0x0B, 5, 7), [F_CHG_STAT] = REG_FIELD(0x0B, 3, 4), @@ -392,6 +393,8 @@ static int bq25890_power_supply_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_MODEL_NAME: if (bq->chip_id == BQ25890_ID) val->strval = "BQ25890"; + else if (bq->chip_id == BQ25895_ID) + val->strval = "BQ25895"; else if (bq->chip_id == BQ25896_ID) val->strval = "BQ25896"; else @@ -862,7 +865,8 @@ static int bq25890_probe(struct i2c_client *client, return bq->chip_id; } - if ((bq->chip_id != BQ25890_ID) && (bq->chip_id != BQ25896_ID)) { + if ((bq->chip_id != BQ25890_ID) && (bq->chip_id != BQ25895_ID) + && (bq->chip_id != BQ25896_ID)) { dev_err(dev, "Chip with ID=%d, not supported!\n", bq->chip_id); return -ENODEV; } From 72e538f6ee883dde0925c89d288d16070f3286e4 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 5 Jul 2019 10:36:12 +0100 Subject: [PATCH 16/24] power: supply: isp1704: remove redundant assignment to variable ret The variable ret is being assigned with a value that is never read and it is being updated later with a new value. The assignment is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: Sebastian Reichel --- drivers/power/supply/isp1704_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/isp1704_charger.c b/drivers/power/supply/isp1704_charger.c index b48cb7aba97b..4812ac1ff2df 100644 --- a/drivers/power/supply/isp1704_charger.c +++ b/drivers/power/supply/isp1704_charger.c @@ -342,7 +342,7 @@ static inline int isp1704_test_ulpi(struct isp1704_charger *isp) int vendor; int product; int i; - int ret = -ENODEV; + int ret; /* Test ULPI interface */ ret = isp1704_write(isp, ULPI_SCRATCH, 0xaa); From 343160e98cff359d9fc96f3efc95d90f5a9c2d35 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 3 Jul 2019 10:48:10 +0200 Subject: [PATCH 17/24] power: supply: max77650: add MODULE_ALIAS() Define a MODULE_ALIAS() in the charger sub-driver for max77650 so that the appropriate module gets loaded together with the core mfd driver. Signed-off-by: Bartosz Golaszewski Signed-off-by: Sebastian Reichel --- drivers/power/supply/max77650-charger.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/power/supply/max77650-charger.c b/drivers/power/supply/max77650-charger.c index e34714cb05ec..5f9477c5cf5a 100644 --- a/drivers/power/supply/max77650-charger.c +++ b/drivers/power/supply/max77650-charger.c @@ -366,3 +366,4 @@ module_platform_driver(max77650_charger_driver); MODULE_DESCRIPTION("MAXIM 77650/77651 charger driver"); MODULE_AUTHOR("Bartosz Golaszewski "); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:max77650-charger"); From 7cff19b9a8ff1fdc61655dad4e2009bb44099d70 Mon Sep 17 00:00:00 2001 From: Yuanjiang Yu Date: Wed, 31 Jul 2019 18:00:23 +0800 Subject: [PATCH 18/24] power: supply: sc27xx: Add POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN attribute Add POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN attribute to provide the battery's design capacity for charger manager to calculate the charging counter. Signed-off-by: Yuanjiang Yu Signed-off-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/supply/sc27xx_fuel_gauge.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index 58b2970cd359..1072fcdfe8b2 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -587,6 +587,10 @@ static int sc27xx_fgu_get_property(struct power_supply *psy, val->intval = value * 1000; break; + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: + val->intval = data->total_cap * 1000; + break; + default: ret = -EINVAL; break; @@ -644,6 +648,7 @@ static enum power_supply_property sc27xx_fgu_props[] = { POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CURRENT_AVG, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, + POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, }; static const struct power_supply_desc sc27xx_fgu_desc = { From 168e68d072756d631a210342d0429c969501b7cf Mon Sep 17 00:00:00 2001 From: Yuanjiang Yu Date: Wed, 31 Jul 2019 18:00:24 +0800 Subject: [PATCH 19/24] power: supply: sc27xx: Fix conditon to enable the FGU interrupt We should allow to enable FGU interrupt to adjust the battery capacity, when charging status is POWER_SUPPLY_STATUS_DISCHARGING. Signed-off-by: Yuanjiang Yu Signed-off-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/supply/sc27xx_fuel_gauge.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index 1072fcdfe8b2..db7d07d5dae9 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -1098,7 +1098,8 @@ static int sc27xx_fgu_suspend(struct device *dev) * If we are charging, then no need to enable the FGU interrupts to * adjust the battery capacity. */ - if (status != POWER_SUPPLY_STATUS_NOT_CHARGING) + if (status != POWER_SUPPLY_STATUS_NOT_CHARGING && + status != POWER_SUPPLY_STATUS_DISCHARGING) return 0; ret = regmap_update_bits(data->regmap, data->base + SC27XX_FGU_INT_EN, From 7384b0e7668f722fcf7abe56f61a7212debd0180 Mon Sep 17 00:00:00 2001 From: Yuanjiang Yu Date: Wed, 31 Jul 2019 18:00:25 +0800 Subject: [PATCH 20/24] power: supply: sc27xx: Fix the the accuracy issue of coulomb calculation The Spreadtrum fuel gauge will multiply by 2 for counting the coulomb counter to improve the accuracy, which means the value saved in fuel gauge is: coulomb counter * 2 * 1000ma_adc. Thus fix the conversion formular to improve the accuracy of calculating the battery capacity. Signed-off-by: Yuanjiang Yu Signed-off-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/supply/sc27xx_fuel_gauge.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index db7d07d5dae9..6a29f00aec48 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -326,8 +326,6 @@ static int sc27xx_fgu_set_clbcnt(struct sc27xx_fgu_data *data, int clbcnt) { int ret; - clbcnt *= SC27XX_FGU_SAMPLE_HZ; - ret = regmap_update_bits(data->regmap, data->base + SC27XX_FGU_CLBCNT_SETL, SC27XX_FGU_CLBCNT_MASK, clbcnt); @@ -362,7 +360,6 @@ static int sc27xx_fgu_get_clbcnt(struct sc27xx_fgu_data *data, int *clb_cnt) *clb_cnt = ccl & SC27XX_FGU_CLBCNT_MASK; *clb_cnt |= (cch & SC27XX_FGU_CLBCNT_MASK) << SC27XX_FGU_CLBCNT_SHIFT; - *clb_cnt /= SC27XX_FGU_SAMPLE_HZ; return 0; } @@ -380,10 +377,10 @@ static int sc27xx_fgu_get_capacity(struct sc27xx_fgu_data *data, int *cap) /* * Convert coulomb counter to delta capacity (mAh), and set multiplier - * as 100 to improve the precision. + * as 10 to improve the precision. */ - temp = DIV_ROUND_CLOSEST(delta_clbcnt, 360); - temp = sc27xx_fgu_adc_to_current(data, temp); + temp = DIV_ROUND_CLOSEST(delta_clbcnt * 10, 36 * SC27XX_FGU_SAMPLE_HZ); + temp = sc27xx_fgu_adc_to_current(data, temp / 1000); /* * Convert to capacity percent of the battery total capacity, @@ -790,7 +787,7 @@ static int sc27xx_fgu_cap_to_clbcnt(struct sc27xx_fgu_data *data, int capacity) * Convert current capacity (mAh) to coulomb counter according to the * formula: 1 mAh =3.6 coulomb. */ - return DIV_ROUND_CLOSEST(cur_cap * 36 * data->cur_1000ma_adc, 10); + return DIV_ROUND_CLOSEST(cur_cap * 36 * data->cur_1000ma_adc * SC27XX_FGU_SAMPLE_HZ, 10); } static int sc27xx_fgu_calibration(struct sc27xx_fgu_data *data) From ff062d06948c012cbfd6f5947b599be5ea1c3799 Mon Sep 17 00:00:00 2001 From: Yuanjiang Yu Date: Wed, 31 Jul 2019 18:00:27 +0800 Subject: [PATCH 21/24] power: supply: sc27xx: Make sure the alarm capacity is larger than 0 We must make sure the alarm capacity is larger than 0, to help to calibrate the low battery capacity. Signed-off-by: Yuanjiang Yu Signed-off-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/supply/sc27xx_fuel_gauge.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index 6a29f00aec48..096da951f465 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -858,6 +858,8 @@ static int sc27xx_fgu_hw_init(struct sc27xx_fgu_data *data) data->alarm_cap = power_supply_ocv2cap_simple(data->cap_table, data->table_len, data->min_volt); + if (!data->alarm_cap) + data->alarm_cap += 1; power_supply_put_battery_info(data->battery, &info); From 580665279fb6a16eb119ec80a5be1b3ec7a641a0 Mon Sep 17 00:00:00 2001 From: Yuanjiang Yu Date: Wed, 31 Jul 2019 18:00:26 +0800 Subject: [PATCH 22/24] power: supply: sc27xx: Optimize the battery capacity calibration This patch factors out the capacity calibration into one single function to calibrate the battery capacity, and adding more abnormal cases to calibrate the capacity when the OCV value is not matchable with current capacity. Moreover we also allow to calibrate the capacity when charger magager tries to get current capacity to make sure we give a correct capacity for userspace. Signed-off-by: Yuanjiang Yu Signed-off-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/supply/sc27xx_fuel_gauge.c | 147 ++++++++++++++++------- 1 file changed, 102 insertions(+), 45 deletions(-) diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index 096da951f465..6071671caaa9 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -109,6 +109,8 @@ struct sc27xx_fgu_data { }; static int sc27xx_fgu_cap_to_clbcnt(struct sc27xx_fgu_data *data, int capacity); +static void sc27xx_fgu_capacity_calibration(struct sc27xx_fgu_data *data, + int cap, bool int_mode); static const char * const sc27xx_charger_supply_name[] = { "sc2731_charger", @@ -389,6 +391,9 @@ static int sc27xx_fgu_get_capacity(struct sc27xx_fgu_data *data, int *cap) delta_cap = DIV_ROUND_CLOSEST(temp * 100, data->total_cap); *cap = delta_cap + data->init_cap; + /* Calibrate the battery capacity in a normal range. */ + sc27xx_fgu_capacity_calibration(data, *cap, false); + return 0; } @@ -661,14 +666,108 @@ static const struct power_supply_desc sc27xx_fgu_desc = { static void sc27xx_fgu_adjust_cap(struct sc27xx_fgu_data *data, int cap) { + int ret; + data->init_cap = cap; - data->init_clbcnt = sc27xx_fgu_cap_to_clbcnt(data, data->init_cap); + ret = sc27xx_fgu_get_clbcnt(data, &data->init_clbcnt); + if (ret) + dev_err(data->dev, "failed to get init coulomb counter\n"); +} + +static void sc27xx_fgu_capacity_calibration(struct sc27xx_fgu_data *data, + int cap, bool int_mode) +{ + int ret, ocv, chg_sts, adc; + + ret = sc27xx_fgu_get_vbat_ocv(data, &ocv); + if (ret) { + dev_err(data->dev, "get battery ocv error.\n"); + return; + } + + ret = sc27xx_fgu_get_status(data, &chg_sts); + if (ret) { + dev_err(data->dev, "get charger status error.\n"); + return; + } + + /* + * If we are in charging mode, then we do not need to calibrate the + * lower capacity. + */ + if (chg_sts == POWER_SUPPLY_STATUS_CHARGING) + return; + + if ((ocv > data->cap_table[0].ocv && cap < 100) || cap > 100) { + /* + * If current OCV value is larger than the max OCV value in + * OCV table, or the current capacity is larger than 100, + * we should force the inititial capacity to 100. + */ + sc27xx_fgu_adjust_cap(data, 100); + } else if (ocv <= data->cap_table[data->table_len - 1].ocv) { + /* + * If current OCV value is leass than the minimum OCV value in + * OCV table, we should force the inititial capacity to 0. + */ + sc27xx_fgu_adjust_cap(data, 0); + } else if ((ocv > data->cap_table[data->table_len - 1].ocv && cap <= 0) || + (ocv > data->min_volt && cap <= data->alarm_cap)) { + /* + * If current OCV value is not matchable with current capacity, + * we should re-calculate current capacity by looking up the + * OCV table. + */ + int cur_cap = power_supply_ocv2cap_simple(data->cap_table, + data->table_len, ocv); + + sc27xx_fgu_adjust_cap(data, cur_cap); + } else if (ocv <= data->min_volt) { + /* + * If current OCV value is less than the low alarm voltage, but + * current capacity is larger than the alarm capacity, we should + * adjust the inititial capacity to alarm capacity. + */ + if (cap > data->alarm_cap) { + sc27xx_fgu_adjust_cap(data, data->alarm_cap); + } else { + int cur_cap; + + /* + * If current capacity is equal with 0 or less than 0 + * (some error occurs), we should adjust inititial + * capacity to the capacity corresponding to current OCV + * value. + */ + cur_cap = power_supply_ocv2cap_simple(data->cap_table, + data->table_len, + ocv); + sc27xx_fgu_adjust_cap(data, cur_cap); + } + + if (!int_mode) + return; + + /* + * After adjusting the battery capacity, we should set the + * lowest alarm voltage instead. + */ + data->min_volt = data->cap_table[data->table_len - 1].ocv; + data->alarm_cap = power_supply_ocv2cap_simple(data->cap_table, + data->table_len, + data->min_volt); + + adc = sc27xx_fgu_voltage_to_adc(data, data->min_volt / 1000); + regmap_update_bits(data->regmap, + data->base + SC27XX_FGU_LOW_OVERLOAD, + SC27XX_FGU_LOW_OVERLOAD_MASK, adc); + } } static irqreturn_t sc27xx_fgu_interrupt(int irq, void *dev_id) { struct sc27xx_fgu_data *data = dev_id; - int ret, cap, ocv, adc; + int ret, cap; u32 status; mutex_lock(&data->lock); @@ -694,49 +793,7 @@ static irqreturn_t sc27xx_fgu_interrupt(int irq, void *dev_id) if (ret) goto out; - ret = sc27xx_fgu_get_vbat_ocv(data, &ocv); - if (ret) - goto out; - - /* - * If current OCV value is less than the minimum OCV value in OCV table, - * which means now battery capacity is 0%, and we should adjust the - * inititial capacity to 0. - */ - if (ocv <= data->cap_table[data->table_len - 1].ocv) { - sc27xx_fgu_adjust_cap(data, 0); - } else if (ocv <= data->min_volt) { - /* - * If current OCV value is less than the low alarm voltage, but - * current capacity is larger than the alarm capacity, we should - * adjust the inititial capacity to alarm capacity. - */ - if (cap > data->alarm_cap) { - sc27xx_fgu_adjust_cap(data, data->alarm_cap); - } else if (cap <= 0) { - int cur_cap; - - /* - * If current capacity is equal with 0 or less than 0 - * (some error occurs), we should adjust inititial - * capacity to the capacity corresponding to current OCV - * value. - */ - cur_cap = power_supply_ocv2cap_simple(data->cap_table, - data->table_len, - ocv); - sc27xx_fgu_adjust_cap(data, cur_cap); - } - - /* - * After adjusting the battery capacity, we should set the - * lowest alarm voltage instead. - */ - data->min_volt = data->cap_table[data->table_len - 1].ocv; - adc = sc27xx_fgu_voltage_to_adc(data, data->min_volt / 1000); - regmap_update_bits(data->regmap, data->base + SC27XX_FGU_LOW_OVERLOAD, - SC27XX_FGU_LOW_OVERLOAD_MASK, adc); - } + sc27xx_fgu_capacity_calibration(data, cap, true); out: mutex_unlock(&data->lock); From 7cfd33d997a4c320b6bbce5e9592230dae1e73d2 Mon Sep 17 00:00:00 2001 From: Yuanjiang Yu Date: Wed, 31 Jul 2019 18:00:28 +0800 Subject: [PATCH 23/24] power: supply: sc27xx: Add POWER_SUPPLY_PROP_CALIBRATE attribute Add the 'POWER_SUPPLY_PROP_CALIBRATE' attribute to allow chareger manager to calibrate the battery capacity. Signed-off-by: Yuanjiang Yu Signed-off-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/supply/sc27xx_fuel_gauge.c | 27 +++++++++++++++++------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index 6071671caaa9..bc8f5bda5762 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -111,6 +111,7 @@ struct sc27xx_fgu_data { static int sc27xx_fgu_cap_to_clbcnt(struct sc27xx_fgu_data *data, int capacity); static void sc27xx_fgu_capacity_calibration(struct sc27xx_fgu_data *data, int cap, bool int_mode); +static void sc27xx_fgu_adjust_cap(struct sc27xx_fgu_data *data, int cap); static const char * const sc27xx_charger_supply_name[] = { "sc2731_charger", @@ -610,18 +611,26 @@ static int sc27xx_fgu_set_property(struct power_supply *psy, struct sc27xx_fgu_data *data = power_supply_get_drvdata(psy); int ret; - if (psp != POWER_SUPPLY_PROP_CAPACITY) - return -EINVAL; - mutex_lock(&data->lock); - ret = sc27xx_fgu_save_last_cap(data, val->intval); + switch (psp) { + case POWER_SUPPLY_PROP_CAPACITY: + ret = sc27xx_fgu_save_last_cap(data, val->intval); + if (ret < 0) + dev_err(data->dev, "failed to save battery capacity\n"); + break; + + case POWER_SUPPLY_PROP_CALIBRATE: + sc27xx_fgu_adjust_cap(data, val->intval); + ret = 0; + break; + + default: + ret = -EINVAL; + } mutex_unlock(&data->lock); - if (ret < 0) - dev_err(data->dev, "failed to save battery capacity\n"); - return ret; } @@ -635,7 +644,8 @@ static void sc27xx_fgu_external_power_changed(struct power_supply *psy) static int sc27xx_fgu_property_is_writeable(struct power_supply *psy, enum power_supply_property psp) { - return psp == POWER_SUPPLY_PROP_CAPACITY; + return psp == POWER_SUPPLY_PROP_CAPACITY || + psp == POWER_SUPPLY_PROP_CALIBRATE; } static enum power_supply_property sc27xx_fgu_props[] = { @@ -651,6 +661,7 @@ static enum power_supply_property sc27xx_fgu_props[] = { POWER_SUPPLY_PROP_CURRENT_AVG, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, + POWER_SUPPLY_PROP_CALIBRATE, }; static const struct power_supply_desc sc27xx_fgu_desc = { From 7f7378618b4103c083db7de5017df958f8ada070 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 30 Aug 2019 16:23:16 -0700 Subject: [PATCH 24/24] power: supply: cpcap-charger: Enable vbus boost voltage We are currently not enabling VBUS boost for cpcap when in host mode. This means the VBUS is fed at the battery voltage level, which can cause flakeyness enumerating devices. Looks like the boost control for VBUS is CPCAP_BIT_VBUS_SWITCH that we must enable in the charger for nice 4.92 V VBUS output. And looks like we must not use the STBY pin enabling but must instead use manual VBUS control in phy-cpcap-usb. We want to do this in cpcap_charger_vbus_work() and also set a flag for feeding_vbus to avoid races between USB detection and charger detection, and disable charging if feeding_vbus is set. Cc: Jacopo Mondi Cc: Kishon Vijay Abraham I Cc: Marcel Partap Cc: Merlijn Wajer Cc: Michael Scott Cc: NeKit Cc: Pavel Machek Cc: Sebastian Reichel Signed-off-by: Tony Lindgren Signed-off-by: Sebastian Reichel --- drivers/phy/motorola/phy-cpcap-usb.c | 8 +++++--- drivers/power/supply/cpcap-charger.c | 23 ++++++++++++++++++++--- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c index 6601ad0dfb3a..ead06c6c2601 100644 --- a/drivers/phy/motorola/phy-cpcap-usb.c +++ b/drivers/phy/motorola/phy-cpcap-usb.c @@ -231,8 +231,9 @@ static void cpcap_usb_detect(struct work_struct *work) goto out_err; error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, - CPCAP_BIT_VBUSSTBY_EN, - CPCAP_BIT_VBUSSTBY_EN); + CPCAP_BIT_VBUSSTBY_EN | + CPCAP_BIT_VBUSEN_SPI, + CPCAP_BIT_VBUSEN_SPI); if (error) goto out_err; @@ -240,7 +241,8 @@ static void cpcap_usb_detect(struct work_struct *work) } error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, - CPCAP_BIT_VBUSSTBY_EN, 0); + CPCAP_BIT_VBUSSTBY_EN | + CPCAP_BIT_VBUSEN_SPI, 0); if (error) goto out_err; diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c index cc546bc40a78..74258c7fe17d 100644 --- a/drivers/power/supply/cpcap-charger.c +++ b/drivers/power/supply/cpcap-charger.c @@ -108,6 +108,9 @@ #define CPCAP_REG_CRM_ICHRG_1A596 CPCAP_REG_CRM_ICHRG(0xe) #define CPCAP_REG_CRM_ICHRG_NO_LIMIT CPCAP_REG_CRM_ICHRG(0xf) +/* CPCAP_REG_VUSBC register bits needed for VBUS */ +#define CPCAP_BIT_VBUS_SWITCH BIT(0) /* VBUS boost to 5V */ + enum { CPCAP_CHARGER_IIO_BATTDET, CPCAP_CHARGER_IIO_VOLTAGE, @@ -130,7 +133,8 @@ struct cpcap_charger_ddata { struct power_supply *usb; struct phy_companion comparator; /* For USB VBUS */ - bool vbus_enabled; + unsigned int vbus_enabled:1; + unsigned int feeding_vbus:1; atomic_t active; int status; @@ -325,7 +329,6 @@ static bool cpcap_charger_vbus_valid(struct cpcap_charger_ddata *ddata) } /* VBUS control functions for the USB PHY companion */ - static void cpcap_charger_vbus_work(struct work_struct *work) { struct cpcap_charger_ddata *ddata; @@ -343,6 +346,7 @@ static void cpcap_charger_vbus_work(struct work_struct *work) return; } + ddata->feeding_vbus = true; cpcap_charger_set_cable_path(ddata, false); cpcap_charger_set_inductive_path(ddata, false); @@ -350,12 +354,23 @@ static void cpcap_charger_vbus_work(struct work_struct *work) if (error) goto out_err; + error = regmap_update_bits(ddata->reg, CPCAP_REG_VUSBC, + CPCAP_BIT_VBUS_SWITCH, + CPCAP_BIT_VBUS_SWITCH); + if (error) + goto out_err; + error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM, CPCAP_REG_CRM_RVRSMODE, CPCAP_REG_CRM_RVRSMODE); if (error) goto out_err; } else { + error = regmap_update_bits(ddata->reg, CPCAP_REG_VUSBC, + CPCAP_BIT_VBUS_SWITCH, 0); + if (error) + goto out_err; + error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM, CPCAP_REG_CRM_RVRSMODE, 0); if (error) @@ -363,6 +378,7 @@ static void cpcap_charger_vbus_work(struct work_struct *work) cpcap_charger_set_cable_path(ddata, true); cpcap_charger_set_inductive_path(ddata, true); + ddata->feeding_vbus = false; } return; @@ -431,7 +447,8 @@ static void cpcap_usb_detect(struct work_struct *work) if (error) return; - if (cpcap_charger_vbus_valid(ddata) && s.chrgcurr1) { + if (!ddata->feeding_vbus && cpcap_charger_vbus_valid(ddata) && + s.chrgcurr1) { int max_current; if (cpcap_charger_battery_found(ddata))