2020-09-22 11:47:11

by Iskren Chernev

[permalink] [raw]
Subject: [PATCH v5 0/7] power: supply: max17040 support compatible devices

The max17040 fuel gauge is part of a family of 8 chips that have very
similar mode of operations and registers.

This patch set adds:
- compatible strings for all supported devices and handles the minor
differences between them;
- handling for devices reporting double capacity via maxim,double-soc;
- handling for setting rcomp, a compensation value for more accurate
reading, affected by battery chemistry and operating temps;
- suppot for SOC alerts (capacity changes by +/- 1%), to prevent polling
every second;
- improved max17040 driver with regmap and devm_

The datasheets of the supported devices are linked [0] [1] [2] [3].

[0] https://datasheets.maximintegrated.com/en/ds/MAX17040-MAX17041.pdf
[1] https://datasheets.maximintegrated.com/en/ds/MAX17043-MAX17044.pdf
[2] https://datasheets.maximintegrated.com/en/ds/MAX17048-MAX17049.pdf
[3] https://datasheets.maximintegrated.com/en/ds/MAX17058-MAX17059.pdf

v4: https://lkml.org/lkml/2020/9/6/237
v3: https://lkml.org/lkml/2020/6/24/874
v2: https://lkml.org/lkml/2020/6/18/260
v1: https://lkml.org/lkml/2020/6/8/682

Changes from v4:
- fix warning reported by kernel test robot <[email protected]> for v4
patch 4/7
- ensure all patches have Sign-off-by matching author (was violated
for v4 patch 2/7)

Iskren Chernev (7):
power: supply: max17040: Use devm_ to automate remove
power: supply: max17040: Use regmap i2c
dt-bindings: power: supply: Extend max17040 compatibility
power: supply: max17040: Support compatible devices
dt-bindings: power: supply: max17040: Add maxim,rcomp
power: supply: max17040: Support setting rcomp
power: supply: max17040: Support soc alert

.../power/supply/max17040_battery.txt | 21 +-
drivers/power/supply/Kconfig | 11 +-
drivers/power/supply/max17040_battery.c | 489 ++++++++++++------
3 files changed, 367 insertions(+), 154 deletions(-)


base-commit: e64997027d5f171148687e58b78c8b3c869a6158
--
2.28.0


2020-09-22 11:49:08

by Iskren Chernev

[permalink] [raw]
Subject: [PATCH v5 7/7] power: supply: max17040: Support soc alert

max17048 and max17049 support SOC alerts (interrupts when battery
capacity changes by +/- 1%). At the moment the driver polls for changes
every second. Using the alerts removes the need for polling.

Signed-off-by: Iskren Chernev <[email protected]>
Tested-by: Jonathan Bakker <[email protected]>
---
drivers/power/supply/max17040_battery.c | 82 ++++++++++++++++++++++---
1 file changed, 73 insertions(+), 9 deletions(-)

diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c
index ae39ca5c6753e..1d7510a59295d 100644
--- a/drivers/power/supply/max17040_battery.c
+++ b/drivers/power/supply/max17040_battery.c
@@ -25,6 +25,7 @@
#define MAX17040_MODE 0x06
#define MAX17040_VER 0x08
#define MAX17040_CONFIG 0x0C
+#define MAX17040_STATUS 0x1A
#define MAX17040_CMD 0xFE


@@ -33,7 +34,10 @@
#define MAX17040_RCOMP_DEFAULT 0x9700

#define MAX17040_ATHD_MASK 0x3f
+#define MAX17040_ALSC_MASK 0x40
#define MAX17040_ATHD_DEFAULT_POWER_UP 4
+#define MAX17040_STATUS_HD_MASK 0x1000
+#define MAX17040_STATUS_SC_MASK 0x2000
#define MAX17040_CFG_RCOMP_MASK 0xff00

