]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
power: supply: max17042: initial support for Maxim MAX77759
authorAndré Draszik <andre.draszik@linaro.org>
Mon, 2 Mar 2026 13:32:08 +0000 (13:32 +0000)
committerSebastian Reichel <sebastian.reichel@collabora.com>
Tue, 3 Mar 2026 22:58:07 +0000 (23:58 +0100)
The Maxim MAX77759 is a companion PMIC intended for use in mobile
phones and tablets. It is used on Google Pixel 6 and 6 Pro (oriole and
raven). Amongst others, it contains a fuel gauge that is similar to the
ones supported by this driver.

The fuel gauge can measure battery charge and discharge current,
battery voltage, battery temperature, and the Type C connector's
temperature.

The MAX77759 incorporates the Maxim ModelGauge m5 algorithm. It, as
well as previous generations like m3 on max17047/max17050, requires
the host to save/restore some register values across power cycles to
maintain full accuracy. Extending the driver for such support is out of
scope in this initial commit.

Reviewed-by: Peter Griffin <peter.griffin@linaro.org>
Signed-off-by: André Draszik <andre.draszik@linaro.org>
Link: https://patch.msgid.link/20260302-max77759-fg-v3-9-3c5f01dbda23@linaro.org
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
drivers/power/supply/max17042_battery.c
include/linux/power/max17042_battery.h

index e21d2bd7e23117809febfe6c183d3d109ba3eb7a..b9a21cef2cc61988b52ae6e0e0db261aff906b75 100644 (file)
@@ -650,7 +650,8 @@ static void max17042_write_config_regs(struct max17042_chip *chip)
        regmap_write(map, MAX17042_RelaxCFG, config->relax_cfg);
        if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047 ||
                        chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050 ||
-                       chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055)
+                       chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055 ||
+                       chip->chip_type == MAXIM_DEVICE_TYPE_MAX77759)
                regmap_write(map, MAX17047_FullSOCThr,
                                                config->full_soc_thresh);
 }
@@ -787,7 +788,8 @@ static inline void max17042_override_por_values(struct max17042_chip *chip)
 
        if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) ||
            (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) ||
-           (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050)) {
+           (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050) ||
+           (chip->chip_type == MAXIM_DEVICE_TYPE_MAX77759)) {
                max17042_override_por(map, MAX17042_IAvg_empty, config->iavg_empty);
                max17042_override_por(map, MAX17042_TempNom, config->temp_nom);
                max17042_override_por(map, MAX17042_TempLim, config->temp_lim);
@@ -796,7 +798,8 @@ static inline void max17042_override_por_values(struct max17042_chip *chip)
 
        if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) ||
            (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050) ||
-           (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055)) {
+           (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055) ||
+           (chip->chip_type == MAXIM_DEVICE_TYPE_MAX77759)) {
                max17042_override_por(map, MAX17047_V_empty, config->vempty);
        }
 }
@@ -1019,6 +1022,45 @@ static const struct regmap_config max17042_regmap_config = {
        .val_format_endian = REGMAP_ENDIAN_NATIVE,
 };
 
