Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

power: supply: bq27xxx: Stop and start delayed work in suspend and resume

This driver uses delayed work to perform periodic battery state read out.
This delayed work is not stopped across suspend and resume cycle. The
read out can occur early in the resume cycle. In case of an I2C variant
of this hardware, that read out triggers I2C transfer. That I2C transfer
may happen while the I2C controller is still suspended, which produces a
WARNING in the kernel log.

Fix this by introducing trivial PM ops, which stop the delayed work before
the system enters suspend, and schedule the delayed work right after the
system resumes.

Signed-off-by: Marek Vasut <marex@denx.de>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20231104154920.68585-1-marex@denx.de
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>

authored by

Marek Vasut and committed by
Sebastian Reichel
dfcb264a 5739da3e

+24
+22
drivers/power/supply/bq27xxx_battery.c
··· 2162 2162 } 2163 2163 EXPORT_SYMBOL_GPL(bq27xxx_battery_teardown); 2164 2164 2165 + #ifdef CONFIG_PM_SLEEP 2166 + static int bq27xxx_battery_suspend(struct device *dev) 2167 + { 2168 + struct bq27xxx_device_info *di = dev_get_drvdata(dev); 2169 + 2170 + cancel_delayed_work(&di->work); 2171 + return 0; 2172 + } 2173 + 2174 + static int bq27xxx_battery_resume(struct device *dev) 2175 + { 2176 + struct bq27xxx_device_info *di = dev_get_drvdata(dev); 2177 + 2178 + schedule_delayed_work(&di->work, 0); 2179 + return 0; 2180 + } 2181 + #endif /* CONFIG_PM_SLEEP */ 2182 + 2183 + SIMPLE_DEV_PM_OPS(bq27xxx_battery_battery_pm_ops, 2184 + bq27xxx_battery_suspend, bq27xxx_battery_resume); 2185 + EXPORT_SYMBOL_GPL(bq27xxx_battery_battery_pm_ops); 2186 + 2165 2187 MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); 2166 2188 MODULE_DESCRIPTION("BQ27xxx battery monitor driver"); 2167 2189 MODULE_LICENSE("GPL");
+1
drivers/power/supply/bq27xxx_battery_i2c.c
··· 295 295 .driver = { 296 296 .name = "bq27xxx-battery", 297 297 .of_match_table = of_match_ptr(bq27xxx_battery_i2c_of_match_table), 298 + .pm = &bq27xxx_battery_battery_pm_ops, 298 299 }, 299 300 .probe = bq27xxx_battery_i2c_probe, 300 301 .remove = bq27xxx_battery_i2c_remove,
+1
include/linux/power/bq27xxx_battery.h
··· 83 83 void bq27xxx_battery_update(struct bq27xxx_device_info *di); 84 84 int bq27xxx_battery_setup(struct bq27xxx_device_info *di); 85 85 void bq27xxx_battery_teardown(struct bq27xxx_device_info *di); 86 + extern const struct dev_pm_ops bq27xxx_battery_battery_pm_ops; 86 87 87 88 #endif