From: Hans de Goede Date: Sun, 31 Aug 2025 12:29:40 +0000 (+0200) Subject: power: supply: adc-battery-helper: Add support for optional charge_finished GPIO X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=926b144366c589a0c0c471d02a71590ed24284e0;p=users%2Fhch%2Fmisc.git power: supply: adc-battery-helper: Add support for optional charge_finished GPIO Charger ICs often have a status pin which indicates when the charger has finished charging the battery. Sometimes the status of this pin can be read over a GPIO. Add support for optionally reading a charge-finished GPIO and when available use this to determine when to return POWER_SUPPLY_STATUS_FULL. Reviewed-by: Linus Walleij Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20250831122942.47875-5-hansg@kernel.org Signed-off-by: Sebastian Reichel --- diff --git a/drivers/power/supply/adc-battery-helper.c b/drivers/power/supply/adc-battery-helper.c index f8f6d2f8ec89..229b49fef8ad 100644 --- a/drivers/power/supply/adc-battery-helper.c +++ b/drivers/power/supply/adc-battery-helper.c @@ -51,6 +51,7 @@ #include #include +#include #include #include #include @@ -82,8 +83,17 @@ static int adc_battery_helper_get_status(struct adc_battery_helper *help) if (help->curr_ua < -CURR_HYST_UA) return POWER_SUPPLY_STATUS_DISCHARGING; - if (help->supplied && help->ocv_avg_uv > full_uv) - return POWER_SUPPLY_STATUS_FULL; + if (help->supplied) { + bool full; + + if (help->charge_finished) + full = gpiod_get_value_cansleep(help->charge_finished); + else + full = help->ocv_avg_uv > full_uv; + + if (full) + return POWER_SUPPLY_STATUS_FULL; + } return POWER_SUPPLY_STATUS_NOT_CHARGING; } @@ -255,13 +265,15 @@ static void adc_battery_helper_start_work(struct adc_battery_helper *help) } int adc_battery_helper_init(struct adc_battery_helper *help, struct power_supply *psy, - adc_battery_helper_get_func get_voltage_and_current_now) + adc_battery_helper_get_func get_voltage_and_current_now, + struct gpio_desc *charge_finished_gpio) { struct device *dev = psy->dev.parent; int ret; help->psy = psy; help->get_voltage_and_current_now = get_voltage_and_current_now; + help->charge_finished = charge_finished_gpio; ret = devm_mutex_init(dev, &help->lock); if (ret) diff --git a/drivers/power/supply/adc-battery-helper.h b/drivers/power/supply/adc-battery-helper.h index 90c7edcb9ab1..4e42181c8983 100644 --- a/drivers/power/supply/adc-battery-helper.h +++ b/drivers/power/supply/adc-battery-helper.h @@ -11,6 +11,7 @@ #define ADC_BAT_HELPER_MOV_AVG_WINDOW_SIZE 8 struct power_supply; +struct gpio_desc; /* * The adc battery helper code needs voltage- and current-now to be sampled as @@ -21,6 +22,7 @@ typedef int (*adc_battery_helper_get_func)(struct power_supply *psy, int *volt, struct adc_battery_helper { struct power_supply *psy; + struct gpio_desc *charge_finished; struct delayed_work work; struct mutex lock; adc_battery_helper_get_func get_voltage_and_current_now; @@ -44,7 +46,8 @@ extern const enum power_supply_property adc_battery_helper_properties[]; #define ADC_HELPER_NUM_PROPERTIES 7 int adc_battery_helper_init(struct adc_battery_helper *help, struct power_supply *psy, - adc_battery_helper_get_func get_voltage_and_current_now); + adc_battery_helper_get_func get_voltage_and_current_now, + struct gpio_desc *charge_finished_gpio); /* * The below functions can be directly used as power-supply / suspend-resume * callbacks. They cast the power_supply_get_drvdata() / dev_get_drvdata() data diff --git a/drivers/power/supply/ug3105_battery.c b/drivers/power/supply/ug3105_battery.c index c4d4ac859fa4..210e0f9aa5e0 100644 --- a/drivers/power/supply/ug3105_battery.c +++ b/drivers/power/supply/ug3105_battery.c @@ -161,7 +161,7 @@ static int ug3105_probe(struct i2c_client *client) } ret = adc_battery_helper_init(&chip->helper, chip->psy, - ug3105_get_voltage_and_current_now); + ug3105_get_voltage_and_current_now, NULL); if (ret) goto stop;