Power Supply Fixes for 7.3 cycle

* power-supply core
   - prevent unregistering a power supply while a callback runs
  * power-supply drivers
   - generic-adc-battery: Fix temperature IIO channel conversion
   - ds2780: Fix ds2780_get_capacity() returning raw value
   - max17042_battery: Fix vmin assigned instead of vmax in DT parsing
   - Fix maintenance charge table kernel-doc
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAmrOwSkACgkQ2O7X88g7
 +prAqw//d/NwWB6j/ZgAmi7Ww7BDnZrpHIaPrwc6t2qLG6Mu+WgWeGuKjIEd3dye
 +j+nSQBwEnE2yI1bJK/R2suV3c3MeMBga24W3QQ9smYvRsH+btR59TVb5Aak/l0B
 eo3UM8DC36k9+pzOpPFFqqf7tJNcatkC3jUdqp9nL1FA/dITc7OrVhsFkSAijjO+
 U2BhXFvw9Oy1vkXPbEew9kmfi0DyYVsJJc0G7PNsJmlmS1q+VOZMTtGhXKy5/BG0
 XR4BDOv7Sas7gETkTz3CKD+5IYRx7j2nah4slVYXmFImnpWfhsVCBPGdPR4jhGW6
 5L5+TlK21DRvIEoaQZWdkvxvAqXIqHINUZzGNHiqdhBEYRT2Qr+KtyTVfYOeUmh7
 IHLUJl+HpuZn5V/jfCkxfrSrNqmyK0/8O6hVVyvn7I6eEmTWvd6b8AcWr++TQTZa
 xgZl2js9F7DZ176cJaf/3rn9twShuQ2xhAtbVTr1V+HbD5IBGheQ/TfELLVUr/m1
 JKBUjDRY060EROXhTkcXs3Lwt7hSFqj/fKggiWJZKqsMnSgJjyaTwpLx9k88Qqqn
 5eyyjFZDEqcT8fzb5MwRvCLYVJbcJ0Up72e5xi4nXBfLcuC1jVeOG4hiwF55obrb
 XvFx8TQvOLVdy7H15ZX0fwOiNj68lUZi+1jebQWhoTb5z9GdkBg=
 =QLJn
 -----END PGP SIGNATURE-----

Merge tag 'for-v7.3-rc' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply

Pull power supply fixes from Sebastian Reichel:
 "power-supply core:
   - prevent unregistering a power supply while a callback runs

  power-supply drivers:
   - generic-adc-battery: Fix temperature IIO channel conversion
   - ds2780: Fix ds2780_get_capacity() returning raw value
   - max17042_battery: Fix vmin assigned instead of vmax in DT parsing
   - Fix maintenance charge table kernel-doc"

* tag 'for-v7.3-rc' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply:
  power: supply: core: prevent unregistering a power supply while a callback runs
  power: supply: generic-adc-battery: Fix temperature IIO channel conversion
  power: supply: ds2780: Fix ds2780_get_capacity() returning raw value
  power: supply: Fix maintenance charge table kernel-doc
  power: supply: max17042_battery: Fix vmin assigned instead of vmax in DT parsing
This commit is contained in:
Linus Torvalds 2026-10-13 18:02:11 -07:00
commit d77bd0d469
5 changed files with 47 additions and 8 deletions

View File

@ -304,7 +304,7 @@ static int ds2780_get_capacity(struct ds2780_device_info *dev_info,
return ret;
*capacity = raw;
return raw;
return 0;
}
static int ds2780_get_status(struct ds2780_device_info *dev_info, int *status)

View File

@ -90,12 +90,17 @@ static int gab_read_channel(struct gab *adc_bat, enum gab_chan_type channel,
int ret;
ret = iio_read_channel_processed(adc_bat->channel[channel], result);
if (ret < 0)
if (ret < 0) {
dev_err(&adc_bat->psy->dev, "read channel error: %d\n", ret);
return ret;
}
if (channel == GAB_TEMP)
*result /= 100; /* Convert from milli- to deci-degree */
else
*result *= 1000;
return ret;
return 0;
}
static int gab_get_property(struct power_supply *psy,

View File

@ -1233,7 +1233,7 @@ static int max17042_parse_dt(struct max17042_chip *chip)
if (of_property_read_u32(np, "maxim,over-volt", &prop))
chip->vmax = INT_MAX;
else
chip->vmin = prop;
chip->vmax = prop;
return 0;
}

View File

@ -1530,6 +1530,19 @@ void power_supply_external_power_changed(struct power_supply *psy)
!psy->desc->external_power_changed)
return;
/*
* Keep power_supply_unregister() from returning, and thus from letting
* the driver's data be freed, while the callback is running. The
* ->removing check has to happen under the lock: on its own, just like
* the use_cnt check above, it only tells us the supply was still there
* when we looked, not that it still is by the time the callback
* dereferences its driver data.
*/
guard(rwsem_read)(&psy->epc_sem);
if (psy->removing)
return;
psy->desc->external_power_changed(psy);
}
EXPORT_SYMBOL_GPL(power_supply_external_power_changed);
@ -1774,6 +1787,7 @@ __power_supply_register(struct device *parent,
}
spin_lock_init(&psy->changed_lock);
init_rwsem(&psy->epc_sem);
init_rwsem(&psy->extensions_sem);
INIT_LIST_HEAD(&psy->extensions);
@ -1914,7 +1928,17 @@ EXPORT_SYMBOL_GPL(devm_power_supply_register);
void power_supply_unregister(struct power_supply *psy)
{
WARN_ON(atomic_dec_return(&psy->use_cnt));
psy->removing = true;
/*
* Publish ->removing so that no new ->external_power_changed() call can
* start, and wait via semaphore for one that is already running: it may
* be a supplier's changed_work, which cancel_work_sync() below does not
* cover, and it may still dereference driver data that the caller is
* about to free.
*/
scoped_guard(rwsem_write, &psy->epc_sem)
psy->removing = true;
cancel_work_sync(&psy->changed_work);
cancel_delayed_work_sync(&psy->deferred_register_work);
sysfs_remove_link(&psy->dev.kobj, "powers");

View File

@ -351,6 +351,16 @@ struct power_supply {
bool removing;
atomic_t use_cnt;
struct power_supply_battery_info *battery_info;
/*
* Held for read while ->external_power_changed() runs, and for write by
* power_supply_unregister() when it publishes @removing, so that it
* waits for an in-flight callback to finish. Without this a driver's
* data, typically devm-allocated on its own device, can be freed while
* the callback is still using it.
* Must not be shared with extensions_sem: callbacks may read their own
* properties, which takes that one for read.
*/
struct rw_semaphore epc_sem;
struct rw_semaphore extensions_sem; /* protects "extensions" */
struct list_head extensions;
#ifdef CONFIG_THERMAL
@ -414,9 +424,9 @@ struct power_supply_vbat_ri_table {
* @charge_voltage_max_uv: maintenance charging voltage that is usually a bit
* lower than the constant_charge_voltage_max_uv. We can apply this settings
* charge_current_max_ua until we get back up to this voltage.
* @safety_timer_minutes: maintenance charging safety timer, with an expiry
* time in minutes. We will only use maintenance charging in this setting
* for a certain amount of time, then we will first move to the next
* @charge_safety_timer_minutes: maintenance charging safety timer, with an
* expiry time in minutes. We will only use maintenance charging in this
* setting for a certain amount of time, then we will first move to the next
* maintenance charge current and voltage pair in respective array and wait
* for the next safety timer timeout, or, if we reached the last maintencance
* charging setting, disable charging until we reach