+static const struct regmap_range max77759_fg_registers[] = {
+       regmap_reg_range(MAX17042_STATUS, MAX77759_MixAtFull),
+       regmap_reg_range(MAX17042_VFSOC0Enable, MAX17042_VFSOC0Enable),
+       regmap_reg_range(MAX17042_MLOCKReg1, MAX17042_MLOCKReg2),
+       regmap_reg_range(MAX17042_MODELChrTbl, MAX17055_TimerH),
+       regmap_reg_range(MAX77759_IIn, MAX77759_IIn),
+       regmap_reg_range(MAX17055_AtQResidual, MAX17055_AtAvCap),
+       regmap_reg_range(MAX17042_OCVInternal, MAX17042_OCVInternal),
+       regmap_reg_range(MAX17042_VFSOC, MAX17042_VFSOC),
+};
+
+static const struct regmap_range max77759_fg_ro_registers[] = {
+       regmap_reg_range(MAX17042_FSTAT, MAX17042_FSTAT),
+       regmap_reg_range(MAX17042_OCVInternal, MAX17042_OCVInternal),
+       regmap_reg_range(MAX17042_VFSOC, MAX17042_VFSOC),
+};
+
+static const struct regmap_access_table max77759_fg_write_table = {
+       .yes_ranges = max77759_fg_registers,
+       .n_yes_ranges = ARRAY_SIZE(max77759_fg_registers),
+       .no_ranges = max77759_fg_ro_registers,
+       .n_no_ranges = ARRAY_SIZE(max77759_fg_ro_registers),
+};
+
+static const struct regmap_access_table max77759_fg_rd_table = {
+       .yes_ranges = max77759_fg_registers,
+       .n_yes_ranges = ARRAY_SIZE(max77759_fg_registers),
+};
+
+static const struct regmap_config max77759_fg_regmap_cfg = {
+       .reg_bits = 8,
+       .val_bits = 16,
+       .max_register = 0xff,
+       .wr_table = &max77759_fg_write_table,
+       .rd_table = &max77759_fg_rd_table,
+       .val_format_endian = REGMAP_ENDIAN_NATIVE,
+       .cache_type = REGCACHE_NONE,
+};
+
 static const struct power_supply_desc max17042_psy_desc = {
        .name           = "max170xx_battery",
        .type           = POWER_SUPPLY_TYPE_BATTERY,
@@ -1045,6 +1087,7 @@ static int max17042_probe(struct i2c_client *client, struct device *dev, int irq
 {
        struct i2c_adapter *adapter = client->adapter;
        const struct power_supply_desc *max17042_desc = &max17042_psy_desc;
+       const struct regmap_config *regmap_config;
        struct power_supply_config psy_cfg = {};
        struct max17042_chip *chip;
        int ret;
@@ -1060,7 +1103,12 @@ static int max17042_probe(struct i2c_client *client, struct device *dev, int irq
 
        chip->dev = dev;
        chip->chip_type = chip_type;
-       chip->regmap = devm_regmap_init_i2c(client, &max17042_regmap_config);
+
+       if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX77759)
+               regmap_config = &max77759_fg_regmap_cfg;
+       else
+               regmap_config = &max17042_regmap_config;
+       chip->regmap = devm_regmap_init_i2c(client, regmap_config);
        if (IS_ERR(chip->regmap))
                return dev_err_probe(dev, PTR_ERR(chip->regmap),
                                     "Failed to initialize regmap\n");
@@ -1241,6 +1289,8 @@ static const struct of_device_id max17042_dt_match[] __used = {
                .data = (void *) MAXIM_DEVICE_TYPE_MAX17055 },
        { .compatible = "maxim,max77705-battery",
                .data = (void *) MAXIM_DEVICE_TYPE_MAX17047 },
+       { .compatible = "maxim,max77759-fg",
+               .data = (void *) MAXIM_DEVICE_TYPE_MAX77759 },
        { .compatible = "maxim,max77849-battery",
                .data = (void *) MAXIM_DEVICE_TYPE_MAX17047 },
        { },
@@ -1253,6 +1303,7 @@ static const struct i2c_device_id max17042_id[] = {
        { "max17047", MAXIM_DEVICE_TYPE_MAX17047 },
        { "max17050", MAXIM_DEVICE_TYPE_MAX17050 },
        { "max17055", MAXIM_DEVICE_TYPE_MAX17055 },
+       { "max77759-fg", MAXIM_DEVICE_TYPE_MAX77759 },
        { "max77849-battery", MAXIM_DEVICE_TYPE_MAX17047 },
        { }
 };
index c417abd2ab703b273d69da28f9deb62fca51a934..05097f08ea36a8c97628fddba8a3bbce29fb6a98 100644 (file)
@@ -105,7 +105,7 @@ enum max17042_register {
 
        MAX17042_OCV            = 0xEE,
 
-       MAX17042_OCVInternal    = 0xFB,  /* MAX17055 VFOCV */
+       MAX17042_OCVInternal    = 0xFB, /* MAX17055/77759 VFOCV */
 
        MAX17042_VFSOC          = 0xFF,
 };
@@ -156,7 +156,7 @@ enum max17055_register {
        MAX17055_AtAvCap        = 0xDF,
 };
 
-/* Registers specific to max17047/50/55 */
+/* Registers specific to max17047/50/55/77759 */
 enum max17047_register {
        MAX17047_QRTbl00        = 0x12,
        MAX17047_FullSOCThr     = 0x13,
@@ -167,12 +167,32 @@ enum max17047_register {
        MAX17047_QRTbl30        = 0x42,
 };
 
+enum max77759_register {
+       MAX77759_AvgTA0         = 0x26,
+       MAX77759_AtTTF          = 0x33,
+       MAX77759_Tconvert       = 0x34,
+       MAX77759_AvgCurrent0    = 0x3B,
+       MAX77759_THMHOT         = 0x40,
+       MAX77759_CTESample      = 0x41,
+       MAX77759_ISys           = 0x43,
+       MAX77759_AvgVCell0      = 0x44,
+       MAX77759_RlxSOC         = 0x47,
+       MAX77759_AvgISys        = 0x4B,
+       MAX77759_QH0            = 0x4C,
+       MAX77759_MixAtFull      = 0x4F,
+       MAX77759_VSys           = 0xB1,
+       MAX77759_TAlrtTh2       = 0xB2,
+       MAX77759_VByp           = 0xB3,
+       MAX77759_IIn            = 0xD0,
+};
+
 enum max170xx_chip_type {
        MAXIM_DEVICE_TYPE_UNKNOWN       = 0,
        MAXIM_DEVICE_TYPE_MAX17042,
        MAXIM_DEVICE_TYPE_MAX17047,
        MAXIM_DEVICE_TYPE_MAX17050,
        MAXIM_DEVICE_TYPE_MAX17055,
+       MAXIM_DEVICE_TYPE_MAX77759,
 
        MAXIM_DEVICE_TYPE_NUM
 };