Merge tag 'for-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 19 Dec 2020 19:58:46 +0000 (11:58 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 19 Dec 2020 19:58:46 +0000 (11:58 -0800)
Pull power supply and reset updates from Sebastian Reichel:
 "Battery/charger driver changes:

   - collie_battery, generic-adc-battery, s3c-adc-battery: convert to
     GPIO descriptors (incl ARM board files)

   - misc cleanup and fixes

  Reset drivers:

   - new poweroff driver for force disabling a regulator

   - use printk format symbol resolver

   - ocelot: add support for Luton and Jaguar2"

* tag 'for-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (31 commits)
  power: supply: Fix a typo in warning message
  Documentation: DT: binding documentation for regulator-poweroff
  power: reset: new driver regulator-poweroff
  power: supply: ab8500: Use dev_err_probe() for IIO channels
  power: supply: ab8500_fg: Request all IRQs as threaded
  power: supply: ab8500_charger: Oneshot threaded IRQs
  power: supply: ab8500: Convert to dev_pm_ops
  power: supply: ab8500: Use local helper
  power: supply: wm831x_power: remove unneeded break
  power: supply: bq24735: Drop unused include
  power: supply: bq24190_charger: Drop unused include
  power: supply: generic-adc-battery: Use GPIO descriptors
  power: supply: collie_battery: Convert to GPIO descriptors
  power: supply: bq24190_charger: fix reference leak
  power: supply: s3c-adc-battery: Convert to GPIO descriptors
  power: reset: Use printk format symbol resolver
  power: supply: axp20x_usb_power: Use power efficient workqueue for debounce
  power: supply: axp20x_usb_power: fix typo
  power: supply: max8997-charger: Improve getting charger status
  power: supply: max8997-charger: Fix platform data retrieval
  ...

30 files changed:
Documentation/devicetree/bindings/power/reset/ocelot-reset.txt
Documentation/devicetree/bindings/power/reset/regulator-poweroff.yaml [new file with mode: 0644]
arch/arm/mach-s3c/mach-h1940.c
arch/arm/mach-s3c/mach-rx1950.c
arch/arm/mach-sa1100/collie.c
drivers/power/reset/Kconfig
drivers/power/reset/Makefile
drivers/power/reset/ocelot-reset.c
drivers/power/reset/qnap-poweroff.c
drivers/power/reset/regulator-poweroff.c [new file with mode: 0644]
drivers/power/reset/syscon-poweroff.c
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_usb_power.c
drivers/power/supply/axp288_charger.c
drivers/power/supply/bq24190_charger.c
drivers/power/supply/bq24735-charger.c
drivers/power/supply/bq25890_charger.c
drivers/power/supply/collie_battery.c
drivers/power/supply/generic-adc-battery.c
drivers/power/supply/max17042_battery.c
drivers/power/supply/max8997_charger.c
drivers/power/supply/pm2301_charger.c
drivers/power/supply/power_supply_sysfs.c
drivers/power/supply/s3c_adc_battery.c
drivers/power/supply/wm831x_power.c
include/linux/power/generic-adc-battery.h
include/linux/s3c_adc_battery.h

index 4d530d8..c5de7b5 100644 (file)
@@ -7,7 +7,9 @@ The reset registers are both present in the MSCC vcoreiii MIPS and
 microchip Sparx5 armv8 SoC's.
 
 Required Properties:
