From nobody Sun Oct 5 12:49:51 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 88142229B02; Mon, 4 Aug 2025 14:25:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754317522; cv=none; b=U+gHD736+w3oQfFYBodcFSYbher2dDSKL9UOibd6pUPUW4gNQiY9vU3IpTpu4PG3e+MyjS3U8+TDNYrcKPyHI48eNJ3/nVeJZXoH2jnrtoFfU5bUgOICXcUtaajSgUany8dfdnpC4mWq4TiRRbFaugGItprmFxXqVhsjdD1MldM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754317522; c=relaxed/simple; bh=Vq6uf4nrsNFoy8cBpoj51XrZFWsjsXWvc12saLJlrz0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=XqfuHpjY7PTCMauCNU8LVBpqhIQvgORPZeDIRPewR/4gdZWOa4uJ1bWrWZYS1SA+26VSPJB5q0PQ6aT7hmEBKpGqVW75P884Rtqdsj32X+4nVSEWDGNhq0AZ/RJ9FY7+ToH9CSlNZu2vjoLtm72xXupkwuNZtHeQ/ZUyjdUYEHA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=XS7UkglV; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="XS7UkglV" Received: by smtp.kernel.org (Postfix) with ESMTPS id 2E915C4CEF6; Mon, 4 Aug 2025 14:25:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1754317522; bh=Vq6uf4nrsNFoy8cBpoj51XrZFWsjsXWvc12saLJlrz0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=XS7UkglVT51I1npSsdoy6fG5Vf78SwHmac/OH7Gl3HBUuwDksu0ef9UjJmUBySWLz G9DvTWO3837VtyG8lj2ke+MMus/0zf7cUH0rgOdvu0z0KQIRW3y4VNX4TbYDSuyGas tn3L/vdqViP1sEeZng9Ty8i8E6oBfuILW78O721U4Q2ChPKZcCMkeuJFd+QQq62ldy TeNuqYuKzmUjaPUi+j3MMhpl+vBSHcFxaJ1xIoSxONssWIL7wlFYFRQEife3FsZ0BS f8EWgfjVcjkPUjlxvf+IGBJvmzrDV7xmQZNBQ2BgDYwMR3uvbNhJwdrrQCovlAvstb yI2Jdi2VQ/oCg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1F75FC87FCF; Mon, 4 Aug 2025 14:25:22 +0000 (UTC) From: Thomas Antoine via B4 Relay Date: Mon, 04 Aug 2025 16:26:38 +0200 Subject: [PATCH v5 1/4] power: supply: add support for MAX77759 fuel gauge Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250804-b4-gs101_max77759_fg-v5-1-03a40e6c0e3d@uclouvain.be> References: <20250804-b4-gs101_max77759_fg-v5-0-03a40e6c0e3d@uclouvain.be> In-Reply-To: <20250804-b4-gs101_max77759_fg-v5-0-03a40e6c0e3d@uclouvain.be> To: Sebastian Reichel , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Dimitri Fedrau , Catalin Marinas , Will Deacon , Peter Griffin , =?utf-8?q?Andr=C3=A9_Draszik?= , Tudor Ambarus , Alim Akhtar Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, Thomas Antoine X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1754317658; l=23142; i=t.antoine@uclouvain.be; s=20241202; h=from:subject:message-id; bh=u8t1ovIq76Vj1PKNgRllR6iPDlhCyom9PENVvWBK2eQ=; b=SKJuWt5D2AklvO/59QxruQzYbCb17k4BoJ+OU0f7SPRB6f4CqHaLMaii1KtS/n+uJkfftaucm 2GZMwAUJEvnBWhlPkNriYr0VtUm1clsTAMozJrGz/F01QWlqcVB4PRT X-Developer-Key: i=t.antoine@uclouvain.be; a=ed25519; pk=sw7UYl31W1LTpgWRiX4xIF5x6ok7YWZ6XZnHqy/d3dY= X-Endpoint-Received: by B4 Relay for t.antoine@uclouvain.be/20241202 with auth_id=289 X-Original-From: Thomas Antoine Reply-To: t.antoine@uclouvain.be From: Thomas Antoine 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 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=C3=A9 Draszik in Link: https://lore.kernel.org/all/d1bade77b5281c1de6b2ddcb4dbbd033e455a116.= camel@linaro.org/ Signed-off-by: Thomas Antoine Reviewed-by: Peter Griffin Reviewed-by: Sebastian Reichel --- 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..147d049b836c3fbb24b762dbaf3= 1eebb8ba041f7 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. =20 +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..114578fa4fd08356822f13ce1fb= ad29923defad8 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_BATTERY_MAX17040) +=3D max17040_battery.o obj-$(CONFIG_BATTERY_MAX17042) +=3D max17042_battery.o obj-$(CONFIG_BATTERY_MAX1720X) +=3D max1720x_battery.o obj-$(CONFIG_BATTERY_MAX1721X) +=3D max1721x_battery.o +obj-$(CONFIG_BATTERY_MAX77759) +=3D max77759_battery.o obj-$(CONFIG_BATTERY_RT5033) +=3D rt5033_battery.o obj-$(CONFIG_CHARGER_RT5033) +=3D rt5033_charger.o obj-$(CONFIG_CHARGER_RT9455) +=3D 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..d8d702af607211e391733cd1432= 3698b54be734c --- /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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MAX77759_FG_CRC8_POLYNOMIAL 0x07 +DECLARE_CRC8_TABLE(max77759_fg_crc8_table); + +#define MAX77759_FG_STATUS 0x00 /* Status */ +#define MAX77759_FG_STATUS_POR BIT(1) /* Power-On Reset */ +#define MAX77759_FG_STATUS_BAT_ABSENT BIT(3) /* Battery absent */ +#define MAX77759_FG_REPCAP 0x05 /* Average capacity */ +#define MAX77759_FG_REPSOC 0x06 /* Percentage of charge */ +#define MAX77759_FG_TEMP 0x08 /* Temperature */ +#define MAX77759_FG_CURRENT 0x0A /* Actual current */ +#define MAX77759_FG_AVG_CURRENT 0x0B /* Average current */ +#define MAX77759_FG_FULL_CAP 0x10 /* Calculated full capacity */ +#define MAX77759_FG_QR_TABLE00 0x12 +#define MAX77759_FG_FULLSOCTHR 0x13 +#define MAX77759_FG_CYCLES 0x17 +#define MAX77759_FG_DESIGN_CAP 0x18 /* Design capacity */ +#define MAX77759_FG_CONFIG 0x1D +#define MAX77759_FG_ICHGTERM 0x1E +#define MAX77759_FG_DEV_NAME 0x21 /* Device name */ +#define MAX77759_FG_DEV_NAME_TYPE_MASK GENMASK(15, 9) +#define MAX77759_FG_DEV_NAME_TYPE 0x31 +#define MAX77759_FG_QR_TABLE10 0x22 +#define MAX77759_FG_FULLCAPNOM 0x23 /* Nominal full capacity */ +#define MAX77759_FG_LEARNCFG 0x28 +#define MAX77759_FG_FILTERCFG 0x29 +#define MAX77759_FG_RELAXCFG 0x2A +#define MAX77759_FG_MISCCFG 0x2B +#define MAX77759_FG_TGAIN 0x2C +#define MAX77759_FG_TOFF 0x2D +#define MAX77759_FG_CGAIN 0x2E +#define MAX77759_FG_QR_TABLE20 0x32 +#define MAX77759_FG_FULLCAPREP 0x35 /* Reported full capacity */ +#define MAX77759_FG_RCOMP0 0x38 +#define MAX77759_FG_TEMPCO 0x39 /* Temperature Compensation*/ +#define MAX77759_FG_TASKPERIOD 0x3C +#define MAX77759_FG_TASKPERIOD_175MS 0x1680 +#define MAX77759_FG_TASKPERIOD_351MS 0x2D00 +#define MAX77759_FG_QR_TABLE30 0x42 +#define MAX77759_FG_DQACC 0x45 +#define MAX77759_FG_DPACC 0x46 +#define MAX77759_FG_VFSOC0 0x48 +#define MAX77759_FG_CONVGCFG 0x49 +#define MAX77759_FG_COMMAND 0x60 +#define MAX77759_FG_COMMAND_LOCK_CONF 0x0000 /* Lock extra config */ +#define MAX77759_FG_COMMAND_UNLOCK_CONF 0x0080 /* Unlock extra config */ +#define MAX77759_FG_CV_MIXCAP 0xB6 +#define MAX77759_FG_CV_HALFTIME 0xB7 +#define MAX77759_FG_CURVE 0xB9 +#define MAX77759_FG_CONFIG2 0xBB +#define MAX77759_FG_CONFIG2_OCVQEN BIT(4) +#define MAX77759_FG_CONFIG2_LDMDL BIT(5) /* Load model */ +#define MAX77759_FG_CONFIG2_DSOCEN BIT(7) +#define MAX77759_FG_VFSOC 0xFF + +static const char *const max77759_fg_manufacturer =3D "Maxim Integrated"; +static const char *const max77759_fg_model =3D "MAX77759"; + +struct max77759_fg_device_info { + struct regmap *regmap; + int rsense; +}; + +/* + * Registers 0x80 up to 0xaf which contain the model for the fuel gauge + * algorithm are locked. They can be unlocked by writing 0x59 to 0x62 + * and 0xc4 to 0x63. They should be enabled in the regmap if the driver + * is extended to manage the model. + */ +static const struct regmap_range max77759_fg_registers[] =3D { + regmap_reg_range(0x00, 0x4f), + regmap_reg_range(0x60, 0x60), + regmap_reg_range(0xb0, 0xbf), + regmap_reg_range(0xd0, 0xd0), + regmap_reg_range(0xdc, 0xdf), + regmap_reg_range(0xfb, 0xfb), + regmap_reg_range(0xff, 0xff), +}; + +static const struct regmap_range max77759_fg_ro_registers[] =3D { + regmap_reg_range(0x3d, 0x3d), + regmap_reg_range(0xfb, 0xfb), + regmap_reg_range(0xff, 0xff), +}; + +static const struct regmap_access_table max77759_fg_write_table =3D { + .no_ranges =3D max77759_fg_ro_registers, + .n_no_ranges =3D ARRAY_SIZE(max77759_fg_ro_registers), +}; + +static const struct regmap_access_table max77759_fg_rd_table =3D { + .yes_ranges =3D max77759_fg_registers, + .n_yes_ranges =3D ARRAY_SIZE(max77759_fg_registers), +}; + +static const struct regmap_config max77759_fg_regmap_cfg =3D { + .reg_bits =3D 8, + .val_bits =3D 16, + .max_register =3D 0xff, + .wr_table =3D &max77759_fg_write_table, + .rd_table =3D &max77759_fg_rd_table, + .val_format_endian =3D REGMAP_ENDIAN_LITTLE, + .cache_type =3D REGCACHE_NONE, +}; + +static const enum power_supply_property max77759_fg_battery_props[] =3D { + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_AVG, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CURRENT_AVG, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +struct max77759_fg_state_save { + u16 rcomp0; + u16 tempco; + u16 fullcaprep; + u16 cycles; + u16 fullcapnom; + u16 qrtable00; + u16 qrtable10; + u16 qrtable20; + u16 qrtable30; + u16 mixcap; + u16 halftime; + u8 crc; +} __packed; + +/* Convert regs value to power_supply units */ + +static int max77759_fg_percent_to_ps(unsigned int reg) +{ + return reg / 256; /* in percent from 0 to 100 */ +} + +static int max77759_fg_capacity_to_ps(unsigned int reg, + struct max77759_fg_device_info *info) +{ + return reg * (500000 / info->rsense); /* in uAh */ +} + +static int max77759_fg_capacity_lsb(struct max77759_fg_device_info *info, + unsigned int *lsb) +{ + unsigned int reg_task_period; + int ret; + + ret =3D regmap_read(info->regmap, MAX77759_FG_TASKPERIOD, + ®_task_period); + if (ret < 0) + return ret; + + switch (reg_task_period) { + case MAX77759_FG_TASKPERIOD_175MS: + *lsb =3D 1; + break; + case MAX77759_FG_TASKPERIOD_351MS: + *lsb =3D 2; + break; + default: + return -ENODEV; + } + + return 0; +} + +/* + * Current and temperature is signed values, so unsigned regs + * value must be converted to signed type + */ + +static int max77759_fg_temperature_to_ps(unsigned int reg) +{ + int val =3D (int16_t)reg; + + return val * 10 / 256; /* in tenths of deg. C */ +} + +/* + * Calculating current registers resolution: + * + * RSense stored in 10^-5 Ohm, so measurement voltage must be + * in 10^-11 Volts for get current in uA. + * 16 bit current reg fullscale +/-51.2mV is 102400 uV. + * So: 102400 / 65535 * 10^5 =3D 156252 + */ +static int max77759_fg_current_to_voltage(unsigned int reg) +{ + int val =3D (int16_t)reg; + + return val * 156252; +} + +static int max77759_fg_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct max77759_fg_device_info *info =3D power_supply_get_drvdata(psy); + unsigned int reg_val; + int ret =3D 0; + + 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. + */ + ret =3D regmap_read(info->regmap, MAX77759_FG_STATUS, ®_val); + if (ret < 0) { + val->intval =3D 0; + return 0; + } + + val->intval =3D !FIELD_GET(MAX77759_FG_STATUS_BAT_ABSENT, reg_val); + break; + case POWER_SUPPLY_PROP_CAPACITY: + ret =3D regmap_read(info->regmap, MAX77759_FG_REPSOC, ®_val); + val->intval =3D max77759_fg_percent_to_ps(reg_val); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + ret =3D regmap_read(info->regmap, MAX77759_FG_DESIGN_CAP, ®_val); + if (ret < 0) + return ret; + + val->intval =3D max77759_fg_capacity_to_ps(reg_val, info); + ret =3D max77759_fg_capacity_lsb(info, ®_val); + val->intval *=3D reg_val; + break; + case POWER_SUPPLY_PROP_CHARGE_AVG: + ret =3D regmap_read(info->regmap, MAX77759_FG_REPCAP, ®_val); + if (ret < 0) + return ret; + + val->intval =3D max77759_fg_capacity_to_ps(reg_val, info); + ret =3D max77759_fg_capacity_lsb(info, ®_val); + val->intval *=3D reg_val; + break; + case POWER_SUPPLY_PROP_TEMP: + ret =3D regmap_read(info->regmap, MAX77759_FG_TEMP, ®_val); + val->intval =3D max77759_fg_temperature_to_ps(reg_val); + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + ret =3D regmap_read(info->regmap, MAX77759_FG_CURRENT, ®_val); + val->intval =3D max77759_fg_current_to_voltage(reg_val) / info->rsense; + break; + case POWER_SUPPLY_PROP_CURRENT_AVG: + ret =3D regmap_read(info->regmap, MAX77759_FG_AVG_CURRENT, ®_val); + val->intval =3D max77759_fg_current_to_voltage(reg_val) / info->rsense; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + ret =3D regmap_read(info->regmap, MAX77759_FG_FULL_CAP, ®_val); + if (ret < 0) + return ret; + + val->intval =3D max77759_fg_capacity_to_ps(reg_val, info); + ret =3D max77759_fg_capacity_lsb(info, ®_val); + val->intval *=3D reg_val; + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + ret =3D regmap_read(info->regmap, MAX77759_FG_DEV_NAME, ®_val); + if (ret < 0) + return ret; + + reg_val =3D FIELD_GET(MAX77759_FG_DEV_NAME_TYPE_MASK, reg_val); + if (reg_val =3D=3D MAX77759_FG_DEV_NAME_TYPE) + val->strval =3D max77759_fg_model; + else + return -ENODEV; + break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval =3D 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); + + cell =3D devm_nvmem_cell_get(dev, "fg_state"); + if (IS_ERR(cell)) + return PTR_ERR(cell); + state =3D (struct max77759_fg_state_save *)nvmem_cell_read(cell, &len); + if (IS_ERR(state)) + return PTR_ERR(state); + if (len !=3D sizeof(struct max77759_fg_state_save)) { + ret =3D -EINVAL; + goto err_init; + } + + ret =3D regmap_write(info->regmap, MAX77759_FG_REPCAP, 0x0000); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_RELAXCFG, 0x0839); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_COMMAND, + MAX77759_FG_COMMAND_UNLOCK_CONF); + if (ret < 0) + goto err_init; + + ret =3D regmap_read(info->regmap, MAX77759_FG_VFSOC, &val); + if (ret < 0) + goto err_init; + ret =3D regmap_write(info->regmap, MAX77759_FG_VFSOC0, val); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_LEARNCFG, 0x260E); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_CONFIG, 0x4217); + if (ret < 0) + goto err_init; + + val =3D MAX77759_FG_CONFIG2_DSOCEN | MAX77759_FG_CONFIG2_OCVQEN; + ret =3D regmap_write(info->regmap, MAX77759_FG_CONFIG2, val); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_FULLSOCTHR, 0x5F00); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_FULLCAPREP, + state->fullcaprep); + if (ret < 0) + goto err_init; + + //Use an LSB of 2 because TASKPERIOD will be set to 351MS + val =3D bat_info->charge_full_design_uah * (info->rsense / 100) / 10000; + ret =3D regmap_write(info->regmap, MAX77759_FG_DESIGN_CAP, val); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_DPACC, 0x0C80); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_DQACC, + state->fullcapnom >> 4); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_STATUS, + MAX77759_FG_STATUS_POR); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_FULLCAPNOM, + state->fullcapnom); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_QR_TABLE00, + state->qrtable00); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_QR_TABLE10, + state->qrtable10); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_QR_TABLE20, + state->qrtable20); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_QR_TABLE30, + state->qrtable30); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_RCOMP0, state->rcomp0); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_TEMPCO, state->tempco); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_TASKPERIOD, + MAX77759_FG_TASKPERIOD_351MS); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_ICHGTERM, + bat_info->charge_term_current_ua * + info->rsense / 15625); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_TGAIN, 0xED51); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_TOFF, 0x1EBA); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_MISCCFG, 0x3870); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_CV_MIXCAP, state->mixcap); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_CV_HALFTIME, + state->halftime); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_CONVGCFG, 0x2241); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_COMMAND, + MAX77759_FG_COMMAND_LOCK_CONF); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_CURVE, 0x0014); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_FILTERCFG, 0xc623); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_CGAIN, 0x0400); + if (ret < 0) + goto err_init; + + val =3D MAX77759_FG_CONFIG2_DSOCEN | MAX77759_FG_CONFIG2_OCVQEN; + val |=3D MAX77759_FG_CONFIG2_LDMDL; + ret =3D regmap_write(info->regmap, MAX77759_FG_CONFIG2, val); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_STATUS, 0x0000); + if (ret < 0) + goto err_init; + + ret =3D regmap_write(info->regmap, MAX77759_FG_CYCLES, state->cycles); + if (ret < 0) + goto err_init; + + kfree(state); + return 0; + +err_init: + kfree(state); + return ret; +} + +static const struct power_supply_desc max77759_fg_bat_desc =3D { + .name =3D "max77759-fg", + .type =3D POWER_SUPPLY_TYPE_BATTERY, + .properties =3D max77759_fg_battery_props, + .num_properties =3D ARRAY_SIZE(max77759_fg_battery_props), + .get_property =3D max77759_fg_battery_get_property, +}; + +static int max77759_fg_backup_fg_state(struct device *dev, + struct regmap *regmap) +{ + struct max77759_fg_state_save state; + struct nvmem_cell *cell; + int val; + int ret; + + ret =3D regmap_read(regmap, MAX77759_FG_RCOMP0, &val); + if (ret < 0) + return ret; + state.rcomp0 =3D (u16)val; + + ret =3D regmap_read(regmap, MAX77759_FG_TEMPCO, &val); + if (ret < 0) + return ret; + state.tempco =3D (u16)val; + + ret =3D regmap_read(regmap, MAX77759_FG_FULLCAPREP, &val); + if (ret < 0) + return ret; + state.fullcaprep =3D (u16)val; + + ret =3D regmap_read(regmap, MAX77759_FG_CYCLES, &val); + if (ret < 0) + return ret; + state.cycles =3D (u16)val; + + ret =3D regmap_read(regmap, MAX77759_FG_FULLCAPNOM, &val); + if (ret < 0) + return ret; + state.fullcapnom =3D (u16)val; + + ret =3D regmap_read(regmap, MAX77759_FG_QR_TABLE00, &val); + if (ret < 0) + return ret; + state.qrtable00 =3D (u16)val; + + ret =3D regmap_read(regmap, MAX77759_FG_QR_TABLE10, &val); + if (ret < 0) + return ret; + state.qrtable10 =3D (u16)val; + + ret =3D regmap_read(regmap, MAX77759_FG_QR_TABLE20, &val); + if (ret < 0) + return ret; + state.qrtable20 =3D (u16)val; + + ret =3D regmap_read(regmap, MAX77759_FG_QR_TABLE30, &val); + if (ret < 0) + return ret; + state.qrtable30 =3D (u16)val; + + ret =3D regmap_read(regmap, MAX77759_FG_CV_MIXCAP, &val); + if (ret < 0) + return ret; + state.mixcap =3D (u16)val; + + ret =3D regmap_read(regmap, MAX77759_FG_CV_HALFTIME, &val); + if (ret < 0) + return ret; + state.halftime =3D (u16)val; + + state.crc =3D crc8(max77759_fg_crc8_table, (u8 *)&state, + sizeof(state) - sizeof(state.crc), CRC8_INIT_VALUE); + + cell =3D devm_nvmem_cell_get(dev, "fg_state"); + if (IS_ERR(cell)) + return PTR_ERR(cell); + ret =3D nvmem_cell_write(cell, &state, sizeof(state)); + if (ret < 0) + dev_err(dev, "Failed to write fg_state to NVMEM: %d\n", ret); + + return ret; +} + +static void max77759_fg_remove(struct i2c_client *client) +{ + struct max77759_fg_device_info *info =3D i2c_get_clientdata(client); + + max77759_fg_backup_fg_state(&client->dev, info->regmap); +} + +static int max77759_fg_probe(struct i2c_client *client) +{ + struct power_supply_config psy_cfg =3D {}; + struct device *dev =3D &client->dev; + struct max77759_fg_device_info *info; + struct power_supply *bat; + int ret, val; + + info =3D devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + psy_cfg.drv_data =3D info; + psy_cfg.fwnode =3D dev_fwnode(dev); + + crc8_populate_msb(max77759_fg_crc8_table, MAX77759_FG_CRC8_POLYNOMIAL); + + i2c_set_clientdata(client, info); + + info->regmap =3D devm_regmap_init_i2c(client, &max77759_fg_regmap_cfg); + if (IS_ERR(info->regmap)) + return dev_err_probe(dev, PTR_ERR(info->regmap), + "regmap initialization failed\n"); + + ret =3D device_property_read_u32(dev, "shunt-resistor-micro-ohms", &val); + if (ret) + return dev_err_probe(dev, ret, + "Failed to read RSense from devicetree\n"); + info->rsense =3D val / 10; + + bat =3D devm_power_supply_register(dev, &max77759_fg_bat_desc, &psy_cfg); + if (IS_ERR(bat)) + return dev_err_probe(dev, PTR_ERR(bat), + "Failed to register power supply\n"); + + ret =3D max77759_fg_init(dev, info, bat); + if (ret) + return dev_err_probe(dev, ret, "Failed to initialize chip\n"); + + return 0; +} + +static const struct of_device_id max77759_fg_of_match[] =3D { + { .compatible =3D "maxim,max77759-fg" }, + {} +}; +MODULE_DEVICE_TABLE(of, max77759_fg_of_match); + +static struct i2c_driver max77759_fg_i2c_driver =3D { + .driver =3D { + .name =3D "max77759_fg", + .of_match_table =3D max77759_fg_of_match, + }, + .probe =3D max77759_fg_probe, + .remove =3D max77759_fg_remove, +}; +module_i2c_driver(max77759_fg_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Thomas Antoine "); +MODULE_DESCRIPTION("Maxim MAX77759 Fuel Gauge IC driver"); --=20 2.50.1 From nobody Sun Oct 5 12:49:51 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AD2E927057C; Mon, 4 Aug 2025 14:25:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754317522; cv=none; b=kNbusrA/it5Kwyf7S1pls4IclHQn2FRhqy6Vp6WCqLrclgbcJJbEkLwwgGotG7UcSCV7swZHQWp4mYgRlydCMuk9RfWMLOVIj7PUwUEDSw+6XDzrDWzUrjxCQcbi5E0MW7YzTtkqrpHe9Kkm14iQm2X2/VtZgK0FIHnjCW9I/zQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754317522; c=relaxed/simple; bh=phXVktnsQFsRlCPE6gQZzgzGOtAWOzVU4TdMa++7y/o=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=RqyWAh1wIfMns+iUEwqnDODD0Akb39XRM+819VDYeUDBHsvfEyq9MyCxivxHTfGH8p9gK60RqqHXbZo3cRqH5D1QbWeoJXCIEaSfWjKS1+HLV0WF+SD/8D5SAEH2eXW53vqO1vHz3DGJOLYT46GlWNgqFPgXopTTJAE7WF3aPJY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=AIzpMlPD; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="AIzpMlPD" Received: by smtp.kernel.org (Postfix) with ESMTPS id 3BCB0C4CEF0; Mon, 4 Aug 2025 14:25:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1754317522; bh=phXVktnsQFsRlCPE6gQZzgzGOtAWOzVU4TdMa++7y/o=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=AIzpMlPDVnGXezvDECm4IubKoW3sHxSkk8/TRBOLjyRdhxEOIQDpagLmRRRwdme8a 2WFkjR0Fo/edEN7jD1ZgYrVyk8p6AssX3jqUx6pnz6OViiEiIyWuvHffBhz/hY96F3 uL0CpFBSjNcH+xeemMpj9iBp32mdO4wLhryOx2FxsjxI9vfdn1sRvbK0xrfXopMW4D Q+LmALnrUqMgcblaiMJEsx/+cnXhr8+VBe+hUrWDCqCVWzgY7TWNPwsbr2i8e2LTWn DjmAU4q86kLWDwrNwCEj+MwqewIzYZO6PLkethQD4sWI/Jv7fIuThcKhxlwvehTqg7 Z04lOp14fcpzA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3036CC87FD1; Mon, 4 Aug 2025 14:25:22 +0000 (UTC) From: Thomas Antoine via B4 Relay Date: Mon, 04 Aug 2025 16:26:39 +0200 Subject: [PATCH v5 2/4] dt-bindings: power: supply: add support for MAX77759 fuel gauge Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250804-b4-gs101_max77759_fg-v5-2-03a40e6c0e3d@uclouvain.be> References: <20250804-b4-gs101_max77759_fg-v5-0-03a40e6c0e3d@uclouvain.be> In-Reply-To: <20250804-b4-gs101_max77759_fg-v5-0-03a40e6c0e3d@uclouvain.be> To: Sebastian Reichel , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Dimitri Fedrau , Catalin Marinas , Will Deacon , Peter Griffin , =?utf-8?q?Andr=C3=A9_Draszik?= , Tudor Ambarus , Alim Akhtar Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, Thomas Antoine X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1754317658; l=3442; i=t.antoine@uclouvain.be; s=20241202; h=from:subject:message-id; bh=/JRl4+oKCLeCuqYwla/ChjnUkO3GOKVE7rQTxDRH5UQ=; b=tgtf8lqDV0ObDF50iRsgPV1Unq9+iIRAg+SVhyYpWX3tGCMpZB1+Vp5TRqf0bItrLaWJRaSXD jP8ijQYNxeMAs3RY+62WWnpJ1nea18tByTxj2rCoBfOakT7zAYND03I X-Developer-Key: i=t.antoine@uclouvain.be; a=ed25519; pk=sw7UYl31W1LTpgWRiX4xIF5x6ok7YWZ6XZnHqy/d3dY= X-Endpoint-Received: by B4 Relay for t.antoine@uclouvain.be/20241202 with auth_id=289 X-Original-From: Thomas Antoine Reply-To: t.antoine@uclouvain.be From: Thomas Antoine The Maxim MAX77759 is a companion PMIC for USB Type-C. It contains Battery Charger, Fuel Gauge, temperature sensors, USB Type-C Port Controller (TCPC), NVMEM, and additional GPIO interfaces Use max77759-fg compatible to avoid conflict with drivers for other functions. The battery node is used to pass the REPCAP and ICHGTERM values needed for the initialization of the fuel gauge. The nvmem cells are used to get initialization values and to backup the learning and the number of cycles. It should work out of the box with gs101-oriole and gs101-raven which were previously running Android. Signed-off-by: Thomas Antoine --- .../bindings/power/supply/maxim,max77759.yaml | 76 ++++++++++++++++++= ++++ 1 file changed, 76 insertions(+) diff --git a/Documentation/devicetree/bindings/power/supply/maxim,max77759.= yaml b/Documentation/devicetree/bindings/power/supply/maxim,max77759.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5e160e3ad86849f9ee0be54e20e= 195fc455eba6d --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/maxim,max77759.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/maxim,max77759.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim Integrated MAX77759 fuel gauge + +maintainers: + - Thomas Antoine + +properties: + compatible: + const: maxim,max77759-fg + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + shunt-resistor-micro-ohms: + description: The value of the current sense resistor in microohms. + + monitored-battery: + description: | + The fuel gauge needs the following battery properties: + - charge-full-design-microamp-hours + - charge-term-current-microamp + + nvmem-cells: + maxItems: 1 + description: | + Saved fuel gauge state. This state will be used during the initializ= ation + and saved on exit. It must be initialized beforehand. + Its layout must be composed of + - RCOMP0 (characterization of the open-circuit voltage) + - TCOMPO (temperature compensation information) + - FULLCAPREP (reported full capacity) + - QRTABLE00, QRTABLE10, QRTABLE20, QRTABLE30 (cell capacity inform= ation) + - cv_mixcap (remaining capacity of the cell without empty compensa= tion) + - cv_halftime (time-to-full characterization time constant) + They must all be aligned on 2 bytes. A valid CRC8 checksum must + also be found at the end (polynomial x^8 + x^2 + x + 1). + + nvmem-cell-names: + const: fg_state + +required: + - compatible + - reg + - shunt-resistor-micro-ohms + - monitored-battery + - nvmem-cells + - nvmem-cell-names + +unevaluatedProperties: false + +examples: + - | + #include + i2c { + #address-cells =3D <1>; + #size-cells =3D <0>; + + fuel-gauge@36 { + compatible =3D "maxim,max77759-fg"; + reg =3D <0x36>; + interrupt-parent =3D <&gpa9>; + interrupts =3D <3 IRQ_TYPE_LEVEL_LOW>; + shunt-resistor-micro-ohms =3D <5000>; + monitored-battery =3D <&battery>; + nvmem-cell-names =3D "fg_state"; + nvmem-cells =3D <&fg_state>; + }; + }; --=20 2.50.1 From nobody Sun Oct 5 12:49:51 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AD28226F463; Mon, 4 Aug 2025 14:25:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754317522; cv=none; b=oLNBqIqPW0AtNRW5I3G8guu4smyJWEhdaTJt5+OLHRtNA7NvgqRAnsdXUqSBDmmqU0nFEwRG6tXdc0eGIKAzD3VNNur//kwKAItNOoKN7H9X0RrT6DCYp2QXseTHAy06BIusOpqwYm7SM3Edhaqbi4oCC843plLsP69/bmy3RCg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754317522; c=relaxed/simple; bh=mAWZyywLB1ip9iUzT4X4Zu/0/IQZja/30TmIx21F/xo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=QCSRRJwdoRk27B+Kht9wpyEywh1+nsqboCMty1iWLk4/fWvhAAQmuT2YZrmj3NhLPKABKVBCcdvJGmTkTvKnLdSJusxfHq4EnV8ncbsW5x/+vs1SsU4UBAArso6EPlzmOdEJR9Wux0+UPK5ll8oVYs6f3H9HJ/qUQjcinfPjOSI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=p072hH0C; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="p072hH0C" Received: by smtp.kernel.org (Postfix) with ESMTPS id 47CFAC4CEF7; Mon, 4 Aug 2025 14:25:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1754317522; bh=mAWZyywLB1ip9iUzT4X4Zu/0/IQZja/30TmIx21F/xo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=p072hH0CBBYxBAoDsTtvfWGCWzfO20uAyO6Za3aNZDLir3smkrHZ04yd8upydWi04 1KSQjQlD+gBvew1KRdH2lAmYiRpZlCOUMR7C/+oSbC3qII0Ytu+EPIJB5QYFrolLje kQF1+H0+h0yvBWR29iN3oO8fHlx3PRjvTlJjuXCd53R7pk4pQiydpngva/bDZZWQ9T TTZ/6eZ6SmogZQI5BAMhYlh9n522mX+jtRPPw6NUmwS2b5WvKq8ndPW9kCQ6Qvv5gT kD5j9jooP+pEwhaCDs6o2XRzWJeZPCMWK8p+onMHJqXjkWoXR0SSV1LAwfk01QqK2m R5yOo8E5jgkmQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3E9C1CA0EC0; Mon, 4 Aug 2025 14:25:22 +0000 (UTC) From: Thomas Antoine via B4 Relay Date: Mon, 04 Aug 2025 16:26:40 +0200 Subject: [PATCH v5 3/4] arm64: defconfig: enable Maxim MAX77759 fuel-gauge driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250804-b4-gs101_max77759_fg-v5-3-03a40e6c0e3d@uclouvain.be> References: <20250804-b4-gs101_max77759_fg-v5-0-03a40e6c0e3d@uclouvain.be> In-Reply-To: <20250804-b4-gs101_max77759_fg-v5-0-03a40e6c0e3d@uclouvain.be> To: Sebastian Reichel , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Dimitri Fedrau , Catalin Marinas , Will Deacon , Peter Griffin , =?utf-8?q?Andr=C3=A9_Draszik?= , Tudor Ambarus , Alim Akhtar Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, Thomas Antoine X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1754317658; l=764; i=t.antoine@uclouvain.be; s=20241202; h=from:subject:message-id; bh=gaoSugHRAz5fOiJGPTrSTYl8U3fwbJdk2k1I718EDsY=; b=ZG9Xmwog66bZ8cSUspq6GfK/PeRmbJru5wn9agjtUDDP6k3RzK0VaZzzaMfkTbctuK/5+YMlv VGOddOKH0rrDFrORISbF19f5WBqEmXuzmboc/ROIKMOnvlmk2PA+mSb X-Developer-Key: i=t.antoine@uclouvain.be; a=ed25519; pk=sw7UYl31W1LTpgWRiX4xIF5x6ok7YWZ6XZnHqy/d3dY= X-Endpoint-Received: by B4 Relay for t.antoine@uclouvain.be/20241202 with auth_id=289 X-Original-From: Thomas Antoine Reply-To: t.antoine@uclouvain.be From: Thomas Antoine Enable the Maxim MAX77759 fuel gauge as it is used by the gs101-oriole (Google Pixel 6) and gs101-raven (Google Pixe 6 Pro) boards. Signed-off-by: Thomas Antoine Reviewed-by: Peter Griffin --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 7e04a2905ce4ec71e8263a85f20398f702917390..dd90e72e71dfd45c62942f83db6= 814f263517a0c 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -691,6 +691,7 @@ CONFIG_BATTERY_QCOM_BATTMGR=3Dm CONFIG_BATTERY_SBS=3Dm CONFIG_BATTERY_BQ27XXX=3Dy CONFIG_BATTERY_MAX17042=3Dm +CONFIG_BATTERY_MAX77759=3Dm CONFIG_CHARGER_MT6360=3Dm CONFIG_CHARGER_BQ25890=3Dm CONFIG_CHARGER_BQ25980=3Dm --=20 2.50.1 From nobody Sun Oct 5 12:49:51 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CE64E271A9A; Mon, 4 Aug 2025 14:25:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754317522; cv=none; b=AkiUPgmVeKC2qjXRGxUzqx/NPR/IzxmpN8D4w/YWA/JKttZMQwtHNI8WbZBqjCClf6rWa84D4nVc/Q/eFvR9Eh+/JHI+1Bzeyi7WPS+FZkraxvaSHtNF6XlnMw+c05EhNUAGMQJmUjSrvW5b6UIlzDJ29tkhUs/dLeiD6FwXIGw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754317522; c=relaxed/simple; bh=SUEmfllbxCfuPwlmfLNSQ5Zq6XjkIAA05us9mJD3pTY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UUUZa4V8NGpokc1MAWVJ+ggdQ/OfsIYDmn0nYH4CqStCM2pWjBuJ+6cny/48jihGAIEou6Yzx+kUWA8SYk9oICin78NekjiOJt7mBwSP1j4GAStx0OVF0ImIt68Aqpga395B1i2Xs/q6Ip1TNv/qcH+0iW/R1d74KfTZpIFZTTU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=uDLoSEjz; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="uDLoSEjz" Received: by smtp.kernel.org (Postfix) with ESMTPS id 57C23C4CEFA; Mon, 4 Aug 2025 14:25:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1754317522; bh=SUEmfllbxCfuPwlmfLNSQ5Zq6XjkIAA05us9mJD3pTY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=uDLoSEjzgY7QQQV+umULTFZuwx+xylsxVX1YDLNRl4T1Q3WovI9DeTCl7qi+6lVsf MblQfE/YyybwAGYTB6jGC+cJ2PNfeA03I+5Z9VHFKIIlWYJVnc0XL+wNMhb4eAizck 4J0GOUmZu1pKC+l+yP3chWK9We0LgfrhgM0/GA6Esp7lmOfYHJ2pqZ/E7xZC18Pxon P7SV4YviMDVrP+FXbVHxmKgFlrr7O/wIJPGd85+c72A/UeictqJeWuVT7rpkhdnAwR VSy1ORKB84K46Zb/iR9kBH25x/C8aCpOjfpSs7E9NrlbOprxhAvh+wpmFpAVWDQnyX FxpBjkjaE4Bmw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4EB71C87FCF; Mon, 4 Aug 2025 14:25:22 +0000 (UTC) From: Thomas Antoine via B4 Relay Date: Mon, 04 Aug 2025 16:26:41 +0200 Subject: [PATCH v5 4/4] arm64: dts: exynos: google: add Maxim MAX77759 Fuel-gauge Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250804-b4-gs101_max77759_fg-v5-4-03a40e6c0e3d@uclouvain.be> References: <20250804-b4-gs101_max77759_fg-v5-0-03a40e6c0e3d@uclouvain.be> In-Reply-To: <20250804-b4-gs101_max77759_fg-v5-0-03a40e6c0e3d@uclouvain.be> To: Sebastian Reichel , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Dimitri Fedrau , Catalin Marinas , Will Deacon , Peter Griffin , =?utf-8?q?Andr=C3=A9_Draszik?= , Tudor Ambarus , Alim Akhtar Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, Thomas Antoine X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1754317658; l=4842; i=t.antoine@uclouvain.be; s=20241202; h=from:subject:message-id; bh=WF3EeuQVRCI8z8XyGntN8UgYyyixrVyY5uSQUCZ94dw=; b=v68T20khFe1UGQ2JyoNgy4ms6kbeJYjj9SRA+1t4Mx+n0o6kAgF3AMdV/EemaH96ywtN6rd6t EPtpPJzp0m8A2BonUtQTkzYgodWp+grRpoUrNC1z/wYrp6tl5qw45Kw X-Developer-Key: i=t.antoine@uclouvain.be; a=ed25519; pk=sw7UYl31W1LTpgWRiX4xIF5x6ok7YWZ6XZnHqy/d3dY= X-Endpoint-Received: by B4 Relay for t.antoine@uclouvain.be/20241202 with auth_id=289 X-Original-From: Thomas Antoine Reply-To: t.antoine@uclouvain.be From: Thomas Antoine Add the node for the Maxim MAX77759 fuel gauge as a slave of the i2c. The TODO is still applicable given there are other slaves on the bus (e.g. PCA9468, other MAX77759 functions and the MAX20339 OVP). For the device specific values (full design capacity and terminal current), the device should check an EEPROM at address 0x50 of the hsi2c_8 for a battery id stored in register 0x17. A set of parameters for the initialization of the fuel gauge should be chosen based on this id. Those sets are defined here: Link: https://android.googlesource.com/kernel/gs/+/refs/heads/android-gs-ra= viole-5.10-android15/arch/arm64/boot/dts/google/gs101-oriole-battery-data.d= tsi Link: https://android.googlesource.com/kernel/gs/+/refs/heads/android-gs-ra= viole-5.10-android15/arch/arm64/boot/dts/google/gs101-raven-battery-data.dt= si This does not seem to be a standard pattern in the kernel currently so it is not implemented. Values observed on tested devices are instead used. The driver or the devicetree should be should be extended in the future to take versions into account. The pinctrl name follows the convention proposed in Link: https://lore.kernel.org/all/20250524-b4-max77759-mfd-dts-v2-2-b479542= eb97d@linaro.org/ Signed-off-by: Thomas Antoine Reviewed-by: Peter Griffin --- arch/arm64/boot/dts/exynos/google/gs101-oriole.dts | 10 ++++++++ .../boot/dts/exynos/google/gs101-pixel-common.dtsi | 30 ++++++++++++++++++= ++++ arch/arm64/boot/dts/exynos/google/gs101-raven.dts | 11 ++++++++ 3 files changed, 51 insertions(+) diff --git a/arch/arm64/boot/dts/exynos/google/gs101-oriole.dts b/arch/arm6= 4/boot/dts/exynos/google/gs101-oriole.dts index 8df42bedbc036b5e97f6238d64820370043ffef2..18d147f6ea4a1a76c3759965573= 49c866b9dad72 100644 --- a/arch/arm64/boot/dts/exynos/google/gs101-oriole.dts +++ b/arch/arm64/boot/dts/exynos/google/gs101-oriole.dts @@ -13,6 +13,12 @@ / { model =3D "Oriole"; compatible =3D "google,gs101-oriole", "google,gs101"; + + battery: battery { + compatible =3D "simple-battery"; + charge-full-design-microamp-hours =3D <4524000>; + charge-term-current-microamp =3D <45000>; + }; }; =20 &cont_splash_mem { @@ -27,3 +33,7 @@ &framebuffer0 { format =3D "a8r8g8b8"; status =3D "okay"; }; + +&fuel_gauge { + monitored-battery =3D <&battery>; +}; diff --git a/arch/arm64/boot/dts/exynos/google/gs101-pixel-common.dtsi b/ar= ch/arm64/boot/dts/exynos/google/gs101-pixel-common.dtsi index d6ddcc13f7b20c6dfbe92e86abafe965870d0c78..3362ad89ef6bacb7349259cf9e1= 4452193ff7361 100644 --- a/arch/arm64/boot/dts/exynos/google/gs101-pixel-common.dtsi +++ b/arch/arm64/boot/dts/exynos/google/gs101-pixel-common.dtsi @@ -10,6 +10,7 @@ =20 #include #include +#include #include #include "gs101-pinctrl.h" #include "gs101.dtsi" @@ -99,6 +100,16 @@ &hsi2c_8 { eeprom: eeprom@50 { compatible =3D "atmel,24c08"; reg =3D <0x50>; + + nvmem-layout { + compatible =3D "fixed-layout"; + #address-cells =3D <1>; + #size-cells =3D <1>; + + fg_state: fgstate@42 { + reg =3D <0x42 0x17>; + }; + }; }; }; =20 @@ -188,6 +199,18 @@ usbc0_role_sw: endpoint { }; }; }; + + fuel_gauge: fuel-gauge@36 { + compatible =3D "maxim,max77759-fg"; + reg =3D <0x36>; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&if_pmic_fg_int>; + interrupt-parent =3D <&gpa9>; + interrupts =3D <3 IRQ_TYPE_LEVEL_LOW>; + shunt-resistor-micro-ohms =3D <5000>; + nvmem-cell-names =3D "fg_state"; + nvmem-cells =3D <&fg_state>; + }; }; =20 &pinctrl_far_alive { @@ -214,6 +237,13 @@ typec_int: typec-int-pins { }; =20 &pinctrl_gpio_alive { + if_pmic_fg_int: if-pmic-fg-int-pins { + samsung,pins =3D "gpa9-3"; + samsung,pin-function =3D ; + samsung,pin-pud =3D ; + samsung,pin-drv =3D ; + }; + key_power: key-power-pins { samsung,pins =3D "gpa10-1"; samsung,pin-function =3D ; diff --git a/arch/arm64/boot/dts/exynos/google/gs101-raven.dts b/arch/arm64= /boot/dts/exynos/google/gs101-raven.dts index 1e7e6b34b8649bc700a745c579a0268f0f6a9524..f91800879ea94b8fb0008c5e1f8= 28072cabc1ac7 100644 --- a/arch/arm64/boot/dts/exynos/google/gs101-raven.dts +++ b/arch/arm64/boot/dts/exynos/google/gs101-raven.dts @@ -13,6 +13,13 @@ / { model =3D "Raven"; compatible =3D "google,gs101-raven", "google,gs101"; + + battery: battery { + compatible =3D "simple-battery"; + + charge-full-design-microamp-hours =3D <4904000>; + charge-term-current-microamp =3D <49000>; + }; }; =20 &cont_splash_mem { @@ -27,3 +34,7 @@ &framebuffer0 { format =3D "a8r8g8b8"; status =3D "okay"; }; + +&fuel_gauge { + monitored-battery =3D <&battery>; +}; --=20 2.50.1