[PATCH V1 3/3] power: supply: sbs-battery: Add optional status monitoring
From: LI Qingwu
Date: Mon Dec 29 2025 - 03:57:30 EST
Some systems do not have GPIO interrupt support for battery detection.
Without GPIO IRQ or SMBus Alert, the driver cannot proactively report
battery status changes.
Add an optional "sbs,monitoring-interval-ms" device property to enable
periodic status checks. When set, the driver polls the SBS status
register at the given interval and calls power_supply_changed() if the
battery state changes.
If a GPIO IRQ is successfully registered, monitoring is automatically
disabled since interrupt-based detection is preferred.
Signed-off-by: LI Qingwu <Qing-wu.Li@xxxxxxxxxxxxxxxxxxxxxxx>
---
drivers/power/supply/sbs-battery.c | 50 ++++++++++++++++++++++--------
1 file changed, 37 insertions(+), 13 deletions(-)
diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
index 9537b692f9fd..2874a741c809 100644
--- a/drivers/power/supply/sbs-battery.c
+++ b/drivers/power/supply/sbs-battery.c
@@ -214,6 +214,7 @@ struct sbs_info {
u32 poll_retry_count;
struct delayed_work work;
struct mutex mode_lock;
+ u32 monitoring_interval_ms;
u32 flags;
int technology;
char strings[NR_STRING_BUFFERS][I2C_SMBUS_BLOCK_MAX + 1];
@@ -1089,21 +1090,27 @@ static void sbs_delayed_work(struct work_struct *work)
/* if the read failed, give up on this work */
if (ret < 0) {
chip->poll_time = 0;
- return;
- }
-
- if (ret & BATTERY_FULL_CHARGED)
- ret = POWER_SUPPLY_STATUS_FULL;
- else if (ret & BATTERY_DISCHARGING)
- ret = POWER_SUPPLY_STATUS_DISCHARGING;
- else
- ret = POWER_SUPPLY_STATUS_CHARGING;
+ if (!chip->monitoring_interval_ms)
+ return;
+ } else {
+ if (ret & BATTERY_FULL_CHARGED)
+ ret = POWER_SUPPLY_STATUS_FULL;
+ else if (ret & BATTERY_DISCHARGING)
+ ret = POWER_SUPPLY_STATUS_DISCHARGING;
+ else
+ ret = POWER_SUPPLY_STATUS_CHARGING;
- sbs_status_correct(chip->client, &ret);
+ sbs_status_correct(chip->client, &ret);
- if (chip->last_state != ret) {
- chip->poll_time = 0;
- power_supply_changed(chip->power_supply);
+ if (chip->last_state != ret) {
+ chip->poll_time = 0;
+ power_supply_changed(chip->power_supply);
+ }
+ }
+ if (chip->monitoring_interval_ms) {
+ schedule_delayed_work(
+ &chip->work,
+ msecs_to_jiffies(chip->monitoring_interval_ms));
return;
}
if (chip->poll_time > 0) {
@@ -1171,6 +1178,13 @@ static int sbs_probe(struct i2c_client *client)
}
chip->i2c_retry_count = chip->i2c_retry_count + 1;
+ rc = device_property_read_u32(&client->dev, "sbs,monitoring-interval-ms",
+ &chip->monitoring_interval_ms);
+ if (rc)
+ chip->monitoring_interval_ms = 0;
+ if (chip->monitoring_interval_ms)
+ force_load = true;
+
chip->charger_broadcasts = !device_property_read_bool(&client->dev,
"sbs,disable-charger-broadcasts");
@@ -1198,6 +1212,11 @@ static int sbs_probe(struct i2c_client *client)
dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
goto skip_gpio;
}
+ if (chip->monitoring_interval_ms) {
+ dev_info(&client->dev,
+ "GPIO IRQ registered, monitoring disabled\n");
+ chip->monitoring_interval_ms = 0;
+ }
skip_gpio:
/*
@@ -1228,6 +1247,11 @@ static int sbs_probe(struct i2c_client *client)
dev_info(&client->dev,
"%s: battery gas gauge device registered\n", client->name);
+ if (chip->monitoring_interval_ms > 0)
+ schedule_delayed_work(
+ &chip->work,
+ msecs_to_jiffies(chip->monitoring_interval_ms));
+
return 0;
}
--
2.43.0