enum chip_id {
@@ -55,6 +59,7 @@ struct chip_data {
u16 vcell_div;
u8 has_low_soc_alert;
u8 rcomp_bytes;
+ u8 has_soc_alert;
};

static struct chip_data max17040_family[] = {
@@ -65,6 +70,7 @@ static struct chip_data max17040_family[] = {
.vcell_div = 1,
.has_low_soc_alert = 0,
.rcomp_bytes = 2,
+ .has_soc_alert = 0,
},
[ID_MAX17041] = {
.reset_val = 0x0054,
@@ -73,6 +79,7 @@ static struct chip_data max17040_family[] = {
.vcell_div = 1,
.has_low_soc_alert = 0,
.rcomp_bytes = 2,
+ .has_soc_alert = 0,
},
[ID_MAX17043] = {
.reset_val = 0x0054,
@@ -81,6 +88,7 @@ static struct chip_data max17040_family[] = {
.vcell_div = 1,
.has_low_soc_alert = 1,
.rcomp_bytes = 1,
+ .has_soc_alert = 0,
},
[ID_MAX17044] = {
.reset_val = 0x0054,
@@ -89,6 +97,7 @@ static struct chip_data max17040_family[] = {
.vcell_div = 1,
.has_low_soc_alert = 1,
.rcomp_bytes = 1,
+ .has_soc_alert = 0,
},
[ID_MAX17048] = {
.reset_val = 0x5400,
@@ -97,6 +106,7 @@ static struct chip_data max17040_family[] = {
.vcell_div = 8,
.has_low_soc_alert = 1,
.rcomp_bytes = 1,
+ .has_soc_alert = 1,
},
[ID_MAX17049] = {
.reset_val = 0x5400,
@@ -105,6 +115,7 @@ static struct chip_data max17040_family[] = {
.vcell_div = 4,
.has_low_soc_alert = 1,
.rcomp_bytes = 1,
+ .has_soc_alert = 1,
},
[ID_MAX17058] = {
.reset_val = 0x5400,
@@ -113,6 +124,7 @@ static struct chip_data max17040_family[] = {
.vcell_div = 8,
.has_low_soc_alert = 1,
.rcomp_bytes = 1,
+ .has_soc_alert = 0,
},
[ID_MAX17059] = {
.reset_val = 0x5400,
@@ -121,6 +133,7 @@ static struct chip_data max17040_family[] = {
.vcell_div = 4,
.has_low_soc_alert = 1,
.rcomp_bytes = 1,
+ .has_soc_alert = 0,
},
};

@@ -156,6 +169,12 @@ static int max17040_set_low_soc_alert(struct max17040_chip *chip, u32 level)
MAX17040_ATHD_MASK, level);
}

+static int max17040_set_soc_alert(struct max17040_chip *chip, bool enable)
+{
+ return regmap_update_bits(chip->regmap, MAX17040_CONFIG,
+ MAX17040_ALSC_MASK, enable ? MAX17040_ALSC_MASK : 0);
+}
+
static int max17040_set_rcomp(struct max17040_chip *chip, u16 rcomp)
{
u16 mask = chip->data.rcomp_bytes == 2 ?
@@ -300,11 +319,33 @@ static void max17040_work(struct work_struct *work)
max17040_queue_work(chip);
}

+/* Returns true if alert cause was SOC change, not low SOC */
+static bool max17040_handle_soc_alert(struct max17040_chip *chip)
+{
+ bool ret = true;
+ u32 data;
+
+ regmap_read(chip->regmap, MAX17040_STATUS, &data);
+
+ if (data & MAX17040_STATUS_HD_MASK) {
+ // this alert was caused by low soc
+ ret = false;
+ }
+ if (data & MAX17040_STATUS_SC_MASK) {
+ // soc change bit -- deassert to mark as handled
+ regmap_write(chip->regmap, MAX17040_STATUS,
+ data & ~MAX17040_STATUS_SC_MASK);
+ }
+
+ return ret;
+}
+
static irqreturn_t max17040_thread_handler(int id, void *dev)
{
struct max17040_chip *chip = dev;

- dev_warn(&chip->client->dev, "IRQ: Alert battery low level");
+ if (!(chip->data.has_soc_alert && max17040_handle_soc_alert(chip)))
+ dev_warn(&chip->client->dev, "IRQ: Alert battery low level\n");

/* read registers */
max17040_check_changes(chip);
@@ -428,6 +469,7 @@ static int max17040_probe(struct i2c_client *client,
struct power_supply_config psy_cfg = {};
struct max17040_chip *chip;
enum chip_id chip_id;
+ bool enable_irq = false;
int ret;

if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
@@ -479,6 +521,27 @@ static int max17040_probe(struct i2c_client *client,
return ret;
}

+ enable_irq = true;
+ }
+
+ if (client->irq && chip->data.has_soc_alert) {
+ ret = max17040_set_soc_alert(chip, 1);
+ if (ret) {
+ dev_err(&client->dev,
+ "Failed to set SOC alert: err %d\n", ret);
+ return ret;
+ }
+ enable_irq = true;
+ } else {
+ /* soc alerts negate the need for polling */
+ INIT_DEFERRABLE_WORK(&chip->work, max17040_work);
+ ret = devm_add_action(&client->dev, max17040_stop_work, chip);
+ if (ret)
+ return ret;
+ max17040_queue_work(chip);
+ }
+
+ if (enable_irq) {
ret = max17040_enable_alert_irq(chip);
if (ret) {
client->irq = 0;
@@ -487,12 +550,6 @@ static int max17040_probe(struct i2c_client *client,
}
}

- INIT_DEFERRABLE_WORK(&chip->work, max17040_work);
- ret = devm_add_action(&client->dev, max17040_stop_work, chip);
- if (ret)
- return ret;
- max17040_queue_work(chip);
-
return 0;
}

@@ -503,7 +560,11 @@ static int max17040_suspend(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct max17040_chip *chip = i2c_get_clientdata(client);

- cancel_delayed_work(&chip->work);
+ if (client->irq && chip->data.has_soc_alert)
+ // disable soc alert to prevent wakeup
+ max17040_set_soc_alert(chip, 0);
+ else
+ cancel_delayed_work(&chip->work);

if (client->irq && device_may_wakeup(dev))
enable_irq_wake(client->irq);
@@ -519,7 +580,10 @@ static int max17040_resume(struct device *dev)
if (client->irq && device_may_wakeup(dev))
disable_irq_wake(client->irq);

- max17040_queue_work(chip);
+ if (client->irq && chip->data.has_soc_alert)
+ max17040_set_soc_alert(chip, 1);
+ else
+ max17040_queue_work(chip);

return 0;
}
--
2.28.0

2020-09-22 11:50:02

by Iskren Chernev

[permalink] [raw]
Subject: [PATCH v5 5/7] dt-bindings: power: supply: max17040: Add maxim,rcomp

To compensate for the battery chemistry and operating conditions the
chips support a compensation value. Specify one or two byte compensation
via the maxim,rcomp byte array.

Signed-off-by: Iskren Chernev <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---
.../devicetree/bindings/power/supply/max17040_battery.txt | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/power/supply/max17040_battery.txt b/Documentation/devicetree/bindings/power/supply/max17040_battery.txt
index 554bce82a08e6..2cf046d12d922 100644
--- a/Documentation/devicetree/bindings/power/supply/max17040_battery.txt
+++ b/Documentation/devicetree/bindings/power/supply/max17040_battery.txt
@@ -17,6 +17,11 @@ Optional properties :
Specify this boolean property to divide the
reported value in 2 and thus normalize it.
SOC == State of Charge == Capacity.
+- maxim,rcomp : A value to compensate readings for various
+ battery chemistries and operating temperatures.
+ max17040,41 have 2 byte rcomp, default to
+ 0x97 0x00. All other devices have one byte
+ rcomp, default to 0x97.
- interrupts : Interrupt line see Documentation/devicetree/
bindings/interrupt-controller/interrupts.txt
- wakeup-source : This device has wakeup capabilities. Use this
@@ -41,6 +46,7 @@ Example:
battery-fuel-gauge@36 {
compatible = "maxim,max17048";
reg = <0x36>;
+ maxim,rcomp = /bits/ 8 <0x56>;
maxim,alert-low-soc-level = <10>;
maxim,double-soc;
};
--
2.28.0

2020-09-22 11:50:07

by Iskren Chernev

[permalink] [raw]
Subject: [PATCH v5 6/7] power: supply: max17040: Support setting rcomp

The Maxim ModelGauge family supports fine-tuning by setting
a compensation value (named rcomp in the docs). The value is affected by
battery chemistry and ambient temperature.

Add support for reading maxim,rcomp from DT and configuring the device
with the supplied value. Temperature adjustment is not implemented at
the moment, because there is no provision for receiving the ambient
temperature at the moment.

Signed-off-by: Iskren Chernev <[email protected]>
Tested-by: Jonathan Bakker <[email protected]>
---
drivers/power/supply/max17040_battery.c | 40 +++++++++++++++++++++++++
1 file changed, 40 insertions(+)

diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c
index 4bcec86d92098..ae39ca5c6753e 100644
--- a/drivers/power/supply/max17040_battery.c
+++ b/drivers/power/supply/max17040_battery.c
@@ -30,9 +30,11 @@

#define MAX17040_DELAY 1000
#define MAX17040_BATTERY_FULL 95
+#define MAX17040_RCOMP_DEFAULT 0x9700

#define MAX17040_ATHD_MASK 0x3f
#define MAX17040_ATHD_DEFAULT_POWER_UP 4
+#define MAX17040_CFG_RCOMP_MASK 0xff00

enum chip_id {
ID_MAX17040,
@@ -52,6 +54,7 @@ struct chip_data {
u16 vcell_mul;
u16 vcell_div;
u8 has_low_soc_alert;
+ u8 rcomp_bytes;
};

static struct chip_data max17040_family[] = {
@@ -61,6 +64,7 @@ static struct chip_data max17040_family[] = {
.vcell_mul = 1250,
.vcell_div = 1,
.has_low_soc_alert = 0,
+ .rcomp_bytes = 2,
},
[ID_MAX17041] = {
.reset_val = 0x0054,
@@ -68,6 +72,7 @@ static struct chip_data max17040_family[] = {
.vcell_mul = 2500,
.vcell_div = 1,
.has_low_soc_alert = 0,
+ .rcomp_bytes = 2,
},
[ID_MAX17043] = {
.reset_val = 0x0054,
@@ -75,6 +80,7 @@ static struct chip_data max17040_family[] = {
.vcell_mul = 1250,
.vcell_div = 1,
.has_low_soc_alert = 1,
+ .rcomp_bytes = 1,
},
[ID_MAX17044] = {
.reset_val = 0x0054,
@@ -82,6 +88,7 @@ static struct chip_data max17040_family[] = {
.vcell_mul = 2500,
.vcell_div = 1,
.has_low_soc_alert = 1,
+ .rcomp_bytes = 1,
},
[ID_MAX17048] = {
.reset_val = 0x5400,
@@ -89,6 +96,7 @@ static struct chip_data max17040_family[] = {
.vcell_mul = 625,
.vcell_div = 8,
.has_low_soc_alert = 1,
+ .rcomp_bytes = 1,
},
[ID_MAX17049] = {
.reset_val = 0x5400,
@@ -96,6 +104,7 @@ static struct chip_data max17040_family[] = {
.vcell_mul = 625,
.vcell_div = 4,
.has_low_soc_alert = 1,
+ .rcomp_bytes = 1,
},
[ID_MAX17058] = {
.reset_val = 0x5400,
@@ -103,6 +112,7 @@ static struct chip_data max17040_family[] = {
.vcell_mul = 625,
.vcell_div = 8,
.has_low_soc_alert = 1,
+ .rcomp_bytes = 1,
},
[ID_MAX17059] = {
.reset_val = 0x5400,
@@ -110,6 +120,7 @@ static struct chip_data max17040_family[] = {
.vcell_mul = 625,
.vcell_div = 4,
.has_low_soc_alert = 1,
+ .rcomp_bytes = 1,
},
};

@@ -129,6 +140,8 @@ struct max17040_chip {
u32 low_soc_alert;
/* some devices return twice the capacity */
bool quirk_double_soc;
+ /* higher 8 bits for 17043+, 16 bits for 17040,41 */
+ u16 rcomp;
};

static int max17040_reset(struct max17040_chip *chip)
@@ -143,6 +156,14 @@ static int max17040_set_low_soc_alert(struct max17040_chip *chip, u32 level)
MAX17040_ATHD_MASK, level);
}

+static int max17040_set_rcomp(struct max17040_chip *chip, u16 rcomp)
+{
+ u16 mask = chip->data.rcomp_bytes == 2 ?
+ 0xffff : MAX17040_CFG_RCOMP_MASK;
+
+ return regmap_update_bits(chip->regmap, MAX17040_CONFIG, mask, rcomp);
+}
+
static int max17040_raw_vcell_to_uvolts(struct max17040_chip *chip, u16 vcell)
{
struct chip_data *d = &chip->data;
@@ -206,6 +227,10 @@ static int max17040_get_status(struct max17040_chip *chip)
static int max17040_get_of_data(struct max17040_chip *chip)
{
struct device *dev = &chip->client->dev;
+ struct chip_data *data = &max17040_family[
+ (enum chip_id) of_device_get_match_data(dev)];
+ int rcomp_len;
+ u8 rcomp[2];

chip->quirk_double_soc = device_property_read_bool(dev,
"maxim,double-soc");
@@ -221,6 +246,19 @@ static int max17040_get_of_data(struct max17040_chip *chip)
return -EINVAL;
}

+ rcomp_len = device_property_count_u8(dev, "maxim,rcomp");
+ chip->rcomp = MAX17040_RCOMP_DEFAULT;
+ if (rcomp_len == data->rcomp_bytes) {
+ device_property_read_u8_array(dev, "maxim,rcomp",
+ rcomp, rcomp_len);
+ chip->rcomp = rcomp_len == 2 ?
+ rcomp[0] << 8 | rcomp[1] :
+ rcomp[0] << 8;
+ } else if (rcomp_len > 0) {
+ dev_err(dev, "maxim,rcomp has incorrect length\n");
+ return -EINVAL;
+ }
+
return 0;
}

@@ -430,6 +468,8 @@ static int max17040_probe(struct i2c_client *client,
if (chip_id == ID_MAX17040 || chip_id == ID_MAX17041)
max17040_reset(chip);

+ max17040_set_rcomp(chip, chip->rcomp);
+
/* check interrupt */
if (client->irq && chip->data.has_low_soc_alert) {
ret = max17040_set_low_soc_alert(chip, chip->low_soc_alert);
--
2.28.0

2020-09-22 11:50:28

by Iskren Chernev

[permalink] [raw]
Subject: [PATCH v5 4/7] power: supply: max17040: Support compatible devices

The max17040 fuel gauge is part of a family of 8 chips that have very
similar mode of operations and registers.

This change adds:
- compatible strings for all supported devices and handling for the
minor differences between them;
- handling for devices reporting double capacity via maxim,double-soc;

The datasheets of the supported devices are linked [0] [1] [2] [3].

[0] https://datasheets.maximintegrated.com/en/ds/MAX17040-MAX17041.pdf
[1] https://datasheets.maximintegrated.com/en/ds/MAX17043-MAX17044.pdf
[2] https://datasheets.maximintegrated.com/en/ds/MAX17048-MAX17049.pdf
[3] https://datasheets.maximintegrated.com/en/ds/MAX17058-MAX17059.pdf

Signed-off-by: Iskren Chernev <[email protected]>
Tested-by: Jonathan Bakker <[email protected]>
Reported-by: kernel test robot <[email protected]>
---
drivers/power/supply/Kconfig | 10 +-
drivers/power/supply/max17040_battery.c | 155 +++++++++++++++++++++---
2 files changed, 143 insertions(+), 22 deletions(-)

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 47a4e1d363fc3..de9e0fa9a861b 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -369,9 +369,13 @@ config BATTERY_MAX17040
depends on I2C
select REGMAP_I2C
help
- MAX17040 is fuel-gauge systems for lithium-ion (Li+) batteries
- in handheld and portable equipment. The MAX17040 is configured
- to operate with a single lithium cell
+ Maxim models with ModelGauge are fuel-gauge systems for lithium-ion
+ (Li+) batteries in handheld and portable equipment, including
+ max17040, max17041, max17043, max17044, max17048, max17049, max17058,
+ max17059. It is also included in some batteries like max77836.
+
+ Driver supports reporting SOC (State of Charge, i.e capacity),
+ voltage and configurable low-SOC wakeup interrupt.

config BATTERY_MAX17042
tristate "Maxim MAX17042/17047/17050/8997/8966 Fuel Gauge"
diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c
index fae4217960761..4bcec86d92098 100644
--- a/drivers/power/supply/max17040_battery.c
+++ b/drivers/power/supply/max17040_battery.c
@@ -15,6 +15,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/power_supply.h>
+#include <linux/of_device.h>
#include <linux/max17040_battery.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -33,12 +34,92 @@
#define MAX17040_ATHD_MASK 0x3f
#define MAX17040_ATHD_DEFAULT_POWER_UP 4

+enum chip_id {
+ ID_MAX17040,
+ ID_MAX17041,
+ ID_MAX17043,
+ ID_MAX17044,
+ ID_MAX17048,
+ ID_MAX17049,
+ ID_MAX17058,
+ ID_MAX17059,
+};
+
+/* values that differ by chip_id */
+struct chip_data {
+ u16 reset_val;
+ u16 vcell_shift;
+ u16 vcell_mul;
+ u16 vcell_div;
+ u8 has_low_soc_alert;
+};
+
+static struct chip_data max17040_family[] = {
+ [ID_MAX17040] = {
+ .reset_val = 0x0054,
+ .vcell_shift = 4,
+ .vcell_mul = 1250,
+ .vcell_div = 1,
+ .has_low_soc_alert = 0,
+ },
+ [ID_MAX17041] = {
+ .reset_val = 0x0054,
+ .vcell_shift = 4,
+ .vcell_mul = 2500,
+ .vcell_div = 1,
+ .has_low_soc_alert = 0,
+ },
+ [ID_MAX17043] = {
+ .reset_val = 0x0054,
+ .vcell_shift = 4,
+ .vcell_mul = 1250,
+ .vcell_div = 1,
+ .has_low_soc_alert = 1,
+ },
+ [ID_MAX17044] = {
+ .reset_val = 0x0054,
+ .vcell_shift = 4,
+ .vcell_mul = 2500,
+ .vcell_div = 1,
+ .has_low_soc_alert = 1,
+ },
+ [ID_MAX17048] = {
+ .reset_val = 0x5400,
+ .vcell_shift = 0,
+ .vcell_mul = 625,
+ .vcell_div = 8,
+ .has_low_soc_alert = 1,
+ },
+ [ID_MAX17049] = {
+ .reset_val = 0x5400,
+ .vcell_shift = 0,
+ .vcell_mul = 625,
+ .vcell_div = 4,
+ .has_low_soc_alert = 1,
+ },
+ [ID_MAX17058] = {
+ .reset_val = 0x5400,
+ .vcell_shift = 0,
+ .vcell_mul = 625,
+ .vcell_div = 8,
+ .has_low_soc_alert = 1,
+ },
+ [ID_MAX17059] = {
+ .reset_val = 0x5400,
+ .vcell_shift = 0,
+ .vcell_mul = 625,
+ .vcell_div = 4,
+ .has_low_soc_alert = 1,
+ },
+};
+
struct max17040_chip {
struct i2c_client *client;
struct regmap *regmap;
struct delayed_work work;
struct power_supply *battery;
struct max17040_platform_data *pdata;
+ struct chip_data data;

/* battery capacity */
int soc;
@@ -46,27 +127,37 @@ struct max17040_chip {
int status;
/* Low alert threshold from 32% to 1% of the State of Charge */
u32 low_soc_alert;
+ /* some devices return twice the capacity */
+ bool quirk_double_soc;
};

static int max17040_reset(struct max17040_chip *chip)
{
- return regmap_write(chip->regmap, MAX17040_CMD, 0x0054);
+ return regmap_write(chip->regmap, MAX17040_CMD, chip->data.reset_val);
}

static int max17040_set_low_soc_alert(struct max17040_chip *chip, u32 level)
{
- level = 32 - level;
+ level = 32 - level * (chip->quirk_double_soc ? 2 : 1);
return regmap_update_bits(chip->regmap, MAX17040_CONFIG,
MAX17040_ATHD_MASK, level);
}

+static int max17040_raw_vcell_to_uvolts(struct max17040_chip *chip, u16 vcell)
+{
+ struct chip_data *d = &chip->data;
+
+ return (vcell >> d->vcell_shift) * d->vcell_mul / d->vcell_div;
+}
+
+
static int max17040_get_vcell(struct max17040_chip *chip)
{
u32 vcell;

regmap_read(chip->regmap, MAX17040_VCELL, &vcell);

- return (vcell >> 4) * 1250;
+ return max17040_raw_vcell_to_uvolts(chip, vcell);
}

static int max17040_get_soc(struct max17040_chip *chip)
@@ -75,7 +166,7 @@ static int max17040_get_soc(struct max17040_chip *chip)

regmap_read(chip->regmap, MAX17040_SOC, &soc);

- return soc >> 8;
+ return soc >> (chip->quirk_double_soc ? 9 : 8);
}

static int max17040_get_version(struct max17040_chip *chip)
@@ -116,12 +207,16 @@ static int max17040_get_of_data(struct max17040_chip *chip)
{
struct device *dev = &chip->client->dev;

+ chip->quirk_double_soc = device_property_read_bool(dev,
+ "maxim,double-soc");
+
chip->low_soc_alert = MAX17040_ATHD_DEFAULT_POWER_UP;
device_property_read_u32(dev,
"maxim,alert-low-soc-level",
&chip->low_soc_alert);

- if (chip->low_soc_alert <= 0 || chip->low_soc_alert >= 33) {
+ if (chip->low_soc_alert <= 0 ||
+ chip->low_soc_alert > (chip->quirk_double_soc ? 16 : 32)) {
dev_err(dev, "maxim,alert-low-soc-level out of bounds\n");
return -EINVAL;
}
@@ -219,8 +314,9 @@ static int max17040_set_property(struct power_supply *psy,

switch (psp) {
case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN:
- /* alert threshold can be programmed from 1% up to 32% */
- if ((val->intval < 1) || (val->intval > 32)) {
+ /* alert threshold can be programmed from 1% up to 16/32% */
+ if ((val->intval < 1) ||
+ (val->intval > (chip->quirk_double_soc ? 16 : 32))) {
ret = -EINVAL;
break;
}
@@ -293,6 +389,7 @@ static int max17040_probe(struct i2c_client *client,
struct i2c_adapter *adapter = client->adapter;
struct power_supply_config psy_cfg = {};
struct max17040_chip *chip;
+ enum chip_id chip_id;
int ret;

if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
@@ -305,9 +402,15 @@ static int max17040_probe(struct i2c_client *client,
chip->client = client;
chip->regmap = devm_regmap_init_i2c(client, &max17040_regmap);
chip->pdata = client->dev.platform_data;
- ret = max17040_get_of_data(chip);
- if (ret)
- return ret;
+ chip_id = (enum chip_id) id->driver_data;
+ if (client->dev.of_node) {
+ ret = max17040_get_of_data(chip);
+ if (ret)
+ return ret;
+ chip_id = (enum chip_id) (uintptr_t)
+ of_device_get_match_data(&client->dev);
+ }
+ chip->data = max17040_family[chip_id];

i2c_set_clientdata(client, chip);
psy_cfg.drv_data = chip;
@@ -324,11 +427,11 @@ static int max17040_probe(struct i2c_client *client,
return ret;
dev_dbg(&chip->client->dev, "MAX17040 Fuel-Gauge Ver 0x%x\n", ret);

- max17040_reset(chip);
+ if (chip_id == ID_MAX17040 || chip_id == ID_MAX17041)
+ max17040_reset(chip);

/* check interrupt */
- if (client->irq && of_device_is_compatible(client->dev.of_node,
- "maxim,max77836-battery")) {
+ if (client->irq && chip->data.has_low_soc_alert) {
ret = max17040_set_low_soc_alert(chip, chip->low_soc_alert);
if (ret) {
dev_err(&client->dev,
@@ -391,16 +494,30 @@ static SIMPLE_DEV_PM_OPS(max17040_pm_ops, max17040_suspend, max17040_resume);
#endif /* CONFIG_PM_SLEEP */

static const struct i2c_device_id max17040_id[] = {
- { "max17040" },
- { "max77836-battery" },
- { }
+ { "max17040", ID_MAX17040 },
+ { "max17041", ID_MAX17041 },
+ { "max17043", ID_MAX17043 },
+ { "max77836-battery", ID_MAX17043 },
+ { "max17044", ID_MAX17044 },
+ { "max17048", ID_MAX17048 },
+ { "max17049", ID_MAX17049 },
+ { "max17058", ID_MAX17058 },
+ { "max17059", ID_MAX17059 },
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, max17040_id);

static const struct of_device_id max17040_of_match[] = {
- { .compatible = "maxim,max17040" },
- { .compatible = "maxim,max77836-battery" },
- { },
+ { .compatible = "maxim,max17040", .data = (void *) ID_MAX17040 },
+ { .compatible = "maxim,max17041", .data = (void *) ID_MAX17041 },
+ { .compatible = "maxim,max17043", .data = (void *) ID_MAX17043 },
+ { .compatible = "maxim,max77836-battery", .data = (void *) ID_MAX17043 },
+ { .compatible = "maxim,max17044", .data = (void *) ID_MAX17044 },
+ { .compatible = "maxim,max17048", .data = (void *) ID_MAX17048 },
+ { .compatible = "maxim,max17049", .data = (void *) ID_MAX17049 },
+ { .compatible = "maxim,max17058", .data = (void *) ID_MAX17058 },
+ { .compatible = "maxim,max17059", .data = (void *) ID_MAX17059 },
+ { /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, max17040_of_match);

--
2.28.0

2020-09-22 11:51:52

by Iskren Chernev

[permalink] [raw]
Subject: [PATCH v5 2/7] power: supply: max17040: Use regmap i2c

Rewrite i2c operations from i2c client read/write to regmap i2c. As
a result, most private functions now accept the private driver data
instead of an i2c client pointer.

Signed-off-by: Iskren Chernev <[email protected]>
Tested-by: Jonathan Bakker <[email protected]>
---
drivers/power/supply/Kconfig | 1 +
drivers/power/supply/max17040_battery.c | 219 ++++++++++--------------
2 files changed, 93 insertions(+), 127 deletions(-)

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index a4657484f38be..47a4e1d363fc3 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -367,6 +367,7 @@ config AXP288_FUEL_GAUGE
config BATTERY_MAX17040
tristate "Maxim MAX17040 Fuel Gauge"
depends on I2C
+ select REGMAP_I2C
help
MAX17040 is fuel-gauge systems for lithium-ion (Li+) batteries
in handheld and portable equipment. The MAX17040 is configured
diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c
index 19b9e710bbd2f..fae4217960761 100644
--- a/drivers/power/supply/max17040_battery.c
+++ b/drivers/power/supply/max17040_battery.c
@@ -16,32 +16,30 @@
#include <linux/interrupt.h>
#include <linux/power_supply.h>
#include <linux/max17040_battery.h>
+#include <linux/regmap.h>
#include <linux/slab.h>

#define MAX17040_VCELL 0x02
#define MAX17040_SOC 0x04
#define MAX17040_MODE 0x06
#define MAX17040_VER 0x08
-#define MAX17040_RCOMP 0x0C
+#define MAX17040_CONFIG 0x0C
#define MAX17040_CMD 0xFE


#define MAX17040_DELAY 1000
#define MAX17040_BATTERY_FULL 95

-#define MAX17040_ATHD_MASK 0xFFC0
+#define MAX17040_ATHD_MASK 0x3f
#define MAX17040_ATHD_DEFAULT_POWER_UP 4

struct max17040_chip {
struct i2c_client *client;
+ struct regmap *regmap;
struct delayed_work work;
struct power_supply *battery;
struct max17040_platform_data *pdata;

- /* State Of Connect */
- int online;
- /* battery voltage */
- int vcell;
/* battery capacity */
int soc;
/* State Of Charge */
@@ -50,138 +48,68 @@ struct max17040_chip {
u32 low_soc_alert;
};

-static int max17040_get_property(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
+static int max17040_reset(struct max17040_chip *chip)
{
- struct max17040_chip *chip = power_supply_get_drvdata(psy);
-
- switch (psp) {
- case POWER_SUPPLY_PROP_STATUS:
- val->intval = chip->status;
- break;
- case POWER_SUPPLY_PROP_ONLINE:
- val->intval = chip->online;
- break;
- case POWER_SUPPLY_PROP_VOLTAGE_NOW:
- val->intval = chip->vcell;
- break;
- case POWER_SUPPLY_PROP_CAPACITY:
- val->intval = chip->soc;
- break;
- case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN:
- val->intval = chip->low_soc_alert;
- break;
- default:
- return -EINVAL;
- }
- return 0;
+ return regmap_write(chip->regmap, MAX17040_CMD, 0x0054);
}

-static int max17040_write_reg(struct i2c_client *client, int reg, u16 value)
+static int max17040_set_low_soc_alert(struct max17040_chip *chip, u32 level)
{
- int ret;
-
- ret = i2c_smbus_write_word_swapped(client, reg, value);
-
- if (ret < 0)
- dev_err(&client->dev, "%s: err %d\n", __func__, ret);
-
- return ret;
-}
-
-static int max17040_read_reg(struct i2c_client *client, int reg)
-{
- int ret;
-
- ret = i2c_smbus_read_word_swapped(client, reg);
-
- if (ret < 0)
- dev_err(&client->dev, "%s: err %d\n", __func__, ret);
-
- return ret;
-}
-
-static void max17040_reset(struct i2c_client *client)
-{
- max17040_write_reg(client, MAX17040_CMD, 0x0054);
-}
-
-static int max17040_set_low_soc_alert(struct i2c_client *client, u32 level)
-{
- int ret;
- u16 data;
-
level = 32 - level;
- data = max17040_read_reg(client, MAX17040_RCOMP);
- /* clear the alrt bit and set LSb 5 bits */
- data &= MAX17040_ATHD_MASK;
- data |= level;
- ret = max17040_write_reg(client, MAX17040_RCOMP, data);
-
- return ret;
+ return regmap_update_bits(chip->regmap, MAX17040_CONFIG,
+ MAX17040_ATHD_MASK, level);
}

-static void max17040_get_vcell(struct i2c_client *client)
+static int max17040_get_vcell(struct max17040_chip *chip)
{
- struct max17040_chip *chip = i2c_get_clientdata(client);
- u16 vcell;
+ u32 vcell;

- vcell = max17040_read_reg(client, MAX17040_VCELL);
+ regmap_read(chip->regmap, MAX17040_VCELL, &vcell);

- chip->vcell = (vcell >> 4) * 1250;
+ return (vcell >> 4) * 1250;
}

-static void max17040_get_soc(struct i2c_client *client)
+static int max17040_get_soc(struct max17040_chip *chip)
{
- struct max17040_chip *chip = i2c_get_clientdata(client);
- u16 soc;
+ u32 soc;

- soc = max17040_read_reg(client, MAX17040_SOC);
+ regmap_read(chip->regmap, MAX17040_SOC, &soc);

- chip->soc = (soc >> 8);
+ return soc >> 8;
}

-static void max17040_get_version(struct i2c_client *client)
+static int max17040_get_version(struct max17040_chip *chip)
{
- u16 version;
+ int ret;
+ u32 version;

- version = max17040_read_reg(client, MAX17040_VER);
+ ret = regmap_read(chip->regmap, MAX17040_VER, &version);

- dev_info(&client->dev, "MAX17040 Fuel-Gauge Ver 0x%x\n", version);
+ return ret ? ret : version;
}

-static void max17040_get_online(struct i2c_client *client)
+static int max17040_get_online(struct max17040_chip *chip)
{
- struct max17040_chip *chip = i2c_get_clientdata(client);
-
- if (chip->pdata && chip->pdata->battery_online)
- chip->online = chip->pdata->battery_online();
- else
- chip->online = 1;
+ return chip->pdata && chip->pdata->battery_online ?
+ chip->pdata->battery_online() : 1;
}

-static void max17040_get_status(struct i2c_client *client)
+static int max17040_get_status(struct max17040_chip *chip)
{
- struct max17040_chip *chip = i2c_get_clientdata(client);
-
if (!chip->pdata || !chip->pdata->charger_online
- || !chip->pdata->charger_enable) {
- chip->status = POWER_SUPPLY_STATUS_UNKNOWN;
- return;
- }
+ || !chip->pdata->charger_enable)
+ return POWER_SUPPLY_STATUS_UNKNOWN;
+
+ if (max17040_get_soc(chip) > MAX17040_BATTERY_FULL)
+ return POWER_SUPPLY_STATUS_FULL;

- if (chip->pdata->charger_online()) {
+ if (chip->pdata->charger_online())
if (chip->pdata->charger_enable())
- chip->status = POWER_SUPPLY_STATUS_CHARGING;
+ return POWER_SUPPLY_STATUS_CHARGING;
else
- chip->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
- } else {
- chip->status = POWER_SUPPLY_STATUS_DISCHARGING;
- }
-
- if (chip->soc > MAX17040_BATTERY_FULL)
- chip->status = POWER_SUPPLY_STATUS_FULL;
+ return POWER_SUPPLY_STATUS_NOT_CHARGING;
+ else
+ return POWER_SUPPLY_STATUS_DISCHARGING;
}

static int max17040_get_of_data(struct max17040_chip *chip)
@@ -193,18 +121,18 @@ static int max17040_get_of_data(struct max17040_chip *chip)
"maxim,alert-low-soc-level",
&chip->low_soc_alert);

- if (chip->low_soc_alert <= 0 || chip->low_soc_alert >= 33)
+ if (chip->low_soc_alert <= 0 || chip->low_soc_alert >= 33) {
+ dev_err(dev, "maxim,alert-low-soc-level out of bounds\n");
return -EINVAL;
+ }

return 0;
}

-static void max17040_check_changes(struct i2c_client *client)
+static void max17040_check_changes(struct max17040_chip *chip)
{
- max17040_get_vcell(client);
- max17040_get_soc(client);
- max17040_get_online(client);
- max17040_get_status(client);
+ chip->soc = max17040_get_soc(chip);
+ chip->status = max17040_get_status(chip);
}

static void max17040_queue_work(struct max17040_chip *chip)
@@ -230,7 +158,7 @@ static void max17040_work(struct work_struct *work)
/* store SOC and status to check changes */
last_soc = chip->soc;
last_status = chip->status;
- max17040_check_changes(chip->client);
+ max17040_check_changes(chip);

/* check changes and send uevent */
if (last_soc != chip->soc || last_status != chip->status)
@@ -242,17 +170,17 @@ static void max17040_work(struct work_struct *work)
static irqreturn_t max17040_thread_handler(int id, void *dev)
{
struct max17040_chip *chip = dev;
- struct i2c_client *client = chip->client;

- dev_warn(&client->dev, "IRQ: Alert battery low level");
+ dev_warn(&chip->client->dev, "IRQ: Alert battery low level");
+
/* read registers */
- max17040_check_changes(chip->client);
+ max17040_check_changes(chip);

/* send uevent */
power_supply_changed(chip->battery);

/* reset alert bit */
- max17040_set_low_soc_alert(client, chip->low_soc_alert);
+ max17040_set_low_soc_alert(chip, chip->low_soc_alert);

return IRQ_HANDLED;
}
@@ -296,7 +224,7 @@ static int max17040_set_property(struct power_supply *psy,
ret = -EINVAL;
break;
}
- ret = max17040_set_low_soc_alert(chip->client, val->intval);
+ ret = max17040_set_low_soc_alert(chip, val->intval);
chip->low_soc_alert = val->intval;
break;
default:
@@ -306,6 +234,41 @@ static int max17040_set_property(struct power_supply *psy,
return ret;
}

+static int max17040_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct max17040_chip *chip = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = max17040_get_status(chip);
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = max17040_get_online(chip);
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = max17040_get_vcell(chip);
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = max17040_get_soc(chip);
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN:
+ val->intval = chip->low_soc_alert;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct regmap_config max17040_regmap = {
+ .reg_bits = 8,
+ .reg_stride = 2,
+ .val_bits = 16,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+
static enum power_supply_property max17040_battery_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_ONLINE,
@@ -340,13 +303,11 @@ static int max17040_probe(struct i2c_client *client,
return -ENOMEM;

chip->client = client;
+ chip->regmap = devm_regmap_init_i2c(client, &max17040_regmap);
chip->pdata = client->dev.platform_data;
ret = max17040_get_of_data(chip);
- if (ret) {
- dev_err(&client->dev,
- "failed: low SOC alert OF data out of bounds\n");
+ if (ret)
return ret;
- }

i2c_set_clientdata(client, chip);
psy_cfg.drv_data = chip;
@@ -358,13 +319,17 @@ static int max17040_probe(struct i2c_client *client,
return PTR_ERR(chip->battery);
}

- max17040_reset(client);
- max17040_get_version(client);
+ ret = max17040_get_version(chip);
+ if (ret < 0)
+ return ret;
+ dev_dbg(&chip->client->dev, "MAX17040 Fuel-Gauge Ver 0x%x\n", ret);
+
+ max17040_reset(chip);

/* check interrupt */
if (client->irq && of_device_is_compatible(client->dev.of_node,
"maxim,max77836-battery")) {
- ret = max17040_set_low_soc_alert(client, chip->low_soc_alert);
+ ret = max17040_set_low_soc_alert(chip, chip->low_soc_alert);
if (ret) {
dev_err(&client->dev,
"Failed to set low SOC alert: err %d\n", ret);
--
2.28.0

2020-09-22 11:51:53

by Iskren Chernev

[permalink] [raw]
Subject: [PATCH v5 3/7] dt-bindings: power: supply: Extend max17040 compatibility

Maxim max17040 is a fuel gauge from a larger family utilising the Model
Gauge technology. Document all different compatible strings that the
max17040 driver recognizes.

Some devices in the wild report double the capacity. The
maxim,double-soc (from State-Of-Charge) property fixes that.
Examples: https://lore.kernel.org/patchwork/patch/1263411/#1468420

Signed-off-by: Iskren Chernev <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---
.../bindings/power/supply/max17040_battery.txt | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/power/supply/max17040_battery.txt b/Documentation/devicetree/bindings/power/supply/max17040_battery.txt
index 4e0186b8380fa..554bce82a08e6 100644
--- a/Documentation/devicetree/bindings/power/supply/max17040_battery.txt
+++ b/Documentation/devicetree/bindings/power/supply/max17040_battery.txt
@@ -2,7 +2,9 @@ max17040_battery
~~~~~~~~~~~~~~~~

Required properties :
- - compatible : "maxim,max17040" or "maxim,max77836-battery"
+ - compatible : "maxim,max17040", "maxim,max17041", "maxim,max17043",
+ "maxim,max17044", "maxim,max17048", "maxim,max17049",
+ "maxim,max17058", "maxim,max17059" or "maxim,max77836-battery"
- reg: i2c slave address

Optional properties :
@@ -11,6 +13,10 @@ Optional properties :
generated. Can be configured from 1 up to 32
(%). If skipped the power up default value of
4 (%) will be used.
+- maxim,double-soc : Certain devices return double the capacity.
+ Specify this boolean property to divide the
+ reported value in 2 and thus normalize it.
+ SOC == State of Charge == Capacity.
- interrupts : Interrupt line see Documentation/devicetree/
bindings/interrupt-controller/interrupts.txt
- wakeup-source : This device has wakeup capabilities. Use this
@@ -31,3 +37,10 @@ Example:
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
wakeup-source;
};
+
+ battery-fuel-gauge@36 {
+ compatible = "maxim,max17048";
+ reg = <0x36>;
+ maxim,alert-low-soc-level = <10>;
+ maxim,double-soc;
+ };
--
2.28.0

2020-09-22 11:53:10

by Iskren Chernev

[permalink] [raw]
Subject: [PATCH v5 1/7] power: supply: max17040: Use devm_ to automate remove

Two actions were performed during remove - power supply dereg and
delayed work cleanup. Power supply dereg can be handled by using the
devm_ version of the registration function. Work cleanup can be added as
a devm_action.

If probe fails after psy registration it will now be cleaned up
properly.

Signed-off-by: Iskren Chernev <[email protected]>
Tested-by: Jonathan Bakker <[email protected]>
---
drivers/power/supply/max17040_battery.c | 39 +++++++++++++------------
1 file changed, 21 insertions(+), 18 deletions(-)

diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c
index 6cb31b9a958dd..19b9e710bbd2f 100644
--- a/drivers/power/supply/max17040_battery.c
+++ b/drivers/power/supply/max17040_battery.c
@@ -207,6 +207,19 @@ static void max17040_check_changes(struct i2c_client *client)
max17040_get_status(client);
}

+static void max17040_queue_work(struct max17040_chip *chip)
+{
+ queue_delayed_work(system_power_efficient_wq, &chip->work,
+ MAX17040_DELAY);
+}
+
+static void max17040_stop_work(void *data)
+{
+ struct max17040_chip *chip = data;
+
+ cancel_delayed_work_sync(&chip->work);
+}
+
static void max17040_work(struct work_struct *work)
{
struct max17040_chip *chip;
@@ -223,8 +236,7 @@ static void max17040_work(struct work_struct *work)
if (last_soc != chip->soc || last_status != chip->status)
power_supply_changed(chip->battery);

- queue_delayed_work(system_power_efficient_wq, &chip->work,
- MAX17040_DELAY);
+ max17040_queue_work(chip);
}

static irqreturn_t max17040_thread_handler(int id, void *dev)
@@ -339,7 +351,7 @@ static int max17040_probe(struct i2c_client *client,
i2c_set_clientdata(client, chip);
psy_cfg.drv_data = chip;

- chip->battery = power_supply_register(&client->dev,
+ chip->battery = devm_power_supply_register(&client->dev,
&max17040_battery_desc, &psy_cfg);
if (IS_ERR(chip->battery)) {
dev_err(&client->dev, "failed: power supply register\n");
@@ -368,18 +380,11 @@ static int max17040_probe(struct i2c_client *client,
}

INIT_DEFERRABLE_WORK(&chip->work, max17040_work);
- queue_delayed_work(system_power_efficient_wq, &chip->work,
- MAX17040_DELAY);
-
- return 0;
-}
-
-static int max17040_remove(struct i2c_client *client)
-{
- struct max17040_chip *chip = i2c_get_clientdata(client);
+ ret = devm_add_action(&client->dev, max17040_stop_work, chip);
+ if (ret)
+ return ret;
+ max17040_queue_work(chip);

- power_supply_unregister(chip->battery);
- cancel_delayed_work(&chip->work);
return 0;
}

@@ -403,12 +408,11 @@ static int max17040_resume(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct max17040_chip *chip = i2c_get_clientdata(client);

- queue_delayed_work(system_power_efficient_wq, &chip->work,
- MAX17040_DELAY);
-
if (client->irq && device_may_wakeup(dev))
disable_irq_wake(client->irq);

+ max17040_queue_work(chip);
+
return 0;
}

@@ -442,7 +446,6 @@ static struct i2c_driver max17040_i2c_driver = {
.pm = MAX17040_PM_OPS,
},
.probe = max17040_probe,
- .remove = max17040_remove,
.id_table = max17040_id,
};
module_i2c_driver(max17040_i2c_driver);
--
2.28.0

2020-10-03 19:14:03

by Sebastian Reichel

[permalink] [raw]
Subject: Re: [PATCH v5 0/7] power: supply: max17040 support compatible devices

Hi,

On Tue, Sep 22, 2020 at 02:42:30PM +0300, Iskren Chernev wrote:
> The max17040 fuel gauge is part of a family of 8 chips that have very
> similar mode of operations and registers.
>
> This patch set adds:
> - compatible strings for all supported devices and handles the minor
> differences between them;
> - handling for devices reporting double capacity via maxim,double-soc;
> - handling for setting rcomp, a compensation value for more accurate
> reading, affected by battery chemistry and operating temps;
> - suppot for SOC alerts (capacity changes by +/- 1%), to prevent polling
> every second;
> - improved max17040 driver with regmap and devm_
>
> The datasheets of the supported devices are linked [0] [1] [2] [3].
>
> [0] https://datasheets.maximintegrated.com/en/ds/MAX17040-MAX17041.pdf
> [1] https://datasheets.maximintegrated.com/en/ds/MAX17043-MAX17044.pdf
> [2] https://datasheets.maximintegrated.com/en/ds/MAX17048-MAX17049.pdf
> [3] https://datasheets.maximintegrated.com/en/ds/MAX17058-MAX17059.pdf
>
> v4: https://lkml.org/lkml/2020/9/6/237
> v3: https://lkml.org/lkml/2020/6/24/874
> v2: https://lkml.org/lkml/2020/6/18/260
> v1: https://lkml.org/lkml/2020/6/8/682
>
> Changes from v4:
> - fix warning reported by kernel test robot <[email protected]> for v4
> patch 4/7
> - ensure all patches have Sign-off-by matching author (was violated
> for v4 patch 2/7)

Thanks, queued.

-- Sebastian


Attachments:
(No filename) (1.43 kB)
signature.asc (849.00 B)
Download all attachments