Merge tag 'for-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 7 Jul 2021 20:17:48 +0000 (13:17 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 7 Jul 2021 20:17:48 +0000 (13:17 -0700)
Pull power supply and reset updates from Sebastian Reichel:
 "Battery/charger driver changes:

   - convert charger-manager binding to YAML

   - drop bd70528-charger driver

   - drop pm2301-charger driver

   - introduce rt5033-battery driver

   - misc improvements and fixes"

* tag 'for-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (42 commits)
  power: supply: ab8500: Fix an old bug
  power: supply: axp288_fuel_gauge: remove redundant continue statement
  power: supply: axp288_fuel_gauge: Make "T3 MRD" no_battery_list DMI entry more generic
  power: supply: axp288_fuel_gauge: Rename fuel_gauge_blacklist to no_battery_list
  power: supply: bq24190_charger: drop of_match_ptr() from device ID table
  drivers: power: add missing MODULE_DEVICE_TABLE in keystone-reset.c
  power: supply: ab8500: add missing MODULE_DEVICE_TABLE
  power: supply: charger-manager: add missing MODULE_DEVICE_TABLE
  power: reset: regulator-poweroff: add missing MODULE_DEVICE_TABLE
  power: supply: cpcap-charger: get the battery inserted infomation from cpcap-battery
  power: supply: cpcap-battery: invalidate config when incompatible measurements are read
  power: supply: axp20x_battery: allow disabling battery charging
  power: supply: max17040: drop unused platform data support
  power: supply: max17040: simplify POWER_SUPPLY_PROP_ONLINE
  power: supply: max17040: remove non-working POWER_SUPPLY_PROP_STATUS
  power: reset: at91-sama5d2_shdwc: Remove redundant error printing in at91_shdwc_probe()
  power: reset: gpio-poweroff: add missing MODULE_DEVICE_TABLE
  power: supply: rt5033_battery: Fix device tree enumeration
  dt-bindings: power: supply: Add DT schema for richtek,rt5033-battery
  power: supply: Drop BD70528 support
  ...

38 files changed:
Documentation/devicetree/bindings/power/supply/charger-manager.txt [deleted file]
Documentation/devicetree/bindings/power/supply/charger-manager.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml
Documentation/devicetree/bindings/power/supply/richtek,rt5033-battery.yaml [new file with mode: 0644]
MAINTAINERS
drivers/power/reset/at91-sama5d2_shdwc.c
drivers/power/reset/gpio-poweroff.c
drivers/power/reset/keystone-reset.c
drivers/power/reset/regulator-poweroff.c
drivers/power/supply/Kconfig
drivers/power/supply/Makefile
drivers/power/supply/ab8500-bm.h
drivers/power/supply/ab8500-chargalg.h
drivers/power/supply/ab8500_btemp.c
drivers/power/supply/ab8500_charger.c
drivers/power/supply/ab8500_fg.c
drivers/power/supply/abx500_chargalg.c
drivers/power/supply/axp20x_battery.c
drivers/power/supply/axp288_fuel_gauge.c
drivers/power/supply/bd70528-charger.c [deleted file]
drivers/power/supply/bq24190_charger.c
drivers/power/supply/charger-manager.c
drivers/power/supply/cpcap-battery.c
drivers/power/supply/cpcap-charger.c
drivers/power/supply/max17040_battery.c
drivers/power/supply/max17042_battery.c
drivers/power/supply/pm2301_charger.c [deleted file]
drivers/power/supply/rn5t618_power.c
drivers/power/supply/rt5033_battery.c
drivers/power/supply/sbs-battery.c
drivers/power/supply/sc2731_charger.c
drivers/power/supply/sc27xx_fuel_gauge.c
drivers/power/supply/smb347-charger.c
drivers/power/supply/surface_battery.c
drivers/power/supply/surface_charger.c
include/linux/max17040_battery.h [deleted file]
include/linux/pm2301_charger.h [deleted file]
include/linux/power/ab8500.h [deleted file]

diff --git a/Documentation/devicetree/bindings/power/supply/charger-manager.txt b/Documentation/devicetree/bindings/power/supply/charger-manager.txt
deleted file mode 100644 (file)
index b5ae906..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-charger-manager bindings
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-Required properties :
- - compatible : "charger-manager"
- - <>-supply : for regulator consumer, named according to cm-regulator-name
- - cm-chargers : name of chargers
- - cm-fuel-gauge : name of battery fuel gauge
- - subnode <regulator> :
-       - cm-regulator-name : name of charger regulator
-       - subnode <cable> :
-               - cm-cable-name : name of charger cable - one of USB, USB-HOST,
-                       SDP, DCP, CDP, ACA, FAST-CHARGER, SLOW-CHARGER, WPT,
-                       PD, DOCK, JIG, or MECHANICAL
-               - cm-cable-extcon : name of extcon dev
-(optional)     - cm-cable-min : minimum current of cable
-(optional)     - cm-cable-max : maximum current of cable
-
-Optional properties :
- - cm-name : charger manager's name (default : "battery")
- - cm-poll-mode : polling mode - 0 for disabled, 1 for always, 2 for when
-       external power is connected, or 3 for when charging.  If not present,
-       then polling is disabled
- - cm-poll-interval : polling interval (in ms)
- - cm-battery-stat : battery status - 0 for battery always present, 1 for no
-       battery, 2 to check presence via fuel gauge, or 3 to check presence
-       via charger
- - cm-fullbatt-vchkdrop-volt : voltage drop (in uV) before restarting charging
- - cm-fullbatt-voltage : voltage (in uV) of full battery
- - cm-fullbatt-soc : state of charge to consider as full battery
- - cm-fullbatt-capacity : capcity (in uAh) to consider as full battery
- - cm-thermal-zone : name of external thermometer's thermal zone
- - cm-battery-* : threshold battery temperature for charging
-       -cold : critical cold temperature of battery for charging
-       -cold-in-minus : flag that cold temperature is in minus degrees
-       -hot : critical hot temperature of battery for charging
-       -temp-diff : temperature difference to allow recharging
- - cm-dis/charging-max = limits of charging duration
-
-Deprecated properties:
- - cm-num-chargers
- - cm-fullbatt-vchkdrop-ms
-
-Example :
-       charger-manager@0 {
-               compatible = "charger-manager";
-               chg-reg-supply = <&charger_regulator>;
-
-               cm-name = "battery";
-               /* Always polling ON : 30s */
-               cm-poll-mode = <1>;
-               cm-poll-interval = <30000>;
-
-               cm-fullbatt-vchkdrop-volt = <150000>;
-               cm-fullbatt-soc = <100>;
-
-               cm-battery-stat = <3>;
-
-               cm-chargers = "charger0", "charger1", "charger2";
-
-               cm-fuel-gauge = "fuelgauge0";
-
-               cm-thermal-zone = "thermal_zone.1"
-               /* in deci centigrade */
-               cm-battery-cold = <50>;
-               cm-battery-cold-in-minus;
-               cm-battery-hot = <800>;
-               cm-battery-temp-diff = <100>;
-
-               /* Allow charging for 5hr */
-               cm-charging-max = <18000000>;
-               /* Allow discharging for 2hr */
-               cm-discharging-max = <7200000>;
-
-               regulator@0 {
-                       cm-regulator-name = "chg-reg";
-                       cable@0 {
-                               cm-cable-name = "USB";
-                               cm-cable-extcon = "extcon-dev.0";
-                               cm-cable-min = <475000>;
-                               cm-cable-max = <500000>;
-                       };
-                       cable@1 {
-                               cm-cable-name = "SDP";
-                               cm-cable-extcon = "extcon-dev.0";
-                               cm-cable-min = <650000>;
-                               cm-cable-max = <675000>;
-                       };
-               };
-
-       };
diff --git a/Documentation/devicetree/bindings/power/supply/charger-manager.yaml b/Documentation/devicetree/bindings/power/supply/charger-manager.yaml
new file mode 100644 (file)
index 0000000..c863cfa
--- /dev/null
@@ -0,0 +1,215 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/supply/charger-manager.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Charger Manager
+
+maintainers:
+  - Sebastian Reichel <sre@kernel.org>
+
+description: |
+  Binding for the legacy charger manager driver.
+  Please do not use for new products.
+
+properties:
+  compatible:
+    const: charger-manager
+
+  cm-chargers:
+    description: name of chargers
+    $ref: /schemas/types.yaml#/definitions/string-array
+
+  cm-num-chargers:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+
+  cm-fuel-gauge:
+    description: name of battery fuel gauge
+    $ref: /schemas/types.yaml#/definitions/string
+
+  cm-name:
+    description: name of the charger manager
+    default: battery
+    $ref: /schemas/types.yaml#/definitions/string
+
+  cm-poll-mode:
+    description: polling mode
+    default: 0
+    enum:
+      - 0 # disabled
+      - 1 # always
+      - 2 # when external power is connected
+      - 3 # when charging
+
+  cm-poll-interval:
+    description: polling interval (in ms)
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  cm-battery-stat:
+    description: battery status
+    enum:
+      - 0 # battery always present
+      - 1 # no battery
+      - 2 # check presence via fuel gauge
+      - 3 # check presence via charger
+
+  cm-fullbatt-vchkdrop-volt:
+    description: voltage drop before restarting charging in uV
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  cm-fullbatt-vchkdrop-ms:
+    deprecated: true
+
+  cm-fullbatt-voltage:
+    description: voltage of full battery in uV
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  cm-fullbatt-soc:
+    description: state of charge to consider as full battery in %
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  cm-fullbatt-capacity:
+    description: capcity to consider as full battery in uAh
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  cm-thermal-zone:
+    description: name of external thermometer's thermal zone
+    $ref: /schemas/types.yaml#/definitions/string
+
+  cm-discharging-max:
+    description: limits of discharging duration in ms
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  cm-charging-max:
+    description: limits of charging duration in ms
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  cm-battery-cold:
+    description: critical cold temperature of battery for charging in deci-degree celsius
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  cm-battery-cold-in-minus:
+    description: if set cm-battery-cold temperature is in minus degrees
+    type: boolean
+
+  cm-battery-hot:
+    description: critical hot temperature of battery for charging in deci-degree celsius
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  cm-battery-temp-diff:
+    description: temperature difference to allow recharging in deci-degree celsius
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+patternProperties:
+  "-supply$":
+    description: regulator consumer, named according to cm-regulator-name
+    $ref: /schemas/types.yaml#/definitions/phandle
+
+  "^regulator[@-][0-9]$":
+    type: object
+    properties:
+      cm-regulator-name:
+        description: name of charger regulator
+        $ref: /schemas/types.yaml#/definitions/string
+
+    required:
+      - cm-regulator-name
+
+    additionalProperties: false
+
+    patternProperties:
+      "^cable[@-][0-9]$":
+        type: object
+        properties:
+          cm-cable-name:
+            description: name of charger cable
+            enum:
+              - USB
+              - USB-HOST
+              - SDP
+              - DCP
+              - CDP
+              - ACA
+              - FAST-CHARGER
+              - SLOW-CHARGER
+              - WPT
+              - PD
+              - DOCK
+              - JIG
+              - MECHANICAL
+
+          cm-cable-extcon:
+            description: name of extcon dev
+            $ref: /schemas/types.yaml#/definitions/string
+
+          cm-cable-min:
+            description: minimum current of cable in uA
+            $ref: /schemas/types.yaml#/definitions/uint32
+
+          cm-cable-max:
+            description: maximum current of cable in uA
+            $ref: /schemas/types.yaml#/definitions/uint32
+
+        required:
+          - cm-cable-name
+          - cm-cable-extcon
+
+        additionalProperties: false
+
+required:
+  - compatible
+  - cm-chargers
+  - cm-fuel-gauge
+
+additionalProperties: false
+
+examples:
+  - |
+    charger-manager {
+        compatible = "charger-manager";
+        chg-reg-supply = <&charger_regulator>;
+
+        cm-name = "battery";
+        /* Always polling ON : 30s */
+        cm-poll-mode = <1>;
+        cm-poll-interval = <30000>;
+
+        cm-fullbatt-vchkdrop-volt = <150000>;
+        cm-fullbatt-soc = <100>;
+
+        cm-battery-stat = <3>;
+
+        cm-chargers = "charger0", "charger1", "charger2";
+
+        cm-fuel-gauge = "fuelgauge0";
+
+        cm-thermal-zone = "thermal_zone.1";
+        /* in deci centigrade */
+        cm-battery-cold = <50>;
+        cm-battery-cold-in-minus;
+        cm-battery-hot = <800>;
+        cm-battery-temp-diff = <100>;
+
+        /* Allow charging for 5hr */
+        cm-charging-max = <18000000>;
+        /* Allow discharging for 2hr */
+        cm-discharging-max = <7200000>;
+
+        regulator-0 {
+            cm-regulator-name = "chg-reg";
+            cable-0 {
+                cm-cable-name = "USB";
+                cm-cable-extcon = "extcon-dev.0";
+                cm-cable-min = <475000>;
+                cm-cable-max = <500000>;
+            };
+            cable-1 {
+                cm-cable-name = "SDP";
+                cm-cable-extcon = "extcon-dev.0";
+                cm-cable-min = <650000>;
+                cm-cable-max = <675000>;
+            };
+        };
+    };
index de91cf3..f792d06 100644 (file)
@@ -89,7 +89,7 @@ examples:
         reg = <0x36>;
         maxim,alert-low-soc-level = <10>;
         interrupt-parent = <&gpio7>;
-        interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
+        interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
         wakeup-source;
       };
     };
diff --git a/Documentation/devicetree/bindings/power/supply/richtek,rt5033-battery.yaml b/Documentation/devicetree/bindings/power/supply/richtek,rt5033-battery.yaml
new file mode 100644 (file)
index 0000000..ae647d3
--- /dev/null
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/power/supply/richtek,rt5033-battery.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Richtek RT5033 PMIC Fuel Gauge
+
+maintainers:
+  - Stephan Gerhold <stephan@gerhold.net>
+
+allOf:
+  - $ref: power-supply.yaml#
+
+properties:
+  compatible:
+    const: richtek,rt5033-battery
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      battery@35 {
+        compatible = "richtek,rt5033-battery";
+        reg = <0x35>;
+      };
+    };
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      battery@35 {
+        compatible = "richtek,rt5033-battery";
+        reg = <0x35>;
+        interrupt-parent = <&msmgpio>;
+        interrupts = <121 IRQ_TYPE_EDGE_FALLING>;
+      };
+    };
index a51ba31..c745677 100644 (file)
@@ -14827,6 +14827,7 @@ T:      git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git
 F:     Documentation/ABI/testing/sysfs-class-power
 F:     Documentation/devicetree/bindings/power/supply/
 F:     drivers/power/supply/
+F:     include/linux/power/
 F:     include/linux/power_supply.h
 
 POWERNV OPERATOR PANEL LCD DISPLAY DRIVER
@@ -16213,7 +16214,7 @@ W:      http://www.ibm.com/developerworks/linux/linux390/
 F:     drivers/s390/scsi/zfcp_*
 
 S3C ADC BATTERY DRIVER
-M:     Krzysztof Kozlowski <krzk@kernel.org>
+M:     Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
 L:     linux-samsung-soc@vger.kernel.org
 S:     Odd Fixes
 F:     drivers/power/supply/s3c_adc_battery.c
index 125e592..d8ecffe 100644 (file)
@@ -351,10 +351,8 @@ static int __init at91_shdwc_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        at91_shdwc->shdwc_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(at91_shdwc->shdwc_base)) {
-               dev_err(&pdev->dev, "Could not map reset controller address\n");
+       if (IS_ERR(at91_shdwc->shdwc_base))
                return PTR_ERR(at91_shdwc->shdwc_base);
-       }
 
        match = of_match_node(at91_shdwc_of_match, pdev->dev.of_node);
        at91_shdwc->rcfg = match->data;
index c5067eb..1c5af2f 100644 (file)
@@ -90,6 +90,7 @@ static const struct of_device_id of_gpio_poweroff_match[] = {
        { .compatible = "gpio-poweroff", },
        {},
 };
+MODULE_DEVICE_TABLE(of, of_gpio_poweroff_match);
 
 static struct platform_driver gpio_poweroff_driver = {
        .probe = gpio_poweroff_probe,
index 211eeef..c720112 100644 (file)
@@ -71,6 +71,7 @@ static const struct of_device_id rsctrl_of_match[] = {
        {.compatible = "ti,keystone-reset", },
        {},
 };
+MODULE_DEVICE_TABLE(of, rsctrl_of_match);
 
 static int rsctrl_probe(struct platform_device *pdev)
 {
index f697088..2070120 100644 (file)
@@ -64,6 +64,7 @@ static const struct of_device_id of_regulator_poweroff_match[] = {
        { .compatible = "regulator-poweroff", },
        {},
 };
+MODULE_DEVICE_TABLE(of, of_regulator_poweroff_match);
 
 static struct platform_driver regulator_poweroff_driver = {
        .probe = regulator_poweroff_probe,
index e696364..11f5368 100644 (file)
@@ -712,7 +712,8 @@ config BATTERY_GOLDFISH
 
 config BATTERY_RT5033
        tristate "RT5033 fuel gauge support"
-       depends on MFD_RT5033
+       depends on I2C
+       select REGMAP_I2C
        help
          This adds support for battery fuel gauge in Richtek RT5033 PMIC.
          The fuelgauge calculates and determines the battery state of charge
@@ -760,15 +761,6 @@ config CHARGER_UCS1002
          Say Y to enable support for Microchip UCS1002 Programmable
          USB Port Power Controller with Charger Emulation.
 
-config CHARGER_BD70528
-       tristate "ROHM bd70528 charger driver"
-       depends on MFD_ROHM_BD70528
-       select LINEAR_RANGES
-       help
-         Say Y here to enable support for getting battery status
-         information and altering charger configurations from charger
-         block of the ROHM BD70528 Power Management IC.
-
 config CHARGER_BD99954
        tristate "ROHM bd99954 charger driver"
        depends on I2C
index a7309a3..33059a9 100644 (file)
@@ -60,7 +60,7 @@ obj-$(CONFIG_BATTERY_TWL4030_MADC)    += twl4030_madc_battery.o
 obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
 obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
 obj-$(CONFIG_BATTERY_RX51)     += rx51_battery.o
-obj-$(CONFIG_AB8500_BM)                += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o pm2301_charger.o
+obj-$(CONFIG_AB8500_BM)                += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o
 obj-$(CONFIG_CHARGER_CPCAP)    += cpcap-charger.o
 obj-$(CONFIG_CHARGER_ISP1704)  += isp1704_charger.o
 obj-$(CONFIG_CHARGER_MAX8903)  += max8903_charger.o
@@ -96,7 +96,6 @@ obj-$(CONFIG_CHARGER_CROS_USBPD)      += cros_usbpd-charger.o
 obj-$(CONFIG_CHARGER_SC2731)   += sc2731_charger.o
 obj-$(CONFIG_FUEL_GAUGE_SC27XX)        += sc27xx_fuel_gauge.o
 obj-$(CONFIG_CHARGER_UCS1002)  += ucs1002_power.o
-obj-$(CONFIG_CHARGER_BD70528)  += bd70528-charger.o
 obj-$(CONFIG_CHARGER_BD99954)  += bd99954-charger.o
 obj-$(CONFIG_CHARGER_WILCO)    += wilco-charger.o
 obj-$(CONFIG_RN5T618_POWER)    += rn5t618_power.o
index 41c69a4..0c94057 100644 (file)
@@ -506,9 +506,6 @@ struct abx500_bm_data {
        int usb_safety_tmr_h;
        int bkup_bat_v;
        int bkup_bat_i;
-       bool autopower_cfg;
-       bool ac_enabled;
-       bool usb_enabled;
        bool no_maintenance;
        bool capacity_scaling;
        bool chg_unknown_bat;
@@ -730,4 +727,8 @@ int ab8500_bm_of_probe(struct device *dev,
                       struct device_node *np,
                       struct abx500_bm_data *bm);
 
+extern struct platform_driver ab8500_fg_driver;
+extern struct platform_driver ab8500_btemp_driver;
+extern struct platform_driver abx500_chargalg_driver;
+
 #endif /* _AB8500_CHARGER_H_ */
index 94a6f90..07e6ff5 100644 (file)
@@ -15,7 +15,7 @@
  * - POWER_SUPPLY_TYPE_USB,
  * because only them store as drv_data pointer to struct ux500_charger.
  */
-#define psy_to_ux500_charger(x) power_supply_get_drvdata(psy)
+#define psy_to_ux500_charger(x) power_supply_get_drvdata(x)
 
 /* Forward declaration */
 struct ux500_charger;
index fdfcd59..dbdcff3 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/component.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -932,26 +933,6 @@ static int __maybe_unused ab8500_btemp_suspend(struct device *dev)
        return 0;
 }
 
-static int ab8500_btemp_remove(struct platform_device *pdev)
-{
-       struct ab8500_btemp *di = platform_get_drvdata(pdev);
-       int i, irq;
-
-       /* Disable interrupts */
-       for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) {
-               irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
-               free_irq(irq, di);
-       }
-
-       /* Delete the work queue */
-       destroy_workqueue(di->btemp_wq);
-
-       flush_scheduled_work();
-       power_supply_unregister(di->btemp_psy);
-
-       return 0;
-}
-
 static char *supply_interface[] = {
        "ab8500_chargalg",
        "ab8500_fg",
@@ -966,9 +947,42 @@ static const struct power_supply_desc ab8500_btemp_desc = {
        .external_power_changed = ab8500_btemp_external_power_changed,
 };
 
+static int ab8500_btemp_bind(struct device *dev, struct device *master,
+                            void *data)
+{
+       struct ab8500_btemp *di = dev_get_drvdata(dev);
+
+       /* Create a work queue for the btemp */
+       di->btemp_wq =
+               alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM, 0);
+       if (di->btemp_wq == NULL) {
+               dev_err(dev, "failed to create work queue\n");
+               return -ENOMEM;
+       }
+
+       /* Kick off periodic temperature measurements */
+       ab8500_btemp_periodic(di, true);
+
+       return 0;
+}
+
+static void ab8500_btemp_unbind(struct device *dev, struct device *master,
+                               void *data)
+{
+       struct ab8500_btemp *di = dev_get_drvdata(dev);
+
+       /* Delete the work queue */
+       destroy_workqueue(di->btemp_wq);
+       flush_scheduled_work();
+}
+
+static const struct component_ops ab8500_btemp_component_ops = {
+       .bind = ab8500_btemp_bind,
+       .unbind = ab8500_btemp_unbind,
+};
+
 static int ab8500_btemp_probe(struct platform_device *pdev)
 {
-       struct device_node *np = pdev->dev.of_node;
        struct power_supply_config psy_cfg = {};
        struct device *dev = &pdev->dev;
        struct ab8500_btemp *di;
@@ -981,12 +995,6 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
 
        di->bm = &ab8500_bm_data;
 
-       ret = ab8500_bm_of_probe(dev, np, di->bm);
-       if (ret) {
-               dev_err(dev, "failed to get battery information\n");
-               return ret;
-       }
-
        /* get parent data */
        di->dev = dev;
        di->parent = dev_get_drvdata(pdev->dev.parent);
@@ -1011,14 +1019,6 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
        psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface);
        psy_cfg.drv_data = di;
 
-       /* Create a work queue for the btemp */
-       di->btemp_wq =
-               alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM, 0);
-       if (di->btemp_wq == NULL) {
-               dev_err(dev, "failed to create work queue\n");
-               return -ENOMEM;
-       }
-
        /* Init work for measuring temperature periodically */
        INIT_DEFERRABLE_WORK(&di->btemp_periodic_work,
                ab8500_btemp_periodic_work);
@@ -1031,7 +1031,7 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
                AB8500_BTEMP_HIGH_TH, &val);
        if (ret < 0) {
                dev_err(dev, "%s ab8500 read failed\n", __func__);
-               goto free_btemp_wq;
+               return ret;
        }
        switch (val) {
        case BTEMP_HIGH_TH_57_0:
@@ -1050,30 +1050,28 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
        }
 
        /* Register BTEMP power supply class */
