summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-class-power13
-rw-r--r--Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml2
-rw-r--r--Documentation/devicetree/bindings/power/supply/samsung,battery.yaml56
-rw-r--r--Documentation/devicetree/bindings/power/supply/stericsson,ab8500-btemp.yaml10
-rw-r--r--Documentation/devicetree/bindings/power/supply/stericsson,ab8500-chargalg.yaml10
-rw-r--r--Documentation/devicetree/bindings/power/supply/stericsson,ab8500-charger.yaml10
-rw-r--r--Documentation/devicetree/bindings/power/supply/stericsson,ab8500-fg.yaml10
-rw-r--r--MAINTAINERS21
-rw-r--r--drivers/power/reset/at91-reset.c4
-rw-r--r--drivers/power/reset/ltc2952-poweroff.c4
-rw-r--r--drivers/power/supply/Kconfig23
-rw-r--r--drivers/power/supply/ab8500_bmdata.c3
-rw-r--r--drivers/power/supply/axp288_charger.c178
-rw-r--r--drivers/power/supply/bq25890_charger.c65
-rw-r--r--drivers/power/supply/bq27xxx_battery_i2c.c3
-rw-r--r--drivers/power/supply/cpcap-battery.c15
-rw-r--r--drivers/power/supply/max17040_battery.c2
-rw-r--r--drivers/power/supply/max17042_battery.c14
-rw-r--r--drivers/power/supply/power_supply_core.c65
-rw-r--r--drivers/power/supply/rt5033_battery.c2
-rw-r--r--drivers/power/supply/wm831x_power.c12
-rw-r--r--include/linux/power/max17042_battery.h4
22 files changed, 335 insertions, 191 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power
index ca830c6cd809..f7904efc4cfa 100644
--- a/Documentation/ABI/testing/sysfs-class-power
+++ b/Documentation/ABI/testing/sysfs-class-power
@@ -480,6 +480,19 @@ Description:
Valid values: Represented in microvolts
+What: /sys/class/power_supply/<supply_name>/cycle_count
+Date: January 2010
+Contact: linux-pm@vger.kernel.org
+Description:
+ Reports the number of full charge + discharge cycles the
+ battery has undergone.
+
+ Access: Read
+
+ Valid values:
+ Integer > 0: representing full cycles
+ Integer = 0: cycle_count info is not available
+
**USB Properties**
What: /sys/class/power_supply/<supply_name>/input_current_limit
diff --git a/Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml b/Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml
index f792d06db413..ffb344987a7b 100644
--- a/Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml
+++ b/Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml
@@ -62,7 +62,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/power/supply/samsung,battery.yaml b/Documentation/devicetree/bindings/power/supply/samsung,battery.yaml
new file mode 100644
index 000000000000..40292d581b10
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/samsung,battery.yaml
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/supply/samsung,battery.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung SDI Batteries
+
+maintainers:
+ - Linus Walleij <linus.walleij@linaro.org>
+
+description: |
+ Samsung SDI (Samsung Digital Interface) batteries are all different versions
+ of lithium ion chemistry devices used for mobile phones, laptops and other
+ portable electronics. The batteries are adapted to a specific product and
+ the physical restrictions make it impossible to use another battery with the
+ product, so product device trees can specify these batteries. Operating
+ systems should determine hardware characteristics of the batteries from the
+ compatible string.
+
+properties:
+ compatible:
+ oneOf:
+ - const: samsung,eb-l1m7flu
+ description: 3.8V 1500 mAh battery used in Samsung GT-I8190
+ - const: samsung,eb425161la
+ description: 3.8V 1500 mAh battery used in Samsung SGH-T599 and SGH-I407
+ - const: samsung,eb425161lu
+ description: 3.8V 1500 mAh battery used in Samsung GT-I8160
+ - const: samsung,eb485159lu
+ description: 3.8V 1700 mAh battery used in Samsung GT-S7710
+ - const: samsung,eb535151vu
+ description: 3.8V 1500 mAh battery used in Samsung GT-I9070
+ - const: samsung,eb585157lu
+ description: 3.8V 2000 mAh battery used in Samsung GT-I8530
+
+required:
+ - compatible
+
+additionalProperties: false
+
+examples:
+ - |
+ power {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ battery: battery {
+ compatible = "samsung,eb425161la";
+ };
+
+ charger@11 {
+ reg = <0x11>;
+ monitored-battery = <&battery>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-btemp.yaml b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-btemp.yaml
index 2f57aa5a5f4e..4b8a00cec39c 100644
--- a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-btemp.yaml
+++ b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-btemp.yaml
@@ -17,10 +17,14 @@ properties:
compatible:
const: stericsson,ab8500-btemp
- battery:
+ monitored-battery:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle to battery node
+ battery:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ deprecated: true
+
interrupts:
maxItems: 5
@@ -42,7 +46,7 @@ properties:
required:
- compatible
- - battery
+ - monitored-battery
- interrupts
- interrupt-names
- io-channels
@@ -56,7 +60,7 @@ examples:
pmic {
battery-temperature {
compatible = "stericsson,ab8500-btemp";
- battery = <&ab8500_battery>;
+ monitored-battery = <&battery>;
interrupts = <20 IRQ_TYPE_LEVEL_HIGH>,
<80 IRQ_TYPE_LEVEL_HIGH>,
<83 IRQ_TYPE_LEVEL_HIGH>,
diff --git a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-chargalg.yaml b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-chargalg.yaml
index 0897231c2f6e..6799224f7fb4 100644
--- a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-chargalg.yaml
+++ b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-chargalg.yaml
@@ -17,13 +17,17 @@ properties:
compatible:
const: stericsson,ab8500-chargalg
- battery:
+ monitored-battery:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle to battery node
+ battery:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ deprecated: true
+
required:
- compatible
- - battery
+ - monitored-battery
additionalProperties: false
@@ -32,6 +36,6 @@ examples:
pmic {
charging-algorithm {
compatible = "stericsson,ab8500-chargalg";
- battery = <&ab8500_battery>;
+ monitored-battery = <&ab8500_battery>;
};
};
diff --git a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-charger.yaml b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-charger.yaml
index e13305afea69..9518eb7289d0 100644
--- a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-charger.yaml
+++ b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-charger.yaml
@@ -17,10 +17,14 @@ properties:
compatible:
const: stericsson,ab8500-charger
- battery:
+ monitored-battery:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle to battery node
+ battery:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ deprecated: true
+
vddadc-supply:
description: Supply for USB and Main charger
@@ -66,7 +70,7 @@ properties:
required:
- compatible
- - battery
+ - monitored-battery
- vddadc-supply
- interrupts
- interrupt-names
@@ -81,7 +85,7 @@ examples:
pmic {
charger {
compatible = "stericsson,ab8500-charger";
- battery = <&ab8500_battery>;
+ monitored-battery = <&battery>;
vddadc-supply = <&ab8500_ldo_tvout_reg>;
interrupts = <10 IRQ_TYPE_LEVEL_HIGH>,
<11 IRQ_TYPE_LEVEL_HIGH>,
diff --git a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-fg.yaml b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-fg.yaml
index db342e5ac0d1..54ac42a9d354 100644
--- a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-fg.yaml
+++ b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-fg.yaml
@@ -17,10 +17,14 @@ properties:
compatible:
const: stericsson,ab8500-fg
- battery:
+ monitored-battery:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle to battery node
+ battery:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ deprecated: true
+
interrupts:
maxItems: 5
@@ -41,7 +45,7 @@ properties:
required:
- compatible
- - battery
+ - monitored-battery
- interrupts
- interrupt-names
- io-channels
@@ -55,7 +59,7 @@ examples:
pmic {
fuel-gauge {
compatible = "stericsson,ab8500-fg";
- battery = <&ab8500_battery>;
+ monitored-battery = <&battery>;
interrupts = <24 IRQ_TYPE_LEVEL_HIGH>,
<8 IRQ_TYPE_LEVEL_HIGH>,
<28 IRQ_TYPE_LEVEL_HIGH>,
diff --git a/MAINTAINERS b/MAINTAINERS
index 4eb537e015d1..886639f1fa0b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11508,6 +11508,27 @@ S: Maintained
F: Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.yaml
F: drivers/iio/proximity/mb1232.c
+MAXIM MAX17040 FAMILY FUEL GAUGE DRIVERS
+R: Iskren Chernev <iskren.chernev@gmail.com>
+R: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+R: Marek Szyprowski <m.szyprowski@samsung.com>
+R: Matheus Castello <matheus@castello.eng.br>
+L: linux-pm@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml
+F: drivers/power/supply/max17040_battery.c
+
+MAXIM MAX17042 FAMILY FUEL GAUGE DRIVERS
+R: Hans de Goede <hdegoede@redhat.com>
+R: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+R: Marek Szyprowski <m.szyprowski@samsung.com>
+R: Sebastian Krzyszkowiak <sebastian.krzyszkowiak@puri.sm>
+R: Purism Kernel Team <kernel@puri.sm>
+L: linux-pm@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml
+F: drivers/power/supply/max17042_battery.c
+
MAXIM MAX77650 PMIC MFD DRIVER
M: Bartosz Golaszewski <brgl@bgdev.pl>
L: linux-kernel@vger.kernel.org
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index 026649409135..64def79d557a 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -193,7 +193,7 @@ static int __init at91_reset_probe(struct platform_device *pdev)
return -ENOMEM;
reset->rstc_base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL);
- if (!reset->rstc_base) {
+ if (IS_ERR(reset->rstc_base)) {
dev_err(&pdev->dev, "Could not map reset controller address\n");
return -ENODEV;
}
@@ -203,7 +203,7 @@ static int __init at91_reset_probe(struct platform_device *pdev)
for_each_matching_node_and_match(np, at91_ramc_of_match, &match) {
reset->ramc_lpr = (u32)match->data;
reset->ramc_base[idx] = devm_of_iomap(&pdev->dev, np, 0, NULL);
- if (!reset->ramc_base[idx]) {
+ if (IS_ERR(reset->ramc_base[idx])) {
dev_err(&pdev->dev, "Could not map ram controller address\n");
of_node_put(np);
return -ENODEV;
diff --git a/drivers/power/reset/ltc2952-poweroff.c b/drivers/power/reset/ltc2952-poweroff.c
index 8688c8ba8894..fbb344353fe4 100644
--- a/drivers/power/reset/ltc2952-poweroff.c
+++ b/drivers/power/reset/ltc2952-poweroff.c
@@ -94,7 +94,6 @@ static struct ltc2952_poweroff *ltc2952_data;
*/
static enum hrtimer_restart ltc2952_poweroff_timer_wde(struct hrtimer *timer)
{
- ktime_t now;
int state;
struct ltc2952_poweroff *data = to_ltc2952(timer, timer_wde);
@@ -104,8 +103,7 @@ static enum hrtimer_restart ltc2952_poweroff_timer_wde(struct hrtimer *timer)
state = gpiod_get_value(data->gpio_watchdog);
gpiod_set_value(data->gpio_watchdog, !state);
- now = hrtimer_cb_get_time(timer);
- hrtimer_forward(timer, now, data->wde_interval);
+ hrtimer_forward_now(timer, data->wde_interval);
return HRTIMER_RESTART;
}
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index fcc7534edcb2..5cf5bb56d2e3 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -351,7 +351,7 @@ config AXP20X_POWER
config AXP288_CHARGER
tristate "X-Powers AXP288 Charger"
- depends on MFD_AXP20X && EXTCON_AXP288
+ depends on MFD_AXP20X && EXTCON_AXP288 && IOSF_MBI
help
Say yes here to have support X-Power AXP288 power management IC (PMIC)
integrated charger.
@@ -366,20 +366,22 @@ config AXP288_FUEL_GAUGE
over/under temperature.
config BATTERY_MAX17040
- tristate "Maxim MAX17040 Fuel Gauge"
+ tristate "Maxim MAX17040/17041/17043 family Fuel Gauge"
depends on I2C
select REGMAP_I2C
help
- Maxim models with ModelGauge are fuel-gauge systems for lithium-ion
- (Li+) batteries in handheld and portable equipment, including
- max17040, max17041, max17043, max17044, max17048, max17049, max17058,
- max17059. It is also included in some batteries like max77836.
+ Driver supports Maxim fuel-gauge systems for lithium-ion (Li+)
+ batteries used mainly in handheld and portable equipment.
+ Supported devices: max17040, max17041, max17043, max17044, max17048,
+ max17049, max17058, max17059, max77836.
Driver supports reporting SOC (State of Charge, i.e capacity),
voltage and configurable low-SOC wakeup interrupt.
+ Driver can be build as a module (max17040_battery).
+
config BATTERY_MAX17042
- tristate "Maxim MAX17042/17047/17050/8997/8966 Fuel Gauge"
+ tristate "Maxim MAX17042/17047/17050/8997/8966 family Fuel Gauge"
depends on I2C
select REGMAP_I2C
help
@@ -387,8 +389,11 @@ config BATTERY_MAX17042
in handheld and portable equipment. The MAX17042 is configured
to operate with a single lithium cell. MAX8997 and MAX8966 are
multi-function devices that include fuel gauages that are compatible
- with MAX17042. This driver also supports max17047/50 chips which are
- improved version of max17042.
+ with MAX17042.
+ Supported devices: max8966, max8997, max17042, max17047, max17050,
+ max17055, max77693, max77849.
+
+ Driver can be build as a module (max17042_battery).
config BATTERY_MAX1721X
tristate "MAX17211/MAX17215 standalone gas-gauge"
diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c
index 6f5fb794042c..bfc1245d7912 100644
--- a/drivers/power/supply/ab8500_bmdata.c
+++ b/drivers/power/supply/ab8500_bmdata.c
@@ -497,8 +497,7 @@ int ab8500_bm_of_probe(struct device *dev,
const char *btech;
int i;
- /* get phandle to 'battery-info' node */
- battery_node = of_parse_phandle(np, "battery", 0);
+ battery_node = of_parse_phandle(np, "monitored-battery", 0);
if (!battery_node) {
dev_err(dev, "battery node or reference missing\n");
return -EINVAL;
diff --git a/drivers/power/supply/axp288_charger.c b/drivers/power/supply/axp288_charger.c
index b9553be9bed5..ec41f6cd3f93 100644
--- a/drivers/power/supply/axp288_charger.c
+++ b/drivers/power/supply/axp288_charger.c
@@ -22,6 +22,7 @@
#include <linux/mfd/axp20x.h>
#include <linux/extcon.h>
#include <linux/dmi.h>
+#include <asm/iosf_mbi.h>
#define PS_STAT_VBUS_TRIGGER BIT(0)
#define PS_STAT_BAT_CHRG_DIR BIT(2)
@@ -95,6 +96,8 @@
#define CV_4200MV 4200 /* 4200mV */
#define CV_4350MV 4350 /* 4350mV */
+#define AXP288_REG_UPDATE_INTERVAL (60 * HZ)
+
#define AXP288_EXTCON_DEV_NAME "axp288_extcon"
#define USB_HOST_EXTCON_HID "INT3496"
#define USB_HOST_EXTCON_NAME "INT3496:00"
@@ -118,6 +121,7 @@ struct axp288_chrg_info {
struct regmap_irq_chip_data *regmap_irqc;
int irq[CHRG_INTR_END];
struct power_supply *psy_usb;
+ struct mutex lock;
/* OTG/Host mode */
struct {
@@ -138,6 +142,12 @@ struct axp288_chrg_info {
int cv;
int max_cc;
int max_cv;
+
+ unsigned long last_updated;
+ unsigned int input_status;
+ unsigned int op_mode;
+ unsigned int backend_control;
+ bool valid;
};
static inline int axp288_charger_set_cc(struct axp288_chrg_info *info, int cc)
@@ -197,11 +207,8 @@ static inline int axp288_charger_set_cv(struct axp288_chrg_info *info, int cv)
static int axp288_charger_get_vbus_inlmt(struct axp288_chrg_info *info)
{
unsigned int val;
- int ret;
- ret = regmap_read(info->regmap, AXP20X_CHRG_BAK_CTRL, &val);
- if (ret < 0)
- return ret;
+ val = info->backend_control;
val >>= CHRG_VBUS_ILIM_BIT_POS;
switch (val) {
@@ -295,63 +302,19 @@ static int axp288_charger_enable_charger(struct axp288_chrg_info *info,
return ret;
}
-static int axp288_charger_is_present(struct axp288_chrg_info *info)
-{
- int ret, present = 0;
- unsigned int val;
-
- ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val);
- if (ret < 0)
- return ret;
-
- if (val & PS_STAT_VBUS_PRESENT)
- present = 1;
- return present;
-}
-
-static int axp288_charger_is_online(struct axp288_chrg_info *info)
-{
- int ret, online = 0;
- unsigned int val;
-
- ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val);
- if (ret < 0)
- return ret;
-
- if (val & PS_STAT_VBUS_VALID)
- online = 1;
- return online;
-}
-
static int axp288_get_charger_health(struct axp288_chrg_info *info)
{
- int ret, pwr_stat, chrg_stat;
- int health = POWER_SUPPLY_HEALTH_UNKNOWN;
- unsigned int val;
-
- ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val);
- if ((ret < 0) || !(val & PS_STAT_VBUS_PRESENT))
- goto health_read_fail;
+ if (!(info->input_status & PS_STAT_VBUS_PRESENT))
+ return POWER_SUPPLY_HEALTH_UNKNOWN;
+
+ if (!(info->input_status & PS_STAT_VBUS_VALID))
+ return POWER_SUPPLY_HEALTH_DEAD;
+ else if (info->op_mode & CHRG_STAT_PMIC_OTP)
+ return POWER_SUPPLY_HEALTH_OVERHEAT;
+ else if (info->op_mode & CHRG_STAT_BAT_SAFE_MODE)
+ return POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
else
- pwr_stat = val;
-
- ret = regmap_read(info->regmap, AXP20X_PWR_OP_MODE, &val);
- if (ret < 0)
- goto health_read_fail;
- else
- chrg_stat = val;
-
- if (!(pwr_stat & PS_STAT_VBUS_VALID))
- health = POWER_SUPPLY_HEALTH_DEAD;
- else if (chrg_stat & CHRG_STAT_PMIC_OTP)
- health = POWER_SUPPLY_HEALTH_OVERHEAT;
- else if (chrg_stat & CHRG_STAT_BAT_SAFE_MODE)
- health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
- else
- health = POWER_SUPPLY_HEALTH_GOOD;
-
-health_read_fail:
- return health;
+ return POWER_SUPPLY_HEALTH_GOOD;
}
static int axp288_charger_usb_set_property(struct power_supply *psy,
@@ -362,30 +325,86 @@ static int axp288_charger_usb_set_property(struct power_supply *psy,
int ret = 0;
int scaled_val;
+ mutex_lock(&info->lock);
switch (psp) {
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
scaled_val = min(val->intval, info->max_cc);
scaled_val = DIV_ROUND_CLOSEST(scaled_val, 1000);
ret = axp288_charger_set_cc(info, scaled_val);
- if (ret < 0)
+ if (ret < 0) {
dev_warn(&info->pdev->dev, "set charge current failed\n");
+ goto out;
+ }
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
scaled_val = min(val->intval, info->max_cv);
scaled_val = DIV_ROUND_CLOSEST(scaled_val, 1000);
ret = axp288_charger_set_cv(info, scaled_val);
- if (ret < 0)
+ if (ret < 0) {
dev_warn(&info->pdev->dev, "set charge voltage failed\n");
+ goto out;
+ }
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
ret = axp288_charger_set_vbus_inlmt(info, val->intval);
- if (ret < 0)
+ if (ret < 0) {
dev_warn(&info->pdev->dev, "set input current limit failed\n");
+ goto out;
+ }
+ info->valid = false;
break;
default:
ret = -EINVAL;
}
+out:
+ mutex_unlock(&info->lock);
+ return ret;
+}
+
+static int axp288_charger_reg_readb(struct axp288_chrg_info *info, int reg, unsigned int *ret_val)
+{
+ int ret;
+
+ ret = regmap_read(info->regmap, reg, ret_val);
+ if (ret < 0) {
+ dev_err(&info->pdev->dev, "Error %d on reading value from register 0x%04x\n",
+ ret,
+ reg);
+ return ret;
+ }
+ return 0;
+}
+
+static int axp288_charger_usb_update_property(struct axp288_chrg_info *info)
+{
+ int ret = 0;
+
+ if (info->valid && time_before(jiffies, info->last_updated + AXP288_REG_UPDATE_INTERVAL))
+ return 0;
+
+ dev_dbg(&info->pdev->dev, "Charger updating register values...\n");
+
+ ret = iosf_mbi_block_punit_i2c_access();
+ if (ret < 0)
+ return ret;
+
+ ret = axp288_charger_reg_readb(info, AXP20X_PWR_INPUT_STATUS, &info->input_status);
+ if (ret < 0)
+ goto out;
+
+ ret = axp288_charger_reg_readb(info, AXP20X_PWR_OP_MODE, &info->op_mode);
+ if (ret < 0)
+ goto out;
+
+ ret = axp288_charger_reg_readb(info, AXP20X_CHRG_BAK_CTRL, &info->backend_control);
+ if (ret < 0)
+ goto out;
+
+ info->last_updated = jiffies;
+ info->valid = true;
+out:
+ iosf_mbi_unblock_punit_i2c_access();
return ret;
}
@@ -396,6 +415,11 @@ static int axp288_charger_usb_get_property(struct power_supply *psy,
struct axp288_chrg_info *info = power_supply_get_drvdata(psy);
int ret;
+ mutex_lock(&info->lock);
+ ret = axp288_charger_usb_update_property(info);
+ if (ret < 0)
+ goto out;
+
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
/* Check for OTG case first */
@@ -403,10 +427,7 @@ static int axp288_charger_usb_get_property(struct power_supply *psy,
val->intval = 0;
break;
}
- ret = axp288_charger_is_present(info);
- if (ret < 0)
- return ret;
- val->intval = ret;
+ val->intval = (info->input_status & PS_STAT_VBUS_PRESENT) ? 1 : 0;
break;
case POWER_SUPPLY_PROP_ONLINE:
/* Check for OTG case first */
@@ -414,10 +435,7 @@ static int axp288_charger_usb_get_property(struct power_supply *psy,
val->intval = 0;
break;
}
- ret = axp288_charger_is_online(info);
- if (ret < 0)
- return ret;
- val->intval = ret;
+ val->intval = (info->input_status & PS_STAT_VBUS_VALID) ? 1 : 0;
break;
case POWER_SUPPLY_PROP_HEALTH:
val->intval = axp288_get_charger_health(info);
@@ -435,16 +453,15 @@ static int axp288_charger_usb_get_property(struct power_supply *psy,
val->intval = info->max_cv * 1000;
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
- ret = axp288_charger_get_vbus_inlmt(info);
- if (ret < 0)
- return ret;
- val->intval = ret;
+ val->intval = axp288_charger_get_vbus_inlmt(info);
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+out:
+ mutex_unlock(&info->lock);
+ return ret;
}
static int axp288_charger_property_is_writeable(struct power_supply *psy,
@@ -540,7 +557,9 @@ static irqreturn_t axp288_charger_irq_thread_handler(int irq, void *dev)
dev_warn(&info->pdev->dev, "Spurious Interrupt!!!\n");
goto out;
}
-
+ mutex_lock(&info->lock);
+ info->valid = false;
+ mutex_unlock(&info->lock);
power_supply_changed(info->psy_usb);
out:
return IRQ_HANDLED;
@@ -613,6 +632,9 @@ static void axp288_charger_extcon_evt_worker(struct work_struct *work)
if (!(val & PS_STAT_VBUS_VALID)) {
dev_dbg(&info->pdev->dev, "USB charger disconnected\n");
axp288_charger_enable_charger(info, false);
+ mutex_lock(&info->lock);
+ info->valid = false;
+ mutex_unlock(&info->lock);
power_supply_changed(info->psy_usb);
return;
}
@@ -644,6 +666,9 @@ static void axp288_charger_extcon_evt_worker(struct work_struct *work)
dev_err(&info->pdev->dev,
"error setting current limit (%d)\n", ret);
+ mutex_lock(&info->lock);
+ info->valid = false;
+ mutex_unlock(&info->lock);
power_supply_changed(info->psy_usb);
}
@@ -817,6 +842,7 @@ static int axp288_charger_probe(struct platform_device *pdev)
if (!info)
return -ENOMEM;
+ mutex_init(&info->lock);
info->pdev = pdev;
info->regmap = axp20x->regmap;
info->regmap_irqc = axp20x->regmap_irqc;
diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c
index 945c3257ca93..34ec186a2e9a 100644
--- a/drivers/power/supply/bq25890_charger.c
+++ b/drivers/power/supply/bq25890_charger.c
@@ -682,16 +682,16 @@ static int bq25890_hw_init(struct bq25890_device *bq)
}
}
- /* Configure ADC for continuous conversions when charging */
- ret = bq25890_field_write(bq, F_CONV_RATE, !!bq->state.online);
+ ret = bq25890_get_chip_state(bq, &bq->state);
if (ret < 0) {
- dev_dbg(bq->dev, "Config ADC failed %d\n", ret);
+ dev_dbg(bq->dev, "Get state failed %d\n", ret);
return ret;
}
- ret = bq25890_get_chip_state(bq, &bq->state);
+ /* Configure ADC for continuous conversions when charging */
+ ret = bq25890_field_write(bq, F_CONV_RATE, !!bq->state.online);
if (ret < 0) {
- dev_dbg(bq->dev, "Get state failed %d\n", ret);
+ dev_dbg(bq->dev, "Config ADC failed %d\n", ret);
return ret;
}
@@ -734,8 +734,9 @@ static int bq25890_power_supply_init(struct bq25890_device *bq)
psy_cfg.supplied_to = bq25890_charger_supplied_to;
psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to);
- bq->charger = power_supply_register(bq->dev, &bq25890_power_supply_desc,
- &psy_cfg);
+ bq->charger = devm_power_supply_register(bq->dev,
+ &bq25890_power_supply_desc,
+ &psy_cfg);
return PTR_ERR_OR_ZERO(bq->charger);
}
@@ -788,13 +789,13 @@ static int bq25890_get_chip_version(struct bq25890_device *bq)
id = bq25890_field_read(bq, F_PN);
if (id < 0) {
- dev_err(bq->dev, "Cannot read chip ID.\n");
+ dev_err(bq->dev, "Cannot read chip ID: %d\n", id);
return id;
}
rev = bq25890_field_read(bq, F_DEV_REV);
if (rev < 0) {
- dev_err(bq->dev, "Cannot read chip revision.\n");
+ dev_err(bq->dev, "Cannot read chip revision: %d\n", rev);
return rev;
}
@@ -837,10 +838,9 @@ static int bq25890_irq_probe(struct bq25890_device *bq)
struct gpio_desc *irq;
irq = devm_gpiod_get(bq->dev, BQ25890_IRQ_PIN, GPIOD_IN);
- if (IS_ERR(irq)) {
- dev_err(bq->dev, "Could not probe irq pin.\n");
- return PTR_ERR(irq);
- }
+ if (IS_ERR(irq))
+ return dev_err_probe(bq->dev, PTR_ERR(irq),
+ "Could not probe irq pin.\n");
return gpiod_to_irq(irq);
}
@@ -929,34 +929,33 @@ static int bq25890_probe(struct i2c_client *client,
mutex_init(&bq->lock);
bq->rmap = devm_regmap_init_i2c(client, &bq25890_regmap_config);
- if (IS_ERR(bq->rmap)) {
- dev_err(dev, "failed to allocate register map\n");
- return PTR_ERR(bq->rmap);
- }
+ if (IS_ERR(bq->rmap))
+ return dev_err_probe(dev, PTR_ERR(bq->rmap),
+ "failed to allocate register map\n");
for (i = 0; i < ARRAY_SIZE(bq25890_reg_fields); i++) {
const struct reg_field *reg_fields = bq25890_reg_fields;
bq->rmap_fields[i] = devm_regmap_field_alloc(dev, bq->rmap,
reg_fields[i]);
- if (IS_ERR(bq->rmap_fields[i])) {
- dev_err(dev, "cannot allocate regmap field\n");
- return PTR_ERR(bq->rmap_fields[i]);
- }
+ if (IS_ERR(bq->rmap_fields[i]))
+ return dev_err_probe(dev, PTR_ERR(bq->rmap_fields[i]),
+ "cannot allocate regmap field\n");
}
i2c_set_clientdata(client, bq);
ret = bq25890_get_chip_version(bq);
if (ret) {
- dev_err(dev, "Cannot read chip ID or unknown chip.\n");
+ dev_err(dev, "Cannot read chip ID or unknown chip: %d\n", ret);
return ret;
}
if (!dev->platform_data) {
ret = bq25890_fw_probe(bq);
if (ret < 0) {
- dev_err(dev, "Cannot read device properties.\n");
+ dev_err(dev, "Cannot read device properties: %d\n",
+ ret);
return ret;
}
} else {
@@ -965,7 +964,7 @@ static int bq25890_probe(struct i2c_client *client,
ret = bq25890_hw_init(bq);
if (ret < 0) {
- dev_err(dev, "Cannot initialize the chip.\n");
+ dev_err(dev, "Cannot initialize the chip: %d\n", ret);
return ret;
}
@@ -985,22 +984,22 @@ static int bq25890_probe(struct i2c_client *client,
usb_register_notifier(bq->usb_phy, &bq->usb_nb);
}
+ ret = bq25890_power_supply_init(bq);
+ if (ret < 0) {
+ dev_err(dev, "Failed to register power supply\n");
+ goto err_unregister_usb_notifier;
+ }
+
ret = devm_request_threaded_irq(dev, client->irq, NULL,
bq25890_irq_handler_thread,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
BQ25890_IRQ_PIN, bq);
if (ret)
- goto irq_fail;
-
- ret = bq25890_power_supply_init(bq);
- if (ret < 0) {
- dev_err(dev, "Failed to register power supply\n");
- goto irq_fail;
- }
+ goto err_unregister_usb_notifier;
return 0;
-irq_fail:
+err_unregister_usb_notifier:
if (!IS_ERR_OR_NULL(bq->usb_phy))
usb_unregister_notifier(bq->usb_phy, &bq->usb_nb);
@@ -1011,8 +1010,6 @@ static int bq25890_remove(struct i2c_client *client)
{
struct bq25890_device *bq = i2c_get_clientdata(client);
- power_supply_unregister(bq->charger);
-
if (!IS_ERR_OR_NULL(bq->usb_phy))
usb_unregister_notifier(bq->usb_phy, &bq->usb_nb);
diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
index 46f078350fd3..cf38cbfe13e9 100644
--- a/drivers/power/supply/bq27xxx_battery_i2c.c
+++ b/drivers/power/supply/bq27xxx_battery_i2c.c
@@ -187,7 +187,8 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
dev_err(&client->dev,
"Unable to register IRQ %d error %d\n",
client->irq, ret);
- return ret;
+ bq27xxx_battery_teardown(di);
+ goto err_failed;
}
}
diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c
index 8d62d4241da3..18e3ff0e15d5 100644
--- a/drivers/power/supply/cpcap-battery.c
+++ b/drivers/power/supply/cpcap-battery.c
@@ -1026,20 +1026,13 @@ static const struct power_supply_desc cpcap_charger_battery_desc = {
static int cpcap_battery_probe(struct platform_device *pdev)
{
struct cpcap_battery_ddata *ddata;
- const struct of_device_id *match;
struct power_supply_config psy_cfg = {};
int error;
+ const struct cpcap_battery_config *cfg;
- match = of_match_device(of_match_ptr(cpcap_battery_id_table),
- &pdev->dev);
- if (!match)
- return -EINVAL;
-
- if (!match->data) {
- dev_err(&pdev->dev, "no configuration data found\n");
-
+ cfg = device_get_match_data(&pdev->dev);
+ if (!cfg)
return -ENODEV;
- }
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
@@ -1047,7 +1040,7 @@ static int cpcap_battery_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&ddata->irq_list);
ddata->dev = &pdev->dev;
- memcpy(&ddata->config, match->data, sizeof(ddata->config));
+ memcpy(&ddata->config, cfg, sizeof(ddata->config));
ddata->reg = dev_get_regmap(ddata->dev->parent, NULL);
if (!ddata->reg)
diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c
index 3cea92e28dc3..a9aef1e8b186 100644
--- a/drivers/power/supply/max17040_battery.c
+++ b/drivers/power/supply/max17040_battery.c
@@ -449,6 +449,8 @@ static int max17040_probe(struct i2c_client *client,
chip->client = client;
chip->regmap = devm_regmap_init_i2c(client, &max17040_regmap);
+ if (IS_ERR(chip->regmap))
+ return PTR_ERR(chip->regmap);
chip_id = (enum chip_id) id->driver_data;
if (client->dev.of_node) {
ret = max17040_get_of_data(chip);
diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c
index 8dffae76b6a3..87128cf0d577 100644
--- a/drivers/power/supply/max17042_battery.c
+++ b/drivers/power/supply/max17042_battery.c
@@ -313,7 +313,10 @@ static int max17042_get_property(struct power_supply *psy,
val->intval = data * 625 / 8;
break;
case POWER_SUPPLY_PROP_CAPACITY:
- ret = regmap_read(map, MAX17042_RepSOC, &data);
+ if (chip->pdata->enable_current_sense)
+ ret = regmap_read(map, MAX17042_RepSOC, &data);
+ else
+ ret = regmap_read(map, MAX17042_VFSOC, &data);
if (ret < 0)
return ret;
@@ -783,7 +786,7 @@ static inline void max17042_override_por_values(struct max17042_chip *chip)
if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) ||
(chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) ||
(chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050)) {
- max17042_override_por(map, MAX17042_LAvg_empty, config->lavg_empty);
+ max17042_override_por(map, MAX17042_IAvg_empty, config->iavg_empty);
max17042_override_por(map, MAX17042_TempNom, config->temp_nom);
max17042_override_por(map, MAX17042_TempLim, config->temp_lim);
max17042_override_por(map, MAX17042_FCTC, config->fctc);
@@ -857,7 +860,8 @@ static void max17042_set_soc_threshold(struct max17042_chip *chip, u16 off)
regmap_read(map, MAX17042_RepSOC, &soc);
soc >>= 8;
soc_tr = (soc + off) << 8;
- soc_tr |= (soc - off);
+ if (off < soc)
+ soc_tr |= soc - off;
regmap_write(map, MAX17042_SALRT_Th, soc_tr);
}
@@ -876,6 +880,10 @@ static irqreturn_t max17042_thread_handler(int id, void *dev)
max17042_set_soc_threshold(chip, 1);
}
+ /* we implicitly handle all alerts via power_supply_changed */
+ regmap_clear_bits(chip->regmap, MAX17042_STATUS,
+ 0xFFFF & ~(STATUS_POR_BIT | STATUS_BST_BIT));
+
power_supply_changed(chip->battery);
return IRQ_HANDLED;
}
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index 0c2132c7f5d4..fc12a4f407f4 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -951,6 +951,22 @@ void power_supply_unreg_notifier(struct notifier_block *nb)
}
EXPORT_SYMBOL_GPL(power_supply_unreg_notifier);
+static bool psy_has_property(const struct power_supply_desc *psy_desc,
+ enum power_supply_property psp)
+{
+ bool found = false;
+ int i;
+
+ for (i = 0; i < psy_desc->num_properties; i++) {
+ if (psy_desc->properties[i] == psp) {
+ found = true;
+ break;
+ }
+ }
+
+ return found;
+}
+
#ifdef CONFIG_THERMAL
static int power_supply_read_temp(struct thermal_zone_device *tzd,
int *temp)
@@ -977,24 +993,23 @@ static struct thermal_zone_device_ops psy_tzd_ops = {
static int psy_register_thermal(struct power_supply *psy)
{
- int i, ret;
+ int ret;
if (psy->desc->no_thermal)
return 0;
/* Register battery zone device psy reports temperature */
- for (i = 0; i < psy->desc->num_properties; i++) {
- if (psy->desc->properties[i] == POWER_SUPPLY_PROP_TEMP) {
- psy->tzd = thermal_zone_device_register(psy->desc->name,
- 0, 0, psy, &psy_tzd_ops, NULL, 0, 0);
- if (IS_ERR(psy->tzd))
- return PTR_ERR(psy->tzd);
- ret = thermal_zone_device_enable(psy->tzd);
- if (ret)
- thermal_zone_device_unregister(psy->tzd);
- return ret;
- }
+ if (psy_has_property(psy->desc, POWER_SUPPLY_PROP_TEMP)) {
+ psy->tzd = thermal_zone_device_register(psy->desc->name,
+ 0, 0, psy, &psy_tzd_ops, NULL, 0, 0);
+ if (IS_ERR(psy->tzd))
+ return PTR_ERR(psy->tzd);
+ ret = thermal_zone_device_enable(psy->tzd);
+ if (ret)
+ thermal_zone_device_unregister(psy->tzd);
+ return ret;
}
+
return 0;
}
@@ -1065,18 +1080,14 @@ static const struct thermal_cooling_device_ops psy_tcd_ops = {
static int psy_register_cooler(struct power_supply *psy)
{
- int i;
-
/* Register for cooling device if psy can control charging */
- for (i = 0; i < psy->desc->num_properties; i++) {
- if (psy->desc->properties[i] ==
- POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT) {
- psy->tcd = thermal_cooling_device_register(
- (char *)psy->desc->name,
- psy, &psy_tcd_ops);
- return PTR_ERR_OR_ZERO(psy->tcd);
- }
+ if (psy_has_property(psy->desc, POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT)) {
+ psy->tcd = thermal_cooling_device_register(
+ (char *)psy->desc->name,
+ psy, &psy_tcd_ops);
+ return PTR_ERR_OR_ZERO(psy->tcd);
}
+
return 0;
}
@@ -1114,7 +1125,7 @@ __power_supply_register(struct device *parent,
{
struct device *dev;
struct power_supply *psy;
- int i, rc;
+ int rc;
if (!parent)
pr_warn("%s: Expected proper parent device for '%s'\n",
@@ -1123,11 +1134,9 @@ __power_supply_register(struct device *parent,
if (!desc || !desc->name || !desc->properties || !desc->num_properties)
return ERR_PTR(-EINVAL);
- for (i = 0; i < desc->num_properties; ++i) {
- if ((desc->properties[i] == POWER_SUPPLY_PROP_USB_TYPE) &&
- (!desc->usb_types || !desc->num_usb_types))
- return ERR_PTR(-EINVAL);
- }
+ if (psy_has_property(desc, POWER_SUPPLY_PROP_USB_TYPE) &&
+ (!desc->usb_types || !desc->num_usb_types))
+ return ERR_PTR(-EINVAL);
psy = kzalloc(sizeof(*psy), GFP_KERNEL);
if (!psy)
diff --git a/drivers/power/supply/rt5033_battery.c b/drivers/power/supply/rt5033_battery.c
index 9ad0afe83d1b..7a23c70f4879 100644
--- a/drivers/power/supply/rt5033_battery.c
+++ b/drivers/power/supply/rt5033_battery.c
@@ -60,7 +60,7 @@ static int rt5033_battery_get_watt_prop(struct i2c_client *client,
regmap_read(battery->regmap, regh, &msb);
regmap_read(battery->regmap, regl, &lsb);
- ret = ((msb << 4) + (lsb >> 4)) * 1250 / 1000;
+ ret = ((msb << 4) + (lsb >> 4)) * 1250;
return ret;
}
diff --git a/drivers/power/supply/wm831x_power.c b/drivers/power/supply/wm831x_power.c
index 4cd2dd870039..82e31066c746 100644
--- a/drivers/power/supply/wm831x_power.c
+++ b/drivers/power/supply/wm831x_power.c
@@ -234,7 +234,7 @@ static struct chg_map chg_times[] = {
{ 510, 15 << WM831X_CHG_TIME_SHIFT },
};
-static void wm831x_battey_apply_config(struct wm831x *wm831x,
+static void wm831x_battery_apply_config(struct wm831x *wm831x,
struct chg_map *map, int count, int val,
int *reg, const char *name,
const char *units)
@@ -281,24 +281,24 @@ static void wm831x_config_battery(struct wm831x *wm831x)
if (pdata->fast_enable)
reg1 |= WM831X_CHG_FAST;
- wm831x_battey_apply_config(wm831x, trickle_ilims,
+ wm831x_battery_apply_config(wm831x, trickle_ilims,
ARRAY_SIZE(trickle_ilims),
pdata->trickle_ilim, &reg2,
"trickle charge current limit", "mA");
- wm831x_battey_apply_config(wm831x, vsels, ARRAY_SIZE(vsels),
+ wm831x_battery_apply_config(wm831x, vsels, ARRAY_SIZE(vsels),
pdata->vsel, &reg2,
"target voltage", "mV");
- wm831x_battey_apply_config(wm831x, fast_ilims, ARRAY_SIZE(fast_ilims),
+ wm831x_battery_apply_config(wm831x, fast_ilims, ARRAY_SIZE(fast_ilims),
pdata->fast_ilim, &reg2,
"fast charge current limit", "mA");
- wm831x_battey_apply_config(wm831x, eoc_iterms, ARRAY_SIZE(eoc_iterms),
+ wm831x_battery_apply_config(wm831x, eoc_iterms, ARRAY_SIZE(eoc_iterms),
pdata->eoc_iterm, &reg1,
"end of charge current threshold", "mA");
- wm831x_battey_apply_config(wm831x, chg_times, ARRAY_SIZE(chg_times),
+ wm831x_battery_apply_config(wm831x, chg_times, ARRAY_SIZE(chg_times),
pdata->timeout, &reg2,
"charger timeout", "min");
diff --git a/include/linux/power/max17042_battery.h b/include/linux/power/max17042_battery.h
index dd24756a8af7..c417abd2ab70 100644
--- a/include/linux/power/max17042_battery.h
+++ b/include/linux/power/max17042_battery.h
@@ -78,7 +78,7 @@ enum max17042_register {
MAX17042_T_empty = 0x34,
MAX17042_FullCAP0 = 0x35,
- MAX17042_LAvg_empty = 0x36,
+ MAX17042_IAvg_empty = 0x36,
MAX17042_FCTC = 0x37,
MAX17042_RCOMP0 = 0x38,
MAX17042_TempCo = 0x39,
@@ -221,7 +221,7 @@ struct max17042_config_data {
u16 fullcap; /* 0x10 */
u16 fullcapnom; /* 0x23 */
u16 socempty; /* 0x33 */
- u16 lavg_empty; /* 0x36 */
+ u16 iavg_empty; /* 0x36 */
u16 dqacc; /* 0x45 */
u16 dpacc; /* 0x46 */
u16 qrtbl00; /* 0x12 */