Merge tag 'for-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 4 Nov 2021 20:53:59 +0000 (13:53 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 4 Nov 2021 20:53:59 +0000 (13:53 -0700)
Pull power supply and reset updates from Sebastian Reichel:
 "Miscellaneous small fixes and improvements all over the place.

  Nothing stands out in particular"

* tag 'for-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (30 commits)
  power: supply: bq25890: Fix initial setting of the F_CONV_RATE field
  power: supply: bq25890: Fix race causing oops at boot
  power: supply: bq27xxx: Fix kernel crash on IRQ handler register error
  power: bq25890: add return values to error messages
  power: supply: axp288-charger: Simplify axp288_get_charger_health()
  power: supply: axp288-charger: Remove unnecessary is_present and is_online helpers
  power: supply: axp288-charger: Add depends on IOSF_MBIO to Kconfig
  power: supply: ab8500_bmdata: Use standard phandle
  dt-bindings: power: supply: ab8500: Standard monitored-battery
  power: supply: axp288_charger: Fix missing mutex_init()
  power: supply: max17042_battery: Prevent int underflow in set_soc_threshold
  power: supply: max17042_battery: Clear status bits in interrupt handler
  MAINTAINERS: power: supply: max17040: add entry with reviewers
  MAINTAINERS: power: supply: max17042: add entry with reviewers
  power: supply: max17040: fix null-ptr-deref in max17040_probe()
  power: supply: rt5033_battery: Change voltage values to µV
  power: supply: axp288-charger: Optimize register reading method
  dt-bindings: power: Bindings for Samsung batteries
  power: supply: cpcap-battery: use device_get_match_data() to simplify code
  power: supply: max17042_battery: fix typo in MAX17042_IAvg_empty
  ...

22 files changed:
Documentation/ABI/testing/sysfs-class-power
Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml
Documentation/devicetree/bindings/power/supply/samsung,battery.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/power/supply/stericsson,ab8500-btemp.yaml
Documentation/devicetree/bindings/power/supply/stericsson,ab8500-chargalg.yaml
Documentation/devicetree/bindings/power/supply/stericsson,ab8500-charger.yaml
Documentation/devicetree/bindings/power/supply/stericsson,ab8500-fg.yaml
MAINTAINERS
drivers/power/reset/at91-reset.c
drivers/power/reset/ltc2952-poweroff.c
drivers/power/supply/Kconfig
drivers/power/supply/ab8500_bmdata.c
drivers/power/supply/axp288_charger.c
drivers/power/supply/bq25890_charger.c
drivers/power/supply/bq27xxx_battery_i2c.c
drivers/power/supply/cpcap-battery.c
drivers/power/supply/max17040_battery.c
drivers/power/supply/max17042_battery.c
drivers/power/supply/power_supply_core.c
drivers/power/supply/rt5033_battery.c
drivers/power/supply/wm831x_power.c
include/linux/power/max17042_battery.h

index ca830c6..f7904ef 100644 (file)
@@ -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/samsung,battery.yaml b/Documentation/devicetree/bindings/power/supply/samsung,battery.yaml
new file mode 100644 (file)
index 0000000..40292d5
--- /dev/null
@@ -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>;
+      };
+    };
index 2f57aa5..4b8a00c 100644 (file)
@@ -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>,
index 0897231..6799224 100644 (file)
@@ -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>;
       };
     };
index e13305a..9518eb7 100644 (file)
@@ -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>,
index db342e5..54ac42a 100644 (file)
@@ -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>,
index 4eb537e..886639f 100644 (file)
@@ -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
index 0266494..64def79 100644 (file)
@@ -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;
index 8688c8b..fbb3443 100644 (file)
@@ -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;
 }
index fcc7534..5cf5bb5 100644 (file)
@@ -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"
index 6f5fb79..bfc1245 100644 (file)
@@ -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;
index b9553be..ec41f6c 100644 (file)
@@ -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;
index 945c325..34ec186 100644 (file)
@@ -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);
 
index 46f0783..cf38cbf 100644 (file)
@@ -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;
                }
        }
 
index 8d62d42..18e3ff0 100644 (file)
@@ -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)
index 3cea92e..a9aef1e 100644 (file)
@@ -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);
index 8dffae7..87128cf 100644 (file)
@@ -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;
 }
index 0c2132c..fc12a4f 100644 (file)
@@ -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)
index 9ad0afe..7a23c70 100644 (file)
@@ -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;
 }
index 4cd2dd8..82e3106 100644 (file)
@@ -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");
 
index dd24756..c417abd 100644 (file)
@@ -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 */