-       di->btemp_psy = power_supply_register(dev, &ab8500_btemp_desc,
-                                             &psy_cfg);
+       di->btemp_psy = devm_power_supply_register(dev, &ab8500_btemp_desc,
+                                                  &psy_cfg);
        if (IS_ERR(di->btemp_psy)) {
                dev_err(dev, "failed to register BTEMP psy\n");
-               ret = PTR_ERR(di->btemp_psy);
-               goto free_btemp_wq;
+               return PTR_ERR(di->btemp_psy);
        }
 
        /* Register interrupts */
        for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) {
                irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
-               if (irq < 0) {
-                       ret = irq;
-                       goto free_irq;
-               }
+               if (irq < 0)
+                       return irq;
 
-               ret = request_threaded_irq(irq, NULL, ab8500_btemp_irq[i].isr,
+               ret = devm_request_threaded_irq(dev, irq, NULL,
+                       ab8500_btemp_irq[i].isr,
                        IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
                        ab8500_btemp_irq[i].name, di);
 
                if (ret) {
                        dev_err(dev, "failed to request %s IRQ %d: %d\n"
                                , ab8500_btemp_irq[i].name, irq, ret);
-                       goto free_irq;
+                       return ret;
                }
                dev_dbg(dev, "Requested %s IRQ %d: %d\n",
                        ab8500_btemp_irq[i].name, irq, ret);
@@ -1081,23 +1079,16 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, di);
 
-       /* Kick off periodic temperature measurements */
-       ab8500_btemp_periodic(di, true);
        list_add_tail(&di->node, &ab8500_btemp_list);
 
-       return ret;
+       return component_add(dev, &ab8500_btemp_component_ops);
+}
 
-free_irq:
-       /* We also have to free all successfully registered irqs */
-       for (i = i - 1; i >= 0; i--) {
-               irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
-               free_irq(irq, di);
-       }
+static int ab8500_btemp_remove(struct platform_device *pdev)
+{
+       component_del(&pdev->dev, &ab8500_btemp_component_ops);
 
-       power_supply_unregister(di->btemp_psy);
-free_btemp_wq:
-       destroy_workqueue(di->btemp_wq);
-       return ret;
+       return 0;
 }
 
 static SIMPLE_DEV_PM_OPS(ab8500_btemp_pm_ops, ab8500_btemp_suspend, ab8500_btemp_resume);
@@ -1106,8 +1097,9 @@ static const struct of_device_id ab8500_btemp_match[] = {
        { .compatible = "stericsson,ab8500-btemp", },
        { },
 };
+MODULE_DEVICE_TABLE(of, ab8500_btemp_match);
 