- - compatible: "mscc,ocelot-chip-reset" or "microchip,sparx5-chip-reset"
+
+ - compatible: "mscc,ocelot-chip-reset", "mscc,luton-chip-reset",
+   "mscc,jaguar2-chip-reset" or "microchip,sparx5-chip-reset"
 
 Example:
        reset@1070008 {
diff --git a/Documentation/devicetree/bindings/power/reset/regulator-poweroff.yaml b/Documentation/devicetree/bindings/power/reset/regulator-poweroff.yaml
new file mode 100644 (file)
index 0000000..03bd1fa
--- /dev/null
@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/reset/regulator-poweroff.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Force-disable power regulator to turn the power off.
+
+maintainers:
+  - Michael Klein <michael@fossekall.de>
+
+description: |
+  When the power-off handler is called, a power regulator is disabled by
+  calling regulator_force_disable(). If the power is still on and the
+  CPU still running after a 3000ms delay, a warning is emitted.
+
+properties:
+  compatible:
+    const: "regulator-poweroff"
+
+  cpu-supply:
+    description:
+      regulator to disable on power-down
+
+required:
+  - compatible
+  - cpu-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    regulator-poweroff {
+        compatible = "regulator-poweroff";
+        cpu-supply = <&reg_vcc1v2>;
+    };
+...
index 53d51aa..8a43ed1 100644 (file)
@@ -297,6 +297,15 @@ static const struct s3c_adc_bat_thresh bat_lut_acin[] = {
        { .volt = 3841, .cur = 0, .level = 0},
 };
 
+static struct gpiod_lookup_table h1940_bat_gpio_table = {
+       .dev_id = "s3c-adc-battery",
+       .table = {
+               /* Charge status S3C2410_GPF(3) */
+               GPIO_LOOKUP("GPIOF", 3, "charge-status", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
 static int h1940_bat_init(void)
 {
        int ret;
@@ -330,8 +339,6 @@ static struct s3c_adc_bat_pdata h1940_bat_cfg = {
        .exit = h1940_bat_exit,
        .enable_charger = h1940_enable_charger,
        .disable_charger = h1940_disable_charger,
-       .gpio_charge_finished = S3C2410_GPF(3),
-       .gpio_inverted = 1,
        .lut_noac = bat_lut_noac,
        .lut_noac_cnt = ARRAY_SIZE(bat_lut_noac),
        .lut_acin = bat_lut_acin,
@@ -720,6 +727,7 @@ static void __init h1940_init(void)
        s3c24xx_fb_set_platdata(&h1940_fb_info);
        gpiod_add_lookup_table(&h1940_mmc_gpio_table);
        gpiod_add_lookup_table(&h1940_audio_gpio_table);
+       gpiod_add_lookup_table(&h1940_bat_gpio_table);
        /* Configure the I2S pins (GPE0...GPE4) in correct mode */
        s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2),
                              S3C_GPIO_PULL_NONE);
index b9758f0..6e19add 100644 (file)
@@ -206,6 +206,15 @@ static const struct s3c_adc_bat_thresh bat_lut_acin[] = {
        { .volt = 3820, .cur = 0, .level = 0},
 };
 
+static struct gpiod_lookup_table rx1950_bat_gpio_table = {
+       .dev_id = "s3c-adc-battery",
+       .table = {
+               /* Charge status S3C2410_GPF(3) */
+               GPIO_LOOKUP("GPIOF", 3, "charge-status", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static int rx1950_bat_init(void)
 {
        int ret;
@@ -331,7 +340,6 @@ static struct s3c_adc_bat_pdata rx1950_bat_cfg = {
        .exit = rx1950_bat_exit,
        .enable_charger = rx1950_enable_charger,
        .disable_charger = rx1950_disable_charger,
-       .gpio_charge_finished = S3C2410_GPF(3),
        .lut_noac = bat_lut_noac,
        .lut_noac_cnt = ARRAY_SIZE(bat_lut_noac),
        .lut_acin = bat_lut_acin,
@@ -840,6 +848,7 @@ static void __init rx1950_init_machine(void)
 
        pwm_add_table(rx1950_pwm_lookup, ARRAY_SIZE(rx1950_pwm_lookup));
        gpiod_add_lookup_table(&rx1950_audio_gpio_table);
+       gpiod_add_lookup_table(&rx1950_bat_gpio_table);
        /* Configure the I2S pins (GPE0...GPE4) in correct mode */
        s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2),
                              S3C_GPIO_PULL_NONE);
index bd3a52f..d4e89a0 100644 (file)
@@ -98,6 +98,26 @@ static struct mcp_plat_data collie_mcp_data = {
        .codec_pdata    = &collie_ucb1x00_data,
 };
 
+/* Battery management GPIOs */
+static struct gpiod_lookup_table collie_battery_gpiod_table = {
+       /* the MCP codec mcp0 has the ucb1x00 as attached device */
+       .dev_id = "ucb1x00",
+       .table = {
+               /* This is found on the main GPIO on the SA1100 */
+               GPIO_LOOKUP("gpio", COLLIE_GPIO_CO,
+                           "main battery full", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("gpio", COLLIE_GPIO_MAIN_BAT_LOW,
+                           "main battery low", GPIO_ACTIVE_HIGH),
+               /*
+                * This is GPIO 0 on the Scoop expander, which is registered
+                * from common/scoop.c with this gpio chip label.
+                */
+               GPIO_LOOKUP("sharp-scoop", 0,
+                           "main charge on", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static int collie_ir_startup(struct device *dev)
 {
        int rc = gpio_request(COLLIE_GPIO_IR_ON, "IrDA");
@@ -395,6 +415,7 @@ static void __init collie_init(void)
        platform_scoop_config = &collie_pcmcia_config;
 
        gpiod_add_lookup_table(&collie_power_gpiod_table);
+       gpiod_add_lookup_table(&collie_battery_gpiod_table);
 
        ret = platform_add_devices(devices, ARRAY_SIZE(devices));
        if (ret) {
index d55b372..b22c4fd 100644 (file)
@@ -177,6 +177,13 @@ config POWER_RESET_QNAP
 
          Say Y if you have a QNAP NAS.
 
+config POWER_RESET_REGULATOR
+       bool "Regulator subsystem power-off driver"
+       depends on OF && REGULATOR
+       help
+         This driver supports turning off your board by disabling a
+         power regulator defined in the devicetree.
+
 config POWER_RESET_RESTART
        bool "Restart power-off driver"
        help
index c51eceb..9dc49d3 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o
 obj-$(CONFIG_POWER_RESET_PIIX4_POWEROFF) += piix4-poweroff.o
 obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
 obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
+obj-$(CONFIG_POWER_RESET_REGULATOR) += regulator-poweroff.o
 obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
 obj-$(CONFIG_POWER_RESET_ST) += st-poweroff.o
 obj-$(CONFIG_POWER_RESET_VERSATILE) += arm-versatile-reboot.o
index f74e1db..8caa90c 100644 (file)
@@ -29,6 +29,8 @@ struct ocelot_reset_context {
        struct notifier_block restart_handler;
 };
 
+#define BIT_OFF_INVALID                                32
+
 #define SOFT_CHIP_RST BIT(0)
 
 #define ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL  0x24
@@ -50,9 +52,11 @@ static int ocelot_restart_handle(struct notifier_block *this,
                           ctx->props->vcore_protect, 0);
 
        /* Make the SI back to boot mode */
-       regmap_update_bits(ctx->cpu_ctrl, ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL,
-                          IF_SI_OWNER_MASK << if_si_owner_bit,
-                          IF_SI_OWNER_SIBM << if_si_owner_bit);
+       if (if_si_owner_bit != BIT_OFF_INVALID)
+               regmap_update_bits(ctx->cpu_ctrl,
+                                  ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL,
+                                  IF_SI_OWNER_MASK << if_si_owner_bit,
+                                  IF_SI_OWNER_SIBM << if_si_owner_bit);
 
        pr_emerg("Resetting SoC\n");
 
@@ -96,6 +100,20 @@ static int ocelot_reset_probe(struct platform_device *pdev)
        return err;
 }
 
+static const struct reset_props reset_props_jaguar2 = {
+       .syscon          = "mscc,ocelot-cpu-syscon",
+       .protect_reg     = 0x20,
+       .vcore_protect   = BIT(2),
+       .if_si_owner_bit = 6,
+};
+
+static const struct reset_props reset_props_luton = {
+       .syscon          = "mscc,ocelot-cpu-syscon",
+       .protect_reg     = 0x20,
+       .vcore_protect   = BIT(2),
+       .if_si_owner_bit = BIT_OFF_INVALID, /* n/a */
+};
+
 static const struct reset_props reset_props_ocelot = {
        .syscon          = "mscc,ocelot-cpu-syscon",
        .protect_reg     = 0x20,
@@ -112,6 +130,12 @@ static const struct reset_props reset_props_sparx5 = {
 
 static const struct of_device_id ocelot_reset_of_match[] = {
        {
+               .compatible = "mscc,jaguar2-chip-reset",
+               .data = &reset_props_jaguar2
+       }, {
+               .compatible = "mscc,luton-chip-reset",
+               .data = &reset_props_luton
+       }, {
                .compatible = "mscc,ocelot-chip-reset",
                .data = &reset_props_ocelot
        }, {
index 52b7dc6..0ddf7f2 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/serial_reg.h>
-#include <linux/kallsyms.h>
 #include <linux/of.h>
 #include <linux/io.h>
 #include <linux/clk.h>
@@ -75,7 +74,6 @@ static int qnap_power_off_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct resource *res;
        struct clk *clk;
-       char symname[KSYM_NAME_LEN];
 
        const struct of_device_id *match =
                of_match_node(qnap_power_off_of_match_table, np);
@@ -104,10 +102,8 @@ static int qnap_power_off_probe(struct platform_device *pdev)
 
        /* Check that nothing else has already setup a handler */
        if (pm_power_off) {
-               lookup_symbol_name((ulong)pm_power_off, symname);
-               dev_err(&pdev->dev,
-                       "pm_power_off already claimed %p %s",
-                       pm_power_off, symname);
+               dev_err(&pdev->dev, "pm_power_off already claimed for %ps",
+                       pm_power_off);
                return -EBUSY;
        }
        pm_power_off = qnap_power_off;
diff --git a/drivers/power/reset/regulator-poweroff.c b/drivers/power/reset/regulator-poweroff.c
new file mode 100644 (file)
index 0000000..f697088
--- /dev/null
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Force-disables a regulator to power down a device
+ *
+ * Michael Klein <michael@fossekall.de>
+ *
+ * Copyright (C) 2020 Michael Klein
+ *
+ * Based on the gpio-poweroff driver.
+ */
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/regulator/consumer.h>
+
+#define TIMEOUT_MS 3000
+
+/*
+ * Hold configuration here, cannot be more than one instance of the driver
+ * since pm_power_off itself is global.
+ */
+static struct regulator *cpu_regulator;
+
+static void regulator_poweroff_do_poweroff(void)
+{
+       if (cpu_regulator && regulator_is_enabled(cpu_regulator))
+               regulator_force_disable(cpu_regulator);
+
+       /* give it some time */
+       mdelay(TIMEOUT_MS);
+
+       WARN_ON(1);
+}
+
+static int regulator_poweroff_probe(struct platform_device *pdev)
+{
+       /* If a pm_power_off function has already been added, leave it alone */
+       if (pm_power_off != NULL) {
+               dev_err(&pdev->dev,
+                       "%s: pm_power_off function already registered\n",
+                       __func__);
+               return -EBUSY;
+       }
+
+       cpu_regulator = devm_regulator_get(&pdev->dev, "cpu");
+       if (IS_ERR(cpu_regulator))
+               return PTR_ERR(cpu_regulator);
+
+       pm_power_off = &regulator_poweroff_do_poweroff;
+       return 0;
+}
+
+static int regulator_poweroff_remove(__maybe_unused struct platform_device *pdev)
+{
+       if (pm_power_off == &regulator_poweroff_do_poweroff)
+               pm_power_off = NULL;
+
+       return 0;
+}
+
+static const struct of_device_id of_regulator_poweroff_match[] = {
+       { .compatible = "regulator-poweroff", },
+       {},
+};
+
+static struct platform_driver regulator_poweroff_driver = {
+       .probe = regulator_poweroff_probe,
+       .remove = regulator_poweroff_remove,
+       .driver = {
+               .name = "poweroff-regulator",
+               .of_match_table = of_regulator_poweroff_match,
+       },
+};
+
+module_platform_driver(regulator_poweroff_driver);
+
+MODULE_AUTHOR("Michael Klein <michael@fossekall.de>");
+MODULE_DESCRIPTION("Regulator poweroff driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:poweroff-regulator");
index 4d6923b..ed58bdf 100644 (file)
@@ -6,7 +6,6 @@
  * Author: Moritz Fischer <moritz.fischer@ettus.com>
  */
 
-#include <linux/kallsyms.h>
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/notifier.h>
@@ -34,7 +33,6 @@ static void syscon_poweroff(void)
 
 static int syscon_poweroff_probe(struct platform_device *pdev)
 {
-       char symname[KSYM_NAME_LEN];
        int mask_err, value_err;
 
        map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "regmap");
@@ -65,10 +63,8 @@ static int syscon_poweroff_probe(struct platform_device *pdev)
        }
 
        if (pm_power_off) {
-               lookup_symbol_name((ulong)pm_power_off, symname);
-               dev_err(&pdev->dev,
-               "pm_power_off already claimed %p %s",
-               pm_power_off, symname);
+               dev_err(&pdev->dev, "pm_power_off already claimed for %ps",
+                       pm_power_off);
                return -EBUSY;
        }
 
index 909f024..d203453 100644 (file)
@@ -936,29 +936,23 @@ static struct ab8500_btemp_interrupts ab8500_btemp_irq[] = {
        {"BTEMP_MEDIUM_HIGH", ab8500_btemp_medhigh_handler},
 };
 
-#if defined(CONFIG_PM)
-static int ab8500_btemp_resume(struct platform_device *pdev)
+static int __maybe_unused ab8500_btemp_resume(struct device *dev)
 {
-       struct ab8500_btemp *di = platform_get_drvdata(pdev);
+       struct ab8500_btemp *di = dev_get_drvdata(dev);
 
        ab8500_btemp_periodic(di, true);
 
        return 0;
 }
 
-static int ab8500_btemp_suspend(struct platform_device *pdev,
-       pm_message_t state)
+static int __maybe_unused ab8500_btemp_suspend(struct device *dev)
 {
-       struct ab8500_btemp *di = platform_get_drvdata(pdev);
+       struct ab8500_btemp *di = dev_get_drvdata(dev);
 
        ab8500_btemp_periodic(di, false);
 
        return 0;
 }
-#else
-#define ab8500_btemp_suspend      NULL
-#define ab8500_btemp_resume       NULL
-#endif
 
 static int ab8500_btemp_remove(struct platform_device *pdev)
 {
@@ -999,48 +993,45 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct abx500_bm_data *plat = pdev->dev.platform_data;
        struct power_supply_config psy_cfg = {};
+       struct device *dev = &pdev->dev;
        struct ab8500_btemp *di;
        int irq, i, ret = 0;
        u8 val;
 
-       di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
-       if (!di) {
-               dev_err(&pdev->dev, "%s no mem for ab8500_btemp\n", __func__);
+       di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
+       if (!di)
                return -ENOMEM;
-       }
 
        if (!plat) {
-               dev_err(&pdev->dev, "no battery management data supplied\n");
+               dev_err(dev, "no battery management data supplied\n");
                return -EINVAL;
        }
        di->bm = plat;
 
        if (np) {
-               ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
+               ret = ab8500_bm_of_probe(dev, np, di->bm);
                if (ret) {
-                       dev_err(&pdev->dev, "failed to get battery information\n");
+                       dev_err(dev, "failed to get battery information\n");
                        return ret;
                }
        }
 
        /* get parent data */
-       di->dev = &pdev->dev;
+       di->dev = dev;
        di->parent = dev_get_drvdata(pdev->dev.parent);
 
        /* Get ADC channels */
-       di->btemp_ball = devm_iio_channel_get(&pdev->dev, "btemp_ball");
+       di->btemp_ball = devm_iio_channel_get(dev, "btemp_ball");
        if (IS_ERR(di->btemp_ball)) {
-               if (PTR_ERR(di->btemp_ball) == -ENODEV)
-                       return -EPROBE_DEFER;
-               dev_err(&pdev->dev, "failed to get BTEMP BALL ADC channel\n");
-               return PTR_ERR(di->btemp_ball);
+               ret = dev_err_probe(dev, PTR_ERR(di->btemp_ball),
+                                   "failed to get BTEMP BALL ADC channel\n");
+               return ret;
        }
-       di->bat_ctrl = devm_iio_channel_get(&pdev->dev, "bat_ctrl");
+       di->bat_ctrl = devm_iio_channel_get(dev, "bat_ctrl");
        if (IS_ERR(di->bat_ctrl)) {
-               if (PTR_ERR(di->bat_ctrl) == -ENODEV)
-                       return -EPROBE_DEFER;
-               dev_err(&pdev->dev, "failed to get BAT CTRL ADC channel\n");
-               return PTR_ERR(di->bat_ctrl);
+               ret = dev_err_probe(dev, PTR_ERR(di->bat_ctrl),
+                                   "failed to get BAT CTRL ADC channel\n");
+               return ret;
        }
 
        di->initialized = false;
@@ -1053,7 +1044,7 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
        di->btemp_wq =
                alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM, 0);
        if (di->btemp_wq == NULL) {
-               dev_err(di->dev, "failed to create work queue\n");
+               dev_err(dev, "failed to create work queue\n");
                return -ENOMEM;
        }
 
@@ -1065,10 +1056,10 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
        di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT;
        di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT;
 
-       ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+       ret = abx500_get_register_interruptible(dev, AB8500_CHARGER,
                AB8500_BTEMP_HIGH_TH, &val);
        if (ret < 0) {
-               dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+               dev_err(dev, "%s ab8500 read failed\n", __func__);
                goto free_btemp_wq;
        }
        switch (val) {
@@ -1088,10 +1079,10 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
        }
 
        /* Register BTEMP power supply class */
-       di->btemp_psy = power_supply_register(di->dev, &ab8500_btemp_desc,
+       di->btemp_psy = power_supply_register(dev, &ab8500_btemp_desc,
                                              &psy_cfg);
        if (IS_ERR(di->btemp_psy)) {
-               dev_err(di->dev, "failed to register BTEMP psy\n");
+               dev_err(dev, "failed to register BTEMP psy\n");
                ret = PTR_ERR(di->btemp_psy);
                goto free_btemp_wq;
        }
@@ -1105,15 +1096,15 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
                }
 
                ret = request_threaded_irq(irq, NULL, ab8500_btemp_irq[i].isr,
-                       IRQF_SHARED | IRQF_NO_SUSPEND,
+                       IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
                        ab8500_btemp_irq[i].name, di);
 
                if (ret) {
-                       dev_err(di->dev, "failed to request %s IRQ %d: %d\n"
+                       dev_err(dev, "failed to request %s IRQ %d: %d\n"
                                , ab8500_btemp_irq[i].name, irq, ret);
                        goto free_irq;
                }
-               dev_dbg(di->dev, "Requested %s IRQ %d: %d\n",
+               dev_dbg(dev, "Requested %s IRQ %d: %d\n",
                        ab8500_btemp_irq[i].name, irq, ret);
        }
 
@@ -1138,6 +1129,8 @@ free_btemp_wq:
        return ret;
 }
 
+static SIMPLE_DEV_PM_OPS(ab8500_btemp_pm_ops, ab8500_btemp_suspend, ab8500_btemp_resume);
+
 static const struct of_device_id ab8500_btemp_match[] = {
        { .compatible = "stericsson,ab8500-btemp", },
        { },
@@ -1146,11 +1139,10 @@ static const struct of_device_id ab8500_btemp_match[] = {
 static struct platform_driver ab8500_btemp_driver = {
        .probe = ab8500_btemp_probe,
        .remove = ab8500_btemp_remove,
-       .suspend = ab8500_btemp_suspend,
-       .resume = ab8500_btemp_resume,
        .driver = {
                .name = "ab8500-btemp",
                .of_match_table = ab8500_btemp_match,
+               .pm = &ab8500_btemp_pm_ops,
        },
 };
 
index db65be0..ac77c88 100644 (file)
@@ -3209,11 +3209,10 @@ static int ab8500_charger_usb_notifier_call(struct notifier_block *nb,
        return NOTIFY_OK;
 }
 
-#if defined(CONFIG_PM)
-static int ab8500_charger_resume(struct platform_device *pdev)
+static int __maybe_unused ab8500_charger_resume(struct device *dev)
 {
        int ret;
-       struct ab8500_charger *di = platform_get_drvdata(pdev);
+       struct ab8500_charger *di = dev_get_drvdata(dev);
 
        /*
         * For ABB revision 1.0 and 1.1 there is a bug in the watchdog
@@ -3247,10 +3246,9 @@ static int ab8500_charger_resume(struct platform_device *pdev)
        return 0;
 }
 
-static int ab8500_charger_suspend(struct platform_device *pdev,
-       pm_message_t state)
+static int __maybe_unused ab8500_charger_suspend(struct device *dev)
 {
-       struct ab8500_charger *di = platform_get_drvdata(pdev);
+       struct ab8500_charger *di = dev_get_drvdata(dev);
 
        /* Cancel any pending jobs */
        cancel_delayed_work(&di->check_hw_failure_work);
@@ -3272,10 +3270,6 @@ static int ab8500_charger_suspend(struct platform_device *pdev,
 
        return 0;
 }
-#else
-#define ab8500_charger_suspend      NULL
-#define ab8500_charger_resume       NULL
-#endif
 
 static struct notifier_block charger_nb = {
        .notifier_call = ab8500_external_charger_prepare,
@@ -3354,23 +3348,22 @@ static int ab8500_charger_probe(struct platform_device *pdev)
        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;
 
-       di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
-       if (!di) {
-               dev_err(&pdev->dev, "%s no mem for ab8500_charger\n", __func__);
+       di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
+       if (!di)
                return -ENOMEM;
-       }
 
        if (!plat) {
-               dev_err(&pdev->dev, "no battery management data supplied\n");
+               dev_err(dev, "no battery management data supplied\n");
                return -EINVAL;
        }
        di->bm = plat;
 
        if (np) {
-               ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
+               ret = ab8500_bm_of_probe(dev, np, di->bm);
                if (ret) {
-                       dev_err(&pdev->dev, "failed to get battery information\n");
+                       dev_err(dev, "failed to get battery information\n");
                        return ret;
                }
                di->autopower_cfg = of_property_read_bool(np, "autopower_cfg");
@@ -3378,40 +3371,33 @@ static int ab8500_charger_probe(struct platform_device *pdev)
                di->autopower_cfg = false;
 
        /* get parent data */
-       di->dev = &pdev->dev;
+       di->dev = dev;
        di->parent = dev_get_drvdata(pdev->dev.parent);
 
        /* Get ADC channels */
-       di->adc_main_charger_v = devm_iio_channel_get(&pdev->dev,
-                                                     "main_charger_v");
+       di->adc_main_charger_v = devm_iio_channel_get(dev, "main_charger_v");
        if (IS_ERR(di->adc_main_charger_v)) {
-               if (PTR_ERR(di->adc_main_charger_v) == -ENODEV)
-                       return -EPROBE_DEFER;
-               dev_err(&pdev->dev, "failed to get ADC main charger voltage\n");
-               return PTR_ERR(di->adc_main_charger_v);
+               ret = dev_err_probe(dev, PTR_ERR(di->adc_main_charger_v),
+                                   "failed to get ADC main charger voltage\n");
+               return ret;
        }
-       di->adc_main_charger_c = devm_iio_channel_get(&pdev->dev,
-                                                     "main_charger_c");
+       di->adc_main_charger_c = devm_iio_channel_get(dev, "main_charger_c");
        if (IS_ERR(di->adc_main_charger_c)) {
-               if (PTR_ERR(di->adc_main_charger_c) == -ENODEV)
-                       return -EPROBE_DEFER;
-               dev_err(&pdev->dev, "failed to get ADC main charger current\n");
-               return PTR_ERR(di->adc_main_charger_c);
+               ret = dev_err_probe(dev, PTR_ERR(di->adc_main_charger_c),
+                                   "failed to get ADC main charger current\n");
+               return ret;
        }
-       di->adc_vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v");
+       di->adc_vbus_v = devm_iio_channel_get(dev, "vbus_v");
        if (IS_ERR(di->adc_vbus_v)) {
-               if (PTR_ERR(di->adc_vbus_v) == -ENODEV)
-                       return -EPROBE_DEFER;
-               dev_err(&pdev->dev, "failed to get ADC USB charger voltage\n");
-               return PTR_ERR(di->adc_vbus_v);
+               ret = dev_err_probe(dev, PTR_ERR(di->adc_vbus_v),
+                                   "failed to get ADC USB charger voltage\n");
+               return ret;
        }
-       di->adc_usb_charger_c = devm_iio_channel_get(&pdev->dev,
-                                                    "usb_charger_c");
+       di->adc_usb_charger_c = devm_iio_channel_get(dev, "usb_charger_c");
        if (IS_ERR(di->adc_usb_charger_c)) {
-               if (PTR_ERR(di->adc_usb_charger_c) == -ENODEV)
-                       return -EPROBE_DEFER;
-               dev_err(&pdev->dev, "failed to get ADC USB charger current\n");
-               return PTR_ERR(di->adc_usb_charger_c);
+               ret = dev_err_probe(dev, PTR_ERR(di->adc_usb_charger_c),
+                                   "failed to get ADC USB charger current\n");
+               return ret;
        }
 
        /* initialize lock */
@@ -3467,7 +3453,7 @@ static int ab8500_charger_probe(struct platform_device *pdev)
        di->charger_wq = alloc_ordered_workqueue("ab8500_charger_wq",
                                                 WQ_MEM_RECLAIM);
        if (di->charger_wq == NULL) {
-               dev_err(di->dev, "failed to create work queue\n");
+               dev_err(dev, "failed to create work queue\n");
                return -ENOMEM;
        }
 
@@ -3526,10 +3512,10 @@ static int ab8500_charger_probe(struct platform_device *pdev)
         * is a charger connected to avoid erroneous BTEMP_HIGH/LOW
         * interrupts during charging
         */
-       di->regu = devm_regulator_get(di->dev, "vddadc");
+       di->regu = devm_regulator_get(dev, "vddadc");
        if (IS_ERR(di->regu)) {
                ret = PTR_ERR(di->regu);
-               dev_err(di->dev, "failed to get vddadc regulator\n");
+               dev_err(dev, "failed to get vddadc regulator\n");
                goto free_charger_wq;
        }
 
@@ -3537,17 +3523,17 @@ static int ab8500_charger_probe(struct platform_device *pdev)
        /* Initialize OVV, and other registers */
        ret = ab8500_charger_init_hw_registers(di);
        if (ret) {
-               dev_err(di->dev, "failed to initialize ABB registers\n");
+               dev_err(dev, "failed to initialize ABB registers\n");
                goto free_charger_wq;
        }
 
        /* Register AC charger class */
        if (di->ac_chg.enabled) {
-               di->ac_chg.psy = power_supply_register(di->dev,
+               di->ac_chg.psy = power_supply_register(dev,
                                                       &ab8500_ac_chg_desc,
                                                       &ac_psy_cfg);
                if (IS_ERR(di->ac_chg.psy)) {
-                       dev_err(di->dev, "failed to register AC charger\n");
+                       dev_err(dev, "failed to register AC charger\n");
                        ret = PTR_ERR(di->ac_chg.psy);
                        goto free_charger_wq;
                }
@@ -3555,11 +3541,11 @@ static int ab8500_charger_probe(struct platform_device *pdev)
 
        /* Register USB charger class */
        if (di->usb_chg.enabled) {
-               di->usb_chg.psy = power_supply_register(di->dev,
+               di->usb_chg.psy = power_supply_register(dev,
                                                        &ab8500_usb_chg_desc,
                                                        &usb_psy_cfg);
                if (IS_ERR(di->usb_chg.psy)) {
-                       dev_err(di->dev, "failed to register USB charger\n");
+                       dev_err(dev, "failed to register USB charger\n");
                        ret = PTR_ERR(di->usb_chg.psy);
                        goto free_ac;
                }
@@ -3567,14 +3553,14 @@ static int ab8500_charger_probe(struct platform_device *pdev)
 
        di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
        if (IS_ERR_OR_NULL(di->usb_phy)) {
-               dev_err(di->dev, "failed to get usb transceiver\n");
+               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(di->dev, "failed to register usb notifier\n");
+               dev_err(dev, "failed to register usb notifier\n");
                goto put_usb_phy;
        }
 
@@ -3603,15 +3589,15 @@ static int ab8500_charger_probe(struct platform_device *pdev)
                }
 
                ret = request_threaded_irq(irq, NULL, ab8500_charger_irq[i].isr,
-                       IRQF_SHARED | IRQF_NO_SUSPEND,
+                       IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
                        ab8500_charger_irq[i].name, di);
 
                if (ret != 0) {
-                       dev_err(di->dev, "failed to request %s IRQ %d: %d\n"
+                       dev_err(dev, "failed to request %s IRQ %d: %d\n"
                                , ab8500_charger_irq[i].name, irq, ret);
                        goto free_irq;
                }
-               dev_dbg(di->dev, "Requested %s IRQ %d: %d\n",
+               dev_dbg(dev, "Requested %s IRQ %d: %d\n",
                        ab8500_charger_irq[i].name, irq, ret);
        }
 
@@ -3659,6 +3645,8 @@ free_charger_wq:
        return ret;
 }
 
+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", },
        { },
@@ -3667,11 +3655,10 @@ static const struct of_device_id ab8500_charger_match[] = {
 static struct platform_driver ab8500_charger_driver = {
        .probe = ab8500_charger_probe,
        .remove = ab8500_charger_remove,
-       .suspend = ab8500_charger_suspend,
-       .resume = ab8500_charger_resume,
        .driver = {
                .name = "ab8500-charger",
                .of_match_table = ab8500_charger_match,
+               .pm = &ab8500_charger_pm_ops,
        },
 };
 
index 592a73d..3873e48 100644 (file)
@@ -2942,10 +2942,9 @@ static void ab8500_fg_sysfs_psy_remove_attrs(struct ab8500_fg *di)
 
 /* Exposure to the sysfs interface <<END>> */
 
-#if defined(CONFIG_PM)
-static int ab8500_fg_resume(struct platform_device *pdev)
+static int __maybe_unused ab8500_fg_resume(struct device *dev)
 {
-       struct ab8500_fg *di = platform_get_drvdata(pdev);
+       struct ab8500_fg *di = dev_get_drvdata(dev);
 
        /*
         * Change state if we're not charging. If we're charging we will wake
@@ -2959,10 +2958,9 @@ static int ab8500_fg_resume(struct platform_device *pdev)
        return 0;
 }
 
-static int ab8500_fg_suspend(struct platform_device *pdev,
-       pm_message_t state)
+static int __maybe_unused ab8500_fg_suspend(struct device *dev)
 {
-       struct ab8500_fg *di = platform_get_drvdata(pdev);
+       struct ab8500_fg *di = dev_get_drvdata(dev);
 
        flush_delayed_work(&di->fg_periodic_work);
        flush_work(&di->fg_work);
@@ -2980,10 +2978,6 @@ static int ab8500_fg_suspend(struct platform_device *pdev,
 
        return 0;
 }
-#else
-#define ab8500_fg_suspend      NULL
-#define ab8500_fg_resume       NULL
-#endif
 
 static int ab8500_fg_remove(struct platform_device *pdev)
 {
@@ -3007,14 +3001,11 @@ static int ab8500_fg_remove(struct platform_device *pdev)
 }
 
 /* ab8500 fg driver interrupts and their respective isr */
-static struct ab8500_fg_interrupts ab8500_fg_irq_th[] = {
+static struct ab8500_fg_interrupts ab8500_fg_irq[] = {
        {"NCONV_ACCU", ab8500_fg_cc_convend_handler},
        {"BATT_OVV", ab8500_fg_batt_ovv_handler},
        {"LOW_BAT_F", ab8500_fg_lowbatf_handler},
        {"CC_INT_CALIB", ab8500_fg_cc_int_calib_handler},
-};
-
-static struct ab8500_fg_interrupts ab8500_fg_irq_bh[] = {
        {"CCEOC", ab8500_fg_cc_data_end_handler},
 };
 
@@ -3037,26 +3028,25 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct abx500_bm_data *plat = pdev->dev.platform_data;
        struct power_supply_config psy_cfg = {};
+       struct device *dev = &pdev->dev;
        struct ab8500_fg *di;
        int i, irq;
        int ret = 0;
 
-       di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
-       if (!di) {
-               dev_err(&pdev->dev, "%s no mem for ab8500_fg\n", __func__);
+       di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
+       if (!di)
                return -ENOMEM;
-       }
 
        if (!plat) {
-               dev_err(&pdev->dev, "no battery management data supplied\n");
+               dev_err(dev, "no battery management data supplied\n");
                return -EINVAL;
        }
        di->bm = plat;
 
        if (np) {
-               ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
+               ret = ab8500_bm_of_probe(dev, np, di->bm);
                if (ret) {
-                       dev_err(&pdev->dev, "failed to get battery information\n");
+                       dev_err(dev, "failed to get battery information\n");
                        return ret;
                }
        }
@@ -3064,15 +3054,14 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        mutex_init(&di->cc_lock);
 
        /* get parent data */
-       di->dev = &pdev->dev;
+       di->dev = dev;
        di->parent = dev_get_drvdata(pdev->dev.parent);
 
-       di->main_bat_v = devm_iio_channel_get(&pdev->dev, "main_bat_v");
+       di->main_bat_v = devm_iio_channel_get(dev, "main_bat_v");
        if (IS_ERR(di->main_bat_v)) {
-               if (PTR_ERR(di->main_bat_v) == -ENODEV)
-                       return -EPROBE_DEFER;
-               dev_err(&pdev->dev, "failed to get main battery ADC channel\n");
-               return PTR_ERR(di->main_bat_v);
+               ret = dev_err_probe(dev, PTR_ERR(di->main_bat_v),
+                                   "failed to get main battery ADC channel\n");
+               return ret;
        }
 
        psy_cfg.supplied_to = supply_interface;
@@ -3094,7 +3083,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        /* 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(di->dev, "failed to create work queue\n");
+               dev_err(dev, "failed to create work queue\n");
                return -ENOMEM;
        }
 
@@ -3129,7 +3118,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        /* Initialize OVV, and other registers */
        ret = ab8500_fg_init_hw_registers(di);
        if (ret) {
-               dev_err(di->dev, "failed to initialize registers\n");
+               dev_err(dev, "failed to initialize registers\n");
                goto free_inst_curr_wq;
        }
 
@@ -3138,9 +3127,9 @@ 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(di->dev, &ab8500_fg_desc, &psy_cfg);
+       di->fg_psy = power_supply_register(dev, &ab8500_fg_desc, &psy_cfg);
        if (IS_ERR(di->fg_psy)) {
-               dev_err(di->dev, "failed to register FG psy\n");
+               dev_err(dev, "failed to register FG psy\n");
                ret = PTR_ERR(di->fg_psy);
                goto free_inst_curr_wq;
        }
@@ -3156,45 +3145,26 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        init_completion(&di->ab8500_fg_complete);
 
        /* Register primary interrupt handlers */
-       for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq_th); i++) {
-               irq = platform_get_irq_byname(pdev, ab8500_fg_irq_th[i].name);
+       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_th;
+                       goto free_irq;
                }
 
-               ret = request_irq(irq, ab8500_fg_irq_th[i].isr,
-                                 IRQF_SHARED | IRQF_NO_SUSPEND,
-                                 ab8500_fg_irq_th[i].name, di);
+               ret = request_threaded_irq(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(di->dev, "failed to request %s IRQ %d: %d\n",
-                               ab8500_fg_irq_th[i].name, irq, ret);
-                       goto free_irq_th;
+                       dev_err(dev, "failed to request %s IRQ %d: %d\n",
+                               ab8500_fg_irq[i].name, irq, ret);
+                       goto free_irq;
                }
-               dev_dbg(di->dev, "Requested %s IRQ %d: %d\n",
-                       ab8500_fg_irq_th[i].name, irq, ret);
+               dev_dbg(dev, "Requested %s IRQ %d: %d\n",
+                       ab8500_fg_irq[i].name, irq, ret);
        }
 
-       /* Register threaded interrupt handler */
-       irq = platform_get_irq_byname(pdev, ab8500_fg_irq_bh[0].name);
-       if (irq < 0) {
-               ret = irq;
-               goto free_irq_th;
-       }
-
-       ret = request_threaded_irq(irq, NULL, ab8500_fg_irq_bh[0].isr,
-                               IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
-                       ab8500_fg_irq_bh[0].name, di);
-
-       if (ret != 0) {
-               dev_err(di->dev, "failed to request %s IRQ %d: %d\n",
-                       ab8500_fg_irq_bh[0].name, irq, ret);
-               goto free_irq_th;
-       }
-       dev_dbg(di->dev, "Requested %s IRQ %d: %d\n",
-               ab8500_fg_irq_bh[0].name, irq, ret);
-
        di->irq = platform_get_irq_byname(pdev, "CCEOC");
        disable_irq(di->irq);
        di->nbr_cceoc_irq_cnt = 0;
@@ -3203,13 +3173,13 @@ static int ab8500_fg_probe(struct platform_device *pdev)
 
        ret = ab8500_fg_sysfs_init(di);
        if (ret) {
-               dev_err(di->dev, "failed to create sysfs entry\n");
+               dev_err(dev, "failed to create sysfs entry\n");
                goto free_irq;
        }
 
        ret = ab8500_fg_sysfs_psy_create_attrs(di);
        if (ret) {
-               dev_err(di->dev, "failed to create FG psy\n");
+               dev_err(dev, "failed to create FG psy\n");
                ab8500_fg_sysfs_exit(di);
                goto free_irq;
        }
@@ -3230,12 +3200,9 @@ static int ab8500_fg_probe(struct platform_device *pdev)
 
 free_irq:
        /* We also have to free all registered irqs */
-       irq = platform_get_irq_byname(pdev, ab8500_fg_irq_bh[0].name);
-       free_irq(irq, di);
-free_irq_th:
        while (--i >= 0) {
                /* Last assignment of i from primary interrupt handlers */
-               irq = platform_get_irq_byname(pdev, ab8500_fg_irq_th[i].name);
+               irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name);
                free_irq(irq, di);
        }
 
@@ -3245,6 +3212,8 @@ free_inst_curr_wq:
        return ret;
 }
 
+static SIMPLE_DEV_PM_OPS(ab8500_fg_pm_ops, ab8500_fg_suspend, ab8500_fg_resume);
+
 static const struct of_device_id ab8500_fg_match[] = {
        { .compatible = "stericsson,ab8500-fg", },
        { },
@@ -3253,11 +3222,10 @@ static const struct of_device_id ab8500_fg_match[] = {
 static struct platform_driver ab8500_fg_driver = {
        .probe = ab8500_fg_probe,
        .remove = ab8500_fg_remove,
-       .suspend = ab8500_fg_suspend,
-       .resume = ab8500_fg_resume,
        .driver = {
                .name = "ab8500-fg",
                .of_match_table = ab8500_fg_match,
+               .pm = &ab8500_fg_pm_ops,
        },
 };
 
index 175c4f3..a9d84d8 100644 (file)
@@ -1913,10 +1913,9 @@ static int abx500_chargalg_sysfs_init(struct abx500_chargalg *di)
 }
 /* Exposure to the sysfs interface <<END>> */
 
-#if defined(CONFIG_PM)
-static int abx500_chargalg_resume(struct platform_device *pdev)
+static int __maybe_unused abx500_chargalg_resume(struct device *dev)
 {
-       struct abx500_chargalg *di = platform_get_drvdata(pdev);
+       struct abx500_chargalg *di = dev_get_drvdata(dev);
 
        /* Kick charger watchdog if charging (any charger online) */
        if (di->chg_info.online_chg)
@@ -1931,10 +1930,9 @@ static int abx500_chargalg_resume(struct platform_device *pdev)
        return 0;
 }
 
-static int abx500_chargalg_suspend(struct platform_device *pdev,
-       pm_message_t state)
+static int __maybe_unused abx500_chargalg_suspend(struct device *dev)
 {
-       struct abx500_chargalg *di = platform_get_drvdata(pdev);
+       struct abx500_chargalg *di = dev_get_drvdata(dev);
 
        if (di->chg_info.online_chg)
                cancel_delayed_work_sync(&di->chargalg_wd_work);
@@ -1943,10 +1941,6 @@ static int abx500_chargalg_suspend(struct platform_device *pdev,
 
        return 0;
 }
-#else
-#define abx500_chargalg_suspend      NULL
-#define abx500_chargalg_resume       NULL
-#endif
 
 static int abx500_chargalg_remove(struct platform_device *pdev)
 {
@@ -2080,6 +2074,8 @@ free_chargalg_wq:
        return ret;
 }
 
+static SIMPLE_DEV_PM_OPS(abx500_chargalg_pm_ops, abx500_chargalg_suspend, abx500_chargalg_resume);
+
 static const struct of_device_id ab8500_chargalg_match[] = {
        { .compatible = "stericsson,ab8500-chargalg", },
        { },
@@ -2088,11 +2084,10 @@ static const struct of_device_id ab8500_chargalg_match[] = {
 static struct platform_driver abx500_chargalg_driver = {
        .probe = abx500_chargalg_probe,
        .remove = abx500_chargalg_remove,
-       .suspend = abx500_chargalg_suspend,
-       .resume = abx500_chargalg_resume,
        .driver = {
                .name = "ab8500-chargalg",
                .of_match_table = ab8500_chargalg_match,
+               .pm = &abx500_chargalg_pm_ops,
        },
 };
 
index 0eaa86c..70b28b6 100644 (file)
@@ -92,7 +92,7 @@ static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
 
        power_supply_changed(power->supply);
 
-       mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
+       mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME);
 
        return IRQ_HANDLED;
 }
@@ -117,7 +117,7 @@ static void axp20x_usb_power_poll_vbus(struct work_struct *work)
 
 out:
        if (axp20x_usb_vbus_needs_polling(power))
-               mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
+               mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME);
 }
 
 static int axp20x_get_current_max(struct axp20x_usb_power *power, int *val)
@@ -397,7 +397,7 @@ static int axp20x_usb_power_prop_writeable(struct power_supply *psy,
        struct axp20x_usb_power *power = power_supply_get_drvdata(psy);
 
        /*
-        * The VBUS path select flag works differently on on AXP288 and newer:
+        * The VBUS path select flag works differently on AXP288 and newer:
         *  - On AXP20x and AXP22x, the flag enables VBUS (ignoring N_VBUSEN).
         *  - On AXP288 and AXP8xx, the flag disables VBUS (ignoring N_VBUSEN).
         * We only expose the control on variants where it can be used to force
@@ -525,7 +525,7 @@ static int axp20x_usb_power_resume(struct device *dev)
        while (i < power->num_irqs)
                enable_irq(power->irqs[i++]);
 
-       mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
+       mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME);
 
        return 0;
 }
@@ -647,7 +647,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
 
        INIT_DELAYED_WORK(&power->vbus_detect, axp20x_usb_power_poll_vbus);
        if (axp20x_usb_vbus_needs_polling(power))
-               queue_delayed_work(system_wq, &power->vbus_detect, 0);
+               queue_delayed_work(system_power_efficient_wq, &power->vbus_detect, 0);
 
        return 0;
 }
index 9d981b7..a4df1ea 100644 (file)
@@ -548,14 +548,15 @@ out:
 
 /*
  * The HP Pavilion x2 10 series comes in a number of variants:
- * Bay Trail SoC    + AXP288 PMIC, DMI_BOARD_NAME: "815D"
- * Cherry Trail SoC + AXP288 PMIC, DMI_BOARD_NAME: "813E"
- * Cherry Trail SoC + TI PMIC,     DMI_BOARD_NAME: "827C" or "82F4"
+ * Bay Trail SoC    + AXP288 PMIC, Micro-USB, DMI_BOARD_NAME: "8021"
+ * Bay Trail SoC    + AXP288 PMIC, Type-C,    DMI_BOARD_NAME: "815D"
+ * Cherry Trail SoC + AXP288 PMIC, Type-C,    DMI_BOARD_NAME: "813E"
+ * Cherry Trail SoC + TI PMIC,     Type-C,    DMI_BOARD_NAME: "827C" or "82F4"
  *
- * The variants with the AXP288 PMIC are all kinds of special:
+ * The variants with the AXP288 + Type-C connector are all kinds of special:
  *
- * 1. All variants use a Type-C connector which the AXP288 does not support, so
- * when using a Type-C charger it is not recognized. Unlike most AXP288 devices,
+ * 1. They use a Type-C connector which the AXP288 does not support, so when
+ * using a Type-C charger it is not recognized. Unlike most AXP288 devices,
  * this model actually has mostly working ACPI AC / Battery code, the ACPI code
  * "solves" this by simply setting the input_current_limit to 3A.
  * There are still some issues with the ACPI code, so we use this native driver,
@@ -578,12 +579,17 @@ out:
  */
 static const struct dmi_system_id axp288_hp_x2_dmi_ids[] = {
        {
-               /*
-                * Bay Trail model has "Hewlett-Packard" as sys_vendor, Cherry
-                * Trail model has "HP", so we only match on product_name.
-                */
                .matches = {
-                       DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "815D"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "HP"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "813E"),
                },
        },
        {} /* Terminating entry */
index d141865..4841e14 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/workqueue.h>
-#include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/extcon-provider.h>
 
@@ -448,8 +447,10 @@ static ssize_t bq24190_sysfs_show(struct device *dev,
                return -EINVAL;
 
        ret = pm_runtime_get_sync(bdi->dev);
-       if (ret < 0)
+       if (ret < 0) {
+               pm_runtime_put_noidle(bdi->dev);
                return ret;
+       }
 
        ret = bq24190_read_mask(bdi, info->reg, info->mask, info->shift, &v);
        if (ret)
@@ -1077,8 +1078,10 @@ static int bq24190_charger_get_property(struct power_supply *psy,
        dev_dbg(bdi->dev, "prop: %d\n", psp);
 
        ret = pm_runtime_get_sync(bdi->dev);
-       if (ret < 0)
+       if (ret < 0) {
+               pm_runtime_put_noidle(bdi->dev);
                return ret;
+       }
 
        switch (psp) {
        case POWER_SUPPLY_PROP_CHARGE_TYPE:
@@ -1149,8 +1152,10 @@ static int bq24190_charger_set_property(struct power_supply *psy,
        dev_dbg(bdi->dev, "prop: %d\n", psp);
 
        ret = pm_runtime_get_sync(bdi->dev);
-       if (ret < 0)
+       if (ret < 0) {
+               pm_runtime_put_noidle(bdi->dev);
                return ret;
+       }
 
        switch (psp) {
        case POWER_SUPPLY_PROP_ONLINE:
@@ -1410,8 +1415,10 @@ static int bq24190_battery_get_property(struct power_supply *psy,
        dev_dbg(bdi->dev, "prop: %d\n", psp);
 
        ret = pm_runtime_get_sync(bdi->dev);
-       if (ret < 0)
+       if (ret < 0) {
+               pm_runtime_put_noidle(bdi->dev);
                return ret;
+       }
 
        switch (psp) {
        case POWER_SUPPLY_PROP_STATUS:
@@ -1456,8 +1463,10 @@ static int bq24190_battery_set_property(struct power_supply *psy,
        dev_dbg(bdi->dev, "prop: %d\n", psp);
 
        ret = pm_runtime_get_sync(bdi->dev);
-       if (ret < 0)
+       if (ret < 0) {
+               pm_runtime_put_noidle(bdi->dev);
                return ret;
+       }
 
        switch (psp) {
        case POWER_SUPPLY_PROP_ONLINE:
index 6931e1d..ab2f4bf 100644 (file)
@@ -18,7 +18,6 @@
  */
 
 #include <linux/err.h>
-#include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 34c21c5..945c325 100644 (file)
@@ -299,7 +299,7 @@ static const union {
        /* TODO: BQ25896 has max ICHG 3008 mA */
        [TBL_ICHG] =    { .rt = {0,       5056000, 64000} },     /* uA */
        [TBL_ITERM] =   { .rt = {64000,   1024000, 64000} },     /* uA */
-       [TBL_IILIM] =   { .rt = {50000,   3200000, 50000} },     /* uA */
+       [TBL_IILIM] =   { .rt = {100000,  3250000, 50000} },     /* uA */
        [TBL_VREG] =    { .rt = {3840000, 4608000, 16000} },     /* uV */
        [TBL_BOOSTV] =  { .rt = {4550000, 5510000, 64000} },     /* uV */
        [TBL_SYSVMIN] = { .rt = {3000000, 3700000, 100000} },    /* uV */
index cbd588e..7fb9b54 100644 (file)
@@ -12,7 +12,9 @@
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio/machine.h>
+#include <linux/gpio/consumer.h>
 #include <linux/mfd/ucb1x00.h>
 
 #include <asm/mach/sharpsl_param.h>
@@ -31,18 +33,18 @@ struct collie_bat {
        struct mutex work_lock; /* protects data */
 
        bool (*is_present)(struct collie_bat *bat);
-       int gpio_full;
-       int gpio_charge_on;
+       struct gpio_desc *gpio_full;
+       struct gpio_desc *gpio_charge_on;
 
        int technology;
 
-       int gpio_bat;
+       struct gpio_desc *gpio_bat;
        int adc_bat;
        int adc_bat_divider;
        int bat_max;
        int bat_min;
 
-       int gpio_temp;
+       struct gpio_desc *gpio_temp;
        int adc_temp;
        int adc_temp_divider;
 };
@@ -53,15 +55,15 @@ static unsigned long collie_read_bat(struct collie_bat *bat)
 {
        unsigned long value = 0;
 
-       if (bat->gpio_bat < 0 || bat->adc_bat < 0)
+       if (!bat->gpio_bat || bat->adc_bat < 0)
                return 0;
        mutex_lock(&bat_lock);
-       gpio_set_value(bat->gpio_bat, 1);
+       gpiod_set_value(bat->gpio_bat, 1);
        msleep(5);
        ucb1x00_adc_enable(ucb);
        value = ucb1x00_adc_read(ucb, bat->adc_bat, UCB_SYNC);
        ucb1x00_adc_disable(ucb);
-       gpio_set_value(bat->gpio_bat, 0);
+       gpiod_set_value(bat->gpio_bat, 0);
        mutex_unlock(&bat_lock);
        value = value * 1000000 / bat->adc_bat_divider;
 
@@ -71,16 +73,16 @@ static unsigned long collie_read_bat(struct collie_bat *bat)
 static unsigned long collie_read_temp(struct collie_bat *bat)
 {
        unsigned long value = 0;
-       if (bat->gpio_temp < 0 || bat->adc_temp < 0)
+       if (!bat->gpio_temp || bat->adc_temp < 0)
                return 0;
 
        mutex_lock(&bat_lock);
-       gpio_set_value(bat->gpio_temp, 1);
+       gpiod_set_value(bat->gpio_temp, 1);
        msleep(5);
        ucb1x00_adc_enable(ucb);
        value = ucb1x00_adc_read(ucb, bat->adc_temp, UCB_SYNC);
        ucb1x00_adc_disable(ucb);
-       gpio_set_value(bat->gpio_temp, 0);
+       gpiod_set_value(bat->gpio_temp, 0);
        mutex_unlock(&bat_lock);
 
        value = value * 10000 / bat->adc_temp_divider;
@@ -162,23 +164,23 @@ static void collie_bat_update(struct collie_bat *bat)
                bat->full_chrg = -1;
        } else if (power_supply_am_i_supplied(psy)) {
                if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING) {
-                       gpio_set_value(bat->gpio_charge_on, 1);
+                       gpiod_set_value(bat->gpio_charge_on, 1);
                        mdelay(15);
                }
 
-               if (gpio_get_value(bat->gpio_full)) {
+               if (gpiod_get_value(bat->gpio_full)) {
                        if (old == POWER_SUPPLY_STATUS_CHARGING ||
                                        bat->full_chrg == -1)
                                bat->full_chrg = collie_read_bat(bat);
 
-                       gpio_set_value(bat->gpio_charge_on, 0);
+                       gpiod_set_value(bat->gpio_charge_on, 0);
                        bat->status = POWER_SUPPLY_STATUS_FULL;
                } else {
-                       gpio_set_value(bat->gpio_charge_on, 1);
+                       gpiod_set_value(bat->gpio_charge_on, 1);
                        bat->status = POWER_SUPPLY_STATUS_CHARGING;
                }
        } else {
-               gpio_set_value(bat->gpio_charge_on, 0);
+               gpiod_set_value(bat->gpio_charge_on, 0);
                bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
        }
 
@@ -230,18 +232,18 @@ static struct collie_bat collie_bat_main = {
        .full_chrg = -1,
        .psy = NULL,
 
-       .gpio_full = COLLIE_GPIO_CO,
-       .gpio_charge_on = COLLIE_GPIO_CHARGE_ON,
+       .gpio_full = NULL,
+       .gpio_charge_on = NULL,
 
        .technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
 
-       .gpio_bat = COLLIE_GPIO_MBAT_ON,
+       .gpio_bat = NULL,
        .adc_bat = UCB_ADC_INP_AD1,
        .adc_bat_divider = 155,
        .bat_max = 4310000,
        .bat_min = 1551 * 1000000 / 414,
 
-       .gpio_temp = COLLIE_GPIO_TMP_ON,
+       .gpio_temp = NULL,
        .adc_temp = UCB_ADC_INP_AD0,
        .adc_temp_divider = 10000,
 };
@@ -260,30 +262,24 @@ static struct collie_bat collie_bat_bu = {
        .full_chrg = -1,
        .psy = NULL,
 
-       .gpio_full = -1,
-       .gpio_charge_on = -1,
+       .gpio_full = NULL,
+       .gpio_charge_on = NULL,
 
        .technology = POWER_SUPPLY_TECHNOLOGY_LiMn,
 
-       .gpio_bat = COLLIE_GPIO_BBAT_ON,
+       .gpio_bat = NULL,
        .adc_bat = UCB_ADC_INP_AD1,
        .adc_bat_divider = 155,
        .bat_max = 3000000,
        .bat_min = 1900000,
 
-       .gpio_temp = -1,
+       .gpio_temp = NULL,
        .adc_temp = -1,
        .adc_temp_divider = -1,
 };
 
-static struct gpio collie_batt_gpios[] = {
-       { COLLIE_GPIO_CO,           GPIOF_IN,           "main battery full" },
-       { COLLIE_GPIO_MAIN_BAT_LOW, GPIOF_IN,           "main battery low" },
-       { COLLIE_GPIO_CHARGE_ON,    GPIOF_OUT_INIT_LOW, "main charge on" },
-       { COLLIE_GPIO_MBAT_ON,      GPIOF_OUT_INIT_LOW, "main battery" },
-       { COLLIE_GPIO_TMP_ON,       GPIOF_OUT_INIT_LOW, "main battery temp" },
-       { COLLIE_GPIO_BBAT_ON,      GPIOF_OUT_INIT_LOW, "backup battery" },
-};
+/* Obtained but unused GPIO */
+static struct gpio_desc *collie_mbat_low;
 
 #ifdef CONFIG_PM
 static int wakeup_enabled;
@@ -295,7 +291,7 @@ static int collie_bat_suspend(struct ucb1x00_dev *dev)
 
        if (device_may_wakeup(&dev->ucb->dev) &&
            collie_bat_main.status == POWER_SUPPLY_STATUS_CHARGING)
-               wakeup_enabled = !enable_irq_wake(gpio_to_irq(COLLIE_GPIO_CO));
+               wakeup_enabled = !enable_irq_wake(gpiod_to_irq(collie_bat_main.gpio_full));
        else
                wakeup_enabled = 0;
 
@@ -305,7 +301,7 @@ static int collie_bat_suspend(struct ucb1x00_dev *dev)
 static int collie_bat_resume(struct ucb1x00_dev *dev)
 {
        if (wakeup_enabled)
-               disable_irq_wake(gpio_to_irq(COLLIE_GPIO_CO));
+               disable_irq_wake(gpiod_to_irq(collie_bat_main.gpio_full));
 
        /* things may have changed while we were away */
        schedule_work(&bat_work);
@@ -320,16 +316,71 @@ static int collie_bat_probe(struct ucb1x00_dev *dev)
 {
        int ret;
        struct power_supply_config psy_main_cfg = {}, psy_bu_cfg = {};
+       struct gpio_chip *gc = &dev->ucb->gpio;
 
        if (!machine_is_collie())
                return -ENODEV;
 
        ucb = dev->ucb;
 
-       ret = gpio_request_array(collie_batt_gpios,
-                                ARRAY_SIZE(collie_batt_gpios));
-       if (ret)
-               return ret;
+       /* Obtain all the main battery GPIOs */
+       collie_bat_main.gpio_full = gpiod_get(&dev->ucb->dev,
+                                             "main battery full",
+                                             GPIOD_IN);
+       if (IS_ERR(collie_bat_main.gpio_full))
+               return PTR_ERR(collie_bat_main.gpio_full);
+
+       collie_mbat_low = gpiod_get(&dev->ucb->dev,
+                                   "main battery low",
+                                   GPIOD_IN);
+       if (IS_ERR(collie_mbat_low)) {
+               ret = PTR_ERR(collie_mbat_low);
+               goto err_put_gpio_full;
+       }
+
+       collie_bat_main.gpio_charge_on = gpiod_get(&dev->ucb->dev,
+                                                  "main charge on",
+                                                  GPIOD_OUT_LOW);
+       if (IS_ERR(collie_bat_main.gpio_charge_on)) {
+               ret = PTR_ERR(collie_bat_main.gpio_charge_on);
+               goto err_put_mbat_low;
+       }
+
+       /* COLLIE_GPIO_MBAT_ON = GPIO 7 on the UCB (TC35143) */
+       collie_bat_main.gpio_bat = gpiochip_request_own_desc(gc,
+                                               7,
+                                               "main battery",
+                                               GPIO_ACTIVE_HIGH,
+                                               GPIOD_OUT_LOW);
+       if (IS_ERR(collie_bat_main.gpio_bat)) {
+               ret = PTR_ERR(collie_bat_main.gpio_bat);
+               goto err_put_gpio_charge_on;
+       }
+
+       /* COLLIE_GPIO_TMP_ON = GPIO 9 on the UCB (TC35143) */
+       collie_bat_main.gpio_temp = gpiochip_request_own_desc(gc,
+                                               9,
+                                               "main battery temp",
+                                               GPIO_ACTIVE_HIGH,
+                                               GPIOD_OUT_LOW);
+       if (IS_ERR(collie_bat_main.gpio_temp)) {
+               ret = PTR_ERR(collie_bat_main.gpio_temp);
+               goto err_free_gpio_bat;
+       }
+
+       /*
+        * Obtain the backup battery COLLIE_GPIO_BBAT_ON which is
+        * GPIO 8 on the UCB (TC35143)
+        */
+       collie_bat_bu.gpio_bat = gpiochip_request_own_desc(gc,
+                                               8,
+                                               "backup battery",
+                                               GPIO_ACTIVE_HIGH,
+                                               GPIOD_OUT_LOW);
+       if (IS_ERR(collie_bat_bu.gpio_bat)) {
+               ret = PTR_ERR(collie_bat_bu.gpio_bat);
+               goto err_free_gpio_temp;
+       }
 
        mutex_init(&collie_bat_main.work_lock);
 
@@ -370,27 +421,43 @@ err_irq:
 err_psy_reg_bu:
        power_supply_unregister(collie_bat_main.psy);
 err_psy_reg_main:
-
        /* see comment in collie_bat_remove */
        cancel_work_sync(&bat_work);
-       gpio_free_array(collie_batt_gpios, ARRAY_SIZE(collie_batt_gpios));
+       gpiochip_free_own_desc(collie_bat_bu.gpio_bat);
+err_free_gpio_temp:
+       gpiochip_free_own_desc(collie_bat_main.gpio_temp);
+err_free_gpio_bat:
+       gpiochip_free_own_desc(collie_bat_main.gpio_bat);
+err_put_gpio_charge_on:
+       gpiod_put(collie_bat_main.gpio_charge_on);
+err_put_mbat_low:
+       gpiod_put(collie_mbat_low);
+err_put_gpio_full:
+       gpiod_put(collie_bat_main.gpio_full);
+
        return ret;
 }
 
 static void collie_bat_remove(struct ucb1x00_dev *dev)
 {
        free_irq(gpio_to_irq(COLLIE_GPIO_CO), &collie_bat_main);
-
        power_supply_unregister(collie_bat_bu.psy);
        power_supply_unregister(collie_bat_main.psy);
 
+       /* These are obtained from the machine */
+       gpiod_put(collie_bat_main.gpio_full);
+       gpiod_put(collie_mbat_low);
+       gpiod_put(collie_bat_main.gpio_charge_on);
+       /* These are directly from the UCB so let's free them */
+       gpiochip_free_own_desc(collie_bat_main.gpio_bat);
+       gpiochip_free_own_desc(collie_bat_main.gpio_temp);
+       gpiochip_free_own_desc(collie_bat_bu.gpio_bat);
        /*
         * Now cancel the bat_work.  We won't get any more schedules,
         * since all sources (isr and external_power_changed) are
         * unregistered now.
         */
        cancel_work_sync(&bat_work);
-       gpio_free_array(collie_batt_gpios, ARRAY_SIZE(collie_batt_gpios));
 }
 
 static struct ucb1x00_driver collie_bat_driver = {
index caa8297..0032069 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/power_supply.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/err.h>
 #include <linux/timer.h>
 #include <linux/jiffies.h>
@@ -52,6 +52,7 @@ struct gab {
        int     level;
        int     status;
        bool cable_plugged;
+       struct gpio_desc *charge_finished;
 };
 
 static struct gab *to_generic_bat(struct power_supply *psy)
@@ -91,13 +92,9 @@ static const enum power_supply_property gab_dyn_props[] = {
 
 static bool gab_charge_finished(struct gab *adc_bat)
 {
-       struct gab_platform_data *pdata = adc_bat->pdata;
-       bool ret = gpio_get_value(pdata->gpio_charge_finished);
-       bool inv = pdata->gpio_inverted;
-
-       if (!gpio_is_valid(pdata->gpio_charge_finished))
+       if (!adc_bat->charge_finished)
                return false;
-       return ret ^ inv;
+       return gpiod_get_value(adc_bat->charge_finished);
 }
 
 static int gab_get_status(struct gab *adc_bat)
@@ -327,18 +324,17 @@ static int gab_probe(struct platform_device *pdev)
 
        INIT_DELAYED_WORK(&adc_bat->bat_work, gab_work);
 
-       if (gpio_is_valid(pdata->gpio_charge_finished)) {
+       adc_bat->charge_finished = devm_gpiod_get_optional(&pdev->dev,
+                                                          "charged", GPIOD_IN);
+       if (adc_bat->charge_finished) {
                int irq;
-               ret = gpio_request(pdata->gpio_charge_finished, "charged");
-               if (ret)
-                       goto gpio_req_fail;
 
-               irq = gpio_to_irq(pdata->gpio_charge_finished);
+               irq = gpiod_to_irq(adc_bat->charge_finished);
                ret = request_any_context_irq(irq, gab_charged,
                                IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                                "battery charged", adc_bat);
                if (ret < 0)
-                       goto err_gpio;
+                       goto gpio_req_fail;
        }
 
        platform_set_drvdata(pdev, adc_bat);
@@ -348,8 +344,6 @@ static int gab_probe(struct platform_device *pdev)
                        msecs_to_jiffies(0));
        return 0;
 
-err_gpio:
-       gpio_free(pdata->gpio_charge_finished);
 gpio_req_fail:
        power_supply_unregister(adc_bat->psy);
 err_reg_fail:
@@ -367,14 +361,11 @@ static int gab_remove(struct platform_device *pdev)
 {
        int chan;
        struct gab *adc_bat = platform_get_drvdata(pdev);
-       struct gab_platform_data *pdata = adc_bat->pdata;
 
        power_supply_unregister(adc_bat->psy);
 
-       if (gpio_is_valid(pdata->gpio_charge_finished)) {
-               free_irq(gpio_to_irq(pdata->gpio_charge_finished), adc_bat);
-               gpio_free(pdata->gpio_charge_finished);
-       }
+       if (adc_bat->charge_finished)
+               free_irq(gpiod_to_irq(adc_bat->charge_finished), adc_bat);
 
        for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) {
                if (adc_bat->channel[chan])
index f284547..79d4b59 100644 (file)
@@ -78,6 +78,7 @@ static enum power_supply_property max17042_battery_props[] = {
        POWER_SUPPLY_PROP_CHARGE_FULL,
        POWER_SUPPLY_PROP_CHARGE_NOW,
        POWER_SUPPLY_PROP_CHARGE_COUNTER,
+       POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
        POWER_SUPPLY_PROP_TEMP,
        POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
        POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
@@ -85,9 +86,10 @@ static enum power_supply_property max17042_battery_props[] = {
        POWER_SUPPLY_PROP_TEMP_MAX,
        POWER_SUPPLY_PROP_HEALTH,
        POWER_SUPPLY_PROP_SCOPE,
+       POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
+       // these two have to be at the end on the list
        POWER_SUPPLY_PROP_CURRENT_NOW,
        POWER_SUPPLY_PROP_CURRENT_AVG,
-       POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
 };
 
 static int max17042_get_temperature(struct max17042_chip *chip, int *temp)
@@ -353,7 +355,8 @@ static int max17042_get_property(struct power_supply *psy,
                if (ret < 0)
                        return ret;
 
-               val->intval = data * 1000 / 2;
+               data64 = sign_extend64(data, 15) * 5000000ll;
+               val->intval = div_s64(data64, chip->pdata->r_sns);
                break;
        case POWER_SUPPLY_PROP_TEMP:
                ret = max17042_get_temperature(chip, &val->intval);
@@ -394,8 +397,8 @@ static int max17042_get_property(struct power_supply *psy,
                        if (ret < 0)
                                return ret;
 
-                       val->intval = sign_extend32(data, 15);
-                       val->intval *= 1562500 / chip->pdata->r_sns;
+                       data64 = sign_extend64(data, 15) * 1562500ll;
+                       val->intval = div_s64(data64, chip->pdata->r_sns);
                } else {
                        return -EINVAL;
                }
@@ -406,12 +409,20 @@ static int max17042_get_property(struct power_supply *psy,
                        if (ret < 0)
                                return ret;
 
-                       val->intval = sign_extend32(data, 15);
-                       val->intval *= 1562500 / chip->pdata->r_sns;
+                       data64 = sign_extend64(data, 15) * 1562500ll;
+                       val->intval = div_s64(data64, chip->pdata->r_sns);
                } else {
                        return -EINVAL;
                }
                break;
+       case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+               ret = regmap_read(map, MAX17042_ICHGTerm, &data);
+               if (ret < 0)
+                       return ret;
+
+               data64 = data * 1562500ll;
+               val->intval = div_s64(data64, chip->pdata->r_sns);
+               break;
        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
                ret = regmap_read(map, MAX17042_TTE, &data);
                if (ret < 0)
index f5e84cd..1947af2 100644 (file)
 #include <linux/mfd/max8997.h>
 #include <linux/mfd/max8997-private.h>
 
+/* MAX8997_REG_STATUS4 */
+#define DCINOK_SHIFT           1
+#define DCINOK_MASK            (1 << DCINOK_SHIFT)
+#define DETBAT_SHIFT           2
+#define DETBAT_MASK            (1 << DETBAT_SHIFT)
+
+/* MAX8997_REG_MBCCTRL1 */
+#define TFCH_SHIFT             4
+#define TFCH_MASK              (7 << TFCH_SHIFT)
+
+/* MAX8997_REG_MBCCTRL5 */
+#define ITOPOFF_SHIFT          0
+#define ITOPOFF_MASK           (0xF << ITOPOFF_SHIFT)
+
 struct charger_data {
        struct device *dev;
        struct max8997_dev *iodev;
@@ -20,7 +34,7 @@ struct charger_data {
 };
 
 static enum power_supply_property max8997_battery_props[] = {
-       POWER_SUPPLY_PROP_STATUS, /* "FULL" or "NOT FULL" only. */
+       POWER_SUPPLY_PROP_STATUS, /* "FULL", "CHARGING" or "DISCHARGING". */
        POWER_SUPPLY_PROP_PRESENT, /* the presence of battery */
        POWER_SUPPLY_PROP_ONLINE, /* charger is active or not */
 };
@@ -43,6 +57,10 @@ static int max8997_battery_get_property(struct power_supply *psy,
                        return ret;
                if ((reg & (1 << 0)) == 0x1)
                        val->intval = POWER_SUPPLY_STATUS_FULL;
+               else if ((reg & DCINOK_MASK))
+                       val->intval = POWER_SUPPLY_STATUS_CHARGING;
+               else
+                       val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
 
                break;
        case POWER_SUPPLY_PROP_PRESENT:
@@ -50,7 +68,7 @@ static int max8997_battery_get_property(struct power_supply *psy,
                ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
                if (ret)
                        return ret;
-               if ((reg & (1 << 2)) == 0x0)
+               if ((reg & DETBAT_MASK) == 0x0)
                        val->intval = 1;
 
                break;
@@ -59,8 +77,7 @@ static int max8997_battery_get_property(struct power_supply *psy,
                ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
                if (ret)
                        return ret;
-               /* DCINOK */
-               if (reg & (1 << 1))
+               if (reg & DCINOK_MASK)
                        val->intval = 1;
 
                break;
@@ -84,11 +101,14 @@ static int max8997_battery_probe(struct platform_device *pdev)
        int ret = 0;
        struct charger_data *charger;
        struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
-       struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
+       struct i2c_client *i2c = iodev->i2c;
+       struct max8997_platform_data *pdata = iodev->pdata;
        struct power_supply_config psy_cfg = {};
 
-       if (!pdata)
+       if (!pdata) {
+               dev_err(&pdev->dev, "No platform data supplied.\n");
                return -EINVAL;
+       }
 
        if (pdata->eoc_mA) {
                int val = (pdata->eoc_mA - 50) / 10;
@@ -97,30 +117,29 @@ static int max8997_battery_probe(struct platform_device *pdev)
                if (val > 0xf)
                        val = 0xf;
 
-               ret = max8997_update_reg(iodev->i2c,
-                               MAX8997_REG_MBCCTRL5, val, 0xf);
+               ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL5,
+                               val << ITOPOFF_SHIFT, ITOPOFF_MASK);
                if (ret < 0) {
                        dev_err(&pdev->dev, "Cannot use i2c bus.\n");
                        return ret;
                }
        }
-
        switch (pdata->timeout) {
        case 5:
-               ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
-                               0x2 << 4, 0x7 << 4);
+               ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL1,
+                               0x2 << TFCH_SHIFT, TFCH_MASK);
                break;
        case 6:
-               ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
-                               0x3 << 4, 0x7 << 4);
+               ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL1,
+                               0x3 << TFCH_SHIFT, TFCH_MASK);
                break;
        case 7:
-               ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
-                               0x4 << 4, 0x7 << 4);
+               ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL1,
+                               0x4 << TFCH_SHIFT, TFCH_MASK);
                break;
        case 0:
-               ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
-                               0x7 << 4, 0x7 << 4);
+               ret = max8997_update_reg(i2c, MAX8997_REG_MBCCTRL1,
+                               0x7 << TFCH_SHIFT, TFCH_MASK);
                break;
        default:
                dev_err(&pdev->dev, "incorrect timeout value (%d)\n",
@@ -138,7 +157,6 @@ static int max8997_battery_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, charger);
 
-
        charger->dev = &pdev->dev;
        charger->iodev = iodev;
 
@@ -168,18 +186,7 @@ static struct platform_driver max8997_battery_driver = {
        .probe = max8997_battery_probe,
        .id_table = max8997_battery_id,
 };
-
-static int __init max8997_battery_init(void)
-{
-       return platform_driver_register(&max8997_battery_driver);
-}
-subsys_initcall(max8997_battery_init);
-
-static void __exit max8997_battery_cleanup(void)
-{
-       platform_driver_unregister(&max8997_battery_driver);
-}
-module_exit(max8997_battery_cleanup);
+module_platform_driver(max8997_battery_driver);
 
 MODULE_DESCRIPTION("MAXIM 8997/8966 battery control driver");
 MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
index 2df6a24..ac06ecf 100644 (file)
@@ -455,7 +455,6 @@ static int pm2_int_reg4(void *pm2_data, int val)
 static int pm2_int_reg5(void *pm2_data, int val)
 {
        struct pm2xxx_charger *pm2 = pm2_data;
-       int ret = 0;
 
        if (val & (PM2XXX_INT6_ITVPWR2DROP | PM2XXX_INT6_ITVPWR1DROP)) {
                dev_dbg(pm2->dev, "VMPWR drop to VBAT level\n");
@@ -468,7 +467,7 @@ static int pm2_int_reg5(void *pm2_data, int val)
                dev_dbg(pm2->dev, "Falling/Rising edge on WPWR1/2\n");
        }
 
-       return ret;
+       return 0;
 }
 
 static irqreturn_t  pm2xxx_irq_int(int irq, void *data)
index a616b9d..92dd631 100644 (file)
@@ -402,7 +402,7 @@ void power_supply_init_attrs(struct device_type *dev_type)
                struct device_attribute *attr;
 
                if (!power_supply_attrs[i].prop_name) {
-                       pr_warn("%s: Property %d skipped because is is missing from power_supply_attrs\n",
+                       pr_warn("%s: Property %d skipped because it is missing from power_supply_attrs\n",
                                __func__, i);
                        sprintf(power_supply_attrs[i].attr_name, "_err_%d", i);
                } else {
index 60b7f41..a2addc2 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/platform_device.h>
 #include <linux/power_supply.h>
 #include <linux/leds.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/err.h>
 #include <linux/timer.h>
 #include <linux/jiffies.h>
@@ -31,6 +31,7 @@ struct s3c_adc_bat {
        struct power_supply             *psy;
        struct s3c_adc_client           *client;
        struct s3c_adc_bat_pdata        *pdata;
+       struct gpio_desc                *charge_finished;
        int                             volt_value;
        int                             cur_value;
        unsigned int                    timestamp;
@@ -132,9 +133,7 @@ static int calc_full_volt(int volt_val, int cur_val, int impedance)
 
 static int charge_finished(struct s3c_adc_bat *bat)
 {
-       return bat->pdata->gpio_inverted ?
-               !gpio_get_value(bat->pdata->gpio_charge_finished) :
-               gpio_get_value(bat->pdata->gpio_charge_finished);
+       return gpiod_get_value(bat->charge_finished);
 }
 
 static int s3c_adc_bat_get_property(struct power_supply *psy,
@@ -169,7 +168,7 @@ static int s3c_adc_bat_get_property(struct power_supply *psy,
        }
 
        if (bat->cable_plugged &&
-               ((bat->pdata->gpio_charge_finished < 0) ||
+               (!bat->charge_finished ||
                !charge_finished(bat))) {
                lut = bat->pdata->lut_acin;
                lut_size = bat->pdata->lut_acin_cnt;
@@ -206,7 +205,7 @@ static int s3c_adc_bat_get_property(struct power_supply *psy,
 
        switch (psp) {
        case POWER_SUPPLY_PROP_STATUS:
-               if (bat->pdata->gpio_charge_finished < 0)
+               if (!bat->charge_finished)
                        val->intval = bat->level == 100000 ?
                                POWER_SUPPLY_STATUS_FULL : bat->status;
                else
@@ -265,7 +264,7 @@ static void s3c_adc_bat_work(struct work_struct *work)
                        bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
                }
        } else {
-               if ((bat->pdata->gpio_charge_finished >= 0) && is_plugged) {
+               if (bat->charge_finished && is_plugged) {
                        is_charged = charge_finished(&main_bat);
                        if (is_charged) {
                                if (bat->pdata->disable_charger)
@@ -294,6 +293,7 @@ static int s3c_adc_bat_probe(struct platform_device *pdev)
        struct s3c_adc_client   *client;
        struct s3c_adc_bat_pdata *pdata = pdev->dev.platform_data;
        struct power_supply_config psy_cfg = {};
+       struct gpio_desc *gpiod;
        int ret;
 
        client = s3c_adc_register(pdev, NULL, NULL, 0);
@@ -304,8 +304,17 @@ static int s3c_adc_bat_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, client);
 
+       gpiod = devm_gpiod_get_optional(&pdev->dev, "charge-status", GPIOD_IN);
+       if (IS_ERR(gpiod)) {
+               /* Could be probe deferral etc */
+               ret = PTR_ERR(gpiod);
+               dev_err(&pdev->dev, "no GPIO %d\n", ret);
+               return ret;
+       }
+
        main_bat.client = client;
        main_bat.pdata = pdata;
+       main_bat.charge_finished = gpiod;
        main_bat.volt_value = -1;
        main_bat.cur_value = -1;
        main_bat.cable_plugged = 0;
@@ -323,6 +332,7 @@ static int s3c_adc_bat_probe(struct platform_device *pdev)
 
                backup_bat.client = client;
                backup_bat.pdata = pdev->dev.platform_data;
+               backup_bat.charge_finished = gpiod;
                backup_bat.volt_value = -1;
                backup_bat.psy = power_supply_register(&pdev->dev,
                                                       &backup_bat_desc,
@@ -335,12 +345,8 @@ static int s3c_adc_bat_probe(struct platform_device *pdev)
 
        INIT_DELAYED_WORK(&bat_work, s3c_adc_bat_work);
 
-       if (pdata->gpio_charge_finished >= 0) {
-               ret = gpio_request(pdata->gpio_charge_finished, "charged");
-               if (ret)
-                       goto err_gpio;
-
-               ret = request_irq(gpio_to_irq(pdata->gpio_charge_finished),
+       if (gpiod) {
+               ret = request_irq(gpiod_to_irq(gpiod),
                                s3c_adc_bat_charged,
                                IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                                "battery charged", NULL);
@@ -364,12 +370,9 @@ static int s3c_adc_bat_probe(struct platform_device *pdev)
        return 0;
 
 err_platform:
-       if (pdata->gpio_charge_finished >= 0)
-               free_irq(gpio_to_irq(pdata->gpio_charge_finished), NULL);
+       if (gpiod)
+               free_irq(gpiod_to_irq(gpiod), NULL);
 err_irq:
-       if (pdata->gpio_charge_finished >= 0)
-               gpio_free(pdata->gpio_charge_finished);
-err_gpio:
        if (pdata->backup_volt_mult)
                power_supply_unregister(backup_bat.psy);
 err_reg_backup:
@@ -389,10 +392,8 @@ static int s3c_adc_bat_remove(struct platform_device *pdev)
 
        s3c_adc_release(client);
 
-       if (pdata->gpio_charge_finished >= 0) {
-               free_irq(gpio_to_irq(pdata->gpio_charge_finished), NULL);
-               gpio_free(pdata->gpio_charge_finished);
-       }
+       if (main_bat.charge_finished)
+               free_irq(gpiod_to_irq(main_bat.charge_finished), NULL);
 
        cancel_delayed_work(&bat_work);
 
@@ -408,12 +409,12 @@ static int s3c_adc_bat_suspend(struct platform_device *pdev,
 {
        struct s3c_adc_bat_pdata *pdata = pdev->dev.platform_data;
 
-       if (pdata->gpio_charge_finished >= 0) {
+       if (main_bat.charge_finished) {
                if (device_may_wakeup(&pdev->dev))
                        enable_irq_wake(
-                               gpio_to_irq(pdata->gpio_charge_finished));
+                               gpiod_to_irq(main_bat.charge_finished));
                else {
-                       disable_irq(gpio_to_irq(pdata->gpio_charge_finished));
+                       disable_irq(gpiod_to_irq(main_bat.charge_finished));
                        main_bat.pdata->disable_charger();
                }
        }
@@ -425,12 +426,12 @@ static int s3c_adc_bat_resume(struct platform_device *pdev)
 {
        struct s3c_adc_bat_pdata *pdata = pdev->dev.platform_data;
 
-       if (pdata->gpio_charge_finished >= 0) {
+       if (main_bat.charge_finished) {
                if (device_may_wakeup(&pdev->dev))
                        disable_irq_wake(
-                               gpio_to_irq(pdata->gpio_charge_finished));
+                               gpiod_to_irq(main_bat.charge_finished));
                else
-                       enable_irq(gpio_to_irq(pdata->gpio_charge_finished));
+                       enable_irq(gpiod_to_irq(main_bat.charge_finished));
        }
 
        /* Schedule timer to check current status */
index 18b33f1..4cd2dd8 100644 (file)
@@ -668,7 +668,6 @@ static int wm831x_power_probe(struct platform_device *pdev)
                fallthrough;
        case -EPROBE_DEFER:
                goto err_bat_irq;
-               break;
        }
 
        return ret;
index 40f9c76..c68cbf3 100644 (file)
  * @battery_info:         recommended structure to specify static power supply
  *                        parameters
  * @cal_charge:           calculate charge level.
- * @gpio_charge_finished: gpio for the charger.
- * @gpio_inverted:        Should be 1 if the GPIO is active low otherwise 0
  * @jitter_delay:         delay required after the interrupt to check battery
  *                       status.Default set is 10ms.
  */
 struct gab_platform_data {
        struct power_supply_info battery_info;
        int     (*cal_charge)(long value);
-       int     gpio_charge_finished;
-       bool    gpio_inverted;
        int     jitter_delay;
 };
 
index 833871d..57f982c 100644 (file)
@@ -14,9 +14,6 @@ struct s3c_adc_bat_pdata {
        void (*enable_charger)(void);
        void (*disable_charger)(void);
 
-       int gpio_charge_finished;
-       int gpio_inverted;
-
        const struct s3c_adc_bat_thresh *lut_noac;
        unsigned int lut_noac_cnt;
        const struct s3c_adc_bat_thresh *lut_acin;