Hi Thomas, Thanks for your patch, and working on this! On Mon, 4 Aug 2025 at 15:25, Thomas Antoine via B4 Relay <devnull+t.antoine.uclouvain.be@xxxxxxxxxx> wrote: > > From: Thomas Antoine <t.antoine@xxxxxxxxxxxx> > > The Maxim MAX77759 is a PMIC used in gs101-oriole and gs101-raven > (Google Pixel 6 and 6 Pro). It contains a fuel gauge on a separate > I2C address. Add basic support for this fuel gauge. The driver is > based on the driver for the MAX17201 and MAX17205 which also use > the MAX M5 fuel gauge. There is a lot of common between the two small nit: "in common" ^^^^^^ > devices with some key differences. The main one is the lack of nvmem > in the fuel gauge of the MAX77759. > > The initialization of the chip is very basic and mostly hardcoded. > Loading the model of the fuel gauge is not implemented here. > > On both gs101-oriole and gs101-raven, the same EEPROM as for the > battery id is used to backup some of the state of the fuel gauge. > Use a standard nvmem binding to access this data. The CRC8 is > computed to allow to go from linux to a stock android without > apparent data corruption. If other devices using the MAX77759 are > found/created, a similar nvmem layout should be made or the driver > should be extended to support those devices. > > The current, capacity, temperature and charge have all been tested. > The charge full design and capacity equal the ones seen on android, > the ratio between average charge and average current does predict > pretty accurately the time to empty under a constant workload and > temperature is coherent with the dynamic state of the device. > > Health is not enabled as it always reports overheating. The time to > empty is wrong by about a factor 2. The voltage reporting is > correct when using VCELL (which reports the lowest voltage of all > cells) when considering that the device is connected to a single > cell. It could be enabled by either confirming that the device is > connected to a single cell or finding an alternative reporting mean. > > Modifications have been made to it since but the regmap was > originally proposed by André Draszik in > > Link: https://lore.kernel.org/all/d1bade77b5281c1de6b2ddcb4dbbd033e455a116.camel@xxxxxxxxxx/ > > Signed-off-by: Thomas Antoine <t.antoine@xxxxxxxxxxxx> > --- > drivers/power/supply/Kconfig | 14 + > drivers/power/supply/Makefile | 1 + > drivers/power/supply/max77759_battery.c | 649 ++++++++++++++++++++++++++++++++ > 3 files changed, 664 insertions(+) > > diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig > index 79ddb006e2dad6bf96b71ed570a37c006b5f9433..147d049b836c3fbb24b762dbaf31eebb8ba041f7 100644 > --- a/drivers/power/supply/Kconfig > +++ b/drivers/power/supply/Kconfig > @@ -458,6 +458,20 @@ config BATTERY_MAX1721X > Say Y here to enable support for the MAX17211/MAX17215 standalone > battery gas-gauge. > > +config BATTERY_MAX77759 > + tristate "Maxim Integrated MAX77759 Fuel Gauge" > + depends on I2C > + select REGMAP_I2C > + help > + Say yes to enable support for the Fuel gauge of the Maxim Integrated > + MAX77759. It is a companion Power Management IC for USB Type-C > + applications with Battery Charger, Fuel Gauge, temperature sensors, > + USB Type-C Port Controller (TCPC), NVMEM, and additional GPIO > + interfaces. > + > + To compile this driver as module, choose M here: the > + module will be called max77759_fg. > + > config BATTERY_TWL4030_MADC > tristate "TWL4030 MADC battery driver" > depends on TWL4030_MADC > diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile > index 4f5f8e3507f80da02812f0d08c2d81ddff0a272f..114578fa4fd08356822f13ce1fbad29923defad8 100644 > --- a/drivers/power/supply/Makefile > +++ b/drivers/power/supply/Makefile > @@ -57,6 +57,7 @@ obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o > obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o > obj-$(CONFIG_BATTERY_MAX1720X) += max1720x_battery.o > obj-$(CONFIG_BATTERY_MAX1721X) += max1721x_battery.o > +obj-$(CONFIG_BATTERY_MAX77759) += max77759_battery.o > obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o > obj-$(CONFIG_CHARGER_RT5033) += rt5033_charger.o > obj-$(CONFIG_CHARGER_RT9455) += rt9455_charger.o > diff --git a/drivers/power/supply/max77759_battery.c b/drivers/power/supply/max77759_battery.c > new file mode 100644 > index 0000000000000000000000000000000000000000..d8d702af607211e391733cd14323698b54be734c > --- /dev/null > +++ b/drivers/power/supply/max77759_battery.c > @@ -0,0 +1,649 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Fuel gauge driver for Maxim 777759 > + * > + * based on max1720x_battery.c > + * > + * Copyright (C) 2024 Liebherr-Electronics and Drives GmbH > + */ > + [..] > + switch (psp) { > + case POWER_SUPPLY_PROP_PRESENT: > + /* > + * POWER_SUPPLY_PROP_PRESENT will always readable via > + * sysfs interface. Value return 0 if battery not > + * present or unaccesable via I2c. small nit: inaccessible ^^^^^^ > + */ > + ret = regmap_read(info->regmap, MAX77759_FG_STATUS, ®_val); > + if (ret < 0) { > + val->intval = 0; > + return 0; > + } > + > + val->intval = !FIELD_GET(MAX77759_FG_STATUS_BAT_ABSENT, reg_val); > + break; > + case POWER_SUPPLY_PROP_CAPACITY: > + ret = regmap_read(info->regmap, MAX77759_FG_REPSOC, ®_val); > + val->intval = max77759_fg_percent_to_ps(reg_val); > + break; > + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: > + ret = regmap_read(info->regmap, MAX77759_FG_DESIGN_CAP, ®_val); > + if (ret < 0) > + return ret; > + > + val->intval = max77759_fg_capacity_to_ps(reg_val, info); > + ret = max77759_fg_capacity_lsb(info, ®_val); > + val->intval *= reg_val; > + break; > + case POWER_SUPPLY_PROP_CHARGE_AVG: > + ret = regmap_read(info->regmap, MAX77759_FG_REPCAP, ®_val); > + if (ret < 0) > + return ret; > + > + val->intval = max77759_fg_capacity_to_ps(reg_val, info); > + ret = max77759_fg_capacity_lsb(info, ®_val); > + val->intval *= reg_val; > + break; > + case POWER_SUPPLY_PROP_TEMP: > + ret = regmap_read(info->regmap, MAX77759_FG_TEMP, ®_val); > + val->intval = max77759_fg_temperature_to_ps(reg_val); > + break; > + case POWER_SUPPLY_PROP_CURRENT_NOW: > + ret = regmap_read(info->regmap, MAX77759_FG_CURRENT, ®_val); > + val->intval = max77759_fg_current_to_voltage(reg_val) / info->rsense; > + break; > + case POWER_SUPPLY_PROP_CURRENT_AVG: > + ret = regmap_read(info->regmap, MAX77759_FG_AVG_CURRENT, ®_val); > + val->intval = max77759_fg_current_to_voltage(reg_val) / info->rsense; > + break; > + case POWER_SUPPLY_PROP_CHARGE_FULL: > + ret = regmap_read(info->regmap, MAX77759_FG_FULL_CAP, ®_val); > + if (ret < 0) > + return ret; > + > + val->intval = max77759_fg_capacity_to_ps(reg_val, info); > + ret = max77759_fg_capacity_lsb(info, ®_val); > + val->intval *= reg_val; > + break; > + case POWER_SUPPLY_PROP_MODEL_NAME: > + ret = regmap_read(info->regmap, MAX77759_FG_DEV_NAME, ®_val); > + if (ret < 0) > + return ret; > + > + reg_val = FIELD_GET(MAX77759_FG_DEV_NAME_TYPE_MASK, reg_val); > + if (reg_val == MAX77759_FG_DEV_NAME_TYPE) > + val->strval = max77759_fg_model; > + else > + return -ENODEV; > + break; > + case POWER_SUPPLY_PROP_MANUFACTURER: > + val->strval = max77759_fg_manufacturer; > + break; > + default: > + return -EINVAL; > + } > + > + return ret; > +} > + > +static int max77759_fg_init(struct device *dev, > + struct max77759_fg_device_info *info, > + struct power_supply *bat_psy) > +{ > + struct max77759_fg_state_save *state; > + struct power_supply_battery_info *bat_info; > + struct nvmem_cell *cell; > + unsigned int val; > + int ret; > + size_t len; > + > + power_supply_get_battery_info(bat_psy, &bat_info); Should check the return code here and exit if not present as if the battery info is missing in DT it will crash in max77759_fg_init(). With that addressed: Reviewed-by: Peter Griffin <peter.griffin@xxxxxxxxxx> I think there was also some feedback from Krysztof on the binding, but aside from that I think Sebastian was ready to queue this. regards, Peter