-static struct platform_driver ab8500_btemp_driver = {
+struct platform_driver ab8500_btemp_driver = {
        .probe = ab8500_btemp_probe,
        .remove = ab8500_btemp_remove,
        .driver = {
@@ -1116,20 +1108,6 @@ static struct platform_driver ab8500_btemp_driver = {
                .pm = &ab8500_btemp_pm_ops,
        },
 };
-
-static int __init ab8500_btemp_init(void)
-{
-       return platform_driver_register(&ab8500_btemp_driver);
-}
-
-static void __exit ab8500_btemp_exit(void)
-{
-       platform_driver_unregister(&ab8500_btemp_driver);
-}
-
-device_initcall(ab8500_btemp_init);
-module_exit(ab8500_btemp_exit);
-
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy");
 MODULE_ALIAS("platform:ab8500-btemp");
index a9be10e..fa49e12 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/component.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/notifier.h>
@@ -414,6 +415,14 @@ disable_otp:
 static void ab8500_power_supply_changed(struct ab8500_charger *di,
                                        struct power_supply *psy)
 {
+       /*
+        * This happens if we get notifications or interrupts and
+        * the platform has been configured not to support one or
+        * other type of charging.
+        */
+       if (!psy)
+               return;
+
        if (di->autopower_cfg) {
                if (!di->usb.charger_connected &&
                    !di->ac.charger_connected &&
@@ -440,7 +449,15 @@ static void ab8500_charger_set_usb_connected(struct ab8500_charger *di,
                if (!connected)
                        di->flags.vbus_drop_end = false;
 
-               sysfs_notify(&di->usb_chg.psy->dev.kobj, NULL, "present");
+               /*
+                * Sometimes the platform is configured not to support
+                * USB charging and no psy has been created, but we still
+                * will get these notifications.
+                */
+               if (di->usb_chg.psy) {
+                       sysfs_notify(&di->usb_chg.psy->dev.kobj, NULL,
+                                    "present");
+               }
 
                if (connected) {
                        mutex_lock(&di->charger_attached_mutex);
@@ -3171,9 +3188,6 @@ static int ab8500_charger_usb_notifier_call(struct notifier_block *nb,
        enum ab8500_usb_state bm_usb_state;
        unsigned mA = *((unsigned *)power);
 
-       if (!di)
-               return NOTIFY_DONE;
-
        if (event != USB_EVENT_VBUS) {
                dev_dbg(di->dev, "not a standard host, returning\n");
                return NOTIFY_DONE;
@@ -3276,10 +3290,74 @@ static struct notifier_block charger_nb = {
        .notifier_call = ab8500_external_charger_prepare,
 };
 
-static int ab8500_charger_remove(struct platform_device *pdev)
+static char *supply_interface[] = {
+       "ab8500_chargalg",
+       "ab8500_fg",
+       "ab8500_btemp",
+};
+
+static const struct power_supply_desc ab8500_ac_chg_desc = {
+       .name           = "ab8500_ac",
+       .type           = POWER_SUPPLY_TYPE_MAINS,
+       .properties     = ab8500_charger_ac_props,
+       .num_properties = ARRAY_SIZE(ab8500_charger_ac_props),
+       .get_property   = ab8500_charger_ac_get_property,
+};
+
+static const struct power_supply_desc ab8500_usb_chg_desc = {
+       .name           = "ab8500_usb",
+       .type           = POWER_SUPPLY_TYPE_USB,
+       .properties     = ab8500_charger_usb_props,
+       .num_properties = ARRAY_SIZE(ab8500_charger_usb_props),
+       .get_property   = ab8500_charger_usb_get_property,
+};
+
+static int ab8500_charger_bind(struct device *dev)
 {
-       struct ab8500_charger *di = platform_get_drvdata(pdev);
-       int i, irq, ret;
+       struct ab8500_charger *di = dev_get_drvdata(dev);
+       int ch_stat;
+       int ret;
+
+       /* Create a work queue for the charger */
+       di->charger_wq = alloc_ordered_workqueue("ab8500_charger_wq",
+                                                WQ_MEM_RECLAIM);
+       if (di->charger_wq == NULL) {
+               dev_err(dev, "failed to create work queue\n");
+               return -ENOMEM;
+       }
+
+       ch_stat = ab8500_charger_detect_chargers(di, false);
+
+       if (ch_stat & AC_PW_CONN) {
+               if (is_ab8500(di->parent))
+                       queue_delayed_work(di->charger_wq,
+                                          &di->ac_charger_attached_work,
+                                          HZ);
+       }
+       if (ch_stat & USB_PW_CONN) {
+               if (is_ab8500(di->parent))
+                       queue_delayed_work(di->charger_wq,
+                                          &di->usb_charger_attached_work,
+                                          HZ);
+               di->vbus_detected = true;
+               di->vbus_detected_start = true;
+               queue_work(di->charger_wq,
+                          &di->detect_usb_type_work);
+       }
+
+       ret = component_bind_all(dev, di);
+       if (ret) {
+               dev_err(dev, "can't bind component devices\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void ab8500_charger_unbind(struct device *dev)
+{
+       struct ab8500_charger *di = dev_get_drvdata(dev);
+       int ret;
 
        /* Disable AC charging */
        ab8500_charger_ac_en(&di->ac_chg, false, 0, 0);
@@ -3287,68 +3365,47 @@ static int ab8500_charger_remove(struct platform_device *pdev)
        /* Disable USB charging */
        ab8500_charger_usb_en(&di->usb_chg, false, 0, 0);
 
-       /* Disable interrupts */
-       for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) {
-               irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name);
-               free_irq(irq, di);
-       }
-
        /* Backup battery voltage and current disable */
        ret = abx500_mask_and_set_register_interruptible(di->dev,
                AB8500_RTC, AB8500_RTC_CTRL_REG, RTC_BUP_CH_ENA, 0);
        if (ret < 0)
                dev_err(di->dev, "%s mask and set failed\n", __func__);
 
-       usb_unregister_notifier(di->usb_phy, &di->nb);
-       usb_put_phy(di->usb_phy);
-
        /* Delete the work queue */
        destroy_workqueue(di->charger_wq);
 
-       /* Unregister external charger enable notifier */
-       if (!di->ac_chg.enabled)
-               blocking_notifier_chain_unregister(
-                       &charger_notifier_list, &charger_nb);
-
        flush_scheduled_work();
-       if (di->usb_chg.enabled)
-               power_supply_unregister(di->usb_chg.psy);
 
-       if (di->ac_chg.enabled && !di->ac_chg.external)
-               power_supply_unregister(di->ac_chg.psy);
-
-       return 0;
+       /* Unbind fg, btemp, algorithm */
+       component_unbind_all(dev, di);
 }
 
-static char *supply_interface[] = {
-       "ab8500_chargalg",
-       "ab8500_fg",
-       "ab8500_btemp",
+static const struct component_master_ops ab8500_charger_comp_ops = {
+       .bind = ab8500_charger_bind,
+       .unbind = ab8500_charger_unbind,
 };
 
-static const struct power_supply_desc ab8500_ac_chg_desc = {
-       .name           = "ab8500_ac",
-       .type           = POWER_SUPPLY_TYPE_MAINS,
-       .properties     = ab8500_charger_ac_props,
-       .num_properties = ARRAY_SIZE(ab8500_charger_ac_props),
-       .get_property   = ab8500_charger_ac_get_property,
+static struct platform_driver *const ab8500_charger_component_drivers[] = {
+       &ab8500_fg_driver,
+       &ab8500_btemp_driver,
+       &abx500_chargalg_driver,
 };
 
-static const struct power_supply_desc ab8500_usb_chg_desc = {
-       .name           = "ab8500_usb",
-       .type           = POWER_SUPPLY_TYPE_USB,
-       .properties     = ab8500_charger_usb_props,
-       .num_properties = ARRAY_SIZE(ab8500_charger_usb_props),
-       .get_property   = ab8500_charger_usb_get_property,
-};
+static int ab8500_charger_compare_dev(struct device *dev, void *data)
+{
+       return dev == data;
+}
 
 static int ab8500_charger_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 component_match *match = NULL;
        struct power_supply_config ac_psy_cfg = {}, usb_psy_cfg = {};
        struct ab8500_charger *di;
-       int irq, i, charger_status, ret = 0, ch_stat;
-       struct device *dev = &pdev->dev;
+       int charger_status;
+       int i, irq;
+       int ret;
 
        di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
        if (!di)
@@ -3393,6 +3450,38 @@ static int ab8500_charger_probe(struct platform_device *pdev)
                return ret;
        }
 
+       /*
+        * VDD ADC supply needs to be enabled from this driver when there
+        * is a charger connected to avoid erroneous BTEMP_HIGH/LOW
+        * interrupts during charging
+        */
+       di->regu = devm_regulator_get(dev, "vddadc");
+       if (IS_ERR(di->regu)) {
+               ret = PTR_ERR(di->regu);
+               dev_err(dev, "failed to get vddadc regulator\n");
+               return ret;
+       }
+
+       /* Request interrupts */
+       for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) {
+               irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name);
+               if (irq < 0)
+                       return irq;
+
+               ret = devm_request_threaded_irq(dev,
+                       irq, NULL, ab8500_charger_irq[i].isr,
+                       IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
+                       ab8500_charger_irq[i].name, di);
+
+               if (ret != 0) {
+                       dev_err(dev, "failed to request %s IRQ %d: %d\n"
+                               , ab8500_charger_irq[i].name, irq, ret);
+                       return ret;
+               }
+               dev_dbg(dev, "Requested %s IRQ %d: %d\n",
+                       ab8500_charger_irq[i].name, irq, ret);
+       }
+
        /* initialize lock */
        spin_lock_init(&di->usb_state.usb_lock);
        mutex_init(&di->usb_ipt_crnt_lock);
@@ -3419,14 +3508,16 @@ static int ab8500_charger_probe(struct platform_device *pdev)
        di->ac_chg.max_out_curr =
                di->bm->chg_output_curr[di->bm->n_chg_out_curr - 1];
        di->ac_chg.wdt_refresh = CHG_WD_INTERVAL;
-       di->ac_chg.enabled = di->bm->ac_enabled;
+       /*
+        * The AB8505 only supports USB charging. If we are not the
+        * AB8505, register an AC charger.
+        *
+        * TODO: if this should be opt-in, add DT properties for this.
+        */
+       if (!is_ab8505(di->parent))
+               di->ac_chg.enabled = true;
        di->ac_chg.external = false;
 
-       /*notifier for external charger enabling*/
-       if (!di->ac_chg.enabled)
-               blocking_notifier_chain_register(
-                       &charger_notifier_list, &charger_nb);
-
        /* USB supply */
        /* ux500_charger sub-class */
        di->usb_chg.ops.enable = &ab8500_charger_usb_en;
@@ -3438,18 +3529,9 @@ static int ab8500_charger_probe(struct platform_device *pdev)
        di->usb_chg.max_out_curr =
                di->bm->chg_output_curr[di->bm->n_chg_out_curr - 1];
        di->usb_chg.wdt_refresh = CHG_WD_INTERVAL;
-       di->usb_chg.enabled = di->bm->usb_enabled;
        di->usb_chg.external = false;
        di->usb_state.usb_current = -1;
 
-       /* Create a work queue for the charger */
-       di->charger_wq = alloc_ordered_workqueue("ab8500_charger_wq",
-                                                WQ_MEM_RECLAIM);
-       if (di->charger_wq == NULL) {
-               dev_err(dev, "failed to create work queue\n");
-               return -ENOMEM;
-       }
-
        mutex_init(&di->charger_attached_mutex);
 
        /* Init work for HW failure check */
@@ -3500,61 +3582,32 @@ static int ab8500_charger_probe(struct platform_device *pdev)
        INIT_WORK(&di->check_usb_thermal_prot_work,
                ab8500_charger_check_usb_thermal_prot_work);
 
-       /*
-        * VDD ADC supply needs to be enabled from this driver when there
-        * is a charger connected to avoid erroneous BTEMP_HIGH/LOW
-        * interrupts during charging
-        */
-       di->regu = devm_regulator_get(dev, "vddadc");
-       if (IS_ERR(di->regu)) {
-               ret = PTR_ERR(di->regu);
-               dev_err(dev, "failed to get vddadc regulator\n");
-               goto free_charger_wq;
-       }
-
 
        /* Initialize OVV, and other registers */
        ret = ab8500_charger_init_hw_registers(di);
        if (ret) {
                dev_err(dev, "failed to initialize ABB registers\n");
-               goto free_charger_wq;
+               return ret;
        }
 
        /* Register AC charger class */
        if (di->ac_chg.enabled) {
-               di->ac_chg.psy = power_supply_register(dev,
+               di->ac_chg.psy = devm_power_supply_register(dev,
                                                       &ab8500_ac_chg_desc,
                                                       &ac_psy_cfg);
                if (IS_ERR(di->ac_chg.psy)) {
                        dev_err(dev, "failed to register AC charger\n");
-                       ret = PTR_ERR(di->ac_chg.psy);
-                       goto free_charger_wq;
+                       return PTR_ERR(di->ac_chg.psy);
                }
        }
 
        /* Register USB charger class */
-       if (di->usb_chg.enabled) {
-               di->usb_chg.psy = power_supply_register(dev,
-                                                       &ab8500_usb_chg_desc,
-                                                       &usb_psy_cfg);
-               if (IS_ERR(di->usb_chg.psy)) {
-                       dev_err(dev, "failed to register USB charger\n");
-                       ret = PTR_ERR(di->usb_chg.psy);
-                       goto free_ac;
-               }
-       }
-
-       di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
-       if (IS_ERR_OR_NULL(di->usb_phy)) {
-               dev_err(dev, "failed to get usb transceiver\n");
-               ret = -EINVAL;
-               goto free_usb;
-       }
-       di->nb.notifier_call = ab8500_charger_usb_notifier_call;
-       ret = usb_register_notifier(di->usb_phy, &di->nb);
-       if (ret) {
-               dev_err(dev, "failed to register usb notifier\n");
-               goto put_usb_phy;
+       di->usb_chg.psy = devm_power_supply_register(dev,
+                                                    &ab8500_usb_chg_desc,
+                                                    &usb_psy_cfg);
+       if (IS_ERR(di->usb_chg.psy)) {
+               dev_err(dev, "failed to register USB charger\n");
+               return PTR_ERR(di->usb_chg.psy);
        }
 
        /* Identify the connected charger types during startup */
@@ -3566,84 +3619,93 @@ static int ab8500_charger_probe(struct platform_device *pdev)
                sysfs_notify(&di->ac_chg.psy->dev.kobj, NULL, "present");
        }
 
-       if (charger_status & USB_PW_CONN) {
-               di->vbus_detected = true;
-               di->vbus_detected_start = true;
-               queue_work(di->charger_wq,
-                       &di->detect_usb_type_work);
-       }
-
-       /* Register interrupts */
-       for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) {
-               irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name);
-               if (irq < 0) {
-                       ret = irq;
-                       goto free_irq;
-               }
+       platform_set_drvdata(pdev, di);
 
-               ret = request_threaded_irq(irq, NULL, ab8500_charger_irq[i].isr,
-                       IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
-                       ab8500_charger_irq[i].name, di);
+       /* Create something that will match the subdrivers when we bind */
+       for (i = 0; i < ARRAY_SIZE(ab8500_charger_component_drivers); i++) {
+               struct device_driver *drv = &ab8500_charger_component_drivers[i]->driver;
+               struct device *p = NULL, *d;
 
-               if (ret != 0) {
-                       dev_err(dev, "failed to request %s IRQ %d: %d\n"
-                               , ab8500_charger_irq[i].name, irq, ret);
-                       goto free_irq;
+               while ((d = platform_find_device_by_driver(p, drv))) {
+                       put_device(p);
+                       component_match_add(dev, &match,
+                                           ab8500_charger_compare_dev, d);
+                       p = d;
                }
-               dev_dbg(dev, "Requested %s IRQ %d: %d\n",
-                       ab8500_charger_irq[i].name, irq, ret);
+               put_device(p);
+       }
+       if (!match) {
+               dev_err(dev, "no matching components\n");
+               return -ENODEV;
+       }
+       if (IS_ERR(match)) {
+               dev_err(dev, "could not create component match\n");
+               return PTR_ERR(match);
        }
 
-       platform_set_drvdata(pdev, di);
-
-       mutex_lock(&di->charger_attached_mutex);
+       /* Notifier for external charger enabling */
+       if (!di->ac_chg.enabled)
+               blocking_notifier_chain_register(
+                       &charger_notifier_list, &charger_nb);
 
-       ch_stat = ab8500_charger_detect_chargers(di, false);
 
-       if ((ch_stat & AC_PW_CONN) == AC_PW_CONN) {
-               if (is_ab8500(di->parent))
-                       queue_delayed_work(di->charger_wq,
-                                          &di->ac_charger_attached_work,
-                                          HZ);
+       di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
+       if (IS_ERR_OR_NULL(di->usb_phy)) {
+               dev_err(dev, "failed to get usb transceiver\n");
+               ret = -EINVAL;
+               goto out_charger_notifier;
        }
-       if ((ch_stat & USB_PW_CONN) == USB_PW_CONN) {
-               if (is_ab8500(di->parent))
-                       queue_delayed_work(di->charger_wq,
-                                          &di->usb_charger_attached_work,
-                                          HZ);
+       di->nb.notifier_call = ab8500_charger_usb_notifier_call;
+       ret = usb_register_notifier(di->usb_phy, &di->nb);
+       if (ret) {
+               dev_err(dev, "failed to register usb notifier\n");
+               goto put_usb_phy;
        }
 
-       mutex_unlock(&di->charger_attached_mutex);
 
-       return ret;
+       ret = component_master_add_with_match(&pdev->dev,
+                                             &ab8500_charger_comp_ops,
+                                             match);
+       if (ret) {
+               dev_err(dev, "failed to add component master\n");
+               goto free_notifier;
+       }
 
-free_irq:
-       usb_unregister_notifier(di->usb_phy, &di->nb);
+       return 0;
 
-       /* We also have to free all successfully registered irqs */
-       for (i = i - 1; i >= 0; i--) {
-               irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name);
-               free_irq(irq, di);
-       }
+free_notifier:
+       usb_unregister_notifier(di->usb_phy, &di->nb);
 put_usb_phy:
        usb_put_phy(di->usb_phy);
-free_usb:
-       if (di->usb_chg.enabled)
-               power_supply_unregister(di->usb_chg.psy);
-free_ac:
-       if (di->ac_chg.enabled)
-               power_supply_unregister(di->ac_chg.psy);
-free_charger_wq:
-       destroy_workqueue(di->charger_wq);
+out_charger_notifier:
+       if (!di->ac_chg.enabled)
+               blocking_notifier_chain_unregister(
+                       &charger_notifier_list, &charger_nb);
        return ret;
 }
 
+static int ab8500_charger_remove(struct platform_device *pdev)
+{
+       struct ab8500_charger *di = platform_get_drvdata(pdev);
+
+       component_master_del(&pdev->dev, &ab8500_charger_comp_ops);
+
+       usb_unregister_notifier(di->usb_phy, &di->nb);
+       usb_put_phy(di->usb_phy);
+       if (!di->ac_chg.enabled)
+               blocking_notifier_chain_unregister(
+                       &charger_notifier_list, &charger_nb);
+
+       return 0;
+}
+
 static SIMPLE_DEV_PM_OPS(ab8500_charger_pm_ops, ab8500_charger_suspend, ab8500_charger_resume);
 
 static const struct of_device_id ab8500_charger_match[] = {
        { .compatible = "stericsson,ab8500-charger", },
        { },
 };
+MODULE_DEVICE_TABLE(of, ab8500_charger_match);
 
 static struct platform_driver ab8500_charger_driver = {
        .probe = ab8500_charger_probe,
@@ -3657,15 +3719,24 @@ static struct platform_driver ab8500_charger_driver = {
 
 static int __init ab8500_charger_init(void)
 {
+       int ret;
+
+       ret = platform_register_drivers(ab8500_charger_component_drivers,
+                       ARRAY_SIZE(ab8500_charger_component_drivers));
+       if (ret)
+               return ret;
+
        return platform_driver_register(&ab8500_charger_driver);
 }
 
 static void __exit ab8500_charger_exit(void)
 {
+       platform_unregister_drivers(ab8500_charger_component_drivers,
+                       ARRAY_SIZE(ab8500_charger_component_drivers));
        platform_driver_unregister(&ab8500_charger_driver);
 }
 
-subsys_initcall_sync(ab8500_charger_init);
+module_init(ab8500_charger_init);
 module_exit(ab8500_charger_exit);
 
 MODULE_LICENSE("GPL v2");
index 0c7c01a..3d45ed0 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/component.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
@@ -59,7 +60,7 @@
        ((y1) + ((((y2) - (y1)) * ((x) - (x1))) / ((x2) - (x1))));
 
 /**
- * struct ab8500_fg_interrupts - ab8500 fg interupts
+ * struct ab8500_fg_interrupts - ab8500 fg interrupts
  * @name:      name of the interrupt
  * @isr                function pointer to the isr
  */
@@ -2980,27 +2981,6 @@ static int __maybe_unused ab8500_fg_suspend(struct device *dev)
        return 0;
 }
 
-static int ab8500_fg_remove(struct platform_device *pdev)
-{
-       int ret = 0;
-       struct ab8500_fg *di = platform_get_drvdata(pdev);
-
-       list_del(&di->node);
-
-       /* Disable coulomb counter */
-       ret = ab8500_fg_coulomb_counter(di, false);
-       if (ret)
-               dev_err(di->dev, "failed to disable coulomb counter\n");
-
-       destroy_workqueue(di->fg_wq);
-       ab8500_fg_sysfs_exit(di);
-
-       flush_scheduled_work();
-       ab8500_fg_sysfs_psy_remove_attrs(di);
-       power_supply_unregister(di->fg_psy);
-       return ret;
-}
-
 /* ab8500 fg driver interrupts and their respective isr */
 static struct ab8500_fg_interrupts ab8500_fg_irq[] = {
        {"NCONV_ACCU", ab8500_fg_cc_convend_handler},
@@ -3024,11 +3004,50 @@ static const struct power_supply_desc ab8500_fg_desc = {
        .external_power_changed = ab8500_fg_external_power_changed,
 };
 
+static int ab8500_fg_bind(struct device *dev, struct device *master,
+                         void *data)
+{
+       struct ab8500_fg *di = dev_get_drvdata(dev);
+
+       /* Create a work queue for running the FG algorithm */
+       di->fg_wq = alloc_ordered_workqueue("ab8500_fg_wq", WQ_MEM_RECLAIM);
+       if (di->fg_wq == NULL) {
+               dev_err(dev, "failed to create work queue\n");
+               return -ENOMEM;
+       }
+
+       /* Start the coulomb counter */
+       ab8500_fg_coulomb_counter(di, true);
+       /* Run the FG algorithm */
+       queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
+
+       return 0;
+}
+
+static void ab8500_fg_unbind(struct device *dev, struct device *master,
+                            void *data)
+{
+       struct ab8500_fg *di = dev_get_drvdata(dev);
+       int ret;
+
+       /* Disable coulomb counter */
+       ret = ab8500_fg_coulomb_counter(di, false);
+       if (ret)
+               dev_err(dev, "failed to disable coulomb counter\n");
+
+       destroy_workqueue(di->fg_wq);
+       flush_scheduled_work();
+}
+
+static const struct component_ops ab8500_fg_component_ops = {
+       .bind = ab8500_fg_bind,
+       .unbind = ab8500_fg_unbind,
+};
+
 static int ab8500_fg_probe(struct platform_device *pdev)
 {
-       struct device_node *np = pdev->dev.of_node;
-       struct power_supply_config psy_cfg = {};
        struct device *dev = &pdev->dev;
+       struct power_supply_config psy_cfg = {};
        struct ab8500_fg *di;
        int i, irq;
        int ret = 0;
@@ -3039,12 +3058,6 @@ static int ab8500_fg_probe(struct platform_device *pdev)
 
        di->bm = &ab8500_bm_data;
 
-       ret = ab8500_bm_of_probe(dev, np, di->bm);
-       if (ret) {
-               dev_err(dev, "failed to get battery information\n");
-               return ret;
-       }
-
        mutex_init(&di->cc_lock);
 
        /* get parent data */
@@ -3074,13 +3087,6 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        ab8500_fg_charge_state_to(di, AB8500_FG_CHARGE_INIT);
        ab8500_fg_discharge_state_to(di, AB8500_FG_DISCHARGE_INIT);
 
-       /* Create a work queue for running the FG algorithm */
-       di->fg_wq = alloc_ordered_workqueue("ab8500_fg_wq", WQ_MEM_RECLAIM);
-       if (di->fg_wq == NULL) {
-               dev_err(dev, "failed to create work queue\n");
-               return -ENOMEM;
-       }
-
        /* Init work for running the fg algorithm instantly */
        INIT_WORK(&di->fg_work, ab8500_fg_instant_work);
 
@@ -3113,7 +3119,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        ret = ab8500_fg_init_hw_registers(di);
        if (ret) {
                dev_err(dev, "failed to initialize registers\n");
-               goto free_inst_curr_wq;
+               return ret;
        }
 
        /* Consider battery unknown until we're informed otherwise */
@@ -3121,15 +3127,13 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        di->flags.batt_id_received = false;
 
        /* Register FG power supply class */
-       di->fg_psy = power_supply_register(dev, &ab8500_fg_desc, &psy_cfg);
+       di->fg_psy = devm_power_supply_register(dev, &ab8500_fg_desc, &psy_cfg);
        if (IS_ERR(di->fg_psy)) {
                dev_err(dev, "failed to register FG psy\n");
-               ret = PTR_ERR(di->fg_psy);
-               goto free_inst_curr_wq;
+               return PTR_ERR(di->fg_psy);
        }
 
        di->fg_samples = SEC_TO_SAMPLE(di->bm->fg_params->init_timer);
-       ab8500_fg_coulomb_counter(di, true);
 
        /*
         * Initialize completion used to notify completion and start
@@ -3141,19 +3145,18 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        /* Register primary interrupt handlers */
        for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq); i++) {
                irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name);
-               if (irq < 0) {
-                       ret = irq;
-                       goto free_irq;
-               }
+               if (irq < 0)
+                       return irq;
 
-               ret = request_threaded_irq(irq, NULL, ab8500_fg_irq[i].isr,
+               ret = devm_request_threaded_irq(dev, irq, NULL,
+                                 ab8500_fg_irq[i].isr,
                                  IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
                                  ab8500_fg_irq[i].name, di);
 
                if (ret != 0) {
                        dev_err(dev, "failed to request %s IRQ %d: %d\n",
                                ab8500_fg_irq[i].name, irq, ret);
-                       goto free_irq;
+                       return ret;
                }
                dev_dbg(dev, "Requested %s IRQ %d: %d\n",
                        ab8500_fg_irq[i].name, irq, ret);
@@ -3168,14 +3171,14 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        ret = ab8500_fg_sysfs_init(di);
        if (ret) {
                dev_err(dev, "failed to create sysfs entry\n");
-               goto free_irq;
+               return ret;
        }
 
        ret = ab8500_fg_sysfs_psy_create_attrs(di);
        if (ret) {
                dev_err(dev, "failed to create FG psy\n");
                ab8500_fg_sysfs_exit(di);
-               goto free_irq;
+               return ret;
        }
 
        /* Calibrate the fg first time */
@@ -3185,24 +3188,21 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        /* Use room temp as default value until we get an update from driver. */
        di->bat_temp = 210;
 
-       /* Run the FG algorithm */
-       queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
-
        list_add_tail(&di->node, &ab8500_fg_list);
 
-       return ret;
+       return component_add(dev, &ab8500_fg_component_ops);
+}
 
-free_irq:
-       /* We also have to free all registered irqs */
-       while (--i >= 0) {
-               /* Last assignment of i from primary interrupt handlers */
-               irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name);
-               free_irq(irq, di);
-       }
+static int ab8500_fg_remove(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct ab8500_fg *di = platform_get_drvdata(pdev);
+
+       component_del(&pdev->dev, &ab8500_fg_component_ops);
+       list_del(&di->node);
+       ab8500_fg_sysfs_exit(di);
+       ab8500_fg_sysfs_psy_remove_attrs(di);
 
-       power_supply_unregister(di->fg_psy);
-free_inst_curr_wq:
-       destroy_workqueue(di->fg_wq);
        return ret;
 }
 
@@ -3212,8 +3212,9 @@ static const struct of_device_id ab8500_fg_match[] = {
        { .compatible = "stericsson,ab8500-fg", },
        { },
 };
+MODULE_DEVICE_TABLE(of, ab8500_fg_match);
 
-static struct platform_driver ab8500_fg_driver = {
+struct platform_driver ab8500_fg_driver = {
        .probe = ab8500_fg_probe,
        .remove = ab8500_fg_remove,
        .driver = {
@@ -3222,20 +3223,6 @@ static struct platform_driver ab8500_fg_driver = {
                .pm = &ab8500_fg_pm_ops,
        },
 };
-
-static int __init ab8500_fg_init(void)
-{
-       return platform_driver_register(&ab8500_fg_driver);
-}
-
-static void __exit ab8500_fg_exit(void)
-{
-       platform_driver_unregister(&ab8500_fg_driver);
-}
-
-subsys_initcall_sync(ab8500_fg_init);
-module_exit(ab8500_fg_exit);
-
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Johan Palsson, Karl Komierowski");
 MODULE_ALIAS("platform:ab8500-fg");
index f5b7922..a17849b 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/component.h>
 #include <linux/hrtimer.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
@@ -1943,13 +1944,44 @@ static int __maybe_unused abx500_chargalg_suspend(struct device *dev)
        return 0;
 }
 
-static int abx500_chargalg_remove(struct platform_device *pdev)
+static char *supply_interface[] = {
+       "ab8500_fg",
+};
+
+static const struct power_supply_desc abx500_chargalg_desc = {
+       .name                   = "abx500_chargalg",
+       .type                   = POWER_SUPPLY_TYPE_BATTERY,
+       .properties             = abx500_chargalg_props,
+       .num_properties         = ARRAY_SIZE(abx500_chargalg_props),
+       .get_property           = abx500_chargalg_get_property,
+       .external_power_changed = abx500_chargalg_external_power_changed,
+};
+
+static int abx500_chargalg_bind(struct device *dev, struct device *master,
+                               void *data)
 {
-       struct abx500_chargalg *di = platform_get_drvdata(pdev);
+       struct abx500_chargalg *di = dev_get_drvdata(dev);
 
-       /* sysfs interface to enable/disbale charging from user space */
-       abx500_chargalg_sysfs_exit(di);
+       /* Create a work queue for the chargalg */
+       di->chargalg_wq = alloc_ordered_workqueue("abx500_chargalg_wq",
+                                                 WQ_MEM_RECLAIM);
+       if (di->chargalg_wq == NULL) {
+               dev_err(di->dev, "failed to create work queue\n");
+               return -ENOMEM;
+       }
+
+       /* Run the charging algorithm */
+       queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, 0);
 
+       return 0;
+}
+
+static void abx500_chargalg_unbind(struct device *dev, struct device *master,
+                                  void *data)
+{
+       struct abx500_chargalg *di = dev_get_drvdata(dev);
+
+       /* Stop all timers and work */
        hrtimer_cancel(&di->safety_timer);
        hrtimer_cancel(&di->maintenance_timer);
 
@@ -1959,48 +1991,29 @@ static int abx500_chargalg_remove(struct platform_device *pdev)
 
        /* Delete the work queue */
        destroy_workqueue(di->chargalg_wq);
-
-       power_supply_unregister(di->chargalg_psy);
-
-       return 0;
+       flush_scheduled_work();
 }
 
-static char *supply_interface[] = {
-       "ab8500_fg",
-};
-
-static const struct power_supply_desc abx500_chargalg_desc = {
-       .name                   = "abx500_chargalg",
-       .type                   = POWER_SUPPLY_TYPE_BATTERY,
-       .properties             = abx500_chargalg_props,
-       .num_properties         = ARRAY_SIZE(abx500_chargalg_props),
-       .get_property           = abx500_chargalg_get_property,
-       .external_power_changed = abx500_chargalg_external_power_changed,
+static const struct component_ops abx500_chargalg_component_ops = {
+       .bind = abx500_chargalg_bind,
+       .unbind = abx500_chargalg_unbind,
 };
 
 static int abx500_chargalg_probe(struct platform_device *pdev)
 {
-       struct device_node *np = pdev->dev.of_node;
+       struct device *dev = &pdev->dev;
        struct power_supply_config psy_cfg = {};
        struct abx500_chargalg *di;
        int ret = 0;
 
-       di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
-       if (!di) {
-               dev_err(&pdev->dev, "%s no mem for ab8500_chargalg\n", __func__);
+       di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
+       if (!di)
                return -ENOMEM;
-       }
 
        di->bm = &ab8500_bm_data;
 
-       ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to get battery information\n");
-               return ret;
-       }
-
        /* get device struct and parent */
-       di->dev = &pdev->dev;
+       di->dev = dev;
        di->parent = dev_get_drvdata(pdev->dev.parent);
 
        psy_cfg.supplied_to = supply_interface;
@@ -2016,14 +2029,6 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
        di->maintenance_timer.function =
                abx500_chargalg_maintenance_timer_expired;
 
-       /* Create a work queue for the chargalg */
-       di->chargalg_wq = alloc_ordered_workqueue("abx500_chargalg_wq",
-                                                  WQ_MEM_RECLAIM);
-       if (di->chargalg_wq == NULL) {
-               dev_err(di->dev, "failed to create work queue\n");
-               return -ENOMEM;
-       }
-
        /* Init work for chargalg */
        INIT_DEFERRABLE_WORK(&di->chargalg_periodic_work,
                abx500_chargalg_periodic_work);
@@ -2037,12 +2042,12 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
        di->chg_info.prev_conn_chg = -1;
 
        /* Register chargalg power supply class */
-       di->chargalg_psy = power_supply_register(di->dev, &abx500_chargalg_desc,
+       di->chargalg_psy = devm_power_supply_register(di->dev,
+                                                &abx500_chargalg_desc,
                                                 &psy_cfg);
        if (IS_ERR(di->chargalg_psy)) {
                dev_err(di->dev, "failed to register chargalg psy\n");
-               ret = PTR_ERR(di->chargalg_psy);
-               goto free_chargalg_wq;
+               return PTR_ERR(di->chargalg_psy);
        }
 
        platform_set_drvdata(pdev, di);
@@ -2051,21 +2056,24 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
        ret = abx500_chargalg_sysfs_init(di);
        if (ret) {
                dev_err(di->dev, "failed to create sysfs entry\n");
-               goto free_psy;
+               return ret;
        }
        di->curr_status.curr_step = CHARGALG_CURR_STEP_HIGH;
 
-       /* Run the charging algorithm */
-       queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, 0);
-
        dev_info(di->dev, "probe success\n");
-       return ret;
+       return component_add(dev, &abx500_chargalg_component_ops);
+}
 
-free_psy:
-       power_supply_unregister(di->chargalg_psy);
-free_chargalg_wq:
-       destroy_workqueue(di->chargalg_wq);
-       return ret;
+static int abx500_chargalg_remove(struct platform_device *pdev)
+{
+       struct abx500_chargalg *di = platform_get_drvdata(pdev);
+
+       component_del(&pdev->dev, &abx500_chargalg_component_ops);
+
+       /* sysfs interface to enable/disable charging from user space */
+       abx500_chargalg_sysfs_exit(di);
+
+       return 0;
 }
 
 static SIMPLE_DEV_PM_OPS(abx500_chargalg_pm_ops, abx500_chargalg_suspend, abx500_chargalg_resume);
@@ -2075,7 +2083,7 @@ static const struct of_device_id ab8500_chargalg_match[] = {
        { },
 };
 
-static struct platform_driver abx500_chargalg_driver = {
+struct platform_driver abx500_chargalg_driver = {
        .probe = abx500_chargalg_probe,
        .remove = abx500_chargalg_remove,
        .driver = {
@@ -2084,9 +2092,6 @@ static struct platform_driver abx500_chargalg_driver = {
                .pm = &abx500_chargalg_pm_ops,
        },
 };
-
-module_platform_driver(abx500_chargalg_driver);
-
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Johan Palsson, Karl Komierowski");
 MODULE_ALIAS("platform:abx500-chargalg");
index e84b6e4..18a9db0 100644 (file)
@@ -40,6 +40,7 @@
 #define AXP209_FG_PERCENT              GENMASK(6, 0)
 #define AXP22X_FG_VALID                        BIT(7)
 
+#define AXP20X_CHRG_CTRL1_ENABLE       BIT(7)
 #define AXP20X_CHRG_CTRL1_TGT_VOLT     GENMASK(6, 5)
 #define AXP20X_CHRG_CTRL1_TGT_4_1V     (0 << 5)
 #define AXP20X_CHRG_CTRL1_TGT_4_15V    (1 << 5)
@@ -468,7 +469,18 @@ static int axp20x_battery_set_prop(struct power_supply *psy,
        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
                return axp20x_set_max_constant_charge_current(axp20x_batt,
                                                              val->intval);
-
+       case POWER_SUPPLY_PROP_STATUS:
+               switch (val->intval) {
+               case POWER_SUPPLY_STATUS_CHARGING:
+                       return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,
+                               AXP20X_CHRG_CTRL1_ENABLE, AXP20X_CHRG_CTRL1_ENABLE);
+
+               case POWER_SUPPLY_STATUS_DISCHARGING:
+               case POWER_SUPPLY_STATUS_NOT_CHARGING:
+                       return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,
+                               AXP20X_CHRG_CTRL1_ENABLE, 0);
+               }
+               fallthrough;
        default:
                return -EINVAL;
        }
@@ -491,7 +503,8 @@ static enum power_supply_property axp20x_battery_props[] = {
 static int axp20x_battery_prop_writeable(struct power_supply *psy,
                                         enum power_supply_property psp)
 {
-       return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN ||
+       return psp == POWER_SUPPLY_PROP_STATUS ||
+              psp == POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN ||
               psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN ||
               psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT ||
               psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;
index 39e16ec..2ba2d8d 100644 (file)
@@ -142,9 +142,7 @@ static int fuel_gauge_reg_readb(struct axp288_fg_info *info, int reg)
 
        for (i = 0; i < NR_RETRY_CNT; i++) {
                ret = regmap_read(info->regmap, reg, &val);
-               if (ret == -EBUSY)
-                       continue;
-               else
+               if (ret != -EBUSY)
                        break;
        }
 
@@ -676,7 +674,7 @@ intr_failed:
  * detection reports one despite it not being there.
  * Please keep this listed sorted alphabetically.
  */
-static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = {
+static const struct dmi_system_id axp288_no_battery_list[] = {
        {
                /* ACEPC T8 Cherry Trail Z8350 mini PC */
                .matches = {
@@ -723,15 +721,6 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "MEEGOPAD T02"),
                },
        },
-       {
-               /* Meegopad T08 */
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Default string"),
-                       DMI_MATCH(DMI_BOARD_VENDOR, "To be filled by OEM."),
-                       DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"),
-                       DMI_MATCH(DMI_BOARD_VERSION, "V1.1"),
-               },
-       },
        {       /* Mele PCG03 Mini PC */
                .matches = {
                        DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Mini PC"),
@@ -745,6 +734,15 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
                }
        },
+       {
+               /* Various Ace PC/Meegopad/MinisForum/Wintel Mini-PCs/HDMI-sticks */
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"),
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "3"),
+                       DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
+                       DMI_MATCH(DMI_BIOS_VERSION, "5.11"),
+               },
+       },
        {}
 };
 
@@ -764,7 +762,7 @@ static int axp288_fuel_gauge_probe(struct platform_device *pdev)
        };
        unsigned int val;
 
-       if (dmi_check_system(axp288_fuel_gauge_blacklist))
+       if (dmi_check_system(axp288_no_battery_list))
                return -ENODEV;
 
        /*
diff --git a/drivers/power/supply/bd70528-charger.c b/drivers/power/supply/bd70528-charger.c
deleted file mode 100644 (file)
index 7c1f0b9..0000000
+++ /dev/null
@@ -1,710 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-//
-// Copyright (C) 2018 ROHM Semiconductors
-//
-// power-supply driver for ROHM BD70528 PMIC
-
-/*
- * BD70528 charger HW state machine.
- *
- * The thermal shutdown state is not drawn. From any other state but
- * battery error and suspend it is possible to go to TSD/TMP states
- * if temperature is out of bounds.
- *
- *  CHG_RST = H
- *  or CHG_EN=L
- *  or (DCIN2_UVLO=L && DCIN1_UVLO=L)
- *  or (DCIN2_OVLO=H & DCIN1_UVKLO=L)
- *
- *  +--------------+         +--------------+
- *  |              |         |              |
- *  |  Any state   +-------> |    Suspend   |
- *  |              |         |              |
- *  +--------------+         +------+-------+
- *                                  |
- *  CHG_EN = H && BAT_DET = H &&    |
- *  No errors (temp, bat_ov, UVLO,  |
- *  OVLO...)                        |
- *                                  |
- *  BAT_OV or             +---------v----------+
- *  (DBAT && TTRI)        |                    |
- *      +-----------------+   Trickle Charge   | <---------------+
- *      |                 |                    |                 |
- *      |                 +-------+------------+                 |
- *      |                         |                              |
- *      |                         |     ^                        |
- *      |        V_BAT > VTRI_TH  |     |  VBAT < VTRI_TH - 50mV |
- *      |                         |     |                        |
- *      |                         v     |                        |
- *      |                               |                        |
- *      |     BAT_OV or      +----------+----+                   |
- *      |     (DBAT && TFST) |               |                   |
- *      |   +----------------+  Fast Charge  |                   |
- *      |   |                |               |                   |
- *      v   v                +----+----------+                   |
- *                                |                              |
- *+----------------+   ILIM_DET=L |    ^ ILIM_DET                |
- *|                |   & CV_DET=H |    | or CV_DET=L             |
- *|  Battery Error |   & VBAT >   |    | or VBAT < VRECHG_TH     |
- *|                |   VRECHG_TH  |    | or IBAT  > IFST/x       |
- *+----------------+   & IBAT <   |    |                         |
- *                     IFST/x     v    |                         |
- *       ^                             |                         |
- *       |                   +---------+-+                       |
- *       |                   |           |                       |
- *       +-------------------+  Top OFF  |                       |
- *  BAT_OV = H or            |           |                       |
- *  (DBAT && TFST)           +-----+-----+                       |
- *                                 |                             |
- *           Stay top-off for 15s  |                             |
- *                                 v                             |
- *                                                               |
- *                            +--------+                         |
- *                            |        |                         |
- *                            |  Done  +-------------------------+
- *                            |        |
- *                            +--------+   VBAT < VRECHG_TH
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/mfd/rohm-bd70528.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/power_supply.h>
-#include <linux/linear_range.h>
-
-#define CHG_STAT_SUSPEND       0x0
-#define CHG_STAT_TRICKLE       0x1
-#define CHG_STAT_FAST          0x3
-#define CHG_STAT_TOPOFF                0xe
-#define CHG_STAT_DONE          0xf
-#define CHG_STAT_OTP_TRICKLE   0x10
-#define CHG_STAT_OTP_FAST      0x11
-#define CHG_STAT_OTP_DONE      0x12
-#define CHG_STAT_TSD_TRICKLE   0x20
-#define CHG_STAT_TSD_FAST      0x21
-#define CHG_STAT_TSD_TOPOFF    0x22
-#define CHG_STAT_BAT_ERR       0x7f
-
-static const char *bd70528_charger_model = "BD70528";
-static const char *bd70528_charger_manufacturer = "ROHM Semiconductors";
-
-#define BD_ERR_IRQ_HND(_name_, _wrn_)                                  \
-static irqreturn_t bd0528_##_name_##_interrupt(int irq, void *arg)     \
-{                                                                      \
-       struct power_supply *psy = (struct power_supply *)arg;          \
-                                                                       \
-       power_supply_changed(psy);                                      \
-       dev_err(&psy->dev, (_wrn_));                                    \
-                                                                       \
-       return IRQ_HANDLED;                                             \
-}
-
-#define BD_INFO_IRQ_HND(_name_, _wrn_)                                 \
-static irqreturn_t bd0528_##_name_##_interrupt(int irq, void *arg)     \
-{                                                                      \
-       struct power_supply *psy = (struct power_supply *)arg;          \
-                                                                       \
-       power_supply_changed(psy);                                      \
-       dev_dbg(&psy->dev, (_wrn_));                                    \
-                                                                       \
-       return IRQ_HANDLED;                                             \
-}
-
-#define BD_IRQ_HND(_name_) bd0528_##_name_##_interrupt
-
-struct bd70528_psy {
-       struct regmap *regmap;
-       struct device *dev;
-       struct power_supply *psy;
-};
-
-BD_ERR_IRQ_HND(BAT_OV_DET, "Battery overvoltage detected\n");
-BD_ERR_IRQ_HND(DBAT_DET, "Dead battery detected\n");
-BD_ERR_IRQ_HND(COLD_DET, "Battery cold\n");
-BD_ERR_IRQ_HND(HOT_DET, "Battery hot\n");
-BD_ERR_IRQ_HND(CHG_TSD, "Charger thermal shutdown\n");
-BD_ERR_IRQ_HND(DCIN2_OV_DET, "DCIN2 overvoltage detected\n");
-
-BD_INFO_IRQ_HND(BAT_OV_RES, "Battery voltage back to normal\n");
-BD_INFO_IRQ_HND(COLD_RES, "Battery temperature back to normal\n");
-BD_INFO_IRQ_HND(HOT_RES, "Battery temperature back to normal\n");
-BD_INFO_IRQ_HND(BAT_RMV, "Battery removed\n");
-BD_INFO_IRQ_HND(BAT_DET, "Battery detected\n");
-BD_INFO_IRQ_HND(DCIN2_OV_RES, "DCIN2 voltage back to normal\n");
-BD_INFO_IRQ_HND(DCIN2_RMV, "DCIN2 removed\n");
-BD_INFO_IRQ_HND(DCIN2_DET, "DCIN2 detected\n");
-BD_INFO_IRQ_HND(DCIN1_RMV, "DCIN1 removed\n");
-BD_INFO_IRQ_HND(DCIN1_DET, "DCIN1 detected\n");
-
-struct irq_name_pair {
-       const char *n;
-       irqreturn_t (*h)(int irq, void *arg);
-};
-
-static int bd70528_get_irqs(struct platform_device *pdev,
-                           struct bd70528_psy *bdpsy)
-{
-       int irq, i, ret;
-       unsigned int mask;
-       static const struct irq_name_pair bd70528_chg_irqs[] = {
-               { .n = "bd70528-bat-ov-res", .h = BD_IRQ_HND(BAT_OV_RES) },
-               { .n = "bd70528-bat-ov-det", .h = BD_IRQ_HND(BAT_OV_DET) },
-               { .n = "bd70528-bat-dead", .h = BD_IRQ_HND(DBAT_DET) },
-               { .n = "bd70528-bat-warmed", .h = BD_IRQ_HND(COLD_RES) },
-               { .n = "bd70528-bat-cold", .h = BD_IRQ_HND(COLD_DET) },
-               { .n = "bd70528-bat-cooled", .h = BD_IRQ_HND(HOT_RES) },
-               { .n = "bd70528-bat-hot", .h = BD_IRQ_HND(HOT_DET) },
-               { .n = "bd70528-chg-tshd", .h = BD_IRQ_HND(CHG_TSD) },
-               { .n = "bd70528-bat-removed", .h = BD_IRQ_HND(BAT_RMV) },
-               { .n = "bd70528-bat-detected", .h = BD_IRQ_HND(BAT_DET) },
-               { .n = "bd70528-dcin2-ov-res", .h = BD_IRQ_HND(DCIN2_OV_RES) },
-               { .n = "bd70528-dcin2-ov-det", .h = BD_IRQ_HND(DCIN2_OV_DET) },
-               { .n = "bd70528-dcin2-removed", .h = BD_IRQ_HND(DCIN2_RMV) },
-               { .n = "bd70528-dcin2-detected", .h = BD_IRQ_HND(DCIN2_DET) },
-               { .n = "bd70528-dcin1-removed", .h = BD_IRQ_HND(DCIN1_RMV) },
-               { .n = "bd70528-dcin1-detected", .h = BD_IRQ_HND(DCIN1_DET) },
-       };
-
-       for (i = 0; i < ARRAY_SIZE(bd70528_chg_irqs); i++) {
-               irq = platform_get_irq_byname(pdev, bd70528_chg_irqs[i].n);
-               if (irq < 0) {
-                       dev_err(&pdev->dev, "Bad IRQ information for %s (%d)\n",
-                               bd70528_chg_irqs[i].n, irq);
-                       return irq;
-               }
-               ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
-                                               bd70528_chg_irqs[i].h,
-                                               IRQF_ONESHOT,
-                                               bd70528_chg_irqs[i].n,
-                                               bdpsy->psy);
-
-               if (ret)
-                       return ret;
-       }
-       /*
-        * BD70528 irq controller is not touching the main mask register.
-        * So enable the charger block interrupts at main level. We can just
-        * leave them enabled as irq-controller should disable irqs
-        * from sub-registers when IRQ is disabled or freed.
-        */
-       mask = BD70528_REG_INT_BAT1_MASK | BD70528_REG_INT_BAT2_MASK;
-       ret = regmap_update_bits(bdpsy->regmap,
-                                BD70528_REG_INT_MAIN_MASK, mask, 0);
-       if (ret)
-               dev_err(&pdev->dev, "Failed to enable charger IRQs\n");
-
-       return ret;
-}
-
-static int bd70528_get_charger_status(struct bd70528_psy *bdpsy, int *val)
-{
-       int ret;
-       unsigned int v;
-
-       ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_CURR_STAT, &v);
-       if (ret) {
-               dev_err(bdpsy->dev, "Charger state read failure %d\n",
-                       ret);
-               return ret;
-       }
-
-       switch (v & BD70528_MASK_CHG_STAT) {
-       case CHG_STAT_SUSPEND:
-       /* Maybe we should check the CHG_TTRI_EN? */
-       case CHG_STAT_OTP_TRICKLE:
-       case CHG_STAT_OTP_FAST:
-       case CHG_STAT_OTP_DONE:
-       case CHG_STAT_TSD_TRICKLE:
-       case CHG_STAT_TSD_FAST:
-       case CHG_STAT_TSD_TOPOFF:
-       case CHG_STAT_BAT_ERR:
-               *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
-               break;
-       case CHG_STAT_DONE:
-               *val = POWER_SUPPLY_STATUS_FULL;
-               break;
-       case CHG_STAT_TRICKLE:
-       case CHG_STAT_FAST:
-       case CHG_STAT_TOPOFF:
-               *val = POWER_SUPPLY_STATUS_CHARGING;
-               break;
-       default:
-               *val = POWER_SUPPLY_STATUS_UNKNOWN;
-               break;
-       }
-
-       return 0;
-}
-
-static int bd70528_get_charge_type(struct bd70528_psy *bdpsy, int *val)
-{
-       int ret;
-       unsigned int v;
-
-       ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_CURR_STAT, &v);
-       if (ret) {
-               dev_err(bdpsy->dev, "Charger state read failure %d\n",
-                       ret);
-               return ret;
-       }
-
-       switch (v & BD70528_MASK_CHG_STAT) {
-       case CHG_STAT_TRICKLE:
-               *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
-               break;
-       case CHG_STAT_FAST:
-       case CHG_STAT_TOPOFF:
-               *val = POWER_SUPPLY_CHARGE_TYPE_FAST;
-               break;
-       case CHG_STAT_DONE:
-       case CHG_STAT_SUSPEND:
-       /* Maybe we should check the CHG_TTRI_EN? */
-       case CHG_STAT_OTP_TRICKLE:
-       case CHG_STAT_OTP_FAST:
-       case CHG_STAT_OTP_DONE:
-       case CHG_STAT_TSD_TRICKLE:
-       case CHG_STAT_TSD_FAST:
-       case CHG_STAT_TSD_TOPOFF:
-       case CHG_STAT_BAT_ERR:
-               *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
-               break;
-       default:
-               *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
-               break;
-       }
-
-       return 0;
-}
-
-static int bd70528_get_battery_health(struct bd70528_psy *bdpsy, int *val)
-{
-       int ret;
-       unsigned int v;
-
-       ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_BAT_STAT, &v);
-       if (ret) {
-               dev_err(bdpsy->dev, "Battery state read failure %d\n",
-                       ret);
-               return ret;
-       }
-       /* No battery? */
-       if (!(v & BD70528_MASK_CHG_BAT_DETECT))
-               *val = POWER_SUPPLY_HEALTH_DEAD;
-       else if (v & BD70528_MASK_CHG_BAT_OVERVOLT)
-               *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
-       else if (v & BD70528_MASK_CHG_BAT_TIMER)
-               *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
-       else
-               *val = POWER_SUPPLY_HEALTH_GOOD;
-
-       return 0;
-}
-
-static int bd70528_get_online(struct bd70528_psy *bdpsy, int *val)
-{
-       int ret;
-       unsigned int v;
-
-       ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_IN_STAT, &v);
-       if (ret) {
-               dev_err(bdpsy->dev, "DC1 IN state read failure %d\n",
-                       ret);
-               return ret;
-       }
-
-       *val = (v & BD70528_MASK_CHG_DCIN1_UVLO) ? 1 : 0;
-
-       return 0;
-}
-
-static int bd70528_get_present(struct bd70528_psy *bdpsy, int *val)
-{
-       int ret;
-       unsigned int v;
-
-       ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_BAT_STAT, &v);
-       if (ret) {
-               dev_err(bdpsy->dev, "Battery state read failure %d\n",
-                       ret);
-               return ret;
-       }
-
-       *val = (v & BD70528_MASK_CHG_BAT_DETECT) ? 1 : 0;
-
-       return 0;
-}
-
-static const struct linear_range current_limit_ranges[] = {
-       {
-               .min = 5,
-               .step = 1,
-               .min_sel = 0,
-               .max_sel = 0x22,
-       },
-       {
-               .min = 40,
-               .step = 5,
-               .min_sel = 0x23,
-               .max_sel = 0x26,
-       },
-       {
-               .min = 60,
-               .step = 20,
-               .min_sel = 0x27,
-               .max_sel = 0x2d,
-       },
-       {
-               .min = 200,
-               .step = 50,
-               .min_sel = 0x2e,
-               .max_sel = 0x34,
-       },
-       {
-               .min = 500,
-               .step = 0,
-               .min_sel = 0x35,
-               .max_sel = 0x3f,
-       },
-};
-
-/*
- * BD70528 would support setting and getting own charge current/
- * voltage for low temperatures. The driver currently only reads
- * the charge current at room temperature. We do set both though.
- */
-static const struct linear_range warm_charge_curr[] = {
-       {
-               .min = 10,
-               .step = 10,
-               .min_sel = 0,
-               .max_sel = 0x12,
-       },
-       {
-               .min = 200,
-               .step = 25,
-               .min_sel = 0x13,
-               .max_sel = 0x1f,
-       },
-};
-
-/*
- * Cold charge current selectors are identical to warm charge current
- * selectors. The difference is that only smaller currents are available
- * at cold charge range.
- */
-#define MAX_COLD_CHG_CURR_SEL 0x15
-#define MAX_WARM_CHG_CURR_SEL 0x1f
-#define MIN_CHG_CURR_SEL 0x0
-
-static int get_charge_current(struct bd70528_psy *bdpsy, int *ma)
-{
-       unsigned int sel;
-       int ret;
-
-       ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_CHG_CURR_WARM,
-                         &sel);
-       if (ret) {
-               dev_err(bdpsy->dev,
-                       "Charge current reading failed (%d)\n", ret);
-               return ret;
-       }
-
-       sel &= BD70528_MASK_CHG_CHG_CURR;
-
-       ret = linear_range_get_value_array(&warm_charge_curr[0],
-                                          ARRAY_SIZE(warm_charge_curr),
-                                          sel, ma);
-       if (ret) {
-               dev_err(bdpsy->dev,
-                       "Unknown charge current value 0x%x\n",
-                       sel);
-       }
-
-       return ret;
-}
-
-static int get_current_limit(struct bd70528_psy *bdpsy, int *ma)
-{
-       unsigned int sel;
-       int ret;
-
-       ret = regmap_read(bdpsy->regmap, BD70528_REG_CHG_DCIN_ILIM,
-                         &sel);
-
-       if (ret) {
-               dev_err(bdpsy->dev,
-                       "Input current limit reading failed (%d)\n", ret);
-               return ret;
-       }
-
-       sel &= BD70528_MASK_CHG_DCIN_ILIM;
-
-       ret = linear_range_get_value_array(&current_limit_ranges[0],
-                                          ARRAY_SIZE(current_limit_ranges),
-                                          sel, ma);
-       if (ret) {
-               /* Unspecified values mean 500 mA */
-               *ma = 500;
-       }
-       return 0;
-}
-
-static enum power_supply_property bd70528_charger_props[] = {
-       POWER_SUPPLY_PROP_STATUS,
-       POWER_SUPPLY_PROP_CHARGE_TYPE,
-       POWER_SUPPLY_PROP_HEALTH,
-       POWER_SUPPLY_PROP_PRESENT,
-       POWER_SUPPLY_PROP_ONLINE,
-       POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
-       POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
-       POWER_SUPPLY_PROP_MODEL_NAME,
-       POWER_SUPPLY_PROP_MANUFACTURER,
-};
-
-static int bd70528_charger_get_property(struct power_supply *psy,
-                                       enum power_supply_property psp,
-                                       union power_supply_propval *val)
-{
-       struct bd70528_psy *bdpsy = power_supply_get_drvdata(psy);
-       int ret = 0;
-
-       switch (psp) {
-       case POWER_SUPPLY_PROP_STATUS:
-               return bd70528_get_charger_status(bdpsy, &val->intval);
-       case POWER_SUPPLY_PROP_CHARGE_TYPE:
-               return bd70528_get_charge_type(bdpsy, &val->intval);
-       case POWER_SUPPLY_PROP_HEALTH:
-               return bd70528_get_battery_health(bdpsy, &val->intval);
-       case POWER_SUPPLY_PROP_PRESENT:
-               return bd70528_get_present(bdpsy, &val->intval);
-       case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
-               ret = get_current_limit(bdpsy, &val->intval);
-               val->intval *= 1000;
-               return ret;
-       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
-               ret = get_charge_current(bdpsy, &val->intval);
-               val->intval *= 1000;
-               return ret;
-       case POWER_SUPPLY_PROP_ONLINE:
-               return bd70528_get_online(bdpsy, &val->intval);
-       case POWER_SUPPLY_PROP_MODEL_NAME:
-               val->strval = bd70528_charger_model;
-               return 0;
-       case POWER_SUPPLY_PROP_MANUFACTURER:
-               val->strval = bd70528_charger_manufacturer;
-               return 0;
-       default:
-               break;
-       }
-
-       return -EINVAL;
-}
-
-static int bd70528_prop_is_writable(struct power_supply *psy,
-                                   enum power_supply_property psp)
-{
-       switch (psp) {
-       case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
-       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
-               return 1;
-       default:
-               break;
-       }
-       return 0;
-}
-
-static int set_charge_current(struct bd70528_psy *bdpsy, int ma)
-{
-       unsigned int reg;
-       int ret = 0, tmpret;
-       bool found;
-
-       if (ma > 500) {
-               dev_warn(bdpsy->dev,
-                        "Requested charge current %u exceed maximum (500mA)\n",
-                        ma);
-               reg = MAX_WARM_CHG_CURR_SEL;
-               goto set;
-       }
-       if (ma < 10) {
-               dev_err(bdpsy->dev,
-                       "Requested charge current %u smaller than min (10mA)\n",
-                        ma);
-               reg = MIN_CHG_CURR_SEL;
-               ret = -EINVAL;
-               goto set;
-       }
-
-/*
- * For BD70528 voltage/current limits we happily accept any value which
- * belongs the range. We could check if value matching the selector is
- * desired by computing the range min + (sel - sel_low) * range step - but
- * I guess it is enough if we use voltage/current which is closest (below)
- * the requested?
- */
-
-       ret = linear_range_get_selector_low_array(warm_charge_curr,
-                                                 ARRAY_SIZE(warm_charge_curr),
-                                                 ma, &reg, &found);
-       if (ret) {
-               dev_err(bdpsy->dev,
-                        "Unsupported charge current %u mA\n", ma);
-               reg = MIN_CHG_CURR_SEL;
-               goto set;
-       }
-       if (!found) {
-               /*
-                * There was a gap in supported values and we hit it.
-                * Yet a smaller value was found so we use it.
-                */
-               dev_warn(bdpsy->dev,
-                        "Unsupported charge current %u mA\n", ma);
-       }
-set:
-
-       tmpret = regmap_update_bits(bdpsy->regmap,
-                                   BD70528_REG_CHG_CHG_CURR_WARM,
-                                   BD70528_MASK_CHG_CHG_CURR, reg);
-       if (tmpret)
-               dev_err(bdpsy->dev,
-                       "Charge current write failure (%d)\n", tmpret);
-
-       if (reg > MAX_COLD_CHG_CURR_SEL)
-               reg = MAX_COLD_CHG_CURR_SEL;
-
-       if (!tmpret)
-               tmpret = regmap_update_bits(bdpsy->regmap,
-                                           BD70528_REG_CHG_CHG_CURR_COLD,
-                                           BD70528_MASK_CHG_CHG_CURR, reg);
-
-       if (!ret)
-               ret = tmpret;
-
-       return ret;
-}
-
-#define MAX_CURR_LIMIT_SEL 0x34
-#define MIN_CURR_LIMIT_SEL 0x0
-
-static int set_current_limit(struct bd70528_psy *bdpsy, int ma)
-{
-       unsigned int reg;
-       int ret = 0, tmpret;
-       bool found;
-
-       if (ma > 500) {
-               dev_warn(bdpsy->dev,
-                        "Requested current limit %u exceed maximum (500mA)\n",
-                        ma);
-               reg = MAX_CURR_LIMIT_SEL;
-               goto set;
-       }
-       if (ma < 5) {
-               dev_err(bdpsy->dev,
-                       "Requested current limit %u smaller than min (5mA)\n",
-                       ma);
-               reg = MIN_CURR_LIMIT_SEL;
-               ret = -EINVAL;
-               goto set;
-       }
-
-       ret = linear_range_get_selector_low_array(current_limit_ranges,
-                                       ARRAY_SIZE(current_limit_ranges),
-                                       ma, &reg, &found);
-       if (ret) {
-               dev_err(bdpsy->dev, "Unsupported current limit %umA\n", ma);
-               reg = MIN_CURR_LIMIT_SEL;
-               goto set;
-       }
-       if (!found) {
-               /*
-                * There was a gap in supported values and we hit it.
-                * We found a smaller value from ranges and use it.
-                * Warn user though.
-                */
-               dev_warn(bdpsy->dev, "Unsupported current limit %umA\n", ma);
-       }
-
-set:
-       tmpret = regmap_update_bits(bdpsy->regmap,
-                                   BD70528_REG_CHG_DCIN_ILIM,
-                                   BD70528_MASK_CHG_DCIN_ILIM, reg);
-
-       if (!ret)
-               ret = tmpret;
-
-       return ret;
-}
-
-static int bd70528_charger_set_property(struct power_supply *psy,
-                                       enum power_supply_property psp,
-                                       const union power_supply_propval *val)
-{
-       struct bd70528_psy *bdpsy = power_supply_get_drvdata(psy);
-
-       switch (psp) {
-       case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
-               return set_current_limit(bdpsy, val->intval / 1000);
-       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
-               return set_charge_current(bdpsy, val->intval / 1000);
-       default:
-               break;
-       }
-       return -EINVAL;
-}
-
-static const struct power_supply_desc bd70528_charger_desc = {
-       .name           = "bd70528-charger",
-       .type           = POWER_SUPPLY_TYPE_MAINS,
-       .properties     = bd70528_charger_props,
-       .num_properties = ARRAY_SIZE(bd70528_charger_props),
-       .get_property   = bd70528_charger_get_property,
-       .set_property   = bd70528_charger_set_property,
-       .property_is_writeable  = bd70528_prop_is_writable,
-};
-
-static int bd70528_power_probe(struct platform_device *pdev)
-{
-       struct bd70528_psy *bdpsy;
-       struct power_supply_config cfg = {};
-
-       bdpsy = devm_kzalloc(&pdev->dev, sizeof(*bdpsy), GFP_KERNEL);
-       if (!bdpsy)
-               return -ENOMEM;
-
-       bdpsy->regmap = dev_get_regmap(pdev->dev.parent, NULL);
-       if (!bdpsy->regmap) {
-               dev_err(&pdev->dev, "No regmap found for chip\n");
-               return -EINVAL;
-       }
-       bdpsy->dev = &pdev->dev;
-
-       platform_set_drvdata(pdev, bdpsy);
-       cfg.drv_data = bdpsy;
-       cfg.of_node = pdev->dev.parent->of_node;
-
-       bdpsy->psy = devm_power_supply_register(&pdev->dev,
-                                               &bd70528_charger_desc, &cfg);
-       if (IS_ERR(bdpsy->psy)) {
-               dev_err(&pdev->dev, "failed: power supply register\n");
-               return PTR_ERR(bdpsy->psy);
-       }
-
-       return bd70528_get_irqs(pdev, bdpsy);
-}
-
-static struct platform_driver bd70528_power = {
-       .driver = {
-               .name = "bd70528-power"
-       },
-       .probe = bd70528_power_probe,
-};
-
-module_platform_driver(bd70528_power);
-
-MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
-MODULE_DESCRIPTION("BD70528 power-supply driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:bd70528-power");
index 852e86b..35ff0c8 100644 (file)
@@ -5,11 +5,10 @@
  * Author: Mark A. Greer <mgreer@animalcreek.com>
  */
 
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/of_irq.h>
-#include <linux/of_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/power_supply.h>
 #include <linux/power/bq24190_charger.h>
@@ -1959,7 +1958,6 @@ static const struct i2c_device_id bq24190_i2c_ids[] = {
 };
 MODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids);
 
