mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 04:04:43 +01:00
Power Supply Fixes for 6.4 cycle
Fixes for the 6.4 cycle:
* Fix power_supply_get_battery_info for devices without parent
devices resulting in NULL pointer dereference
* Fix desktop systems reporting to run on battery once a power-supply
device with device scope appears (e.g. a HID keyboard with a battery)
* Ratelimit debug print about driver not providing data
* Fix race condition related to external_power_changed in multiple
drivers (ab8500, axp288, bq25890, sc27xx, bq27xxx)
* Fix LED trigger switching from blinking to solid-on when charging
finishes
* Fix multiple races in bq27xxx battery driver
* mt6360: handle potential ENOMEM from devm_work_autocancel
* sbs-charger: Fix SBS_CHARGER_STATUS_CHARGE_INHIBITED bit
* rt9467: avoid passing 0 to dev_err_probe
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAmRvknYACgkQ2O7X88g7
+pqM9w/8DrpP3Te4mNoxvdi4teVXkBVmEEaK4aK+KJ8ag+v5hLCDEO7BDEMHYob3
ihfINsIbHRdo3PEAy049fXic847h8NsIUr79HiLZKVPbqFFVxyy17IBElt+FPiLA
nx0Gqi2lkuF3hWsgHXwsOS+ltQzcGMDPUM3xpQbrXDi8zdjDsNFSDHX8Luqqjmo7
+hIaWt1QmzzF4IH9cdAdO0/B5zbEKcfiU6XM/IDgftUdp3gXRxlwawIj67z3hGDC
ObumINevoYir/ZA3J/Q0KKiUS5F6tr3XxMgAi3s2wrIrRRF7VgrWMAf98Laf64Yl
jJwWwDzktYhJ9fMY6qksMdPfP+VT0g/6/mWKH3emmT18w1kGqSbHEvqvThmZvV6E
i+iPol5657dvXI+2Os75yyjJ9lSncXuQEUsi+i6isa+ac249t5XINzo+Gz+rOUrZ
qkZ/Jkkv8xnlnvRZXSNs4FDTE4yBiiqQbg/H5y3anu8Vb4Q99IlVruwjj1ukS3gZ
eIzM72UbWmdYbATXIwhwgiRqVWWkJDJL9BsaLN55th231jRJCzwLoYRG5elOuXQC
JTjgoz31hAoCtc5f16FZS+PIuNEFOsTE32aX3SlnhHhA7NWewSgwsw9tZCmqlaJ2
rA5rdrkEtWooL2JzgAqfgjbKCkWfS2e1oCGBb1lgSiio+YOdRkg=
=jWEO
-----END PGP SIGNATURE-----
Merge tag 'for-v6.4-rc' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply
Pull power supply fixes from Sebastian Reichel:
- Fix power_supply_get_battery_info for devices without parent devices
resulting in NULL pointer dereference
- Fix desktop systems reporting to run on battery once a power-supply
device with device scope appears (e.g. a HID keyboard with a battery)
- Ratelimit debug print about driver not providing data
- Fix race condition related to external_power_changed in multiple
drivers (ab8500, axp288, bq25890, sc27xx, bq27xxx)
- Fix LED trigger switching from blinking to solid-on when charging
finishes
- Fix multiple races in bq27xxx battery driver
- mt6360: handle potential ENOMEM from devm_work_autocancel
- sbs-charger: Fix SBS_CHARGER_STATUS_CHARGE_INHIBITED bit
- rt9467: avoid passing 0 to dev_err_probe
* tag 'for-v6.4-rc' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (21 commits)
power: supply: Fix logic checking if system is running from battery
power: supply: mt6360: add a check of devm_work_autocancel in mt6360_charger_probe
power: supply: sbs-charger: Fix INHIBITED bit for Status reg
power: supply: rt9467: Fix passing zero to 'dev_err_probe'
power: supply: Ratelimit no data debug output
power: supply: Fix power_supply_get_battery_info() if parent is NULL
power: supply: bq24190: Call power_supply_changed() after updating input current
power: supply: bq25890: Call power_supply_changed() after updating input current or voltage
power: supply: bq27xxx: Use mod_delayed_work() instead of cancel() + schedule()
power: supply: bq27xxx: After charger plug in/out wait 0.5s for things to stabilize
power: supply: bq27xxx: Ensure power_supply_changed() is called on current sign changes
power: supply: bq27xxx: Move bq27xxx_battery_update() down
power: supply: bq27xxx: Add cache parameter to bq27xxx_battery_current_and_status()
power: supply: bq27xxx: Fix poll_interval handling and races on remove
power: supply: bq27xxx: Fix I2C IRQ race on remove
power: supply: bq27xxx: Fix bq27xxx_battery_update() race condition
power: supply: leds: Fix blink to LED on transition
power: supply: sc27xx: Fix external_power_changed race
power: supply: bq25890: Fix external_power_changed race
power: supply: axp288_fuel_gauge: Fix external_power_changed race
...
This commit is contained in:
commit
eb03e31813
15 changed files with 136 additions and 112 deletions
|
|
@ -624,10 +624,8 @@ static int ab8500_btemp_get_ext_psy_data(struct device *dev, void *data)
|
|||
*/
|
||||
static void ab8500_btemp_external_power_changed(struct power_supply *psy)
|
||||
{
|
||||
struct ab8500_btemp *di = power_supply_get_drvdata(psy);
|
||||
|
||||
class_for_each_device(power_supply_class, NULL,
|
||||
di->btemp_psy, ab8500_btemp_get_ext_psy_data);
|
||||
class_for_each_device(power_supply_class, NULL, psy,
|
||||
ab8500_btemp_get_ext_psy_data);
|
||||
}
|
||||
|
||||
/* ab8500 btemp driver interrupts and their respective isr */
|
||||
|
|
|
|||
|
|
@ -2407,10 +2407,8 @@ out:
|
|||
*/
|
||||
static void ab8500_fg_external_power_changed(struct power_supply *psy)
|
||||
{
|
||||
struct ab8500_fg *di = power_supply_get_drvdata(psy);
|
||||
|
||||
class_for_each_device(power_supply_class, NULL,
|
||||
di->fg_psy, ab8500_fg_get_ext_psy_data);
|
||||
class_for_each_device(power_supply_class, NULL, psy,
|
||||
ab8500_fg_get_ext_psy_data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -507,7 +507,7 @@ static void fuel_gauge_external_power_changed(struct power_supply *psy)
|
|||
mutex_lock(&info->lock);
|
||||
info->valid = 0; /* Force updating of the cached registers */
|
||||
mutex_unlock(&info->lock);
|
||||
power_supply_changed(info->bat);
|
||||
power_supply_changed(psy);
|
||||
}
|
||||
|
||||
static struct power_supply_desc fuel_gauge_desc = {
|
||||
|
|
|
|||
|
|
@ -1262,6 +1262,7 @@ static void bq24190_input_current_limit_work(struct work_struct *work)
|
|||
bq24190_charger_set_property(bdi->charger,
|
||||
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
|
||||
&val);
|
||||
power_supply_changed(bdi->charger);
|
||||
}
|
||||
|
||||
/* Sync the input-current-limit with our parent supply (if we have one) */
|
||||
|
|
|
|||
|
|
@ -750,7 +750,7 @@ static void bq25890_charger_external_power_changed(struct power_supply *psy)
|
|||
if (bq->chip_version != BQ25892)
|
||||
return;
|
||||
|
||||
ret = power_supply_get_property_from_supplier(bq->charger,
|
||||
ret = power_supply_get_property_from_supplier(psy,
|
||||
POWER_SUPPLY_PROP_USB_TYPE,
|
||||
&val);
|
||||
if (ret)
|
||||
|
|
@ -775,6 +775,7 @@ static void bq25890_charger_external_power_changed(struct power_supply *psy)
|
|||
}
|
||||
|
||||
bq25890_field_write(bq, F_IINLIM, input_current_limit);
|
||||
power_supply_changed(psy);
|
||||
}
|
||||
|
||||
static int bq25890_get_chip_state(struct bq25890_device *bq,
|
||||
|
|
@ -1106,6 +1107,8 @@ static void bq25890_pump_express_work(struct work_struct *data)
|
|||
dev_info(bq->dev, "Hi-voltage charging requested, input voltage is %d mV\n",
|
||||
voltage);
|
||||
|
||||
power_supply_changed(bq->charger);
|
||||
|
||||
return;
|
||||
error_print:
|
||||
bq25890_field_write(bq, F_PUMPX_EN, 0);
|
||||
|
|
|
|||
|
|
@ -1083,10 +1083,8 @@ static int poll_interval_param_set(const char *val, const struct kernel_param *k
|
|||
return ret;
|
||||
|
||||
mutex_lock(&bq27xxx_list_lock);
|
||||
list_for_each_entry(di, &bq27xxx_battery_devices, list) {
|
||||
cancel_delayed_work_sync(&di->work);
|
||||
schedule_delayed_work(&di->work, 0);
|
||||
}
|
||||
list_for_each_entry(di, &bq27xxx_battery_devices, list)
|
||||
mod_delayed_work(system_wq, &di->work, 0);
|
||||
mutex_unlock(&bq27xxx_list_lock);
|
||||
|
||||
return ret;
|
||||
|
|
@ -1761,60 +1759,6 @@ static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di)
|
|||
return POWER_SUPPLY_HEALTH_GOOD;
|
||||
}
|
||||
|
||||
void bq27xxx_battery_update(struct bq27xxx_device_info *di)
|
||||
{
|
||||
struct bq27xxx_reg_cache cache = {0, };
|
||||
bool has_singe_flag = di->opts & BQ27XXX_O_ZERO;
|
||||
|
||||
cache.flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag);
|
||||
if ((cache.flags & 0xff) == 0xff)
|
||||
cache.flags = -1; /* read error */
|
||||
if (cache.flags >= 0) {
|
||||
cache.temperature = bq27xxx_battery_read_temperature(di);
|
||||
if (di->regs[BQ27XXX_REG_TTE] != INVALID_REG_ADDR)
|
||||
cache.time_to_empty = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTE);
|
||||
if (di->regs[BQ27XXX_REG_TTECP] != INVALID_REG_ADDR)
|
||||
cache.time_to_empty_avg = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTECP);
|
||||
if (di->regs[BQ27XXX_REG_TTF] != INVALID_REG_ADDR)
|
||||
cache.time_to_full = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTF);
|
||||
|
||||
cache.charge_full = bq27xxx_battery_read_fcc(di);
|
||||
cache.capacity = bq27xxx_battery_read_soc(di);
|
||||
if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR)
|
||||
cache.energy = bq27xxx_battery_read_energy(di);
|
||||
di->cache.flags = cache.flags;
|
||||
cache.health = bq27xxx_battery_read_health(di);
|
||||
if (di->regs[BQ27XXX_REG_CYCT] != INVALID_REG_ADDR)
|
||||
cache.cycle_count = bq27xxx_battery_read_cyct(di);
|
||||
|
||||
/* We only have to read charge design full once */
|
||||
if (di->charge_design_full <= 0)
|
||||
di->charge_design_full = bq27xxx_battery_read_dcap(di);
|
||||
}
|
||||
|
||||
if ((di->cache.capacity != cache.capacity) ||
|
||||
(di->cache.flags != cache.flags))
|
||||
power_supply_changed(di->bat);
|
||||
|
||||
if (memcmp(&di->cache, &cache, sizeof(cache)) != 0)
|
||||
di->cache = cache;
|
||||
|
||||
di->last_update = jiffies;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bq27xxx_battery_update);
|
||||
|
||||
static void bq27xxx_battery_poll(struct work_struct *work)
|
||||
{
|
||||
struct bq27xxx_device_info *di =
|
||||
container_of(work, struct bq27xxx_device_info,
|
||||
work.work);
|
||||
|
||||
bq27xxx_battery_update(di);
|
||||
|
||||
if (poll_interval > 0)
|
||||
schedule_delayed_work(&di->work, poll_interval * HZ);
|
||||
}
|
||||
|
||||
static bool bq27xxx_battery_is_full(struct bq27xxx_device_info *di, int flags)
|
||||
{
|
||||
if (di->opts & BQ27XXX_O_ZERO)
|
||||
|
|
@ -1833,7 +1777,8 @@ static bool bq27xxx_battery_is_full(struct bq27xxx_device_info *di, int flags)
|
|||
static int bq27xxx_battery_current_and_status(
|
||||
struct bq27xxx_device_info *di,
|
||||
union power_supply_propval *val_curr,
|
||||
union power_supply_propval *val_status)
|
||||
union power_supply_propval *val_status,
|
||||
struct bq27xxx_reg_cache *cache)
|
||||
{
|
||||
bool single_flags = (di->opts & BQ27XXX_O_ZERO);
|
||||
int curr;
|
||||
|
|
@ -1845,10 +1790,14 @@ static int bq27xxx_battery_current_and_status(
|
|||
return curr;
|
||||
}
|
||||
|
||||
flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, single_flags);
|
||||
if (flags < 0) {
|
||||
dev_err(di->dev, "error reading flags\n");
|
||||
return flags;
|
||||
if (cache) {
|
||||
flags = cache->flags;
|
||||
} else {
|
||||
flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, single_flags);
|
||||
if (flags < 0) {
|
||||
dev_err(di->dev, "error reading flags\n");
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
|
||||
if (di->opts & BQ27XXX_O_ZERO) {
|
||||
|
|
@ -1883,6 +1832,78 @@ static int bq27xxx_battery_current_and_status(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void bq27xxx_battery_update_unlocked(struct bq27xxx_device_info *di)
|
||||
{
|
||||
union power_supply_propval status = di->last_status;
|
||||
struct bq27xxx_reg_cache cache = {0, };
|
||||
bool has_singe_flag = di->opts & BQ27XXX_O_ZERO;
|
||||
|
||||
cache.flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag);
|
||||
if ((cache.flags & 0xff) == 0xff)
|
||||
cache.flags = -1; /* read error */
|
||||
if (cache.flags >= 0) {
|
||||
cache.temperature = bq27xxx_battery_read_temperature(di);
|
||||
if (di->regs[BQ27XXX_REG_TTE] != INVALID_REG_ADDR)
|
||||
cache.time_to_empty = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTE);
|
||||
if (di->regs[BQ27XXX_REG_TTECP] != INVALID_REG_ADDR)
|
||||
cache.time_to_empty_avg = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTECP);
|
||||
if (di->regs[BQ27XXX_REG_TTF] != INVALID_REG_ADDR)
|
||||
cache.time_to_full = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTF);
|
||||
|
||||
cache.charge_full = bq27xxx_battery_read_fcc(di);
|
||||
cache.capacity = bq27xxx_battery_read_soc(di);
|
||||
if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR)
|
||||
cache.energy = bq27xxx_battery_read_energy(di);
|
||||
di->cache.flags = cache.flags;
|
||||
cache.health = bq27xxx_battery_read_health(di);
|
||||
if (di->regs[BQ27XXX_REG_CYCT] != INVALID_REG_ADDR)
|
||||
cache.cycle_count = bq27xxx_battery_read_cyct(di);
|
||||
|
||||
/*
|
||||
* On gauges with signed current reporting the current must be
|
||||
* checked to detect charging <-> discharging status changes.
|
||||
*/
|
||||
if (!(di->opts & BQ27XXX_O_ZERO))
|
||||
bq27xxx_battery_current_and_status(di, NULL, &status, &cache);
|
||||
|
||||
/* We only have to read charge design full once */
|
||||
if (di->charge_design_full <= 0)
|
||||
di->charge_design_full = bq27xxx_battery_read_dcap(di);
|
||||
}
|
||||
|
||||
if ((di->cache.capacity != cache.capacity) ||
|
||||
(di->cache.flags != cache.flags) ||
|
||||
(di->last_status.intval != status.intval)) {
|
||||
di->last_status.intval = status.intval;
|
||||
power_supply_changed(di->bat);
|
||||
}
|
||||
|
||||
if (memcmp(&di->cache, &cache, sizeof(cache)) != 0)
|
||||
di->cache = cache;
|
||||
|
||||
di->last_update = jiffies;
|
||||
|
||||
if (!di->removed && poll_interval > 0)
|
||||
mod_delayed_work(system_wq, &di->work, poll_interval * HZ);
|
||||
}
|
||||
|
||||
void bq27xxx_battery_update(struct bq27xxx_device_info *di)
|
||||
{
|
||||
mutex_lock(&di->lock);
|
||||
bq27xxx_battery_update_unlocked(di);
|
||||
mutex_unlock(&di->lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bq27xxx_battery_update);
|
||||
|
||||
static void bq27xxx_battery_poll(struct work_struct *work)
|
||||
{
|
||||
struct bq27xxx_device_info *di =
|
||||
container_of(work, struct bq27xxx_device_info,
|
||||
work.work);
|
||||
|
||||
bq27xxx_battery_update(di);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the average power in µW
|
||||
* Return < 0 if something fails.
|
||||
|
|
@ -1985,10 +2006,8 @@ static int bq27xxx_battery_get_property(struct power_supply *psy,
|
|||
struct bq27xxx_device_info *di = power_supply_get_drvdata(psy);
|
||||
|
||||
mutex_lock(&di->lock);
|
||||
if (time_is_before_jiffies(di->last_update + 5 * HZ)) {
|
||||
cancel_delayed_work_sync(&di->work);
|
||||
bq27xxx_battery_poll(&di->work.work);
|
||||
}
|
||||
if (time_is_before_jiffies(di->last_update + 5 * HZ))
|
||||
bq27xxx_battery_update_unlocked(di);
|
||||
mutex_unlock(&di->lock);
|
||||
|
||||
if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0)
|
||||
|
|
@ -1996,7 +2015,7 @@ static int bq27xxx_battery_get_property(struct power_supply *psy,
|
|||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
ret = bq27xxx_battery_current_and_status(di, NULL, val);
|
||||
ret = bq27xxx_battery_current_and_status(di, NULL, val, NULL);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
ret = bq27xxx_battery_voltage(di, val);
|
||||
|
|
@ -2005,7 +2024,7 @@ static int bq27xxx_battery_get_property(struct power_supply *psy,
|
|||
val->intval = di->cache.flags < 0 ? 0 : 1;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
ret = bq27xxx_battery_current_and_status(di, val, NULL);
|
||||
ret = bq27xxx_battery_current_and_status(di, val, NULL, NULL);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
ret = bq27xxx_simple_value(di->cache.capacity, val);
|
||||
|
|
@ -2078,8 +2097,8 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
|
|||
{
|
||||
struct bq27xxx_device_info *di = power_supply_get_drvdata(psy);
|
||||
|
||||
cancel_delayed_work_sync(&di->work);
|
||||
schedule_delayed_work(&di->work, 0);
|
||||
/* After charger plug in/out wait 0.5s for things to stabilize */
|
||||
mod_delayed_work(system_wq, &di->work, HZ / 2);
|
||||
}
|
||||
|
||||
int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
|
||||
|
|
@ -2127,22 +2146,18 @@ EXPORT_SYMBOL_GPL(bq27xxx_battery_setup);
|
|||
|
||||
void bq27xxx_battery_teardown(struct bq27xxx_device_info *di)
|
||||
{
|
||||
/*
|
||||
* power_supply_unregister call bq27xxx_battery_get_property which
|
||||
* call bq27xxx_battery_poll.
|
||||
* Make sure that bq27xxx_battery_poll will not call
|
||||
* schedule_delayed_work again after unregister (which cause OOPS).
|
||||
*/
|
||||
poll_interval = 0;
|
||||
|
||||
cancel_delayed_work_sync(&di->work);
|
||||
|
||||
power_supply_unregister(di->bat);
|
||||
|
||||
mutex_lock(&bq27xxx_list_lock);
|
||||
list_del(&di->list);
|
||||
mutex_unlock(&bq27xxx_list_lock);
|
||||
|
||||
/* Set removed to avoid bq27xxx_battery_update() re-queuing the work */
|
||||
mutex_lock(&di->lock);
|
||||
di->removed = true;
|
||||
mutex_unlock(&di->lock);
|
||||
|
||||
cancel_delayed_work_sync(&di->work);
|
||||
|
||||
power_supply_unregister(di->bat);
|
||||
mutex_destroy(&di->lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bq27xxx_battery_teardown);
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client)
|
|||
i2c_set_clientdata(client, di);
|
||||
|
||||
if (client->irq) {
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
ret = request_threaded_irq(client->irq,
|
||||
NULL, bq27xxx_battery_irq_handler_thread,
|
||||
IRQF_ONESHOT,
|
||||
di->name, di);
|
||||
|
|
@ -209,6 +209,7 @@ static void bq27xxx_battery_i2c_remove(struct i2c_client *client)
|
|||
{
|
||||
struct bq27xxx_device_info *di = i2c_get_clientdata(client);
|
||||
|
||||
free_irq(client->irq, di);
|
||||
bq27xxx_battery_teardown(di);
|
||||
|
||||
mutex_lock(&battery_mutex);
|
||||
|
|
|
|||
|
|
@ -796,7 +796,9 @@ static int mt6360_charger_probe(struct platform_device *pdev)
|
|||
mci->vinovp = 6500000;
|
||||
mutex_init(&mci->chgdet_lock);
|
||||
platform_set_drvdata(pdev, mci);
|
||||
devm_work_autocancel(&pdev->dev, &mci->chrdet_work, mt6360_chrdet_work);
|
||||
ret = devm_work_autocancel(&pdev->dev, &mci->chrdet_work, mt6360_chrdet_work);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "Failed to set delayed work\n");
|
||||
|
||||
ret = device_property_read_u32(&pdev->dev, "richtek,vinovp-microvolt", &mci->vinovp);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -348,6 +348,10 @@ static int __power_supply_is_system_supplied(struct device *dev, void *data)
|
|||
struct power_supply *psy = dev_get_drvdata(dev);
|
||||
unsigned int *count = data;
|
||||
|
||||
if (!psy->desc->get_property(psy, POWER_SUPPLY_PROP_SCOPE, &ret))
|
||||
if (ret.intval == POWER_SUPPLY_SCOPE_DEVICE)
|
||||
return 0;
|
||||
|
||||
(*count)++;
|
||||
if (psy->desc->type != POWER_SUPPLY_TYPE_BATTERY)
|
||||
if (!psy->desc->get_property(psy, POWER_SUPPLY_PROP_ONLINE,
|
||||
|
|
@ -366,8 +370,8 @@ int power_supply_is_system_supplied(void)
|
|||
__power_supply_is_system_supplied);
|
||||
|
||||
/*
|
||||
* If no power class device was found at all, most probably we are
|
||||
* running on a desktop system, so assume we are on mains power.
|
||||
* If no system scope power class device was found at all, most probably we
|
||||
* are running on a desktop system, so assume we are on mains power.
|
||||
*/
|
||||
if (count == 0)
|
||||
return 1;
|
||||
|
|
@ -573,7 +577,7 @@ int power_supply_get_battery_info(struct power_supply *psy,
|
|||
struct power_supply_battery_info *info;
|
||||
struct device_node *battery_np = NULL;
|
||||
struct fwnode_reference_args args;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct fwnode_handle *fwnode = NULL;
|
||||
const char *value;
|
||||
int err, len, index;
|
||||
const __be32 *list;
|
||||
|
|
@ -585,7 +589,7 @@ int power_supply_get_battery_info(struct power_supply *psy,
|
|||
return -ENODEV;
|
||||
|
||||
fwnode = fwnode_handle_get(of_fwnode_handle(battery_np));
|
||||
} else {
|
||||
} else if (psy->dev.parent) {
|
||||
err = fwnode_property_get_reference_args(
|
||||
dev_fwnode(psy->dev.parent),
|
||||
"monitored-battery", NULL, 0, 0, &args);
|
||||
|
|
@ -595,6 +599,9 @@ int power_supply_get_battery_info(struct power_supply *psy,
|
|||
fwnode = args.fwnode;
|
||||
}
|
||||
|
||||
if (!fwnode)
|
||||
return -ENOENT;
|
||||
|
||||
err = fwnode_property_read_string(fwnode, "compatible", &value);
|
||||
if (err)
|
||||
goto out_put_node;
|
||||
|
|
|
|||
|
|
@ -35,8 +35,9 @@ static void power_supply_update_bat_leds(struct power_supply *psy)
|
|||
led_trigger_event(psy->charging_full_trig, LED_FULL);
|
||||
led_trigger_event(psy->charging_trig, LED_OFF);
|
||||
led_trigger_event(psy->full_trig, LED_FULL);
|
||||
led_trigger_event(psy->charging_blink_full_solid_trig,
|
||||
LED_FULL);
|
||||
/* Going from blink to LED on requires a LED_OFF event to stop blink */
|
||||
led_trigger_event(psy->charging_blink_full_solid_trig, LED_OFF);
|
||||
led_trigger_event(psy->charging_blink_full_solid_trig, LED_FULL);
|
||||
break;
|
||||
case POWER_SUPPLY_STATUS_CHARGING:
|
||||
led_trigger_event(psy->charging_full_trig, LED_FULL);
|
||||
|
|
|
|||
|
|
@ -286,7 +286,8 @@ static ssize_t power_supply_show_property(struct device *dev,
|
|||
|
||||
if (ret < 0) {
|
||||
if (ret == -ENODATA)
|
||||
dev_dbg(dev, "driver has no data for `%s' property\n",
|
||||
dev_dbg_ratelimited(dev,
|
||||
"driver has no data for `%s' property\n",
|
||||
attr->attr.name);
|
||||
else if (ret != -ENODEV && ret != -EAGAIN)
|
||||
dev_err_ratelimited(dev,
|
||||
|
|
|
|||
|
|
@ -1023,7 +1023,7 @@ static int rt9467_request_interrupt(struct rt9467_chg_data *data)
|
|||
for (i = 0; i < num_chg_irqs; i++) {
|
||||
virq = regmap_irq_get_virq(data->irq_chip_data, chg_irqs[i].hwirq);
|
||||
if (virq <= 0)
|
||||
return dev_err_probe(dev, virq, "Failed to get (%s) irq\n",
|
||||
return dev_err_probe(dev, -EINVAL, "Failed to get (%s) irq\n",
|
||||
chg_irqs[i].name);
|
||||
|
||||
ret = devm_request_threaded_irq(dev, virq, NULL, chg_irqs[i].handler,
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
#define SBS_CHARGER_REG_STATUS 0x13
|
||||
#define SBS_CHARGER_REG_ALARM_WARNING 0x16
|
||||
|
||||
#define SBS_CHARGER_STATUS_CHARGE_INHIBITED BIT(1)
|
||||
#define SBS_CHARGER_STATUS_CHARGE_INHIBITED BIT(0)
|
||||
#define SBS_CHARGER_STATUS_RES_COLD BIT(9)
|
||||
#define SBS_CHARGER_STATUS_RES_HOT BIT(10)
|
||||
#define SBS_CHARGER_STATUS_BATTERY_PRESENT BIT(14)
|
||||
|
|
|
|||
|
|
@ -733,13 +733,6 @@ static int sc27xx_fgu_set_property(struct power_supply *psy,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void sc27xx_fgu_external_power_changed(struct power_supply *psy)
|
||||
{
|
||||
struct sc27xx_fgu_data *data = power_supply_get_drvdata(psy);
|
||||
|
||||
power_supply_changed(data->battery);
|
||||
}
|
||||
|
||||
static int sc27xx_fgu_property_is_writeable(struct power_supply *psy,
|
||||
enum power_supply_property psp)
|
||||
{
|
||||
|
|
@ -774,7 +767,7 @@ static const struct power_supply_desc sc27xx_fgu_desc = {
|
|||
.num_properties = ARRAY_SIZE(sc27xx_fgu_props),
|
||||
.get_property = sc27xx_fgu_get_property,
|
||||
.set_property = sc27xx_fgu_set_property,
|
||||
.external_power_changed = sc27xx_fgu_external_power_changed,
|
||||
.external_power_changed = power_supply_changed,
|
||||
.property_is_writeable = sc27xx_fgu_property_is_writeable,
|
||||
.no_thermal = true,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
#ifndef __LINUX_BQ27X00_BATTERY_H__
|
||||
#define __LINUX_BQ27X00_BATTERY_H__
|
||||
|
||||
#include <linux/power_supply.h>
|
||||
|
||||
enum bq27xxx_chip {
|
||||
BQ27000 = 1, /* bq27000, bq27200 */
|
||||
BQ27010, /* bq27010, bq27210 */
|
||||
|
|
@ -68,7 +70,9 @@ struct bq27xxx_device_info {
|
|||
struct bq27xxx_access_methods bus;
|
||||
struct bq27xxx_reg_cache cache;
|
||||
int charge_design_full;
|
||||
bool removed;
|
||||
unsigned long last_update;
|
||||
union power_supply_propval last_status;
|
||||
struct delayed_work work;
|
||||
struct power_supply *bat;
|
||||
struct list_head list;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue