Merge tag 'for-v4.12-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 12 May 2017 19:02:21 +0000 (12:02 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 12 May 2017 19:02:21 +0000 (12:02 -0700)
Pull more power-supply updates from Sebastian Reichel:
 "The power-supply subsystem has a few more changes for the v4.12 merge
  window:

   - New battery driver for AXP20X and AXP22X PMICs

   - Improve max17042_battery for usage on x86

   - Misc small cleanups & fixes"

* tag 'for-v4.12-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (34 commits)
  power: supply: cpcap-charger: Keep trickle charger bits disabled
  power: supply: cpcap-charger: Fix enable for 3.8V charge setting
  power: supply: cpcap-charger: Fix charge voltage configuration
  power: supply: cpcap-charger: Fix charger name
  power: supply: twl4030-charger: make twl4030_bci_property_is_writeable static
  power: supply: sbs-battery: Add alert callback
  mailmap: add Sebastian Reichel
  power: supply: avoid unused twl4030-madc.h
  power: supply: sbs-battery: Correct supply status with current draw
  power: supply: sbs-battery: Don't ignore the first external power change
  power: supply: pda_power: move from timer to delayed_work
  power: supply: max17042_battery: Add support for the SCOPE property
  power: supply: max17042_battery: Add support for the CHARGE_NOW property
  power: supply: max17042_battery: Add support for the CHARGE_FULL_DESIGN property
  power: supply: max17042_battery: mAh readings depend on r_sns value
  power: supply: max17042_battery: Add support for the VOLT_MIN property
  power: supply: max17042_battery: Add support for the TECHNOLOGY attribute
  power: supply: max17042_battery: Add external_power_changed callback
  power: supply: max17042_battery: Add support for the STATUS property
  power: supply: max17042_battery: Add default platform_data fallback data
  ...

18 files changed:
.mailmap
Documentation/devicetree/bindings/power/supply/axp20x_battery.txt [new file with mode: 0644]
drivers/power/supply/Kconfig
drivers/power/supply/Makefile
drivers/power/supply/ab8500_charger.c
drivers/power/supply/axp20x_battery.c [new file with mode: 0644]
drivers/power/supply/bq24190_charger.c
drivers/power/supply/cpcap-charger.c
drivers/power/supply/generic-adc-battery.c
drivers/power/supply/isp1704_charger.c
drivers/power/supply/max17042_battery.c
drivers/power/supply/pda_power.c
drivers/power/supply/power_supply_core.c
drivers/power/supply/rx51_battery.c
drivers/power/supply/sbs-battery.c
drivers/power/supply/twl4030_charger.c
drivers/power/supply/twl4030_madc_battery.c
include/linux/power/max17042_battery.h

index d2aeb146efed7991391841aff9ab21e567b886ec..5273cfd70ad62996ba8374698fb5e22e91d33f45 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -146,6 +146,8 @@ Santosh Shilimkar <ssantosh@kernel.org>
 Santosh Shilimkar <santosh.shilimkar@oracle.org>
 Sascha Hauer <s.hauer@pengutronix.de>
 S.Çağlar Onur <caglar@pardus.org.tr>
+Sebastian Reichel <sre@kernel.org> <sre@debian.org>
+Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk>
 Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com>
 Shuah Khan <shuah@kernel.org> <shuahkhan@gmail.com>
 Shuah Khan <shuah@kernel.org> <shuah.khan@hp.com>
diff --git a/Documentation/devicetree/bindings/power/supply/axp20x_battery.txt b/Documentation/devicetree/bindings/power/supply/axp20x_battery.txt
new file mode 100644 (file)
index 0000000..c248866
--- /dev/null
@@ -0,0 +1,20 @@
+AXP20x and AXP22x battery power supply
+
+Required Properties:
+ - compatible, one of:
+                       "x-powers,axp209-battery-power-supply"
+                       "x-powers,axp221-battery-power-supply"
+
+This node is a subnode of the axp20x/axp22x PMIC.
+
+The AXP20X and AXP22X can read the battery voltage, charge and discharge
+currents of the battery by reading ADC channels from the AXP20X/AXP22X
+ADC.
+
+Example:
+
+&axp209 {
+       battery_power_supply: battery-power-supply {
+               compatible = "x-powers,axp209-battery-power-supply";
+       }
+};
index da922756149fd7e2490f3e786e27f02f6d68dde4..86f40bf37c349d55b4899a4ff0edb9d11bf17542 100644 (file)
@@ -238,6 +238,26 @@ config CHARGER_AXP20X
          This driver can also be built as a module. If so, the module will be
          called axp20x_ac_power.
 
+config BATTERY_AXP20X
+       tristate "X-Powers AXP20X battery driver"
+       depends on MFD_AXP20X
+       depends on AXP20X_ADC
+       depends on IIO
+       help
+         Say Y here to enable support for X-Powers AXP20X PMICs' battery power
+         supply.
+
+         This driver can also be built as a module. If so, the module will be
+         called axp20x_battery.
+
+config AXP20X_POWER
+       tristate "AXP20x power supply driver"
+       depends on MFD_AXP20X
+       depends on IIO
+       help
+         This driver provides support for the power supply features of
+         AXP20x PMIC.
+
 config AXP288_CHARGER
        tristate "X-Powers AXP288 Charger"
        depends on MFD_AXP20X && EXTCON_AXP288
@@ -541,11 +561,4 @@ config CHARGER_RT9455
        help
          Say Y to enable support for Richtek RT9455 battery charger.
 
-config AXP20X_POWER
-       tristate "AXP20x power supply driver"
-       depends on MFD_AXP20X
-       help
-         This driver provides support for the power supply features of
-         AXP20x PMIC.
-
 endif # POWER_SUPPLY
index 39fc733e6cc4dc2dc7fde75f3525ed3c2aebeacd..a39126d7a6ce0364840d625c66d2c0508e7dceaf 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_TEST_POWER)      += test_power.o
 
 obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o
 obj-$(CONFIG_BATTERY_ACT8945A) += act8945a_charger.o
+obj-$(CONFIG_BATTERY_AXP20X)   += axp20x_battery.o
 obj-$(CONFIG_CHARGER_AXP20X)   += axp20x_ac_power.o
 obj-$(CONFIG_BATTERY_DS2760)   += ds2760_battery.o
 obj-$(CONFIG_BATTERY_DS2780)   += ds2780_battery.o
index 5cee9aa87aa338b3e310c136317850e47e62d9cd..4ebbcce45c48407a69ae10d177a786d7f7d52ec7 100644 (file)
@@ -3238,7 +3238,7 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di)
                        BUS_PP_PRECHG_CURRENT_MASK, 0);
                if (ret) {
                        dev_err(di->dev,
-                               "failed to setup usb power path prechage current\n");
+                               "failed to setup usb power path precharge current\n");
                        goto out;
                }
        }
diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c
new file mode 100644 (file)
index 0000000..5d29b2e
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * Battery power supply driver for X-Powers AXP20X and AXP22X PMICs
+ *
+ * Copyright 2016 Free Electrons NextThing Co.
+ *     Quentin Schulz <quentin.schulz@free-electrons.com>
+ *
+ * This driver is based on a previous upstreaming attempt by:
+ *     Bruno Prémont <bonbons@linux-vserver.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/consumer.h>
+#include <linux/mfd/axp20x.h>
+
+#define AXP20X_PWR_STATUS_BAT_CHARGING BIT(2)
+
+#define AXP20X_PWR_OP_BATT_PRESENT     BIT(5)
+#define AXP20X_PWR_OP_BATT_ACTIVATED   BIT(3)
+
+#define AXP209_FG_PERCENT              GENMASK(6, 0)
+#define AXP22X_FG_VALID                        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)
+#define AXP20X_CHRG_CTRL1_TGT_4_2V     (2 << 5)
+#define AXP20X_CHRG_CTRL1_TGT_4_36V    (3 << 5)
+
+#define AXP22X_CHRG_CTRL1_TGT_4_22V    (1 << 5)
+#define AXP22X_CHRG_CTRL1_TGT_4_24V    (3 << 5)
+
+#define AXP20X_CHRG_CTRL1_TGT_CURR     GENMASK(3, 0)
+
+#define AXP20X_V_OFF_MASK              GENMASK(2, 0)
+
+struct axp20x_batt_ps {
+       struct regmap *regmap;
+       struct power_supply *batt;
+       struct device *dev;
+       struct iio_channel *batt_chrg_i;
+       struct iio_channel *batt_dischrg_i;
+       struct iio_channel *batt_v;
+       u8 axp_id;
+};
+
+static int axp20x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
+                                         int *val)
+{
+       int ret, reg;
+
+       ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, &reg);
+       if (ret)
+               return ret;
+
+       switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) {
+       case AXP20X_CHRG_CTRL1_TGT_4_1V:
+               *val = 4100000;
+               break;
+       case AXP20X_CHRG_CTRL1_TGT_4_15V:
+               *val = 4150000;
+               break;
+       case AXP20X_CHRG_CTRL1_TGT_4_2V:
+               *val = 4200000;
+               break;
+       case AXP20X_CHRG_CTRL1_TGT_4_36V:
+               *val = 4360000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int axp22x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
+                                         int *val)
+{
+       int ret, reg;
+
+       ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, &reg);
+       if (ret)
+               return ret;
+
+       switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) {
+       case AXP20X_CHRG_CTRL1_TGT_4_1V:
+               *val = 4100000;
+               break;
+       case AXP20X_CHRG_CTRL1_TGT_4_2V:
+               *val = 4200000;
+               break;
+       case AXP22X_CHRG_CTRL1_TGT_4_22V:
+               *val = 4220000;
+               break;
+       case AXP22X_CHRG_CTRL1_TGT_4_24V:
+               *val = 4240000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void raw_to_constant_charge_current(struct axp20x_batt_ps *axp, int *val)
+{
+       if (axp->axp_id == AXP209_ID)
+               *val = *val * 100000 + 300000;
+       else
+               *val = *val * 150000 + 300000;
+}
+
+static int axp20x_get_constant_charge_current(struct axp20x_batt_ps *axp,
+                                             int *val)
+{
+       int ret;
+
+       ret = regmap_read(axp->regmap, AXP20X_CHRG_CTRL1, val);
+       if (ret)
+               return ret;
+
+       *val &= AXP20X_CHRG_CTRL1_TGT_CURR;
+
+       raw_to_constant_charge_current(axp, val);
+
+       return 0;
+}
+
+static int axp20x_battery_get_prop(struct power_supply *psy,
+                                  enum power_supply_property psp,
+                                  union power_supply_propval *val)
+{
+       struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy);
+       struct iio_channel *chan;
+       int ret = 0, reg, val1;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_PRESENT:
+       case POWER_SUPPLY_PROP_ONLINE:
+               ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE,
+                                 &reg);
+               if (ret)
+                       return ret;
+
+               val->intval = !!(reg & AXP20X_PWR_OP_BATT_PRESENT);
+               break;
+
+       case POWER_SUPPLY_PROP_STATUS:
+               ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_INPUT_STATUS,
+                                 &reg);
+               if (ret)
+                       return ret;
+
+               if (reg & AXP20X_PWR_STATUS_BAT_CHARGING) {
+                       val->intval = POWER_SUPPLY_STATUS_CHARGING;
+                       return 0;
+               }
+
+               ret = iio_read_channel_processed(axp20x_batt->batt_dischrg_i,
+                                                &val1);
+               if (ret)
+                       return ret;
+
+               if (val1) {
+                       val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+                       return 0;
+               }
+
+               ret = regmap_read(axp20x_batt->regmap, AXP20X_FG_RES, &val1);
+               if (ret)
+                       return ret;
+
+               /*
+                * Fuel Gauge data takes 7 bits but the stored value seems to be
+                * directly the raw percentage without any scaling to 7 bits.
+                */
+               if ((val1 & AXP209_FG_PERCENT) == 100)
+                       val->intval = POWER_SUPPLY_STATUS_FULL;
+               else
+                       val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+               break;
+
+       case POWER_SUPPLY_PROP_HEALTH:
+               ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE,
+                                 &val1);
+               if (ret)
+                       return ret;
+
+               if (val1 & AXP20X_PWR_OP_BATT_ACTIVATED) {
+                       val->intval = POWER_SUPPLY_HEALTH_DEAD;
+                       return 0;
+               }
+
+               val->intval = POWER_SUPPLY_HEALTH_GOOD;
+               break;
+
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+               ret = axp20x_get_constant_charge_current(axp20x_batt,
+                                                        &val->intval);
+               if (ret)
+                       return ret;
+               break;
+
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+               val->intval = AXP20X_CHRG_CTRL1_TGT_CURR;
+               raw_to_constant_charge_current(axp20x_batt, &val->intval);
+
+               break;
+
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+               ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_INPUT_STATUS,
+                                 &reg);
+               if (ret)
+                       return ret;
+
+               if (reg & AXP20X_PWR_STATUS_BAT_CHARGING)
+                       chan = axp20x_batt->batt_chrg_i;
+               else
+                       chan = axp20x_batt->batt_dischrg_i;
+
+               ret = iio_read_channel_processed(chan, &val->intval);
+               if (ret)
+                       return ret;
+
+               /* IIO framework gives mA but Power Supply framework gives uA */
+               val->intval *= 1000;
+               break;
+
+       case POWER_SUPPLY_PROP_CAPACITY:
+               /* When no battery is present, return capacity is 100% */
+               ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE,
+                                 &reg);
+               if (ret)
+                       return ret;
+
+               if (!(reg & AXP20X_PWR_OP_BATT_PRESENT)) {
+                       val->intval = 100;
+                       return 0;
+               }
+
+               ret = regmap_read(axp20x_batt->regmap, AXP20X_FG_RES, &reg);
+               if (ret)
+                       return ret;
+
+               if (axp20x_batt->axp_id == AXP221_ID &&
+                   !(reg & AXP22X_FG_VALID))
+                       return -EINVAL;
+
+               /*
+                * Fuel Gauge data takes 7 bits but the stored value seems to be
+                * directly the raw percentage without any scaling to 7 bits.
+                */
+               val->intval = reg & AXP209_FG_PERCENT;
+               break;
+
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+               if (axp20x_batt->axp_id == AXP209_ID)
+                       return axp20x_battery_get_max_voltage(axp20x_batt,
+                                                             &val->intval);
+               return axp22x_battery_get_max_voltage(axp20x_batt,
+                                                     &val->intval);
+
+       case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+               ret = regmap_read(axp20x_batt->regmap, AXP20X_V_OFF, &reg);
+               if (ret)
+                       return ret;
+
+               val->intval = 2600000 + 100000 * (reg & AXP20X_V_OFF_MASK);
+               break;
+
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               ret = iio_read_channel_processed(axp20x_batt->batt_v,
+                                                &val->intval);
+               if (ret)
+                       return ret;
+
+               /* IIO framework gives mV but Power Supply framework gives uV */
+               val->intval *= 1000;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int axp20x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt,
+                                         int val)
+{
+       switch (val) {
+       case 4100000:
+               val = AXP20X_CHRG_CTRL1_TGT_4_1V;
+               break;
+
+       case 4150000:
+               if (axp20x_batt->axp_id == AXP221_ID)
+                       return -EINVAL;
+
+               val = AXP20X_CHRG_CTRL1_TGT_4_15V;
+               break;
+
+       case 4200000:
+               val = AXP20X_CHRG_CTRL1_TGT_4_2V;
+               break;
+
+       default:
+               /*
+                * AXP20x max voltage can be set to 4.36V and AXP22X max voltage
+                * can be set to 4.22V and 4.24V, but these voltages are too
+                * high for Lithium based batteries (AXP PMICs are supposed to
+                * be used with these kinds of battery).
+                */
+               return -EINVAL;
+       }
+
+       return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,
+                                 AXP20X_CHRG_CTRL1_TGT_VOLT, val);
+}
+
+static int axp20x_set_constant_charge_current(struct axp20x_batt_ps *axp_batt,
+                                             int charge_current)
+{
+       if (axp_batt->axp_id == AXP209_ID)
+               charge_current = (charge_current - 300000) / 100000;
+       else
+               charge_current = (charge_current - 300000) / 150000;
+
+       if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0)
+               return -EINVAL;
+
+       return regmap_update_bits(axp_batt->regmap, AXP20X_CHRG_CTRL1,
+                                 AXP20X_CHRG_CTRL1_TGT_CURR, charge_current);
+}
+
+static int axp20x_set_voltage_min_design(struct axp20x_batt_ps *axp_batt,
+                                        int min_voltage)
+{
+       int val1 = (min_voltage - 2600000) / 100000;
+
+       if (val1 < 0 || val1 > AXP20X_V_OFF_MASK)
+               return -EINVAL;
+
+       return regmap_update_bits(axp_batt->regmap, AXP20X_V_OFF,
+                                 AXP20X_V_OFF_MASK, val1);
+}
+
+static int axp20x_battery_set_prop(struct power_supply *psy,
+                                  enum power_supply_property psp,
+                                  const union power_supply_propval *val)
+{
+       struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+               return axp20x_set_voltage_min_design(axp20x_batt, val->intval);
+
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+               return axp20x_battery_set_max_voltage(axp20x_batt, val->intval);
+
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+               return axp20x_set_constant_charge_current(axp20x_batt,
+                                                         val->intval);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static enum power_supply_property axp20x_battery_props[] = {
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_CURRENT_NOW,
+       POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+       POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+       POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+       POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+       POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static int axp20x_battery_prop_writeable(struct power_supply *psy,
+                                        enum power_supply_property psp)
+{
+       return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN ||
+              psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN ||
+              psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT;
+}
+
+static const struct power_supply_desc axp20x_batt_ps_desc = {
+       .name = "axp20x-battery",
+       .type = POWER_SUPPLY_TYPE_BATTERY,
+       .properties = axp20x_battery_props,
+       .num_properties = ARRAY_SIZE(axp20x_battery_props),
+       .property_is_writeable = axp20x_battery_prop_writeable,
+       .get_property = axp20x_battery_get_prop,
+       .set_property = axp20x_battery_set_prop,
+};
+
+static const struct of_device_id axp20x_battery_ps_id[] = {
+       {
+               .compatible = "x-powers,axp209-battery-power-supply",
+               .data = (void *)AXP209_ID,
+       }, {
+               .compatible = "x-powers,axp221-battery-power-supply",
+               .data = (void *)AXP221_ID,
+       }, { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, axp20x_battery_ps_id);
+
+static int axp20x_power_probe(struct platform_device *pdev)
+{
+       struct axp20x_batt_ps *axp20x_batt;
+       struct power_supply_config psy_cfg = {};
+
+       if (!of_device_is_available(pdev->dev.of_node))
+               return -ENODEV;
+
+       axp20x_batt = devm_kzalloc(&pdev->dev, sizeof(*axp20x_batt),
+                                  GFP_KERNEL);
+       if (!axp20x_batt)
+               return -ENOMEM;
+
+       axp20x_batt->dev = &pdev->dev;
+
+       axp20x_batt->batt_v = devm_iio_channel_get(&pdev->dev, "batt_v");
+       if (IS_ERR(axp20x_batt->batt_v)) {
+               if (PTR_ERR(axp20x_batt->batt_v) == -ENODEV)
+                       return -EPROBE_DEFER;
+               return PTR_ERR(axp20x_batt->batt_v);
+       }
+
+       axp20x_batt->batt_chrg_i = devm_iio_channel_get(&pdev->dev,
+                                                       "batt_chrg_i");
+       if (IS_ERR(axp20x_batt->batt_chrg_i)) {
+               if (PTR_ERR(axp20x_batt->batt_chrg_i) == -ENODEV)
+                       return -EPROBE_DEFER;
+               return PTR_ERR(axp20x_batt->batt_chrg_i);
+       }
+
+       axp20x_batt->batt_dischrg_i = devm_iio_channel_get(&pdev->dev,
+                                                          "batt_dischrg_i");
+       if (IS_ERR(axp20x_batt->batt_dischrg_i)) {
+               if (PTR_ERR(axp20x_batt->batt_dischrg_i) == -ENODEV)
+                       return -EPROBE_DEFER;
+               return PTR_ERR(axp20x_batt->batt_dischrg_i);
+       }
+
+       axp20x_batt->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       platform_set_drvdata(pdev, axp20x_batt);
+
+       psy_cfg.drv_data = axp20x_batt;
+       psy_cfg.of_node = pdev->dev.of_node;
+
+       axp20x_batt->axp_id = (uintptr_t)of_device_get_match_data(&pdev->dev);
+
+       axp20x_batt->batt = devm_power_supply_register(&pdev->dev,
+                                                      &axp20x_batt_ps_desc,
+                                                      &psy_cfg);
+       if (IS_ERR(axp20x_batt->batt)) {
+               dev_err(&pdev->dev, "failed to register power supply: %ld\n",
+                       PTR_ERR(axp20x_batt->batt));
+               return PTR_ERR(axp20x_batt->batt);
+       }
+
+       return 0;
+}
+
+static struct platform_driver axp20x_batt_driver = {
+       .probe    = axp20x_power_probe,
+       .driver   = {
+               .name  = "axp20x-battery-power-supply",
+               .of_match_table = axp20x_battery_ps_id,
+       },
+};
+
+module_platform_driver(axp20x_batt_driver);
+
+MODULE_DESCRIPTION("Battery power supply driver for AXP20X and AXP22X PMICs");
+MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
+MODULE_LICENSE("GPL");
index bd9e5c3d8cc2880678f366fa0ec10c130f5c4e43..d5a707e14526ac9b47716b5452cccc8b233ef68b 100644 (file)
@@ -533,6 +533,9 @@ static int bq24190_register_reset(struct bq24190_dev_info *bdi)
        int ret, limit = 100;
        u8 v;
 
+       if (device_property_read_bool(bdi->dev, "disable-reset"))
+               return 0;
+
        /* Reset the registers */
        ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
                        BQ24190_REG_POC_RESET_MASK,
@@ -659,22 +662,25 @@ static int bq24190_charger_get_health(struct bq24190_dev_info *bdi,
        v = bdi->f_reg;
        mutex_unlock(&bdi->f_reg_lock);
 
-       if (v & BQ24190_REG_F_BOOST_FAULT_MASK) {
-               /*
-                * This could be over-current or over-voltage but there's
-                * no way to tell which.  Return 'OVERVOLTAGE' since there
-                * isn't an 'OVERCURRENT' value defined that we can return
-                * even if it was over-current.
-                */
-               health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
-       } else {
-               v &= BQ24190_REG_F_CHRG_FAULT_MASK;
-               v >>= BQ24190_REG_F_CHRG_FAULT_SHIFT;
-
-               switch (v) {
-               case 0x0: /* Normal */
-                       health = POWER_SUPPLY_HEALTH_GOOD;
+       if (v & BQ24190_REG_F_NTC_FAULT_MASK) {
+               switch (v >> BQ24190_REG_F_NTC_FAULT_SHIFT & 0x7) {
+               case 0x1: /* TS1  Cold */
+               case 0x3: /* TS2  Cold */
+               case 0x5: /* Both Cold */
+                       health = POWER_SUPPLY_HEALTH_COLD;
+                       break;
+               case 0x2: /* TS1  Hot */
+               case 0x4: /* TS2  Hot */
+               case 0x6: /* Both Hot */
+                       health = POWER_SUPPLY_HEALTH_OVERHEAT;
                        break;
+               default:
+                       health = POWER_SUPPLY_HEALTH_UNKNOWN;
+               }
+       } else if (v & BQ24190_REG_F_BAT_FAULT_MASK) {
+               health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+       } else if (v & BQ24190_REG_F_CHRG_FAULT_MASK) {
+               switch (v >> BQ24190_REG_F_CHRG_FAULT_SHIFT & 0x3) {
                case 0x1: /* Input Fault (VBUS OVP or VBAT<VBUS<3.8V) */
                        /*
                         * This could be over-voltage or under-voltage
@@ -691,9 +697,19 @@ static int bq24190_charger_get_health(struct bq24190_dev_info *bdi,
                case 0x3: /* Charge Safety Timer Expiration */
                        health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
                        break;
-               default:
-                       health = POWER_SUPPLY_HEALTH_UNKNOWN;
+               default:  /* prevent compiler warning */
+                       health = -1;
                }
+       } else if (v & BQ24190_REG_F_BOOST_FAULT_MASK) {
+               /*
+                * This could be over-current or over-voltage but there's
+                * no way to tell which.  Return 'OVERVOLTAGE' since there
+                * isn't an 'OVERCURRENT' value defined that we can return
+                * even if it was over-current.
+                */
+               health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+       } else {
+               health = POWER_SUPPLY_HEALTH_GOOD;
        }
 
        val->intval = health;
@@ -704,19 +720,59 @@ static int bq24190_charger_get_health(struct bq24190_dev_info *bdi,
 static int bq24190_charger_get_online(struct bq24190_dev_info *bdi,
                union power_supply_propval *val)
 {
-       u8 v;
+       u8 pg_stat, batfet_disable;
        int ret;
 
        ret = bq24190_read_mask(bdi, BQ24190_REG_SS,
                        BQ24190_REG_SS_PG_STAT_MASK,
-                       BQ24190_REG_SS_PG_STAT_SHIFT, &v);
+                       BQ24190_REG_SS_PG_STAT_SHIFT, &pg_stat);
        if (ret < 0)
                return ret;
 
-       val->intval = v;
+       ret = bq24190_read_mask(bdi, BQ24190_REG_MOC,
+                       BQ24190_REG_MOC_BATFET_DISABLE_MASK,
+                       BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, &batfet_disable);
+       if (ret < 0)
+               return ret;
+
+       val->intval = pg_stat && !batfet_disable;
+
        return 0;
 }
 
+static int bq24190_battery_set_online(struct bq24190_dev_info *bdi,
+                                     const union power_supply_propval *val);
+static int bq24190_battery_get_status(struct bq24190_dev_info *bdi,
+                                     union power_supply_propval *val);
+static int bq24190_battery_get_temp_alert_max(struct bq24190_dev_info *bdi,
+                                             union power_supply_propval *val);
+static int bq24190_battery_set_temp_alert_max(struct bq24190_dev_info *bdi,
+                                             const union power_supply_propval *val);
+
+static int bq24190_charger_set_online(struct bq24190_dev_info *bdi,
+                                     const union power_supply_propval *val)
+{
+       return bq24190_battery_set_online(bdi, val);
+}
+
+static int bq24190_charger_get_status(struct bq24190_dev_info *bdi,
+                                     union power_supply_propval *val)
+{
+       return bq24190_battery_get_status(bdi, val);
+}
+
+static int bq24190_charger_get_temp_alert_max(struct bq24190_dev_info *bdi,
+                                             union power_supply_propval *val)
+{
+       return bq24190_battery_get_temp_alert_max(bdi, val);
+}
+
+static int bq24190_charger_set_temp_alert_max(struct bq24190_dev_info *bdi,
+                                             const union power_supply_propval *val)
+{
+       return bq24190_battery_set_temp_alert_max(bdi, val);
+}
+
 static int bq24190_charger_get_current(struct bq24190_dev_info *bdi,
                union power_supply_propval *val)
 {
@@ -831,6 +887,12 @@ static int bq24190_charger_get_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_ONLINE:
                ret = bq24190_charger_get_online(bdi, val);
                break;
+       case POWER_SUPPLY_PROP_STATUS:
+               ret = bq24190_charger_get_status(bdi, val);
+               break;
+       case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
+               ret =  bq24190_charger_get_temp_alert_max(bdi, val);
+               break;
        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
                ret = bq24190_charger_get_current(bdi, val);
                break;
@@ -879,6 +941,12 @@ static int bq24190_charger_set_property(struct power_supply *psy,
                return ret;
 
        switch (psp) {
+       case POWER_SUPPLY_PROP_ONLINE:
+               ret = bq24190_charger_set_online(bdi, val);
+               break;
+       case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
+               ret = bq24190_charger_set_temp_alert_max(bdi, val);
+               break;
        case POWER_SUPPLY_PROP_CHARGE_TYPE:
                ret = bq24190_charger_set_charge_type(bdi, val);
                break;
@@ -904,6 +972,8 @@ static int bq24190_charger_property_is_writeable(struct power_supply *psy,
        int ret;
 
        switch (psp) {
+       case POWER_SUPPLY_PROP_ONLINE:
+       case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
        case POWER_SUPPLY_PROP_CHARGE_TYPE:
        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
@@ -920,6 +990,8 @@ static enum power_supply_property bq24190_charger_properties[] = {
        POWER_SUPPLY_PROP_CHARGE_TYPE,
        POWER_SUPPLY_PROP_HEALTH,
        POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
        POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
        POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
        POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
@@ -1093,6 +1165,7 @@ static int bq24190_battery_get_property(struct power_supply *psy,
        struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy);
        int ret;
 
+       dev_warn(bdi->dev, "warning: /sys/class/power_supply/bq24190-battery is deprecated\n");
        dev_dbg(bdi->dev, "prop: %d\n", psp);
 
        ret = pm_runtime_get_sync(bdi->dev);
@@ -1138,6 +1211,7 @@ static int bq24190_battery_set_property(struct power_supply *psy,
        struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy);
        int ret;
 
+       dev_warn(bdi->dev, "warning: /sys/class/power_supply/bq24190-battery is deprecated\n");
        dev_dbg(bdi->dev, "prop: %d\n", psp);
 
        ret = pm_runtime_get_sync(bdi->dev);
@@ -1266,9 +1340,9 @@ static void bq24190_check_status(struct bq24190_dev_info *bdi)
                bdi->ss_reg = ss_reg;
        }
 
-       if (alert_charger)
+       if (alert_charger || alert_battery)
                power_supply_changed(bdi->charger);
-       if (alert_battery)
+       if (alert_battery && bdi->battery)
                power_supply_changed(bdi->battery);
 
        dev_dbg(bdi->dev, "ss_reg: 0x%02x, f_reg: 0x%02x\n", ss_reg, f_reg);
@@ -1473,19 +1547,23 @@ static int bq24190_probe(struct i2c_client *client,
                goto out_pmrt;
        }
 
-       battery_cfg.drv_data = bdi;
-       bdi->battery = power_supply_register(dev, &bq24190_battery_desc,
-                                               &battery_cfg);
-       if (IS_ERR(bdi->battery)) {
-               dev_err(dev, "Can't register battery\n");
-               ret = PTR_ERR(bdi->battery);
-               goto out_charger;
+       /* the battery class is deprecated and will be removed. */
+       /* in the interim, this property hides it.              */
+       if (!device_property_read_bool(dev, "omit-battery-class")) {
+               battery_cfg.drv_data = bdi;
+               bdi->battery = power_supply_register(dev, &bq24190_battery_desc,
+                                                    &battery_cfg);
+               if (IS_ERR(bdi->battery)) {
+                       dev_err(dev, "Can't register battery\n");
+                       ret = PTR_ERR(bdi->battery);
+                       goto out_charger;
+               }
        }
 
        ret = bq24190_sysfs_create_group(bdi);
        if (ret) {
                dev_err(dev, "Can't create sysfs entries\n");
-               goto out_battery;
+               goto out_charger;
        }
 
        bdi->initialized = true;
@@ -1523,10 +1601,9 @@ static int bq24190_probe(struct i2c_client *client,
 out_sysfs:
        bq24190_sysfs_remove_group(bdi);
 
-out_battery:
-       power_supply_unregister(bdi->battery);
-
 out_charger:
+       if (!IS_ERR_OR_NULL(bdi->battery))
+               power_supply_unregister(bdi->battery);
        power_supply_unregister(bdi->charger);
 
 out_pmrt:
@@ -1549,7 +1626,8 @@ static int bq24190_remove(struct i2c_client *client)
 
        bq24190_register_reset(bdi);
        bq24190_sysfs_remove_group(bdi);
-       power_supply_unregister(bdi->battery);
+       if (bdi->battery)
+               power_supply_unregister(bdi->battery);
        power_supply_unregister(bdi->charger);
        if (error >= 0)
                pm_runtime_put_sync(bdi->dev);
@@ -1636,7 +1714,8 @@ static __maybe_unused int bq24190_pm_resume(struct device *dev)
 
        /* Things may have changed while suspended so alert upper layer */
        power_supply_changed(bdi->charger);
-       power_supply_changed(bdi->battery);
+       if (bdi->battery)
+               power_supply_changed(bdi->battery);
 
        return 0;
 }
index 543a1bd21ab9c74ab15a2a16898fa477ed021818..26a2dc7ac9a2777643ec2b3abda2e19af0b7ea50 100644 (file)
@@ -76,7 +76,7 @@
 #define CPCAP_REG_CRM_VCHRG_4V30       CPCAP_REG_CRM_VCHRG(0x8)
 #define CPCAP_REG_CRM_VCHRG_4V32       CPCAP_REG_CRM_VCHRG(0x9)
 #define CPCAP_REG_CRM_VCHRG_4V34       CPCAP_REG_CRM_VCHRG(0xa)
-#define CPCAP_REG_CRM_VCHRG_4V36       CPCAP_REG_CRM_VCHRG(0xb)
+#define CPCAP_REG_CRM_VCHRG_4V35       CPCAP_REG_CRM_VCHRG(0xb)
 #define CPCAP_REG_CRM_VCHRG_4V38       CPCAP_REG_CRM_VCHRG(0xc)
 #define CPCAP_REG_CRM_VCHRG_4V40       CPCAP_REG_CRM_VCHRG(0xd)
 #define CPCAP_REG_CRM_VCHRG_4V42       CPCAP_REG_CRM_VCHRG(0xe)
@@ -262,7 +262,7 @@ static int cpcap_charger_set_state(struct cpcap_charger_ddata *ddata,
        bool enable;
        int error;
 
-       enable = max_voltage && (charge_current || trickle_current);
+       enable = (charge_current || trickle_current);
        dev_dbg(ddata->dev, "%s enable: %i\n", __func__, enable);
 
        if (!enable) {
@@ -433,9 +433,8 @@ static void cpcap_usb_detect(struct work_struct *work)
                        max_current = CPCAP_REG_CRM_ICHRG_0A528;
 
                error = cpcap_charger_set_state(ddata,
-                                               CPCAP_REG_CRM_VCHRG_4V20,
-                                               max_current,
-                                               CPCAP_REG_CRM_TR_0A72);
+                                               CPCAP_REG_CRM_VCHRG_4V35,
+                                               max_current, 0);
                if (error)
                        goto out_err;
        } else {
@@ -566,7 +565,7 @@ out_err:
 }
 
 static const struct power_supply_desc cpcap_charger_usb_desc = {
-       .name           = "cpcap_usb",
+       .name           = "usb",
        .type           = POWER_SUPPLY_TYPE_USB,
        .properties     = cpcap_charger_props,
        .num_properties = ARRAY_SIZE(cpcap_charger_props),
index edb36bf781b0cb0bb0856b72ab91b2aa8e33aaa4..37e523374fe00ebe44de3f20ae12a1b8674641b5 100644 (file)
@@ -383,8 +383,7 @@ static int gab_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int gab_suspend(struct device *dev)
+static int __maybe_unused gab_suspend(struct device *dev)
 {
        struct gab *adc_bat = dev_get_drvdata(dev);
 
@@ -393,7 +392,7 @@ static int gab_suspend(struct device *dev)
        return 0;
 }
 
-static int gab_resume(struct device *dev)
+static int __maybe_unused gab_resume(struct device *dev)
 {
        struct gab *adc_bat = dev_get_drvdata(dev);
        struct gab_platform_data *pdata = adc_bat->pdata;
@@ -407,20 +406,12 @@ static int gab_resume(struct device *dev)
        return 0;
 }
 
-static const struct dev_pm_ops gab_pm_ops = {
-       .suspend        = gab_suspend,
-       .resume         = gab_resume,
-};
-
-#define GAB_PM_OPS       (&gab_pm_ops)
-#else
-#define GAB_PM_OPS       (NULL)
-#endif
+static SIMPLE_DEV_PM_OPS(gab_pm_ops, gab_suspend, gab_resume);
 
 static struct platform_driver gab_driver = {
        .driver         = {
                .name   = "generic-adc-battery",
-               .pm     = GAB_PM_OPS
+               .pm     = &gab_pm_ops,
        },
        .probe          = gab_probe,
        .remove         = gab_remove,
index 4cd6899b961e780e0623e81951ecc12e1fcd3557..95af5f305838a6508bf1b95988a28854d829a6dc 100644 (file)
@@ -418,6 +418,10 @@ static int isp1704_charger_probe(struct platform_device *pdev)
 
                pdata = devm_kzalloc(&pdev->dev,
                        sizeof(struct isp1704_charger_data), GFP_KERNEL);
+               if (!pdata) {
+                       ret = -ENOMEM;
+                       goto fail0;
+               }
                pdata->enable_gpio = gpio;
 
                dev_info(&pdev->dev, "init gpio %d\n", pdata->enable_gpio);
index da7a75f824891200f9db4c9dd4d274c5125d3dd8..aecaaa2b0586027036f467805358697e979b4538 100644 (file)
@@ -76,15 +76,20 @@ struct max17042_chip {
 };
 
 static enum power_supply_property max17042_battery_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
        POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_TECHNOLOGY,
        POWER_SUPPLY_PROP_CYCLE_COUNT,
        POWER_SUPPLY_PROP_VOLTAGE_MAX,
+       POWER_SUPPLY_PROP_VOLTAGE_MIN,
        POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
        POWER_SUPPLY_PROP_VOLTAGE_NOW,
        POWER_SUPPLY_PROP_VOLTAGE_AVG,
        POWER_SUPPLY_PROP_VOLTAGE_OCV,
        POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
        POWER_SUPPLY_PROP_CHARGE_FULL,
+       POWER_SUPPLY_PROP_CHARGE_NOW,
        POWER_SUPPLY_PROP_CHARGE_COUNTER,
        POWER_SUPPLY_PROP_TEMP,
        POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
@@ -92,6 +97,7 @@ static enum power_supply_property max17042_battery_props[] = {
        POWER_SUPPLY_PROP_TEMP_MIN,
        POWER_SUPPLY_PROP_TEMP_MAX,
        POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_SCOPE,
        POWER_SUPPLY_PROP_CURRENT_NOW,
        POWER_SUPPLY_PROP_CURRENT_AVG,
 };
@@ -106,19 +112,53 @@ static int max17042_get_temperature(struct max17042_chip *chip, int *temp)
        if (ret < 0)
                return ret;
 
-       *temp = data;
-       /* The value is signed. */
-       if (*temp & 0x8000) {
-               *temp = (0x7fff & ~*temp) + 1;
-               *temp *= -1;
-       }
-
+       *temp = sign_extend32(data, 15);
        /* The value is converted into deci-centigrade scale */
        /* Units of LSB = 1 / 256 degree Celsius */
        *temp = *temp * 10 / 256;
        return 0;
 }
 
+static int max17042_get_status(struct max17042_chip *chip, int *status)
+{
+       int ret, charge_full, charge_now;
+
+       ret = power_supply_am_i_supplied(chip->battery);
+       if (ret < 0) {
+               *status = POWER_SUPPLY_STATUS_UNKNOWN;
+               return 0;
+       }
+       if (ret == 0) {
+               *status = POWER_SUPPLY_STATUS_DISCHARGING;
+               return 0;
+       }
+
+       /*
+        * The MAX170xx has builtin end-of-charge detection and will update
+        * FullCAP to match RepCap when it detects end of charging.
+        *
+        * When this cycle the battery gets charged to a higher (calculated)
+        * capacity then the previous cycle then FullCAP will get updated
+        * contineously once end-of-charge detection kicks in, so allow the
+        * 2 to differ a bit.
+        */
+
+       ret = regmap_read(chip->regmap, MAX17042_FullCAP, &charge_full);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_read(chip->regmap, MAX17042_RepCap, &charge_now);
+       if (ret < 0)
+               return ret;
+
+       if ((charge_full - charge_now) <= MAX17042_FULL_THRESHOLD)
+               *status = POWER_SUPPLY_STATUS_FULL;
+       else
+               *status = POWER_SUPPLY_STATUS_CHARGING;
+
+       return 0;
+}
+
 static int max17042_get_battery_health(struct max17042_chip *chip, int *health)
 {
        int temp, vavg, vbatt, ret;
@@ -156,12 +196,12 @@ static int max17042_get_battery_health(struct max17042_chip *chip, int *health)
        if (ret < 0)
                goto health_error;
 
-       if (temp <= chip->pdata->temp_min) {
+       if (temp < chip->pdata->temp_min) {
                *health = POWER_SUPPLY_HEALTH_COLD;
                goto out;
        }
 
-       if (temp >= chip->pdata->temp_max) {
+       if (temp > chip->pdata->temp_max) {
                *health = POWER_SUPPLY_HEALTH_OVERHEAT;
                goto out;
        }
@@ -183,11 +223,17 @@ static int max17042_get_property(struct power_supply *psy,
        struct regmap *map = chip->regmap;
        int ret;
        u32 data;
+       u64 data64;
 
        if (!chip->init_complete)
                return -EAGAIN;
 
        switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               ret = max17042_get_status(chip, &val->intval);
+               if (ret < 0)
+                       return ret;
+               break;
        case POWER_SUPPLY_PROP_PRESENT:
                ret = regmap_read(map, MAX17042_STATUS, &data);
                if (ret < 0)
@@ -198,6 +244,9 @@ static int max17042_get_property(struct power_supply *psy,
                else
                        val->intval = 1;
                break;
+       case POWER_SUPPLY_PROP_TECHNOLOGY:
+               val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+               break;
        case POWER_SUPPLY_PROP_CYCLE_COUNT:
                ret = regmap_read(map, MAX17042_Cycles, &data);
                if (ret < 0)
@@ -213,6 +262,13 @@ static int max17042_get_property(struct power_supply *psy,
                val->intval = data >> 8;
                val->intval *= 20000; /* Units of LSB = 20mV */
                break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MIN:
+               ret = regmap_read(map, MAX17042_MinMaxVolt, &data);
+               if (ret < 0)
+                       return ret;
+
+               val->intval = (data & 0xff) * 20000; /* Units of 20mV */
+               break;
        case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
                if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042)
                        ret = regmap_read(map, MAX17042_V_empty, &data);
@@ -252,12 +308,32 @@ static int max17042_get_property(struct power_supply *psy,
 
                val->intval = data >> 8;
                break;
+       case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+               ret = regmap_read(map, MAX17042_DesignCap, &data);
+               if (ret < 0)
+                       return ret;
+
+               data64 = data * 5000000ll;
+               do_div(data64, chip->pdata->r_sns);
+               val->intval = data64;
+               break;
        case POWER_SUPPLY_PROP_CHARGE_FULL:
                ret = regmap_read(map, MAX17042_FullCAP, &data);
                if (ret < 0)
                        return ret;
 
-               val->intval = data * 1000 / 2;
+               data64 = data * 5000000ll;
+               do_div(data64, chip->pdata->r_sns);
+               val->intval = data64;
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_NOW:
+               ret = regmap_read(map, MAX17042_RepCap, &data);
+               if (ret < 0)
+                       return ret;
+
+               data64 = data * 5000000ll;
+               do_div(data64, chip->pdata->r_sns);
+               val->intval = data64;
                break;
        case POWER_SUPPLY_PROP_CHARGE_COUNTER:
                ret = regmap_read(map, MAX17042_QH, &data);
@@ -276,14 +352,14 @@ static int max17042_get_property(struct power_supply *psy,
                if (ret < 0)
                        return ret;
                /* LSB is Alert Minimum. In deci-centigrade */
-               val->intval = (data & 0xff) * 10;
+               val->intval = sign_extend32(data & 0xff, 7) * 10;
                break;
        case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
                ret = regmap_read(map, MAX17042_TALRT_Th, &data);
                if (ret < 0)
                        return ret;
                /* MSB is Alert Maximum. In deci-centigrade */
-               val->intval = (data >> 8) * 10;
+               val->intval = sign_extend32(data >> 8, 7) * 10;
                break;
        case POWER_SUPPLY_PROP_TEMP_MIN:
                val->intval = chip->pdata->temp_min;
@@ -296,19 +372,16 @@ static int max17042_get_property(struct power_supply *psy,
                if (ret < 0)
                        return ret;
                break;
+       case POWER_SUPPLY_PROP_SCOPE:
+               val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
+               break;
        case POWER_SUPPLY_PROP_CURRENT_NOW:
                if (chip->pdata->enable_current_sense) {
                        ret = regmap_read(map, MAX17042_Current, &data);
                        if (ret < 0)
                                return ret;
 
-                       val->intval = data;
-                       if (val->intval & 0x8000) {
-                               /* Negative */
-                               val->intval = ~val->intval & 0x7fff;
-                               val->intval++;
-                               val->intval *= -1;
-                       }
+                       val->intval = sign_extend32(data, 15);
                        val->intval *= 1562500 / chip->pdata->r_sns;
                } else {
                        return -EINVAL;
@@ -320,13 +393,7 @@ static int max17042_get_property(struct power_supply *psy,
                        if (ret < 0)
                                return ret;
 
-                       val->intval = data;
-                       if (val->intval & 0x8000) {
-                               /* Negative */
-                               val->intval = ~val->intval & 0x7fff;
-                               val->intval++;
-                               val->intval *= -1;
-                       }
+                       val->intval = sign_extend32(data, 15);
                        val->intval *= 1562500 / chip->pdata->r_sns;
                } else {
                        return -EINVAL;
@@ -401,6 +468,11 @@ static int max17042_property_is_writeable(struct power_supply *psy,
        return ret;
 }
 
+static void max17042_external_power_changed(struct power_supply *psy)
+{
+       power_supply_changed(psy);
+}
+
 static int max17042_write_verify_reg(struct regmap *map, u8 reg, u32 value)
 {
        int retries = 8;
@@ -790,8 +862,9 @@ static void max17042_init_worker(struct work_struct *work)
 
 #ifdef CONFIG_OF
 static struct max17042_platform_data *
-max17042_get_pdata(struct device *dev)
+max17042_get_pdata(struct max17042_chip *chip)
 {
+       struct device *dev = &chip->client->dev;
        struct device_node *np = dev->of_node;
        u32 prop;
        struct max17042_platform_data *pdata;
@@ -824,10 +897,55 @@ max17042_get_pdata(struct device *dev)
        return pdata;
 }
 #else
+static struct max17042_reg_data max17047_default_pdata_init_regs[] = {
+       /*
+        * Some firmwares do not set FullSOCThr, Enable End-of-Charge Detection
+        * when the voltage FG reports 95%, as recommended in the datasheet.
+        */
+       { MAX17047_FullSOCThr, MAX17042_BATTERY_FULL << 8 },
+};
+
 static struct max17042_platform_data *
-max17042_get_pdata(struct device *dev)
+max17042_get_pdata(struct max17042_chip *chip)
 {
-       return dev->platform_data;
+       struct device *dev = &chip->client->dev;
+       struct max17042_platform_data *pdata;
+       int ret, misc_cfg;
+
+       if (dev->platform_data)
+               return dev->platform_data;
+
+       /*
+        * The MAX17047 gets used on x86 where we might not have pdata, assume
+        * the firmware will already have initialized the fuel-gauge and provide
+        * default values for the non init bits to make things work.
+        */
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return pdata;
+
+       if (chip->chip_type != MAXIM_DEVICE_TYPE_MAX17042) {
+               pdata->init_data = max17047_default_pdata_init_regs;
+               pdata->num_init_data =
+                       ARRAY_SIZE(max17047_default_pdata_init_regs);
+       }
+
+       ret = regmap_read(chip->regmap, MAX17042_MiscCFG, &misc_cfg);
+       if (ret < 0)
+               return NULL;
+
+       /* If bits 0-1 are set to 3 then only Voltage readings are used */
+       if ((misc_cfg & 0x3) == 0x3)
+               pdata->enable_current_sense = false;
+       else
+               pdata->enable_current_sense = true;
+
+       pdata->vmin = MAX17042_DEFAULT_VMIN;
+       pdata->vmax = MAX17042_DEFAULT_VMAX;
+       pdata->temp_min = MAX17042_DEFAULT_TEMP_MIN;
+       pdata->temp_max = MAX17042_DEFAULT_TEMP_MAX;
+
+       return pdata;
 }
 #endif
 
@@ -843,6 +961,7 @@ static const struct power_supply_desc max17042_psy_desc = {
        .get_property   = max17042_get_property,
        .set_property   = max17042_set_property,
        .property_is_writeable  = max17042_property_is_writeable,
+       .external_power_changed = max17042_external_power_changed,
        .properties     = max17042_battery_props,
        .num_properties = ARRAY_SIZE(max17042_battery_props),
 };
@@ -876,20 +995,20 @@ static int max17042_probe(struct i2c_client *client,
                return -ENOMEM;
 
        chip->client = client;
+       chip->chip_type = id->driver_data;
        chip->regmap = devm_regmap_init_i2c(client, &max17042_regmap_config);
        if (IS_ERR(chip->regmap)) {
                dev_err(&client->dev, "Failed to initialize regmap\n");
                return -EINVAL;
        }
 
-       chip->pdata = max17042_get_pdata(&client->dev);
+       chip->pdata = max17042_get_pdata(chip);
        if (!chip->pdata) {
                dev_err(&client->dev, "no platform data provided\n");
                return -EINVAL;
        }
 
        i2c_set_clientdata(client, chip);
-       chip->chip_type = id->driver_data;
        psy_cfg.drv_data = chip;
 
        /* When current is not measured,
index dfe1ee89f7c7ad06fc014b3986c240904329e6ba..922a86787c5c4c69901bf2f48933e29653e29bf1 100644 (file)
@@ -30,9 +30,9 @@ static inline unsigned int get_irq_flags(struct resource *res)
 static struct device *dev;
 static struct pda_power_pdata *pdata;
 static struct resource *ac_irq, *usb_irq;
-static struct timer_list charger_timer;
-static struct timer_list supply_timer;
-static struct timer_list polling_timer;
+static struct delayed_work charger_work;
+static struct delayed_work polling_work;
+static struct delayed_work supply_work;
 static int polling;
 static struct power_supply *pda_psy_ac, *pda_psy_usb;
 
@@ -140,7 +140,7 @@ static void update_charger(void)
        }
 }
 
-static void supply_timer_func(unsigned long unused)
+static void supply_work_func(struct work_struct *work)
 {
        if (ac_status == PDA_PSY_TO_CHANGE) {
                ac_status = new_ac_status;
@@ -161,11 +161,12 @@ static void psy_changed(void)
         * Okay, charger set. Now wait a bit before notifying supplicants,
         * charge power should stabilize.
         */
-       mod_timer(&supply_timer,
-                 jiffies + msecs_to_jiffies(pdata->wait_for_charger));
+       cancel_delayed_work(&supply_work);
+       schedule_delayed_work(&supply_work,
+                             msecs_to_jiffies(pdata->wait_for_charger));
 }
 
-static void charger_timer_func(unsigned long unused)
+static void charger_work_func(struct work_struct *work)
 {
        update_status();
        psy_changed();
@@ -184,13 +185,14 @@ static irqreturn_t power_changed_isr(int irq, void *power_supply)
         * Wait a bit before reading ac/usb line status and setting charger,
         * because ac/usb status readings may lag from irq.
         */
-       mod_timer(&charger_timer,
-                 jiffies + msecs_to_jiffies(pdata->wait_for_status));
+       cancel_delayed_work(&charger_work);
+       schedule_delayed_work(&charger_work,
+                             msecs_to_jiffies(pdata->wait_for_status));
 
        return IRQ_HANDLED;
 }
 
-static void polling_timer_func(unsigned long unused)
+static void polling_work_func(struct work_struct *work)
 {
        int changed = 0;
 
@@ -211,8 +213,9 @@ static void polling_timer_func(unsigned long unused)
        if (changed)
                psy_changed();
 
-       mod_timer(&polling_timer,
-                 jiffies + msecs_to_jiffies(pdata->polling_interval));
+       cancel_delayed_work(&polling_work);
+       schedule_delayed_work(&polling_work,
+                             msecs_to_jiffies(pdata->polling_interval));
 }
 
 #if IS_ENABLED(CONFIG_USB_PHY)
@@ -250,8 +253,9 @@ static int otg_handle_notification(struct notifier_block *nb,
         * Wait a bit before reading ac/usb line status and setting charger,
         * because ac/usb status readings may lag from irq.
         */
-       mod_timer(&charger_timer,
-                 jiffies + msecs_to_jiffies(pdata->wait_for_status));
+       cancel_delayed_work(&charger_work);
+       schedule_delayed_work(&charger_work,
+                             msecs_to_jiffies(pdata->wait_for_status));
 
        return NOTIFY_OK;
 }
@@ -300,8 +304,8 @@ static int pda_power_probe(struct platform_device *pdev)
        if (!pdata->ac_max_uA)
                pdata->ac_max_uA = 500000;
 
-       setup_timer(&charger_timer, charger_timer_func, 0);
-       setup_timer(&supply_timer, supply_timer_func, 0);
+       INIT_DELAYED_WORK(&charger_work, charger_work_func);
+       INIT_DELAYED_WORK(&supply_work, supply_work_func);
 
        ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac");
        usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb");
@@ -385,9 +389,10 @@ static int pda_power_probe(struct platform_device *pdev)
 
        if (polling) {
                dev_dbg(dev, "will poll for status\n");
-               setup_timer(&polling_timer, polling_timer_func, 0);
-               mod_timer(&polling_timer,
-                         jiffies + msecs_to_jiffies(pdata->polling_interval));
+               INIT_DELAYED_WORK(&polling_work, polling_work_func);
+               cancel_delayed_work(&polling_work);
+               schedule_delayed_work(&polling_work,
+                                     msecs_to_jiffies(pdata->polling_interval));
        }
 
        if (ac_irq || usb_irq)
@@ -433,9 +438,9 @@ static int pda_power_remove(struct platform_device *pdev)
                free_irq(ac_irq->start, pda_psy_ac);
 
        if (polling)
-               del_timer_sync(&polling_timer);
-       del_timer_sync(&charger_timer);
-       del_timer_sync(&supply_timer);
+               cancel_delayed_work_sync(&polling_work);
+       cancel_delayed_work_sync(&charger_work);
+       cancel_delayed_work_sync(&supply_work);
 
        if (pdata->is_usb_online)
                power_supply_unregister(pda_psy_usb);
index 1e0960b646e823caeb82bf9f10bd72ee36a687d4..7ec7c7c202bd1e95e3cff0c940f1a5b103dae326 100644 (file)
@@ -280,13 +280,19 @@ static inline int power_supply_check_supplies(struct power_supply *psy)
 }
 #endif
 
-static int __power_supply_am_i_supplied(struct device *dev, void *data)
+struct psy_am_i_supplied_data {
+       struct power_supply *psy;
+       unsigned int count;
+};
+
+static int __power_supply_am_i_supplied(struct device *dev, void *_data)
 {
        union power_supply_propval ret = {0,};
-       struct power_supply *psy = data;
        struct power_supply *epsy = dev_get_drvdata(dev);
+       struct psy_am_i_supplied_data *data = _data;
 
-       if (__power_supply_is_supplied_by(epsy, psy))
+       data->count++;
+       if (__power_supply_is_supplied_by(epsy, data->psy))
                if (!epsy->desc->get_property(epsy, POWER_SUPPLY_PROP_ONLINE,
                                        &ret))
                        return ret.intval;
@@ -296,12 +302,16 @@ static int __power_supply_am_i_supplied(struct device *dev, void *data)
 
 int power_supply_am_i_supplied(struct power_supply *psy)
 {
+       struct psy_am_i_supplied_data data = { psy, 0 };
        int error;
 
-       error = class_for_each_device(power_supply_class, NULL, psy,
+       error = class_for_each_device(power_supply_class, NULL, &data,
                                      __power_supply_am_i_supplied);
 
-       dev_dbg(&psy->dev, "%s %d\n", __func__, error);
+       dev_dbg(&psy->dev, "%s count %u err %d\n", __func__, data.count, error);
+
+       if (data.count == 0)
+               return -ENODEV;
 
        return error;
 }
index af9383d23d122e36b99efb8868f9c84790f17267..5654708b12790c1b608dae27cf4ed1e5ef392df1 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/platform_device.h>
 #include <linux/power_supply.h>
 #include <linux/slab.h>
-#include <linux/i2c/twl4030-madc.h>
 #include <linux/iio/consumer.h>
 #include <linux/of.h>
 
index 8bb2eb38eb1c872e7a50f7aa765c9c4c712c79f1..e3a114e60f1a3cac1c72bf72800cb859cae12254 100644 (file)
@@ -171,7 +171,6 @@ struct sbs_info {
        u32                             i2c_retry_count;
        u32                             poll_retry_count;
        struct delayed_work             work;
-       int                             ignore_changes;
 };
 
 static char model_name[I2C_SMBUS_BLOCK_MAX + 1];
@@ -296,6 +295,31 @@ static int sbs_write_word_data(struct i2c_client *client, u8 address,
        return 0;
 }
 
+static int sbs_status_correct(struct i2c_client *client, int *intval)
+{
+       int ret;
+
+       ret = sbs_read_word_data(client, sbs_data[REG_CURRENT].addr);
+       if (ret < 0)
+               return ret;
+
+       ret = (s16)ret;
+
+       /* Not drawing current means full (cannot be not charging) */
+       if (ret == 0)
+               *intval = POWER_SUPPLY_STATUS_FULL;
+
+       if (*intval == POWER_SUPPLY_STATUS_FULL) {
+               /* Drawing or providing current when full */
+               if (ret > 0)
+                       *intval = POWER_SUPPLY_STATUS_CHARGING;
+               else if (ret < 0)
+                       *intval = POWER_SUPPLY_STATUS_DISCHARGING;
+       }
+
+       return 0;
+}
+
 static int sbs_get_battery_presence_and_health(
        struct i2c_client *client, enum power_supply_property psp,
        union power_supply_propval *val)
@@ -402,6 +426,8 @@ static int sbs_get_battery_property(struct i2c_client *client,
                else
                        val->intval = POWER_SUPPLY_STATUS_CHARGING;
 
+               sbs_status_correct(client, &val->intval);
+
                if (chip->poll_time == 0)
                        chip->last_state = val->intval;
                else if (chip->last_state != val->intval) {
@@ -675,30 +701,34 @@ done:
        return 0;
 }
 
-static irqreturn_t sbs_irq(int irq, void *devid)
+static void sbs_supply_changed(struct sbs_info *chip)
 {
-       struct sbs_info *chip = devid;
        struct power_supply *battery = chip->power_supply;
        int ret;
 
        ret = gpiod_get_value_cansleep(chip->gpio_detect);
        if (ret < 0)
-               return ret;
+               return;
        chip->is_present = ret;
        power_supply_changed(battery);
+}
 
+static irqreturn_t sbs_irq(int irq, void *devid)
+{
+       sbs_supply_changed(devid);
        return IRQ_HANDLED;
 }
 
+static void sbs_alert(struct i2c_client *client, enum i2c_alert_protocol prot,
+       unsigned int data)
+{
+       sbs_supply_changed(i2c_get_clientdata(client));
+}
+
 static void sbs_external_power_changed(struct power_supply *psy)
 {
        struct sbs_info *chip = power_supply_get_drvdata(psy);
 
-       if (chip->ignore_changes > 0) {
-               chip->ignore_changes--;
-               return;
-       }
-
        /* cancel outstanding work */
        cancel_delayed_work_sync(&chip->work);
 
@@ -727,6 +757,8 @@ static void sbs_delayed_work(struct work_struct *work)
        else
                ret = POWER_SUPPLY_STATUS_CHARGING;
 
+       sbs_status_correct(chip->client, &ret);
+
        if (chip->last_state != ret) {
                chip->poll_time = 0;
                power_supply_changed(chip->power_supply);
@@ -775,10 +807,6 @@ static int sbs_probe(struct i2c_client *client,
        chip->enable_detection = false;
        psy_cfg.of_node = client->dev.of_node;
        psy_cfg.drv_data = chip;
-       /* ignore first notification of external change, it is generated
-        * from the power_supply_register call back
-        */
-       chip->ignore_changes = 1;
        chip->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
 
        /* use pdata if available, fall back to DT properties,
@@ -820,7 +848,7 @@ static int sbs_probe(struct i2c_client *client,
        }
 
        rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
-               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
                dev_name(&client->dev), chip);
        if (rc) {
                dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
@@ -917,6 +945,7 @@ MODULE_DEVICE_TABLE(of, sbs_dt_ids);
 static struct i2c_driver sbs_battery_driver = {
        .probe          = sbs_probe,
        .remove         = sbs_remove,
+       .alert          = sbs_alert,
        .id_table       = sbs_id,
        .driver = {
                .name   = "sbs-battery",
index 990ff3d218bcc7572bd1be15da7731fd36894736..2f82d0e9ec1bf7eaf879a57faa3b1da14303d99c 100644 (file)
@@ -205,35 +205,6 @@ static int twl4030bci_read_adc_val(u8 reg)
        return temp | val;
 }
 
-/*
- * Check if Battery Pack was present
- */
-static int twl4030_is_battery_present(struct twl4030_bci *bci)
-{
-       int ret;
-       u8 val = 0;
-
-       /* Battery presence in Main charge? */
-       ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val, TWL4030_BCIMFSTS3);
-       if (ret)
-               return ret;
-       if (val & TWL4030_BATSTSMCHG)
-               return 0;
-
-       /*
-        * OK, It could be that bootloader did not enable main charger,
-        * pre-charge is h/w auto. So, Battery presence in Pre-charge?
-        */
-       ret = twl_i2c_read_u8(TWL4030_MODULE_PRECHARGE, &val,
-                             TWL4030_BCIMFSTS1);
-       if (ret)
-               return ret;
-       if (val & TWL4030_BATSTSPCHG)
-               return 0;
-
-       return -ENODEV;
-}
-
 /*
  * TI provided formulas:
  * CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85
@@ -922,6 +893,28 @@ static int twl4030_bci_get_property(struct power_supply *psy,
                        twl4030_bci_state_to_status(state) !=
                                POWER_SUPPLY_STATUS_NOT_CHARGING;
                break;
+       case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+               val->intval = -1;
+               if (psy->desc->type != POWER_SUPPLY_TYPE_USB) {
+                       if (!bci->ac_is_active)
+                               val->intval = bci->ac_cur;
+               } else {
+                       if (bci->ac_is_active)
+                               val->intval = bci->usb_cur_target;
+               }
+               if (val->intval < 0) {
+                       u8 bcictl1;
+
+                       val->intval = twl4030bci_read_adc_val(TWL4030_BCIIREF1);
+                       if (val->intval < 0)
+                               return val->intval;
+                       ret = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1);
+                       if (ret < 0)
+                               return ret;
+                       val->intval = regval2ua(val->intval, bcictl1 &
+                                                       TWL4030_CGAIN);
+               }
+               break;
        default:
                return -EINVAL;
        }
@@ -929,11 +922,44 @@ static int twl4030_bci_get_property(struct power_supply *psy,
        return 0;
 }
 
+static int twl4030_bci_set_property(struct power_supply *psy,
+                                   enum power_supply_property psp,
+                                   const union power_supply_propval *val)
+{
+       struct twl4030_bci *bci = dev_get_drvdata(psy->dev.parent);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+               if (psy->desc->type == POWER_SUPPLY_TYPE_USB)
+                       bci->usb_cur_target = val->intval;
+               else
+                       bci->ac_cur = val->intval;
+               twl4030_charger_update_current(bci);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int twl4030_bci_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 enum power_supply_property twl4030_charger_props[] = {
        POWER_SUPPLY_PROP_STATUS,
        POWER_SUPPLY_PROP_ONLINE,
        POWER_SUPPLY_PROP_VOLTAGE_NOW,
        POWER_SUPPLY_PROP_CURRENT_NOW,
+       POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
 };
 
 #ifdef CONFIG_OF
@@ -970,6 +996,8 @@ static const struct power_supply_desc twl4030_bci_ac_desc = {
        .properties     = twl4030_charger_props,
        .num_properties = ARRAY_SIZE(twl4030_charger_props),
        .get_property   = twl4030_bci_get_property,
+       .set_property   = twl4030_bci_set_property,
+       .property_is_writeable  = twl4030_bci_property_is_writeable,
 };
 
 static const struct power_supply_desc twl4030_bci_usb_desc = {
@@ -978,6 +1006,8 @@ static const struct power_supply_desc twl4030_bci_usb_desc = {
        .properties     = twl4030_charger_props,
        .num_properties = ARRAY_SIZE(twl4030_charger_props),
        .get_property   = twl4030_bci_get_property,
+       .set_property   = twl4030_bci_set_property,
+       .property_is_writeable  = twl4030_bci_property_is_writeable,
 };
 
 static int twl4030_bci_probe(struct platform_device *pdev)
@@ -1009,13 +1039,6 @@ static int twl4030_bci_probe(struct platform_device *pdev)
        bci->irq_chg = platform_get_irq(pdev, 0);
        bci->irq_bci = platform_get_irq(pdev, 1);
 
-       /* Only proceed further *IF* battery is physically present */
-       ret = twl4030_is_battery_present(bci);
-       if  (ret) {
-               dev_crit(&pdev->dev, "Battery was not detected:%d\n", ret);
-               return ret;
-       }
-
        platform_set_drvdata(pdev, bci);
 
        bci->ac = devm_power_supply_register(&pdev->dev, &twl4030_bci_ac_desc,
index f5817e422d6499aafc097791301092ce7d763751..4d41acb985761ad976f9de2b2cdc265a50fc9dea 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/power_supply.h>
 #include <linux/slab.h>
 #include <linux/sort.h>
-#include <linux/i2c/twl4030-madc.h>
 #include <linux/power/twl4030_madc_battery.h>
 #include <linux/iio/consumer.h>
 
index 522757ac9cd4d9975a5fe8bbbf144efb54551cd4..a7ed29baf44a6ce6c4ee01ba381655884090d6f2 100644 (file)
 #define __MAX17042_BATTERY_H_
 
 #define MAX17042_STATUS_BattAbsent     (1 << 3)
-#define MAX17042_BATTERY_FULL  (100)
+#define MAX17042_BATTERY_FULL          (95)   /* Recommend. FullSOCThr value */
 #define MAX17042_DEFAULT_SNS_RESISTOR  (10000)
+#define MAX17042_DEFAULT_VMIN          (3000)
+#define MAX17042_DEFAULT_VMAX          (4500) /* LiHV cell max */
+#define MAX17042_DEFAULT_TEMP_MIN      (0)    /* For sys without temp sensor */
+#define MAX17042_DEFAULT_TEMP_MAX      (700)  /* 70 degrees Celcius */
+
+/* Consider RepCap which is less then 10 units below FullCAP full */
+#define MAX17042_FULL_THRESHOLD                10
 
 #define MAX17042_CHARACTERIZATION_DATA_SIZE 48