-#ifdef CONFIG_OF
 static const struct of_device_id bq24190_of_match[] = {
        { .compatible = "ti,bq24190", },
        { .compatible = "ti,bq24192", },
@@ -1968,11 +1966,6 @@ static const struct of_device_id bq24190_of_match[] = {
        { },
 };
 MODULE_DEVICE_TABLE(of, bq24190_of_match);
-#else
-static const struct of_device_id bq24190_of_match[] = {
-       { },
-};
-#endif
 
 static struct i2c_driver bq24190_driver = {
        .probe          = bq24190_probe,
@@ -1981,7 +1974,7 @@ static struct i2c_driver bq24190_driver = {
        .driver = {
                .name           = "bq24190-charger",
                .pm             = &bq24190_pm_ops,
-               .of_match_table = of_match_ptr(bq24190_of_match),
+               .of_match_table = bq24190_of_match,
        },
 };
 module_i2c_driver(bq24190_driver);
index 45da870..d67edb7 100644 (file)
@@ -1279,6 +1279,7 @@ static const struct of_device_id charger_manager_match[] = {
        },
        {},
 };
+MODULE_DEVICE_TABLE(of, charger_manager_match);
 
 static struct charger_desc *of_cm_parse_desc(struct device *dev)
 {
index a3fc008..8d62d42 100644 (file)
@@ -667,10 +667,23 @@ static int cpcap_battery_get_property(struct power_supply *psy,
                if (!empty->voltage)
                        return -ENODATA;
                val->intval = empty->counter_uah - latest->counter_uah;
-               if (val->intval < 0)
+               if (val->intval < 0) {
+                       /* Assume invalid config if CHARGE_NOW is -20% */
+                       if (ddata->charge_full && abs(val->intval) > ddata->charge_full/5) {
+                               empty->voltage = 0;
+                               ddata->charge_full = 0;
+                               return -ENODATA;
+                       }
                        val->intval = 0;
-               else if (ddata->charge_full && ddata->charge_full < val->intval)
+               } else if (ddata->charge_full && ddata->charge_full < val->intval) {
+                       /* Assume invalid config if CHARGE_NOW exceeds CHARGE_FULL by 20% */
+                       if (val->intval > (6*ddata->charge_full)/5) {
+                               empty->voltage = 0;
+                               ddata->charge_full = 0;
+                               return -ENODATA;
+                       }
                        val->intval = ddata->charge_full;
+               }
                break;
        case POWER_SUPPLY_PROP_CHARGE_FULL:
                if (!ddata->charge_full)
@@ -747,7 +760,7 @@ static int cpcap_battery_set_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_CHARGE_FULL:
                if (val->intval < 0)
                        return -EINVAL;
-               if (val->intval > ddata->config.info.charge_full_design)
+               if (val->intval > (6*ddata->config.info.charge_full_design)/5)
                        return -EINVAL;
 
                ddata->charge_full = val->intval;
index df01abc..60e0ce1 100644 (file)
@@ -173,23 +173,6 @@ static enum power_supply_property cpcap_charger_props[] = {
        POWER_SUPPLY_PROP_CURRENT_NOW,
 };
 
-/* No battery always shows temperature of -40000 */
-static bool cpcap_charger_battery_found(struct cpcap_charger_ddata *ddata)
-{
-       struct iio_channel *channel;
-       int error, temperature;
-
-       channel = ddata->channels[CPCAP_CHARGER_IIO_BATTDET];
-       error = iio_read_channel_processed(channel, &temperature);
-       if (error < 0) {
-               dev_warn(ddata->dev, "%s failed: %i\n", __func__, error);
-
-               return false;
-       }
-
-       return temperature > -20000 && temperature < 60000;
-}
-
 static int cpcap_charger_get_charge_voltage(struct cpcap_charger_ddata *ddata)
 {
        struct iio_channel *channel;
@@ -700,11 +683,29 @@ static void cpcap_usb_detect(struct work_struct *work)
 
        if (!ddata->feeding_vbus && cpcap_charger_vbus_valid(ddata) &&
            s.chrgcurr1) {
-               int max_current = 532000;
+               int max_current;
                int vchrg, ichrg;
+               union power_supply_propval val;
+               struct power_supply *battery;
 
-               if (cpcap_charger_battery_found(ddata))
+               battery = power_supply_get_by_name("battery");
+               if (IS_ERR_OR_NULL(battery)) {
+                       dev_err(ddata->dev, "battery power_supply not available %li\n",
+                                       PTR_ERR(battery));
+                       return;
+               }
+
+               error = power_supply_get_property(battery, POWER_SUPPLY_PROP_PRESENT, &val);
+               power_supply_put(battery);
+               if (error)
+                       goto out_err;
+
+               if (val.intval) {
                        max_current = 1596000;
+               } else {
+                       dev_info(ddata->dev, "battery not inserted, charging disabled\n");
+                       max_current = 0;
+               }
 
                if (max_current > ddata->limit_current)
                        max_current = ddata->limit_current;
index 1aab868..3cea92e 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/interrupt.h>
 #include <linux/power_supply.h>
 #include <linux/of_device.h>
-#include <linux/max17040_battery.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 
@@ -142,13 +141,10 @@ struct max17040_chip {
        struct regmap                   *regmap;
        struct delayed_work             work;
        struct power_supply             *battery;
-       struct max17040_platform_data   *pdata;
        struct chip_data                data;
 
        /* battery capacity */
        int soc;
-       /* State Of Charge */
-       int status;
        /* Low alert threshold from 32% to 1% of the State of Charge */
        u32 low_soc_alert;
        /* some devices return twice the capacity */
@@ -221,26 +217,7 @@ static int max17040_get_version(struct max17040_chip *chip)
 
 static int max17040_get_online(struct max17040_chip *chip)
 {
-       return chip->pdata && chip->pdata->battery_online ?
-               chip->pdata->battery_online() : 1;
-}
-
-static int max17040_get_status(struct max17040_chip *chip)
-{
-       if (!chip->pdata || !chip->pdata->charger_online
-                       || !chip->pdata->charger_enable)
-               return POWER_SUPPLY_STATUS_UNKNOWN;
-
-       if (max17040_get_soc(chip) > MAX17040_BATTERY_FULL)
-               return POWER_SUPPLY_STATUS_FULL;
-
-       if (chip->pdata->charger_online())
-               if (chip->pdata->charger_enable())
-                       return POWER_SUPPLY_STATUS_CHARGING;
-               else
-                       return POWER_SUPPLY_STATUS_NOT_CHARGING;
-       else
-               return POWER_SUPPLY_STATUS_DISCHARGING;
+       return 1;
 }
 
 static int max17040_get_of_data(struct max17040_chip *chip)
@@ -283,7 +260,6 @@ static int max17040_get_of_data(struct max17040_chip *chip)
 static void max17040_check_changes(struct max17040_chip *chip)
 {
        chip->soc = max17040_get_soc(chip);
-       chip->status = max17040_get_status(chip);
 }
 
 static void max17040_queue_work(struct max17040_chip *chip)
@@ -302,17 +278,16 @@ static void max17040_stop_work(void *data)
 static void max17040_work(struct work_struct *work)
 {
        struct max17040_chip *chip;
-       int last_soc, last_status;
+       int last_soc;
 
        chip = container_of(work, struct max17040_chip, work.work);
 
-       /* store SOC and status to check changes */
+       /* store SOC to check changes */
        last_soc = chip->soc;
-       last_status = chip->status;
        max17040_check_changes(chip);
 
        /* check changes and send uevent */
-       if (last_soc != chip->soc || last_status != chip->status)
+       if (last_soc != chip->soc)
                power_supply_changed(chip->battery);
 
        max17040_queue_work(chip);
@@ -361,12 +336,10 @@ static irqreturn_t max17040_thread_handler(int id, void *dev)
 static int max17040_enable_alert_irq(struct max17040_chip *chip)
 {
        struct i2c_client *client = chip->client;
-       unsigned int flags;
        int ret;
 
-       flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
        ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
-                                       max17040_thread_handler, flags,
+                                       max17040_thread_handler, IRQF_ONESHOT,
                                        chip->battery->desc->name, chip);
 
        return ret;
@@ -415,9 +388,6 @@ static int max17040_get_property(struct power_supply *psy,
        struct max17040_chip *chip = power_supply_get_drvdata(psy);
 
        switch (psp) {
-       case POWER_SUPPLY_PROP_STATUS:
-               val->intval = max17040_get_status(chip);
-               break;
        case POWER_SUPPLY_PROP_ONLINE:
                val->intval = max17040_get_online(chip);
                break;
@@ -444,7 +414,6 @@ static const struct regmap_config max17040_regmap = {
 };
 
 static enum power_supply_property max17040_battery_props[] = {
-       POWER_SUPPLY_PROP_STATUS,
        POWER_SUPPLY_PROP_ONLINE,
        POWER_SUPPLY_PROP_VOLTAGE_NOW,
        POWER_SUPPLY_PROP_CAPACITY,
@@ -480,7 +449,6 @@ static int max17040_probe(struct i2c_client *client,
 
        chip->client = client;
        chip->regmap = devm_regmap_init_i2c(client, &max17040_regmap);
-       chip->pdata = client->dev.platform_data;
        chip_id = (enum chip_id) id->driver_data;
        if (client->dev.of_node) {
                ret = max17040_get_of_data(chip);
index 1d7326c..ce2041b 100644 (file)
@@ -1104,7 +1104,7 @@ static int max17042_probe(struct i2c_client *client,
        }
 
        if (client->irq) {
-               unsigned int flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+               unsigned int flags = IRQF_ONESHOT;
 
                /*
                 * On ACPI systems the IRQ may be handled by ACPI-event code,
diff --git a/drivers/power/supply/pm2301_charger.c b/drivers/power/supply/pm2301_charger.c
deleted file mode 100644 (file)
index f86bbbe..0000000
+++ /dev/null
@@ -1,1249 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright 2012 ST Ericsson.
- *
- * Power supply driver for ST Ericsson pm2xxx_charger charger
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/power_supply.h>
-#include <linux/regulator/consumer.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/workqueue.h>
-#include <linux/mfd/abx500/ab8500.h>
-#include <linux/pm2301_charger.h>
-#include <linux/gpio.h>
-#include <linux/pm_runtime.h>
-#include <linux/pm.h>
-
-#include "ab8500-bm.h"
-#include "ab8500-chargalg.h"
-#include "pm2301_charger.h"
-
-#define to_pm2xxx_charger_ac_device_info(x) container_of((x), \
-               struct pm2xxx_charger, ac_chg)
-#define SLEEP_MIN              50
-#define SLEEP_MAX              100
-#define PM2XXX_AUTOSUSPEND_DELAY 500
-
-static int pm2xxx_interrupt_registers[] = {
-       PM2XXX_REG_INT1,
-       PM2XXX_REG_INT2,
-       PM2XXX_REG_INT3,
-       PM2XXX_REG_INT4,
-       PM2XXX_REG_INT5,
-       PM2XXX_REG_INT6,
-};
-
-static enum power_supply_property pm2xxx_charger_ac_props[] = {
-       POWER_SUPPLY_PROP_HEALTH,
-       POWER_SUPPLY_PROP_PRESENT,
-       POWER_SUPPLY_PROP_ONLINE,
-       POWER_SUPPLY_PROP_VOLTAGE_AVG,
-};
-
-static int pm2xxx_charger_voltage_map[] = {
-       3500,
-       3525,
-       3550,
-       3575,
-       3600,
-       3625,
-       3650,
-       3675,
-       3700,
-       3725,
-       3750,
-       3775,
-       3800,
-       3825,
-       3850,
-       3875,
-       3900,
-       3925,
-       3950,
-       3975,
-       4000,
-       4025,
-       4050,
-       4075,
-       4100,
-       4125,
-       4150,
-       4175,
-       4200,
-       4225,
-       4250,
-       4275,
-       4300,
-};
-
-static int pm2xxx_charger_current_map[] = {
-       200,
-       200,
-       400,
-       600,
-       800,
-       1000,
-       1200,
-       1400,
-       1600,
-       1800,
-       2000,
-       2200,
-       2400,
-       2600,
-       2800,
-       3000,
-};
-
-static void set_lpn_pin(struct pm2xxx_charger *pm2)
-{
-       if (!pm2->ac.charger_connected && gpio_is_valid(pm2->lpn_pin)) {
-               gpio_set_value(pm2->lpn_pin, 1);
-               usleep_range(SLEEP_MIN, SLEEP_MAX);
-       }
-}
-
-static void clear_lpn_pin(struct pm2xxx_charger *pm2)
-{
-       if (!pm2->ac.charger_connected && gpio_is_valid(pm2->lpn_pin))
-               gpio_set_value(pm2->lpn_pin, 0);
-}
-
-static int pm2xxx_reg_read(struct pm2xxx_charger *pm2, int reg, u8 *val)
-{
-       int ret;
-
-       /* wake up the device */
-       pm_runtime_get_sync(pm2->dev);
-
-       ret = i2c_smbus_read_i2c_block_data(pm2->config.pm2xxx_i2c, reg,
-                               1, val);
-       if (ret < 0)
-               dev_err(pm2->dev, "Error reading register at 0x%x\n", reg);
-       else
-               ret = 0;
-
-       pm_runtime_put_sync(pm2->dev);
-
-       return ret;
-}
-
-static int pm2xxx_reg_write(struct pm2xxx_charger *pm2, int reg, u8 val)
-{
-       int ret;
-
-       /* wake up the device */
-       pm_runtime_get_sync(pm2->dev);
-
-       ret = i2c_smbus_write_i2c_block_data(pm2->config.pm2xxx_i2c, reg,
-                               1, &val);
-       if (ret < 0)
-               dev_err(pm2->dev, "Error writing register at 0x%x\n", reg);
-       else
-               ret = 0;
-
-       pm_runtime_put_sync(pm2->dev);
-
-       return ret;
-}
-
-static int pm2xxx_charging_enable_mngt(struct pm2xxx_charger *pm2)
-{
-       int ret;
-
-       /* Enable charging */
-       ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG2,
-                       (PM2XXX_CH_AUTO_RESUME_EN | PM2XXX_CHARGER_ENA));
-
-       return ret;
-}
-
-static int pm2xxx_charging_disable_mngt(struct pm2xxx_charger *pm2)
-{
-       int ret;
-
-       /* Disable SW EOC ctrl */
-       ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG, PM2XXX_SWCTRL_HW);
-       if (ret < 0) {
-               dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
-               return ret;
-       }
-
-       /* Disable charging */
-       ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG2,
-                       (PM2XXX_CH_AUTO_RESUME_DIS | PM2XXX_CHARGER_DIS));
-       if (ret < 0) {
-               dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int pm2xxx_charger_batt_therm_mngt(struct pm2xxx_charger *pm2, int val)
-{
-       queue_work(pm2->charger_wq, &pm2->check_main_thermal_prot_work);
-
-       return 0;
-}
-
-
-static int pm2xxx_charger_die_therm_mngt(struct pm2xxx_charger *pm2, int val)
-{
-       queue_work(pm2->charger_wq, &pm2->check_main_thermal_prot_work);
-
-       return 0;
-}
-
-static int pm2xxx_charger_ovv_mngt(struct pm2xxx_charger *pm2, int val)
-{
-       dev_err(pm2->dev, "Overvoltage detected\n");
-       pm2->flags.ovv = true;
-       power_supply_changed(pm2->ac_chg.psy);
-
-       /* Schedule a new HW failure check */
-       queue_delayed_work(pm2->charger_wq, &pm2->check_hw_failure_work, 0);
-
-       return 0;
-}
-
-static int pm2xxx_charger_wd_exp_mngt(struct pm2xxx_charger *pm2, int val)
-{
-       dev_dbg(pm2->dev , "20 minutes watchdog expired\n");
-
-       pm2->ac.wd_expired = true;
-       power_supply_changed(pm2->ac_chg.psy);
-
-       return 0;
-}
-
-static int pm2xxx_charger_vbat_lsig_mngt(struct pm2xxx_charger *pm2, int val)
-{
-       int ret;
-
-       switch (val) {
-       case PM2XXX_INT1_ITVBATLOWR:
-               dev_dbg(pm2->dev, "VBAT grows above VBAT_LOW level\n");
-               /* Enable SW EOC ctrl */
-               ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG,
-                                                       PM2XXX_SWCTRL_SW);
-               if (ret < 0) {
-                       dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
-                       return ret;
-               }
-               break;
-
-       case PM2XXX_INT1_ITVBATLOWF:
-               dev_dbg(pm2->dev, "VBAT drops below VBAT_LOW level\n");
-               /* Disable SW EOC ctrl */
-               ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG,
-                                                       PM2XXX_SWCTRL_HW);
-               if (ret < 0) {
-                       dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
-                       return ret;
-               }
-               break;
-
-       default:
-               dev_err(pm2->dev, "Unknown VBAT level\n");
-       }
-
-       return 0;
-}
-
-static int pm2xxx_charger_bat_disc_mngt(struct pm2xxx_charger *pm2, int val)
-{
-       dev_dbg(pm2->dev, "battery disconnected\n");
-
-       return 0;
-}
-
-static int pm2xxx_charger_detection(struct pm2xxx_charger *pm2, u8 *val)
-{
-       int ret;
-
-       ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT2, val);
-
-       if (ret < 0) {
-               dev_err(pm2->dev, "Charger detection failed\n");
-               goto out;
-       }
-
-       *val &= (PM2XXX_INT2_S_ITVPWR1PLUG | PM2XXX_INT2_S_ITVPWR2PLUG);
-
-out:
-       return ret;
-}
-
-static int pm2xxx_charger_itv_pwr_plug_mngt(struct pm2xxx_charger *pm2, int val)
-{
-
-       int ret;
-       u8 read_val;
-
-       /*
-        * Since we can't be sure that the events are received
-        * synchronously, we have the check if the main charger is
-        * connected by reading the interrupt source register.
-        */
-       ret = pm2xxx_charger_detection(pm2, &read_val);
-
-       if ((ret == 0) && read_val) {
-               pm2->ac.charger_connected = 1;
-               pm2->ac_conn = true;
-               queue_work(pm2->charger_wq, &pm2->ac_work);
-       }
-
-
-       return ret;
-}
-
-static int pm2xxx_charger_itv_pwr_unplug_mngt(struct pm2xxx_charger *pm2,
-                                                               int val)
-{
-       pm2->ac.charger_connected = 0;
-       queue_work(pm2->charger_wq, &pm2->ac_work);
-
-       return 0;
-}
-
-static int pm2_int_reg0(void *pm2_data, int val)
-{
-       struct pm2xxx_charger *pm2 = pm2_data;
-       int ret = 0;
-
-       if (val & PM2XXX_INT1_ITVBATLOWR) {
-               ret = pm2xxx_charger_vbat_lsig_mngt(pm2,
-                                               PM2XXX_INT1_ITVBATLOWR);
-               if (ret < 0)
-                       goto out;
-       }
-
-       if (val & PM2XXX_INT1_ITVBATLOWF) {
-               ret = pm2xxx_charger_vbat_lsig_mngt(pm2,
-                                               PM2XXX_INT1_ITVBATLOWF);
-               if (ret < 0)
-                       goto out;
-       }
-
-       if (val & PM2XXX_INT1_ITVBATDISCONNECT) {
-               ret = pm2xxx_charger_bat_disc_mngt(pm2,
-                               PM2XXX_INT1_ITVBATDISCONNECT);
-               if (ret < 0)
-                       goto out;
-       }
-out:
-       return ret;
-}
-
-static int pm2_int_reg1(void *pm2_data, int val)
-{
-       struct pm2xxx_charger *pm2 = pm2_data;
-       int ret = 0;
-
-       if (val & (PM2XXX_INT2_ITVPWR1PLUG | PM2XXX_INT2_ITVPWR2PLUG)) {
-               dev_dbg(pm2->dev , "Main charger plugged\n");
-               ret = pm2xxx_charger_itv_pwr_plug_mngt(pm2, val &
-                       (PM2XXX_INT2_ITVPWR1PLUG | PM2XXX_INT2_ITVPWR2PLUG));
-       }
-
-       if (val &
-               (PM2XXX_INT2_ITVPWR1UNPLUG | PM2XXX_INT2_ITVPWR2UNPLUG)) {
-               dev_dbg(pm2->dev , "Main charger unplugged\n");
-               ret = pm2xxx_charger_itv_pwr_unplug_mngt(pm2, val &
-                                               (PM2XXX_INT2_ITVPWR1UNPLUG |
-                                               PM2XXX_INT2_ITVPWR2UNPLUG));
-       }
-
-       return ret;
-}
-
-static int pm2_int_reg2(void *pm2_data, int val)
-{
-       struct pm2xxx_charger *pm2 = pm2_data;
-       int ret = 0;
-
-       if (val & PM2XXX_INT3_ITAUTOTIMEOUTWD)
-               ret = pm2xxx_charger_wd_exp_mngt(pm2, val);
-
-       if (val & (PM2XXX_INT3_ITCHPRECHARGEWD |
-                               PM2XXX_INT3_ITCHCCWD | PM2XXX_INT3_ITCHCVWD)) {
-               dev_dbg(pm2->dev,
-                       "Watchdog occurred for precharge, CC and CV charge\n");
-       }
-
-       return ret;
-}
-
-static int pm2_int_reg3(void *pm2_data, int val)
-{
-       struct pm2xxx_charger *pm2 = pm2_data;
-       int ret = 0;
-
-       if (val & (PM2XXX_INT4_ITCHARGINGON)) {
-               dev_dbg(pm2->dev ,
-                       "charging operation has started\n");
-       }
-
-       if (val & (PM2XXX_INT4_ITVRESUME)) {
-               dev_dbg(pm2->dev,
-                       "battery discharged down to VResume threshold\n");
-       }
-
-       if (val & (PM2XXX_INT4_ITBATTFULL)) {
-               dev_dbg(pm2->dev , "battery fully detected\n");
-       }
-
-       if (val & (PM2XXX_INT4_ITCVPHASE)) {
-               dev_dbg(pm2->dev, "CV phase enter with 0.5C charging\n");
-       }
-
-       if (val & (PM2XXX_INT4_ITVPWR2OVV | PM2XXX_INT4_ITVPWR1OVV)) {
-               pm2->failure_case = VPWR_OVV;
-               ret = pm2xxx_charger_ovv_mngt(pm2, val &
-                       (PM2XXX_INT4_ITVPWR2OVV | PM2XXX_INT4_ITVPWR1OVV));
-               dev_dbg(pm2->dev, "VPWR/VSYSTEM overvoltage detected\n");
-       }
-
-       if (val & (PM2XXX_INT4_S_ITBATTEMPCOLD |
-                               PM2XXX_INT4_S_ITBATTEMPHOT)) {
-               ret = pm2xxx_charger_batt_therm_mngt(pm2, val &
-                       (PM2XXX_INT4_S_ITBATTEMPCOLD |
-                       PM2XXX_INT4_S_ITBATTEMPHOT));
-               dev_dbg(pm2->dev, "BTEMP is too Low/High\n");
-       }
-
-       return ret;
-}
-
-static int pm2_int_reg4(void *pm2_data, int val)
-{
-       struct pm2xxx_charger *pm2 = pm2_data;
-       int ret = 0;
-
-       if (val & PM2XXX_INT5_ITVSYSTEMOVV) {
-               pm2->failure_case = VSYSTEM_OVV;
-               ret = pm2xxx_charger_ovv_mngt(pm2, val &
-                                               PM2XXX_INT5_ITVSYSTEMOVV);
-               dev_dbg(pm2->dev, "VSYSTEM overvoltage detected\n");
-       }
-
-       if (val & (PM2XXX_INT5_ITTHERMALWARNINGFALL |
-                               PM2XXX_INT5_ITTHERMALWARNINGRISE |
-                               PM2XXX_INT5_ITTHERMALSHUTDOWNFALL |
-                               PM2XXX_INT5_ITTHERMALSHUTDOWNRISE)) {
-               dev_dbg(pm2->dev, "BTEMP die temperature is too Low/High\n");
-               ret = pm2xxx_charger_die_therm_mngt(pm2, val &
-                       (PM2XXX_INT5_ITTHERMALWARNINGFALL |
-                       PM2XXX_INT5_ITTHERMALWARNINGRISE |
-                       PM2XXX_INT5_ITTHERMALSHUTDOWNFALL |
-                       PM2XXX_INT5_ITTHERMALSHUTDOWNRISE));
-       }
-
-       return ret;
-}
-
-static int pm2_int_reg5(void *pm2_data, int val)
-{
-       struct pm2xxx_charger *pm2 = pm2_data;
-
-       if (val & (PM2XXX_INT6_ITVPWR2DROP | PM2XXX_INT6_ITVPWR1DROP)) {
-               dev_dbg(pm2->dev, "VMPWR drop to VBAT level\n");
-       }
-
-       if (val & (PM2XXX_INT6_ITVPWR2VALIDRISE |
-                       PM2XXX_INT6_ITVPWR1VALIDRISE |
-                       PM2XXX_INT6_ITVPWR2VALIDFALL |
-                       PM2XXX_INT6_ITVPWR1VALIDFALL)) {
-               dev_dbg(pm2->dev, "Falling/Rising edge on WPWR1/2\n");
-       }
-
-       return 0;
-}
-
-static irqreturn_t  pm2xxx_irq_int(int irq, void *data)
-{
-       struct pm2xxx_charger *pm2 = data;
-       struct pm2xxx_interrupts *interrupt = pm2->pm2_int;
-       int i;
-
-       /* wake up the device */
-       pm_runtime_get_sync(pm2->dev);
-
-       do {
-               for (i = 0; i < PM2XXX_NUM_INT_REG; i++) {
-                       pm2xxx_reg_read(pm2,
-                               pm2xxx_interrupt_registers[i],
-                               &(interrupt->reg[i]));
-
-                       if (interrupt->reg[i] > 0)
-                               interrupt->handler[i](pm2, interrupt->reg[i]);
-               }
-       } while (gpio_get_value(pm2->pdata->gpio_irq_number) == 0);
-
-       pm_runtime_mark_last_busy(pm2->dev);
-       pm_runtime_put_autosuspend(pm2->dev);
-
-       return IRQ_HANDLED;
-}
-
-static int pm2xxx_charger_get_ac_cv(struct pm2xxx_charger *pm2)
-{
-       int ret = 0;
-       u8 val;
-
-       if (pm2->ac.charger_connected && pm2->ac.charger_online) {
-
-               ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT4, &val);
-               if (ret < 0) {
-                       dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
-                       goto out;
-               }
-
-               if (val & PM2XXX_INT4_S_ITCVPHASE)
-                       ret = PM2XXX_CONST_VOLT;
-               else
-                       ret = PM2XXX_CONST_CURR;
-       }
-out:
-       return ret;
-}
-
-static int pm2xxx_current_to_regval(int curr)
-{
-       int i;
-
-       if (curr < pm2xxx_charger_current_map[0])
-               return 0;
-
-       for (i = 1; i < ARRAY_SIZE(pm2xxx_charger_current_map); i++) {
-               if (curr < pm2xxx_charger_current_map[i])
-                       return (i - 1);
-       }
-
-       i = ARRAY_SIZE(pm2xxx_charger_current_map) - 1;
-       if (curr == pm2xxx_charger_current_map[i])
-               return i;
-       else
-               return -EINVAL;
-}
-
-static int pm2xxx_voltage_to_regval(int curr)
-{
-       int i;
-
-       if (curr < pm2xxx_charger_voltage_map[0])
-               return 0;
-
-       for (i = 1; i < ARRAY_SIZE(pm2xxx_charger_voltage_map); i++) {
-               if (curr < pm2xxx_charger_voltage_map[i])
-                       return i - 1;
-       }
-
-       i = ARRAY_SIZE(pm2xxx_charger_voltage_map) - 1;
-       if (curr == pm2xxx_charger_voltage_map[i])
-               return i;
-       else
-               return -EINVAL;
-}
-
-static int pm2xxx_charger_update_charger_current(struct ux500_charger *charger,
-               int ich_out)
-{
-       int ret;
-       int curr_index;
-       struct pm2xxx_charger *pm2;
-       u8 val;
-
-       if (charger->psy->desc->type == POWER_SUPPLY_TYPE_MAINS)
-               pm2 = to_pm2xxx_charger_ac_device_info(charger);
-       else
-               return -ENXIO;
-
-       curr_index = pm2xxx_current_to_regval(ich_out);
-       if (curr_index < 0) {
-               dev_err(pm2->dev,
-                       "Charger current too high, charging not started\n");
-               return -ENXIO;
-       }
-
-       ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG6, &val);
-       if (ret >= 0) {
-               val &= ~PM2XXX_DIR_CH_CC_CURRENT_MASK;
-               val |= curr_index;
-               ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6, val);
-               if (ret < 0) {
-                       dev_err(pm2->dev,
-                               "%s write failed\n", __func__);
-               }
-       }
-       else
-               dev_err(pm2->dev, "%s read failed\n", __func__);
-
-       return ret;
-}
-
-static int pm2xxx_charger_ac_get_property(struct power_supply *psy,
-       enum power_supply_property psp,
-       union power_supply_propval *val)
-{
-       struct pm2xxx_charger *pm2;
-
-       pm2 = to_pm2xxx_charger_ac_device_info(psy_to_ux500_charger(psy));
-
-       switch (psp) {
-       case POWER_SUPPLY_PROP_HEALTH:
-               if (pm2->flags.mainextchnotok)
-                       val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
-               else if (pm2->ac.wd_expired)
-                       val->intval = POWER_SUPPLY_HEALTH_DEAD;
-               else if (pm2->flags.main_thermal_prot)
-                       val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
-               else if (pm2->flags.ovv)
-                       val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
-               else
-                       val->intval = POWER_SUPPLY_HEALTH_GOOD;
-               break;
-       case POWER_SUPPLY_PROP_ONLINE:
-               val->intval = pm2->ac.charger_online;
-               break;
-       case POWER_SUPPLY_PROP_PRESENT:
-               val->intval = pm2->ac.charger_connected;
-               break;
-       case POWER_SUPPLY_PROP_VOLTAGE_AVG:
-               pm2->ac.cv_active = pm2xxx_charger_get_ac_cv(pm2);
-               val->intval = pm2->ac.cv_active;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int pm2xxx_charging_init(struct pm2xxx_charger *pm2)
-{
-       int ret = 0;
-
-       /* enable CC and CV watchdog */
-       ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG3,
-               (PM2XXX_CH_WD_CV_PHASE_60MIN | PM2XXX_CH_WD_CC_PHASE_60MIN));
-       if( ret < 0)
-               return ret;
-
-       /* enable precharge watchdog */
-       ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG4,
-                                       PM2XXX_CH_WD_PRECH_PHASE_60MIN);
-
-       /* Disable auto timeout */
-       ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG5,
-                                       PM2XXX_CH_WD_AUTO_TIMEOUT_20MIN);
-
-       /*
-     * EOC current level = 100mA
-        * Precharge current level = 100mA
-        * CC current level = 1000mA
-        */
-       ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6,
-               (PM2XXX_DIR_CH_CC_CURRENT_1000MA |
-               PM2XXX_CH_PRECH_CURRENT_100MA |
-               PM2XXX_CH_EOC_CURRENT_100MA));
-
-       /*
-     * recharge threshold = 3.8V
-        * Precharge to CC threshold = 2.9V
-        */
-       ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG7,
-               (PM2XXX_CH_PRECH_VOL_2_9 | PM2XXX_CH_VRESUME_VOL_3_8));
-
-       /* float voltage charger level = 4.2V */
-       ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG8,
-               PM2XXX_CH_VOLT_4_2);
-
-       /* Voltage drop between VBAT and VSYS in HW charging = 300mV */
-       ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG9,
-               (PM2XXX_CH_150MV_DROP_300MV | PM2XXX_CHARCHING_INFO_DIS |
-               PM2XXX_CH_CC_REDUCED_CURRENT_IDENT |
-               PM2XXX_CH_CC_MODEDROP_DIS));
-
-       /* Input charger level of over voltage = 10V */
-       ret = pm2xxx_reg_write(pm2, PM2XXX_INP_VOLT_VPWR2,
-                                       PM2XXX_VPWR2_OVV_10);
-       ret = pm2xxx_reg_write(pm2, PM2XXX_INP_VOLT_VPWR1,
-                                       PM2XXX_VPWR1_OVV_10);
-
-       /* Input charger drop */
-       ret = pm2xxx_reg_write(pm2, PM2XXX_INP_DROP_VPWR2,
-               (PM2XXX_VPWR2_HW_OPT_DIS | PM2XXX_VPWR2_VALID_DIS |
-               PM2XXX_VPWR2_DROP_DIS));
-       ret = pm2xxx_reg_write(pm2, PM2XXX_INP_DROP_VPWR1,
-               (PM2XXX_VPWR1_HW_OPT_DIS | PM2XXX_VPWR1_VALID_DIS |
-               PM2XXX_VPWR1_DROP_DIS));
-
-       /* Disable battery low monitoring */
-       ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_LOW_LEV_COMP_REG,
-               PM2XXX_VBAT_LOW_MONITORING_ENA);
-
-       return ret;
-}
-
-static int pm2xxx_charger_ac_en(struct ux500_charger *charger,
-       int enable, int vset, int iset)
-{
-       int ret;
-       int volt_index;
-       int curr_index;
-       u8 val;
-
-       struct pm2xxx_charger *pm2 = to_pm2xxx_charger_ac_device_info(charger);
-
-       if (enable) {
-               if (!pm2->ac.charger_connected) {
-                       dev_dbg(pm2->dev, "AC charger not connected\n");
-                       return -ENXIO;
-               }
-
-               dev_dbg(pm2->dev, "Enable AC: %dmV %dmA\n", vset, iset);
-               if (!pm2->vddadc_en_ac) {
-                       ret = regulator_enable(pm2->regu);
-                       if (ret)
-                               dev_warn(pm2->dev,
-                                       "Failed to enable vddadc regulator\n");
-                       else
-                               pm2->vddadc_en_ac = true;
-               }
-
-               ret = pm2xxx_charging_init(pm2);
-               if (ret < 0) {
-                       dev_err(pm2->dev, "%s charging init failed\n",
-                                       __func__);
-                       goto error_occured;
-               }
-
-               volt_index = pm2xxx_voltage_to_regval(vset);
-               curr_index = pm2xxx_current_to_regval(iset);
-
-               if (volt_index < 0 || curr_index < 0) {
-                       dev_err(pm2->dev,
-                               "Charger voltage or current too high, "
-                               "charging not started\n");
-                       return -ENXIO;
-               }
-
-               ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG8, &val);
-               if (ret < 0) {
-                       dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
-                       goto error_occured;
-               }
-               val &= ~PM2XXX_CH_VOLT_MASK;
-               val |= volt_index;
-               ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG8, val);
-               if (ret < 0) {
-                       dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
-                       goto error_occured;
-               }
-
-               ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG6, &val);
-               if (ret < 0) {
-                       dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
-                       goto error_occured;
-               }
-               val &= ~PM2XXX_DIR_CH_CC_CURRENT_MASK;
-               val |= curr_index;
-               ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6, val);
-               if (ret < 0) {
-                       dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
-                       goto error_occured;
-               }
-
-               if (!pm2->bat->enable_overshoot) {
-                       ret = pm2xxx_reg_read(pm2, PM2XXX_LED_CTRL_REG, &val);
-                       if (ret < 0) {
-                               dev_err(pm2->dev, "%s pm2xxx read failed\n",
-                                                               __func__);
-                               goto error_occured;
-                       }
-                       val |= PM2XXX_ANTI_OVERSHOOT_EN;
-                       ret = pm2xxx_reg_write(pm2, PM2XXX_LED_CTRL_REG, val);
-                       if (ret < 0) {
-                               dev_err(pm2->dev, "%s pm2xxx write failed\n",
-                                                               __func__);
-                               goto error_occured;
-                       }
-               }
-
-               ret = pm2xxx_charging_enable_mngt(pm2);
-               if (ret < 0) {
-                       dev_err(pm2->dev, "Failed to enable"
-                                               "pm2xxx ac charger\n");
-                       goto error_occured;
-               }
-
-               pm2->ac.charger_online = 1;
-       } else {
-               pm2->ac.charger_online = 0;
-               pm2->ac.wd_expired = false;
-
-               /* Disable regulator if enabled */
-               if (pm2->vddadc_en_ac) {
-                       regulator_disable(pm2->regu);
-                       pm2->vddadc_en_ac = false;
-               }
-
-               ret = pm2xxx_charging_disable_mngt(pm2);
-               if (ret < 0) {
-                       dev_err(pm2->dev, "failed to disable"
-                                               "pm2xxx ac charger\n");
-                       goto error_occured;
-               }
-
-               dev_dbg(pm2->dev, "PM2301: " "Disabled AC charging\n");
-       }
-       power_supply_changed(pm2->ac_chg.psy);
-
-error_occured:
-       return ret;
-}
-
-static int pm2xxx_charger_watchdog_kick(struct ux500_charger *charger)
-{
-       int ret;
-       struct pm2xxx_charger *pm2;
-
-       if (charger->psy->desc->type == POWER_SUPPLY_TYPE_MAINS)
-               pm2 = to_pm2xxx_charger_ac_device_info(charger);
-       else
-               return -ENXIO;
-
-       ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_WD_KICK, WD_TIMER);
-       if (ret)
-               dev_err(pm2->dev, "Failed to kick WD!\n");
-
-       return ret;
-}
-
-static void pm2xxx_charger_ac_work(struct work_struct *work)
-{
-       struct pm2xxx_charger *pm2 = container_of(work,
-               struct pm2xxx_charger, ac_work);
-
-
-       power_supply_changed(pm2->ac_chg.psy);
-       sysfs_notify(&pm2->ac_chg.psy->dev.kobj, NULL, "present");
-};
-
-static void pm2xxx_charger_check_hw_failure_work(struct work_struct *work)
-{
-       u8 reg_value;
-
-       struct pm2xxx_charger *pm2 = container_of(work,
-               struct pm2xxx_charger, check_hw_failure_work.work);
-
-       if (pm2->flags.ovv) {
-               pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT4, &reg_value);
-
-               if (!(reg_value & (PM2XXX_INT4_S_ITVPWR1OVV |
-                                       PM2XXX_INT4_S_ITVPWR2OVV))) {
-                       pm2->flags.ovv = false;
-                       power_supply_changed(pm2->ac_chg.psy);
-               }
-       }
-
-       /* If we still have a failure, schedule a new check */
-       if (pm2->flags.ovv) {
-               queue_delayed_work(pm2->charger_wq,
-                       &pm2->check_hw_failure_work, round_jiffies(HZ));
-       }
-}
-
-static void pm2xxx_charger_check_main_thermal_prot_work(
-       struct work_struct *work)
-{
-       int ret;
-       u8 val;
-
-       struct pm2xxx_charger *pm2 = container_of(work, struct pm2xxx_charger,
-                                       check_main_thermal_prot_work);
-
-       /* Check if die temp warning is still active */
-       ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT5, &val);
-       if (ret < 0) {
-               dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
-               return;
-       }
-       if (val & (PM2XXX_INT5_S_ITTHERMALWARNINGRISE
-                       | PM2XXX_INT5_S_ITTHERMALSHUTDOWNRISE))
-               pm2->flags.main_thermal_prot = true;
-       else if (val & (PM2XXX_INT5_S_ITTHERMALWARNINGFALL
-                               | PM2XXX_INT5_S_ITTHERMALSHUTDOWNFALL))
-               pm2->flags.main_thermal_prot = false;
-
-       power_supply_changed(pm2->ac_chg.psy);
-}
-
-static struct pm2xxx_interrupts pm2xxx_int = {
-       .handler[0] = pm2_int_reg0,
-       .handler[1] = pm2_int_reg1,
-       .handler[2] = pm2_int_reg2,
-       .handler[3] = pm2_int_reg3,
-       .handler[4] = pm2_int_reg4,
-       .handler[5] = pm2_int_reg5,
-};
-
-static struct pm2xxx_irq pm2xxx_charger_irq[] = {
-       {"PM2XXX_IRQ_INT", pm2xxx_irq_int},
-};
-
-static int __maybe_unused pm2xxx_wall_charger_resume(struct device *dev)
-{
-       struct i2c_client *i2c_client = to_i2c_client(dev);
-       struct pm2xxx_charger *pm2;
-
-       pm2 =  (struct pm2xxx_charger *)i2c_get_clientdata(i2c_client);
-       set_lpn_pin(pm2);
-
-       /* If we still have a HW failure, schedule a new check */
-       if (pm2->flags.ovv)
-               queue_delayed_work(pm2->charger_wq,
-                               &pm2->check_hw_failure_work, 0);
-
-       return 0;
-}
-
-static int __maybe_unused pm2xxx_wall_charger_suspend(struct device *dev)
-{
-       struct i2c_client *i2c_client = to_i2c_client(dev);
-       struct pm2xxx_charger *pm2;
-
-       pm2 =  (struct pm2xxx_charger *)i2c_get_clientdata(i2c_client);
-       clear_lpn_pin(pm2);
-
-       /* Cancel any pending HW failure check */
-       if (delayed_work_pending(&pm2->check_hw_failure_work))
-               cancel_delayed_work(&pm2->check_hw_failure_work);
-
-       flush_work(&pm2->ac_work);
-       flush_work(&pm2->check_main_thermal_prot_work);
-
-       return 0;
-}
-
-static int __maybe_unused pm2xxx_runtime_suspend(struct device *dev)
-{
-       struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev);
-       struct pm2xxx_charger *pm2;
-
-       pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(pm2xxx_i2c_client);
-       clear_lpn_pin(pm2);
-
-       return 0;
-}
-
-static int __maybe_unused pm2xxx_runtime_resume(struct device *dev)
-{
-       struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev);
-       struct pm2xxx_charger *pm2;
-
-       pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(pm2xxx_i2c_client);
-
-       if (gpio_is_valid(pm2->lpn_pin) && gpio_get_value(pm2->lpn_pin) == 0)
-               set_lpn_pin(pm2);
-
-       return 0;
-}
-
-static const struct dev_pm_ops pm2xxx_pm_ops __maybe_unused = {
-       SET_SYSTEM_SLEEP_PM_OPS(pm2xxx_wall_charger_suspend,
-               pm2xxx_wall_charger_resume)
-       SET_RUNTIME_PM_OPS(pm2xxx_runtime_suspend, pm2xxx_runtime_resume, NULL)
-};
-
-static int pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
-               const struct i2c_device_id *id)
-{
-       struct pm2xxx_platform_data *pl_data = i2c_client->dev.platform_data;
-       struct power_supply_config psy_cfg = {};
-       struct pm2xxx_charger *pm2;
-       int ret = 0;
-       u8 val;
-       int i;
-
-       if (!pl_data) {
-               dev_err(&i2c_client->dev, "No platform data supplied\n");
-               return -EINVAL;
-       }
-
-       pm2 = kzalloc(sizeof(struct pm2xxx_charger), GFP_KERNEL);
-       if (!pm2) {
-               dev_err(&i2c_client->dev, "pm2xxx_charger allocation failed\n");
-               return -ENOMEM;
-       }
-
-       /* get parent data */
-       pm2->dev = &i2c_client->dev;
-
-       pm2->pm2_int = &pm2xxx_int;
-
-       /* get charger spcific platform data */
-       if (!pl_data->wall_charger) {
-               dev_err(pm2->dev, "no charger platform data supplied\n");
-               ret = -EINVAL;
-               goto free_device_info;
-       }
-
-       pm2->pdata = pl_data->wall_charger;
-
-       /* get battery specific platform data */
-       if (!pl_data->battery) {
-               dev_err(pm2->dev, "no battery platform data supplied\n");
-               ret = -EINVAL;
-               goto free_device_info;
-       }
-
-       pm2->bat = pl_data->battery;
-
-       if (!i2c_check_functionality(i2c_client->adapter,
-                       I2C_FUNC_SMBUS_BYTE_DATA |
-                       I2C_FUNC_SMBUS_READ_WORD_DATA)) {
-               ret = -ENODEV;
-               dev_info(pm2->dev, "pm2301 i2c_check_functionality failed\n");
-               goto free_device_info;
-       }
-
-       pm2->config.pm2xxx_i2c = i2c_client;
-       pm2->config.pm2xxx_id = (struct i2c_device_id *) id;
-       i2c_set_clientdata(i2c_client, pm2);
-
-       /* AC supply */
-       /* power_supply base class */
-       pm2->ac_chg_desc.name = pm2->pdata->label;
-       pm2->ac_chg_desc.type = POWER_SUPPLY_TYPE_MAINS;
-       pm2->ac_chg_desc.properties = pm2xxx_charger_ac_props;
-       pm2->ac_chg_desc.num_properties = ARRAY_SIZE(pm2xxx_charger_ac_props);
-       pm2->ac_chg_desc.get_property = pm2xxx_charger_ac_get_property;
-
-       psy_cfg.supplied_to = pm2->pdata->supplied_to;
-       psy_cfg.num_supplicants = pm2->pdata->num_supplicants;
-       /* pm2xxx_charger sub-class */
-       pm2->ac_chg.ops.enable = &pm2xxx_charger_ac_en;
-       pm2->ac_chg.ops.kick_wd = &pm2xxx_charger_watchdog_kick;
-       pm2->ac_chg.ops.update_curr = &pm2xxx_charger_update_charger_current;
-       pm2->ac_chg.max_out_volt = pm2xxx_charger_voltage_map[
-               ARRAY_SIZE(pm2xxx_charger_voltage_map) - 1];
-       pm2->ac_chg.max_out_curr = pm2xxx_charger_current_map[
-               ARRAY_SIZE(pm2xxx_charger_current_map) - 1];
-       pm2->ac_chg.wdt_refresh = WD_KICK_INTERVAL;
-       pm2->ac_chg.enabled = true;
-       pm2->ac_chg.external = true;
-
-       /* Create a work queue for the charger */
-       pm2->charger_wq = alloc_ordered_workqueue("pm2xxx_charger_wq",
-                                                 WQ_MEM_RECLAIM);
-       if (pm2->charger_wq == NULL) {
-               ret = -ENOMEM;
-               dev_err(pm2->dev, "failed to create work queue\n");
-               goto free_device_info;
-       }
-
-       /* Init work for charger detection */
-       INIT_WORK(&pm2->ac_work, pm2xxx_charger_ac_work);
-
-       /* Init work for checking HW status */
-       INIT_WORK(&pm2->check_main_thermal_prot_work,
-               pm2xxx_charger_check_main_thermal_prot_work);
-
-       /* Init work for HW failure check */
-       INIT_DEFERRABLE_WORK(&pm2->check_hw_failure_work,
-               pm2xxx_charger_check_hw_failure_work);
-
-       /*
-        * VDD ADC supply needs to be enabled from this driver when there
-        * is a charger connected to avoid erroneous BTEMP_HIGH/LOW
-        * interrupts during charging
-        */
-       pm2->regu = regulator_get(pm2->dev, "vddadc");
-       if (IS_ERR(pm2->regu)) {
-               ret = PTR_ERR(pm2->regu);
-               dev_err(pm2->dev, "failed to get vddadc regulator\n");
-               goto free_charger_wq;
-       }
-
-       /* Register AC charger class */
-       pm2->ac_chg.psy = power_supply_register(pm2->dev, &pm2->ac_chg_desc,
-                                               &psy_cfg);
-       if (IS_ERR(pm2->ac_chg.psy)) {
-               dev_err(pm2->dev, "failed to register AC charger\n");
-               ret = PTR_ERR(pm2->ac_chg.psy);
-               goto free_regulator;
-       }
-
-       /* Register interrupts */
-       ret = request_threaded_irq(gpio_to_irq(pm2->pdata->gpio_irq_number),
-                               NULL,
-                               pm2xxx_charger_irq[0].isr,
-                               pm2->pdata->irq_type | IRQF_ONESHOT,
-                               pm2xxx_charger_irq[0].name, pm2);
-
-       if (ret != 0) {
-               dev_err(pm2->dev, "failed to request %s IRQ %d: %d\n",
-               pm2xxx_charger_irq[0].name,
-                       gpio_to_irq(pm2->pdata->gpio_irq_number), ret);
-               goto unregister_pm2xxx_charger;
-       }
-
-       ret = pm_runtime_set_active(pm2->dev);
-       if (ret)
-               dev_err(pm2->dev, "set active Error\n");
-
-       pm_runtime_enable(pm2->dev);
-       pm_runtime_set_autosuspend_delay(pm2->dev, PM2XXX_AUTOSUSPEND_DELAY);
-       pm_runtime_use_autosuspend(pm2->dev);
-       pm_runtime_resume(pm2->dev);
-
-       /* pm interrupt can wake up system */
-       ret = enable_irq_wake(gpio_to_irq(pm2->pdata->gpio_irq_number));
-       if (ret) {
-               dev_err(pm2->dev, "failed to set irq wake\n");
-               goto unregister_pm2xxx_interrupt;
-       }
-
-       mutex_init(&pm2->lock);
-
-       if (gpio_is_valid(pm2->pdata->lpn_gpio)) {
-               /* get lpn GPIO from platform data */
-               pm2->lpn_pin = pm2->pdata->lpn_gpio;
-
-               /*
-                * Charger detection mechanism requires pulling up the LPN pin
-                * while i2c communication if Charger is not connected
-                * LPN pin of PM2301 is GPIO60 of AB9540
-                */
-               ret = gpio_request(pm2->lpn_pin, "pm2301_lpm_gpio");
-
-               if (ret < 0) {
-                       dev_err(pm2->dev, "pm2301_lpm_gpio request failed\n");
-                       goto disable_pm2_irq_wake;
-               }
-               ret = gpio_direction_output(pm2->lpn_pin, 0);
-               if (ret < 0) {
-                       dev_err(pm2->dev, "pm2301_lpm_gpio direction failed\n");
-                       goto free_gpio;
-               }
-               set_lpn_pin(pm2);
-       }
-
-       /* read  interrupt registers */
-       for (i = 0; i < PM2XXX_NUM_INT_REG; i++)
-               pm2xxx_reg_read(pm2,
-                       pm2xxx_interrupt_registers[i],
-                       &val);
-
-       ret = pm2xxx_charger_detection(pm2, &val);
-
-       if ((ret == 0) && val) {
-               pm2->ac.charger_connected = 1;
-               ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON,
-                                            AB8500_MAIN_CH_DET);
-               pm2->ac_conn = true;
-               power_supply_changed(pm2->ac_chg.psy);
-               sysfs_notify(&pm2->ac_chg.psy->dev.kobj, NULL, "present");
-       }
-
-       return 0;
-
-free_gpio:
-       if (gpio_is_valid(pm2->lpn_pin))
-               gpio_free(pm2->lpn_pin);
-disable_pm2_irq_wake:
-       disable_irq_wake(gpio_to_irq(pm2->pdata->gpio_irq_number));
-unregister_pm2xxx_interrupt:
-       /* disable interrupt */
-       free_irq(gpio_to_irq(pm2->pdata->gpio_irq_number), pm2);
-unregister_pm2xxx_charger:
-       /* unregister power supply */
-       power_supply_unregister(pm2->ac_chg.psy);
-free_regulator:
-       /* disable the regulator */
-       regulator_put(pm2->regu);
-free_charger_wq:
-       destroy_workqueue(pm2->charger_wq);
-free_device_info:
-       kfree(pm2);
-
-       return ret;
-}
-
-static int pm2xxx_wall_charger_remove(struct i2c_client *i2c_client)
-{
-       struct pm2xxx_charger *pm2 = i2c_get_clientdata(i2c_client);
-
-       /* Disable pm_runtime */
-       pm_runtime_disable(pm2->dev);
-       /* Disable AC charging */
-       pm2xxx_charger_ac_en(&pm2->ac_chg, false, 0, 0);
-
-       /* Disable wake by pm interrupt */
-       disable_irq_wake(gpio_to_irq(pm2->pdata->gpio_irq_number));
-
-       /* Disable interrupts */
-       free_irq(gpio_to_irq(pm2->pdata->gpio_irq_number), pm2);
-
-       /* Delete the work queue */
-       destroy_workqueue(pm2->charger_wq);
-
-       flush_scheduled_work();
-
-       /* disable the regulator */
-       regulator_put(pm2->regu);
-
-       power_supply_unregister(pm2->ac_chg.psy);
-
-       if (gpio_is_valid(pm2->lpn_pin))
-               gpio_free(pm2->lpn_pin);
-
-       kfree(pm2);
-
-       return 0;
-}
-
-static const struct i2c_device_id pm2xxx_id[] = {
-       { "pm2301", 0 },
-       { }
-};
-
-MODULE_DEVICE_TABLE(i2c, pm2xxx_id);
-
-static struct i2c_driver pm2xxx_charger_driver = {
-       .probe = pm2xxx_wall_charger_probe,
-       .remove = pm2xxx_wall_charger_remove,
-       .driver = {
-               .name = "pm2xxx-wall_charger",
-               .pm = IS_ENABLED(CONFIG_PM) ? &pm2xxx_pm_ops : NULL,
-       },
-       .id_table = pm2xxx_id,
-};
-
-static int __init pm2xxx_charger_init(void)
-{
-       return i2c_add_driver(&pm2xxx_charger_driver);
-}
-
-static void __exit pm2xxx_charger_exit(void)
-{
-       i2c_del_driver(&pm2xxx_charger_driver);
-}
-
-device_initcall_sync(pm2xxx_charger_init);
-module_exit(pm2xxx_charger_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Rajkumar kasirajan, Olivier Launay");
-MODULE_DESCRIPTION("PM2xxx charger management driver");
index dee520f..8190619 100644 (file)
 #define CHG_STATE_NO_BAT2      13
 #define CHG_STATE_CHG_READY_VUSB       14
 
+#define GCHGDET_TYPE_MASK 0x30
+#define GCHGDET_TYPE_SDP 0x00
+#define GCHGDET_TYPE_CDP 0x10
+#define GCHGDET_TYPE_DCP 0x20
+
 #define FG_ENABLE 1
 
+/*
+ * Formula seems accurate for battery current, but for USB current around 70mA
+ * per step was seen on Kobo Clara HD but all sources show the same formula
+ * also fur USB current. To avoid accidentially unwanted high currents we stick
+ * to that formula
+ */
+#define TO_CUR_REG(x) ((x) / 100000 - 1)
+#define FROM_CUR_REG(x) ((((x) & 0x1f) + 1) * 100000)
+#define CHG_MIN_CUR 100000
+#define CHG_MAX_CUR 1800000
+#define ADP_MAX_CUR 2500000
+#define USB_MAX_CUR 1400000
+
+
 struct rn5t618_power_info {
        struct rn5t618 *rn5t618;
        struct platform_device *pdev;
@@ -48,12 +67,24 @@ struct rn5t618_power_info {
        int irq;
 };
 
+static enum power_supply_usb_type rn5t618_usb_types[] = {
+       POWER_SUPPLY_USB_TYPE_SDP,
+       POWER_SUPPLY_USB_TYPE_DCP,
+       POWER_SUPPLY_USB_TYPE_CDP,
+       POWER_SUPPLY_USB_TYPE_UNKNOWN
+};
+
 static enum power_supply_property rn5t618_usb_props[] = {
+       /* input current limit is not very accurate */
+       POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
        POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_USB_TYPE,
        POWER_SUPPLY_PROP_ONLINE,
 };
 
 static enum power_supply_property rn5t618_adp_props[] = {
+       /* input current limit is not very accurate */
+       POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
        POWER_SUPPLY_PROP_STATUS,
        POWER_SUPPLY_PROP_ONLINE,
 };
@@ -69,6 +100,7 @@ static enum power_supply_property rn5t618_battery_props[] = {
        POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
        POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
        POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
        POWER_SUPPLY_PROP_CHARGE_FULL,
        POWER_SUPPLY_PROP_CHARGE_NOW,
 };
@@ -258,6 +290,36 @@ static int rn5t618_battery_ttf(struct rn5t618_power_info *info,
        return 0;
 }
 
+static int rn5t618_battery_set_current_limit(struct rn5t618_power_info *info,
+                               const union power_supply_propval *val)
+{
+       if (val->intval < CHG_MIN_CUR)
+               return -EINVAL;
+
+       if (val->intval >= CHG_MAX_CUR)
+               return -EINVAL;
+
+       return regmap_update_bits(info->rn5t618->regmap,
+                                 RN5T618_CHGISET,
+                                 0x1F, TO_CUR_REG(val->intval));
+}
+
+static int rn5t618_battery_get_current_limit(struct rn5t618_power_info *info,
+                                            union power_supply_propval *val)
+{
+       unsigned int regval;
+       int ret;
+
+       ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGISET,
+                         &regval);
+       if (ret < 0)
+               return ret;
+
+       val->intval = FROM_CUR_REG(regval);
+
+       return 0;
+}
+
 static int rn5t618_battery_charge_full(struct rn5t618_power_info *info,
                                       union power_supply_propval *val)
 {
@@ -323,6 +385,9 @@ static int rn5t618_battery_get_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_TECHNOLOGY:
                val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
                break;
+       case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+               ret = rn5t618_battery_get_current_limit(info, val);
+               break;
        case POWER_SUPPLY_PROP_CHARGE_FULL:
                ret = rn5t618_battery_charge_full(info, val);
                break;
@@ -336,12 +401,38 @@ static int rn5t618_battery_get_property(struct power_supply *psy,
        return ret;
 }
 
+static int rn5t618_battery_set_property(struct power_supply *psy,
+                                       enum power_supply_property psp,
+                                       const union power_supply_propval *val)
+{
+       struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+               return rn5t618_battery_set_current_limit(info, val);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int rn5t618_battery_property_is_writeable(struct power_supply *psy,
+                                               enum power_supply_property psp)
+{
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static int rn5t618_adp_get_property(struct power_supply *psy,
                                    enum power_supply_property psp,
                                    union power_supply_propval *val)
 {
        struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
        unsigned int chgstate;
+       unsigned int regval;
        bool online;
        int ret;
 
@@ -364,6 +455,14 @@ static int rn5t618_adp_get_property(struct power_supply *psy,
                if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
                        val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
 
+               break;
+       case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+               ret = regmap_read(info->rn5t618->regmap,
+                                 RN5T618_REGISET1, &regval);
+               if (ret < 0)
+                       return ret;
+
+               val->intval = FROM_CUR_REG(regval);
                break;
        default:
                return -EINVAL;
@@ -372,12 +471,79 @@ static int rn5t618_adp_get_property(struct power_supply *psy,
        return 0;
 }
 
+static int rn5t618_adp_set_property(struct power_supply *psy,
+                                   enum power_supply_property psp,
+                                   const union power_supply_propval *val)
+{
+       struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
+       int ret;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+               if (val->intval > ADP_MAX_CUR)
+                       return -EINVAL;
+
+               if (val->intval < CHG_MIN_CUR)
+                       return -EINVAL;
+
+               ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET1,
+                                  TO_CUR_REG(val->intval));
+               if (ret < 0)
+                       return ret;
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rn5t618_adp_property_is_writeable(struct power_supply *psy,
+                                            enum power_supply_property psp)
+{
+       switch (psp) {
+       case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static int rc5t619_usb_get_type(struct rn5t618_power_info *info,
+                               union power_supply_propval *val)
+{
+       unsigned int regval;
+       int ret;
+
+       ret = regmap_read(info->rn5t618->regmap, RN5T618_GCHGDET, &regval);
+       if (ret < 0)
+               return ret;
+
+       switch (regval & GCHGDET_TYPE_MASK) {
+       case GCHGDET_TYPE_SDP:
+               val->intval = POWER_SUPPLY_USB_TYPE_SDP;
+               break;
+       case GCHGDET_TYPE_CDP:
+               val->intval = POWER_SUPPLY_USB_TYPE_CDP;
+               break;
+       case GCHGDET_TYPE_DCP:
+               val->intval = POWER_SUPPLY_USB_TYPE_DCP;
+               break;
+       default:
+               val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;
+       }
+
+       return 0;
+}
+
 static int rn5t618_usb_get_property(struct power_supply *psy,
                                    enum power_supply_property psp,
                                    union power_supply_propval *val)
 {
        struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
        unsigned int chgstate;
+       unsigned int regval;
        bool online;
        int ret;
 
@@ -400,6 +566,28 @@ static int rn5t618_usb_get_property(struct power_supply *psy,
                if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
                        val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
 
+               break;
+       case POWER_SUPPLY_PROP_USB_TYPE:
+               if (!online || (info->rn5t618->variant != RC5T619))
+                       return -ENODATA;
+
+               return rc5t619_usb_get_type(info, val);
+       case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+               ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGCTL1,
+                                 &regval);
+               if (ret < 0)
+                       return ret;
+
+               val->intval = 0;
+               if (regval & 2) {
+                       ret = regmap_read(info->rn5t618->regmap,
+                                         RN5T618_REGISET2,
+                                         &regval);
+                       if (ret < 0)
+                               return ret;
+
+                       val->intval = FROM_CUR_REG(regval);
+               }
                break;
        default:
                return -EINVAL;
@@ -408,12 +596,53 @@ static int rn5t618_usb_get_property(struct power_supply *psy,
        return 0;
 }
 
+static int rn5t618_usb_set_property(struct power_supply *psy,
+                                   enum power_supply_property psp,
+                                   const union power_supply_propval *val)
+{
+       struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
+       int ret;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+               if (val->intval > USB_MAX_CUR)
+                       return -EINVAL;
+
+               if (val->intval < CHG_MIN_CUR)
+                       return -EINVAL;
+
+               ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET2,
+                                  0xE0 | TO_CUR_REG(val->intval));
+               if (ret < 0)
+                       return ret;
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rn5t618_usb_property_is_writeable(struct power_supply *psy,
+                                            enum power_supply_property psp)
+{
+       switch (psp) {
+       case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static const struct power_supply_desc rn5t618_battery_desc = {
        .name                   = "rn5t618-battery",
        .type                   = POWER_SUPPLY_TYPE_BATTERY,
        .properties             = rn5t618_battery_props,
        .num_properties         = ARRAY_SIZE(rn5t618_battery_props),
        .get_property           = rn5t618_battery_get_property,
+       .set_property           = rn5t618_battery_set_property,
+       .property_is_writeable  = rn5t618_battery_property_is_writeable,
 };
 
 static const struct power_supply_desc rn5t618_adp_desc = {
@@ -422,14 +651,20 @@ static const struct power_supply_desc rn5t618_adp_desc = {
        .properties             = rn5t618_adp_props,
        .num_properties         = ARRAY_SIZE(rn5t618_adp_props),
        .get_property           = rn5t618_adp_get_property,
+       .set_property           = rn5t618_adp_set_property,
+       .property_is_writeable  = rn5t618_adp_property_is_writeable,
 };
 
 static const struct power_supply_desc rn5t618_usb_desc = {
        .name                   = "rn5t618-usb",
        .type                   = POWER_SUPPLY_TYPE_USB,
+       .usb_types              = rn5t618_usb_types,
+       .num_usb_types          = ARRAY_SIZE(rn5t618_usb_types),
        .properties             = rn5t618_usb_props,
        .num_properties         = ARRAY_SIZE(rn5t618_usb_props),
        .get_property           = rn5t618_usb_get_property,
+       .set_property           = rn5t618_usb_set_property,
+       .property_is_writeable  = rn5t618_usb_property_is_writeable,
 };
 
 static irqreturn_t rn5t618_charger_irq(int irq, void *data)
index f330452..9ad0afe 100644 (file)
@@ -164,9 +164,16 @@ static const struct i2c_device_id rt5033_battery_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, rt5033_battery_id);
 
+static const struct of_device_id rt5033_battery_of_match[] = {
+       { .compatible = "richtek,rt5033-battery", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, rt5033_battery_of_match);
+
 static struct i2c_driver rt5033_battery_driver = {
        .driver = {
                .name = "rt5033-battery",
+               .of_match_table = rt5033_battery_of_match,
        },
        .probe = rt5033_battery_probe,
        .remove = rt5033_battery_remove,
index 8d7a107..f84dbaa 100644 (file)
@@ -189,6 +189,14 @@ static const enum power_supply_property sbs_properties[] = {
 /* Supports special manufacturer commands from TI BQ20Z65 and BQ20Z75 IC. */
 #define SBS_FLAGS_TI_BQ20ZX5           BIT(0)
 
+static const enum power_supply_property string_properties[] = {
+       POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_MANUFACTURER,
+       POWER_SUPPLY_PROP_MODEL_NAME,
+};
+
+#define NR_STRING_BUFFERS      ARRAY_SIZE(string_properties)
+
 struct sbs_info {
        struct i2c_client               *client;
        struct power_supply             *power_supply;
@@ -202,11 +210,32 @@ struct sbs_info {
        struct delayed_work             work;
        struct mutex                    mode_lock;
        u32                             flags;
+       int                             technology;
+       char                            strings[NR_STRING_BUFFERS][I2C_SMBUS_BLOCK_MAX + 1];
 };
 
-static char model_name[I2C_SMBUS_BLOCK_MAX + 1];
-static char manufacturer[I2C_SMBUS_BLOCK_MAX + 1];
-static char chemistry[I2C_SMBUS_BLOCK_MAX + 1];
+static char *sbs_get_string_buf(struct sbs_info *chip,
+                               enum power_supply_property psp)
+{
+       int i = 0;
+
+       for (i = 0; i < NR_STRING_BUFFERS; i++)
+               if (string_properties[i] == psp)
+                       return chip->strings[i];
+
+       return ERR_PTR(-EINVAL);
+}
+
+static void sbs_invalidate_cached_props(struct sbs_info *chip)
+{
+       int i = 0;
+
+       chip->technology = -1;
+
+       for (i = 0; i < NR_STRING_BUFFERS; i++)
+               chip->strings[i][0] = 0;
+}
+
 static bool force_load;
 
 static int sbs_read_word_data(struct i2c_client *client, u8 address);
@@ -244,6 +273,7 @@ static int sbs_update_presence(struct sbs_info *chip, bool is_present)
                chip->is_present = false;
                /* Disable PEC when no device is present */
                client->flags &= ~I2C_CLIENT_PEC;
+               sbs_invalidate_cached_props(chip);
                return 0;
        }
 
@@ -640,17 +670,45 @@ static int sbs_get_battery_property(struct i2c_client *client,
        return 0;
 }
 
-static int sbs_get_battery_string_property(struct i2c_client *client,
-       int reg_offset, enum power_supply_property psp, char *val)
+static int sbs_get_property_index(struct i2c_client *client,
+       enum power_supply_property psp)
 {
-       s32 ret;
+       int count;
 
-       ret = sbs_read_string_data(client, sbs_data[reg_offset].addr, val);
+       for (count = 0; count < ARRAY_SIZE(sbs_data); count++)
+               if (psp == sbs_data[count].psp)
+                       return count;
 
-       if (ret < 0)
-               return ret;
+       dev_warn(&client->dev,
+               "%s: Invalid Property - %d\n", __func__, psp);
 
-       return 0;
+       return -EINVAL;
+}
+
+static const char *sbs_get_constant_string(struct sbs_info *chip,
+                       enum power_supply_property psp)
+{
+       int ret;
+       char *buf;
+       u8 addr;
+
+       buf = sbs_get_string_buf(chip, psp);
+       if (IS_ERR(buf))
+               return buf;
+
+       if (!buf[0]) {
+               ret = sbs_get_property_index(chip->client, psp);
+               if (ret < 0)
+                       return ERR_PTR(ret);
+
+               addr = sbs_data[ret].addr;
+
+               ret = sbs_read_string_data(chip->client, addr, buf);
+               if (ret < 0)
+                       return ERR_PTR(ret);
+       }
+
+       return buf;
 }
 
 static void  sbs_unit_adjustment(struct i2c_client *client,
@@ -773,48 +831,36 @@ static int sbs_get_battery_serial_number(struct i2c_client *client,
        return 0;
 }
 
-static int sbs_get_property_index(struct i2c_client *client,
-       enum power_supply_property psp)
-{
-       int count;
-       for (count = 0; count < ARRAY_SIZE(sbs_data); count++)
-               if (psp == sbs_data[count].psp)
-                       return count;
-
-       dev_warn(&client->dev,
-               "%s: Invalid Property - %d\n", __func__, psp);
-
-       return -EINVAL;
-}
-
-static int sbs_get_chemistry(struct i2c_client *client,
+static int sbs_get_chemistry(struct sbs_info *chip,
                union power_supply_propval *val)
 {
-       enum power_supply_property psp = POWER_SUPPLY_PROP_TECHNOLOGY;
-       int ret;
+       const char *chemistry;
 
-       ret = sbs_get_property_index(client, psp);
-       if (ret < 0)
-               return ret;
+       if (chip->technology != -1) {
+               val->intval = chip->technology;
+               return 0;
+       }
 
-       ret = sbs_get_battery_string_property(client, ret, psp,
-                                             chemistry);
-       if (ret < 0)
-               return ret;
+       chemistry = sbs_get_constant_string(chip, POWER_SUPPLY_PROP_TECHNOLOGY);
+
+       if (IS_ERR(chemistry))
+               return PTR_ERR(chemistry);
 
        if (!strncasecmp(chemistry, "LION", 4))
-               val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+               chip->technology = POWER_SUPPLY_TECHNOLOGY_LION;
        else if (!strncasecmp(chemistry, "LiP", 3))
-               val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO;
+               chip->technology = POWER_SUPPLY_TECHNOLOGY_LIPO;
        else if (!strncasecmp(chemistry, "NiCd", 4))
-               val->intval = POWER_SUPPLY_TECHNOLOGY_NiCd;
+               chip->technology = POWER_SUPPLY_TECHNOLOGY_NiCd;
        else if (!strncasecmp(chemistry, "NiMH", 4))
-               val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH;
+               chip->technology = POWER_SUPPLY_TECHNOLOGY_NiMH;
        else
-               val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
+               chip->technology = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
+
+       if (chip->technology == POWER_SUPPLY_TECHNOLOGY_UNKNOWN)
+               dev_warn(&chip->client->dev, "Unknown chemistry: %s\n", chemistry);
 
-       if (val->intval == POWER_SUPPLY_TECHNOLOGY_UNKNOWN)
-               dev_warn(&client->dev, "Unknown chemistry: %s\n", chemistry);
+       val->intval = chip->technology;
 
        return 0;
 }
@@ -858,6 +904,7 @@ static int sbs_get_property(struct power_supply *psy,
        int ret = 0;
        struct sbs_info *chip = power_supply_get_drvdata(psy);
        struct i2c_client *client = chip->client;
+       const char *str;
 
        if (chip->gpio_detect) {
                ret = gpiod_get_value_cansleep(chip->gpio_detect);
@@ -883,7 +930,7 @@ static int sbs_get_property(struct power_supply *psy,
                break;
 
        case POWER_SUPPLY_PROP_TECHNOLOGY:
-               ret = sbs_get_chemistry(client, val);
+               ret = sbs_get_chemistry(chip, val);
                if (ret < 0)
                        break;
 
@@ -935,23 +982,12 @@ static int sbs_get_property(struct power_supply *psy,
                break;
 
        case POWER_SUPPLY_PROP_MODEL_NAME:
-               ret = sbs_get_property_index(client, psp);
-               if (ret < 0)
-                       break;
-
-               ret = sbs_get_battery_string_property(client, ret, psp,
-                                                     model_name);
-               val->strval = model_name;
-               break;
-
        case POWER_SUPPLY_PROP_MANUFACTURER:
-               ret = sbs_get_property_index(client, psp);
-               if (ret < 0)
-                       break;
-
-               ret = sbs_get_battery_string_property(client, ret, psp,
-                                                     manufacturer);
-               val->strval = manufacturer;
+               str = sbs_get_constant_string(chip, psp);
+               if (IS_ERR(str))
+                       ret = PTR_ERR(str);
+               else
+                       val->strval = str;
                break;
 
        case POWER_SUPPLY_PROP_MANUFACTURE_YEAR:
@@ -1098,6 +1134,7 @@ static int sbs_probe(struct i2c_client *client)
        psy_cfg.of_node = client->dev.of_node;
        psy_cfg.drv_data = chip;
        chip->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
+       sbs_invalidate_cached_props(chip);
        mutex_init(&chip->mode_lock);
 
        /* use pdata if available, fall back to DT properties,
index 335cb85..288b798 100644 (file)
@@ -524,6 +524,7 @@ static const struct of_device_id sc2731_charger_of_match[] = {
        { .compatible = "sprd,sc2731-charger", },
        { }
 };
+MODULE_DEVICE_TABLE(of, sc2731_charger_of_match);
 
 static struct platform_driver sc2731_charger_driver = {
        .driver = {
index 9c62761..1ae8374 100644 (file)
@@ -1342,6 +1342,7 @@ static const struct of_device_id sc27xx_fgu_of_match[] = {
        { .compatible = "sprd,sc2731-fgu", },
        { }
 };
+MODULE_DEVICE_TABLE(of, sc27xx_fgu_of_match);
 
 static struct platform_driver sc27xx_fgu_driver = {
        .probe = sc27xx_fgu_probe,
index 3376f42..df24042 100644 (file)
@@ -10,7 +10,6 @@
 
 #include <linux/delay.h>
 #include <linux/err.h>
-#include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
index 7efa431..5ec2e6b 100644 (file)
@@ -345,6 +345,16 @@ static u32 spwr_notify_bat(struct ssam_event_notifier *nf, const struct ssam_eve
        struct spwr_battery_device *bat = container_of(nf, struct spwr_battery_device, notif);
        int status;
 
+       /*
+        * We cannot use strict matching when registering the notifier as the
+        * EC expects us to register it against instance ID 0. Strict matching
+        * would thus drop events, as those may have non-zero instance IDs in
+        * this subsystem. So we need to check the instance ID of the event
+        * here manually.
+        */
+       if (event->instance_id != bat->sdev->uid.instance)
+               return 0;
+
        dev_dbg(&bat->sdev->dev, "power event (cid = %#04x, iid = %#04x, tid = %#04x)\n",
                event->command_id, event->instance_id, event->target_id);
 
@@ -720,8 +730,8 @@ static void spwr_battery_init(struct spwr_battery_device *bat, struct ssam_devic
        bat->notif.base.fn = spwr_notify_bat;
        bat->notif.event.reg = registry;
        bat->notif.event.id.target_category = sdev->uid.category;
-       bat->notif.event.id.instance = 0;
-       bat->notif.event.mask = SSAM_EVENT_MASK_STRICT;
+       bat->notif.event.id.instance = 0;       /* need to register with instance 0 */
+       bat->notif.event.mask = SSAM_EVENT_MASK_TARGET;
        bat->notif.event.flags = SSAM_EVENT_SEQUENCED;
 
        bat->psy_desc.name = bat->name;
index 81a5b79..a060c36 100644 (file)
@@ -66,7 +66,7 @@ struct spwr_ac_device {
 
 static int spwr_ac_update_unlocked(struct spwr_ac_device *ac)
 {
-       u32 old = ac->state;
+       __le32 old = ac->state;
        int status;
 
        lockdep_assert_held(&ac->lock);
diff --git a/include/linux/max17040_battery.h b/include/linux/max17040_battery.h
deleted file mode 100644 (file)
index 593602f..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- *  Copyright (C) 2009 Samsung Electronics
- *  Minkyu Kang <mk7.kang@samsung.com>
- */
-
-#ifndef __MAX17040_BATTERY_H_
-#define __MAX17040_BATTERY_H_
-
-struct max17040_platform_data {
-       int (*battery_online)(void);
-       int (*charger_online)(void);
-       int (*charger_enable)(void);
-};
-
-#endif
diff --git a/include/linux/pm2301_charger.h b/include/linux/pm2301_charger.h
deleted file mode 100644 (file)
index b8fac96..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * PM2301 charger driver.
- *
- * Copyright (C) 2012 ST Ericsson Corporation
- *
- * Contact: Olivier LAUNAY (olivier.launay@stericsson.com
- */
-
-#ifndef __LINUX_PM2301_H
-#define __LINUX_PM2301_H
-
-/**
- * struct pm2xxx_bm_charger_parameters - Charger specific parameters
- * @ac_volt_max:       maximum allowed AC charger voltage in mV
- * @ac_curr_max:       maximum allowed AC charger current in mA
- */
-struct pm2xxx_bm_charger_parameters {
-       int ac_volt_max;
-       int ac_curr_max;
-};
-
-/**
- * struct pm2xxx_bm_data - pm2xxx battery management data
- * @enable_overshoot    flag to enable VBAT overshoot control
- * @chg_params   charger parameters
- */
-struct pm2xxx_bm_data {
-       bool enable_overshoot;
-       const struct pm2xxx_bm_charger_parameters *chg_params;
-};
-
-struct pm2xxx_charger_platform_data {
-       char **supplied_to;
-       size_t num_supplicants;
-       int i2c_bus;
-       const char *label;
-       int gpio_irq_number;
-       unsigned int lpn_gpio;
-       int irq_type;
-};
-
-struct pm2xxx_platform_data {
-       struct pm2xxx_charger_platform_data *wall_charger;
-       struct pm2xxx_bm_data *battery;
-};
-
-#endif /* __LINUX_PM2301_H */
diff --git a/include/linux/power/ab8500.h b/include/linux/power/ab8500.h
deleted file mode 100644 (file)
index 51976b5..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) ST-Ericsson 2013
- * Author: Hongbo Zhang <hongbo.zhang@linaro.com>
- */
-
-#ifndef PWR_AB8500_H
-#define PWR_AB8500_H
-
-extern const struct abx500_res_to_temp ab8500_temp_tbl_a_thermistor[];
-extern const int ab8500_temp_tbl_a_size;
-
-extern const struct abx500_res_to_temp ab8500_temp_tbl_b_thermistor[];
-extern const int ab8500_temp_tbl_b_size;
-
-#endif /* PWR_AB8500_H */