From 67d85ee4bc749ee94cdfe9638618a506638d1926 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 09:09:10 -0600 Subject: [PATCH 01/66] power: supply: bq27xxx: Switch to a simpler IDA interface We don't need to specify any ranges when allocating IDs so we can switch to ida_alloc() and ida_free() instead of the ida_simple_ counterparts. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123150914.308510-1-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery_i2c.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index 3a1798b0c1a7..86ce13a8ab9d 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -13,8 +13,7 @@ #include -static DEFINE_IDR(battery_id); -static DEFINE_MUTEX(battery_mutex); +static DEFINE_IDA(battery_id); static irqreturn_t bq27xxx_battery_irq_handler_thread(int irq, void *data) { @@ -145,9 +144,7 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client) int num; /* Get new ID for the new battery device */ - mutex_lock(&battery_mutex); - num = idr_alloc(&battery_id, client, 0, 0, GFP_KERNEL); - mutex_unlock(&battery_mutex); + num = ida_alloc(&battery_id, GFP_KERNEL); if (num < 0) return num; @@ -198,9 +195,7 @@ err_mem: ret = -ENOMEM; err_failed: - mutex_lock(&battery_mutex); - idr_remove(&battery_id, num); - mutex_unlock(&battery_mutex); + ida_free(&battery_id, num); return ret; } @@ -212,9 +207,7 @@ static void bq27xxx_battery_i2c_remove(struct i2c_client *client) free_irq(client->irq, di); bq27xxx_battery_teardown(di); - mutex_lock(&battery_mutex); - idr_remove(&battery_id, di->id); - mutex_unlock(&battery_mutex); + ida_free(&battery_id, di->id); } static const struct i2c_device_id bq27xxx_i2c_id_table[] = { From 73697f0acc773a357946a3c5a917bfb4c85128a3 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 09:09:11 -0600 Subject: [PATCH 02/66] power: supply: bq27xxx: Add devm action to free IDA Use a device lifecycle managed action to free the IDA. This helps prevent mistakes like freeing out of order in cleanup functions and forgetting to free on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123150914.308510-2-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery_i2c.c | 35 +++++++++++----------- include/linux/power/bq27xxx_battery.h | 1 - 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index 86ce13a8ab9d..019f29d13d28 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -135,28 +135,39 @@ static int bq27xxx_battery_i2c_bulk_write(struct bq27xxx_device_info *di, return 0; } +static void bq27xxx_battery_i2c_devm_ida_free(void *data) +{ + int num = (long)data; + + ida_free(&battery_id, num); +} + static int bq27xxx_battery_i2c_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); struct bq27xxx_device_info *di; int ret; char *name; - int num; + long num; /* Get new ID for the new battery device */ num = ida_alloc(&battery_id, GFP_KERNEL); if (num < 0) return num; + ret = devm_add_action_or_reset(&client->dev, + bq27xxx_battery_i2c_devm_ida_free, + (void *)num); + if (ret) + return ret; - name = devm_kasprintf(&client->dev, GFP_KERNEL, "%s-%d", id->name, num); + name = devm_kasprintf(&client->dev, GFP_KERNEL, "%s-%ld", id->name, num); if (!name) - goto err_mem; + return -ENOMEM; di = devm_kzalloc(&client->dev, sizeof(*di), GFP_KERNEL); if (!di) - goto err_mem; + return -ENOMEM; - di->id = num; di->dev = &client->dev; di->chip = id->driver_data; di->name = name; @@ -168,7 +179,7 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client) ret = bq27xxx_battery_setup(di); if (ret) - goto err_failed; + return ret; /* Schedule a polling after about 1 min */ schedule_delayed_work(&di->work, 60 * HZ); @@ -185,19 +196,11 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client) "Unable to register IRQ %d error %d\n", client->irq, ret); bq27xxx_battery_teardown(di); - goto err_failed; + return ret; } } return 0; - -err_mem: - ret = -ENOMEM; - -err_failed: - ida_free(&battery_id, num); - - return ret; } static void bq27xxx_battery_i2c_remove(struct i2c_client *client) @@ -206,8 +209,6 @@ static void bq27xxx_battery_i2c_remove(struct i2c_client *client) free_irq(client->irq, di); bq27xxx_battery_teardown(di); - - ida_free(&battery_id, di->id); } static const struct i2c_device_id bq27xxx_i2c_id_table[] = { diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h index 7d8025fb74b7..b9e5bd2b42d3 100644 --- a/include/linux/power/bq27xxx_battery.h +++ b/include/linux/power/bq27xxx_battery.h @@ -61,7 +61,6 @@ struct bq27xxx_reg_cache { struct bq27xxx_device_info { struct device *dev; - int id; enum bq27xxx_chip chip; u32 opts; const char *name; From f2d506d9fe10f0104951f61ad0d414ac8b8dbc38 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 09:09:12 -0600 Subject: [PATCH 03/66] power: supply: bq27xxx: Use devm to free device mutex Use a device lifecycle managed action to free the device mutex. This helps prevent mistakes like freeing out of order in cleanup functions and forgetting to free on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123150914.308510-3-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 1c4a9d137744..d3b6327b16b5 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -2101,6 +2101,13 @@ static void bq27xxx_external_power_changed(struct power_supply *psy) mod_delayed_work(system_wq, &di->work, HZ / 2); } +static void bq27xxx_battery_mutex_destroy(void *data) +{ + struct mutex *lock = data; + + mutex_destroy(lock); +} + int bq27xxx_battery_setup(struct bq27xxx_device_info *di) { struct power_supply_desc *psy_desc; @@ -2108,9 +2115,14 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di) .of_node = di->dev->of_node, .drv_data = di, }; + int ret; INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll); mutex_init(&di->lock); + ret = devm_add_action_or_reset(di->dev, bq27xxx_battery_mutex_destroy, + &di->lock); + if (ret) + return ret; di->regs = bq27xxx_chip_data[di->chip].regs; di->unseal_key = bq27xxx_chip_data[di->chip].unseal_key; @@ -2158,7 +2170,6 @@ void bq27xxx_battery_teardown(struct bq27xxx_device_info *di) cancel_delayed_work_sync(&di->work); power_supply_unregister(di->bat); - mutex_destroy(&di->lock); } EXPORT_SYMBOL_GPL(bq27xxx_battery_teardown); From 7911cf971c1cbf69cb110ab83598c3c415cf2c70 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 09:09:13 -0600 Subject: [PATCH 04/66] power: supply: bq27xxx: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123150914.308510-4-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index d3b6327b16b5..2bf5e007f16b 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -2140,7 +2140,7 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di) psy_desc->get_property = bq27xxx_battery_get_property; psy_desc->external_power_changed = bq27xxx_external_power_changed; - di->bat = power_supply_register_no_ws(di->dev, psy_desc, &psy_cfg); + di->bat = devm_power_supply_register_no_ws(di->dev, psy_desc, &psy_cfg); if (IS_ERR(di->bat)) return dev_err_probe(di->dev, PTR_ERR(di->bat), "failed to register battery\n"); @@ -2168,8 +2168,6 @@ void bq27xxx_battery_teardown(struct bq27xxx_device_info *di) mutex_unlock(&di->lock); cancel_delayed_work_sync(&di->work); - - power_supply_unregister(di->bat); } EXPORT_SYMBOL_GPL(bq27xxx_battery_teardown); From b282c30dad3e10738a4f03043efaff93d9e8de02 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 09:09:14 -0600 Subject: [PATCH 05/66] power: supply: bq27xxx: Move one time design full read out of poll This value only needs read once. Move that read into the function that returns the value to keep the logic all in one place. This also avoids doing this check every time we read in values in the device update poll worker. While here, correct this function's error message. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123150914.308510-5-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 2bf5e007f16b..363428530ee6 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -1595,17 +1595,24 @@ static inline int bq27xxx_battery_read_fcc(struct bq27xxx_device_info *di) * Return the Design Capacity in µAh * Or < 0 if something fails. */ -static int bq27xxx_battery_read_dcap(struct bq27xxx_device_info *di) +static int bq27xxx_battery_read_dcap(struct bq27xxx_device_info *di, + union power_supply_propval *val) { int dcap; + /* We only have to read charge design full once */ + if (di->charge_design_full > 0) { + val->intval = di->charge_design_full; + return 0; + } + if (di->opts & BQ27XXX_O_ZERO) dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, true); else dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, false); if (dcap < 0) { - dev_dbg(di->dev, "error reading initial last measured discharge\n"); + dev_dbg(di->dev, "error reading design capacity\n"); return dcap; } @@ -1614,7 +1621,12 @@ static int bq27xxx_battery_read_dcap(struct bq27xxx_device_info *di) else dcap *= 1000; - return dcap; + /* Save for later reads */ + di->charge_design_full = dcap; + + val->intval = dcap; + + return 0; } /* @@ -1865,10 +1877,6 @@ static void bq27xxx_battery_update_unlocked(struct bq27xxx_device_info *di) */ 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) || @@ -2062,7 +2070,7 @@ static int bq27xxx_battery_get_property(struct power_supply *psy, ret = bq27xxx_simple_value(di->cache.charge_full, val); break; case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: - ret = bq27xxx_simple_value(di->charge_design_full, val); + ret = bq27xxx_battery_read_dcap(di, val); break; /* * TODO: Implement these to make registers set from From 98be59bd03aa50d155ba84208cd964017e397fc9 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:33 -0600 Subject: [PATCH 06/66] power: supply: da9030: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-2-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/da9030_battery.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/da9030_battery.c b/drivers/power/supply/da9030_battery.c index 581cf956d2d2..04e0f4162d42 100644 --- a/drivers/power/supply/da9030_battery.c +++ b/drivers/power/supply/da9030_battery.c @@ -530,8 +530,9 @@ static int da9030_battery_probe(struct platform_device *pdev) da9030_battery_setup_psy(charger); psy_cfg.drv_data = charger; - charger->psy = power_supply_register(&pdev->dev, &charger->psy_desc, - &psy_cfg); + charger->psy = devm_power_supply_register(&pdev->dev, + &charger->psy_desc, + &psy_cfg); if (IS_ERR(charger->psy)) { ret = PTR_ERR(charger->psy); goto err_ps_register; @@ -563,7 +564,6 @@ static void da9030_battery_remove(struct platform_device *dev) DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT); cancel_delayed_work_sync(&charger->work); da9030_set_charge(charger, 0); - power_supply_unregister(charger->psy); } static struct platform_driver da903x_battery_driver = { From 57261cda154b3d0f8671ea222672f75b1e965c15 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:34 -0600 Subject: [PATCH 07/66] power: supply: da9052: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-3-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/da9052-battery.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/power/supply/da9052-battery.c b/drivers/power/supply/da9052-battery.c index 6f7c58a41e91..0d84c42c624e 100644 --- a/drivers/power/supply/da9052-battery.c +++ b/drivers/power/supply/da9052-battery.c @@ -622,7 +622,7 @@ static s32 da9052_bat_probe(struct platform_device *pdev) } } - bat->psy = power_supply_register(&pdev->dev, &psy_desc, &psy_cfg); + bat->psy = devm_power_supply_register(&pdev->dev, &psy_desc, &psy_cfg); if (IS_ERR(bat->psy)) { ret = PTR_ERR(bat->psy); goto err; @@ -644,8 +644,6 @@ static void da9052_bat_remove(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(da9052_bat_irqs); i++) da9052_free_irq(bat->da9052, da9052_bat_irq_bits[i], bat); - - power_supply_unregister(bat->psy); } static struct platform_driver da9052_bat_driver = { From 88a72257a438375894de446885bb40946e0f979f Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:35 -0600 Subject: [PATCH 08/66] power: supply: ds2760: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-4-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/ds2760_battery.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/power/supply/ds2760_battery.c b/drivers/power/supply/ds2760_battery.c index 40fba31be174..7cf4ea06b500 100644 --- a/drivers/power/supply/ds2760_battery.c +++ b/drivers/power/supply/ds2760_battery.c @@ -739,7 +739,7 @@ static int w1_ds2760_add_slave(struct w1_slave *sl) if (current_accum) ds2760_battery_set_current_accum(di, current_accum); - di->bat = power_supply_register(dev, &di->bat_desc, &psy_cfg); + di->bat = devm_power_supply_register(dev, &di->bat_desc, &psy_cfg); if (IS_ERR(di->bat)) { dev_err(di->dev, "failed to register battery\n"); retval = PTR_ERR(di->bat); @@ -762,7 +762,6 @@ static int w1_ds2760_add_slave(struct w1_slave *sl) goto success; workqueue_failed: - power_supply_unregister(di->bat); batt_failed: di_alloc_failed: success: @@ -777,7 +776,6 @@ static void w1_ds2760_remove_slave(struct w1_slave *sl) cancel_delayed_work_sync(&di->monitor_work); cancel_delayed_work_sync(&di->set_charged_work); destroy_workqueue(di->monitor_wqueue); - power_supply_unregister(di->bat); } #ifdef CONFIG_OF From ada63f1ec91b77417cf195dadd646eaadb6f121c Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:36 -0600 Subject: [PATCH 09/66] power: supply: goldfish: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-5-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/goldfish_battery.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/power/supply/goldfish_battery.c b/drivers/power/supply/goldfish_battery.c index 8bb645ad1e5d..479195e35d73 100644 --- a/drivers/power/supply/goldfish_battery.c +++ b/drivers/power/supply/goldfish_battery.c @@ -232,31 +232,22 @@ static int goldfish_battery_probe(struct platform_device *pdev) psy_cfg.drv_data = data; - data->ac = power_supply_register(&pdev->dev, &ac_desc, &psy_cfg); + data->ac = devm_power_supply_register(&pdev->dev, + &ac_desc, + &psy_cfg); if (IS_ERR(data->ac)) return PTR_ERR(data->ac); - data->battery = power_supply_register(&pdev->dev, &battery_desc, - &psy_cfg); - if (IS_ERR(data->battery)) { - power_supply_unregister(data->ac); + data->battery = devm_power_supply_register(&pdev->dev, + &battery_desc, + &psy_cfg); + if (IS_ERR(data->battery)) return PTR_ERR(data->battery); - } - - platform_set_drvdata(pdev, data); GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK); return 0; } -static void goldfish_battery_remove(struct platform_device *pdev) -{ - struct goldfish_battery_data *data = platform_get_drvdata(pdev); - - power_supply_unregister(data->battery); - power_supply_unregister(data->ac); -} - static const struct of_device_id goldfish_battery_of_match[] = { { .compatible = "google,goldfish-battery", }, {}, @@ -273,7 +264,6 @@ MODULE_DEVICE_TABLE(acpi, goldfish_battery_acpi_match); static struct platform_driver goldfish_battery_device = { .probe = goldfish_battery_probe, - .remove_new = goldfish_battery_remove, .driver = { .name = "goldfish-battery", .of_match_table = goldfish_battery_of_match, From 3b4d07fdaf17a8bb79173c2c40876d3221edeea4 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:37 -0600 Subject: [PATCH 10/66] power: supply: lp8727: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-6-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/lp8727_charger.c | 35 ++++++--------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/drivers/power/supply/lp8727_charger.c b/drivers/power/supply/lp8727_charger.c index 0875391f7ac6..34548a4da90b 100644 --- a/drivers/power/supply/lp8727_charger.c +++ b/drivers/power/supply/lp8727_charger.c @@ -453,39 +453,20 @@ static int lp8727_register_psy(struct lp8727_chg *pchg) psy_cfg.supplied_to = battery_supplied_to; psy_cfg.num_supplicants = ARRAY_SIZE(battery_supplied_to); - psy->ac = power_supply_register(pchg->dev, &lp8727_ac_desc, &psy_cfg); + psy->ac = devm_power_supply_register(pchg->dev, &lp8727_ac_desc, &psy_cfg); if (IS_ERR(psy->ac)) - goto err_psy_ac; + return -EPERM; - psy->usb = power_supply_register(pchg->dev, &lp8727_usb_desc, - &psy_cfg); + psy->usb = devm_power_supply_register(pchg->dev, &lp8727_usb_desc, + &psy_cfg); if (IS_ERR(psy->usb)) - goto err_psy_usb; + return -EPERM; - psy->batt = power_supply_register(pchg->dev, &lp8727_batt_desc, NULL); + psy->batt = devm_power_supply_register(pchg->dev, &lp8727_batt_desc, NULL); if (IS_ERR(psy->batt)) - goto err_psy_batt; + return -EPERM; return 0; - -err_psy_batt: - power_supply_unregister(psy->usb); -err_psy_usb: - power_supply_unregister(psy->ac); -err_psy_ac: - return -EPERM; -} - -static void lp8727_unregister_psy(struct lp8727_chg *pchg) -{ - struct lp8727_psy *psy = pchg->psy; - - if (!psy) - return; - - power_supply_unregister(psy->ac); - power_supply_unregister(psy->usb); - power_supply_unregister(psy->batt); } #ifdef CONFIG_OF @@ -583,7 +564,6 @@ static int lp8727_probe(struct i2c_client *cl) ret = lp8727_setup_irq(pchg); if (ret) { dev_err(pchg->dev, "irq handler err: %d", ret); - lp8727_unregister_psy(pchg); return ret; } @@ -595,7 +575,6 @@ static void lp8727_remove(struct i2c_client *cl) struct lp8727_chg *pchg = i2c_get_clientdata(cl); lp8727_release_irq(pchg); - lp8727_unregister_psy(pchg); } static const struct of_device_id lp8727_dt_ids[] __maybe_unused = { From 2abb571143c39f581df9951d263948726db42d86 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:38 -0600 Subject: [PATCH 11/66] power: supply: lp8788: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-7-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/lp8788-charger.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/power/supply/lp8788-charger.c b/drivers/power/supply/lp8788-charger.c index 2c81be82a41a..72b170b4ac46 100644 --- a/drivers/power/supply/lp8788-charger.c +++ b/drivers/power/supply/lp8788-charger.c @@ -406,12 +406,6 @@ static const struct power_supply_desc lp8788_psy_battery_desc = { .get_property = lp8788_battery_get_property, }; -static void lp8788_psy_unregister(struct lp8788_charger *pchg) -{ - power_supply_unregister(pchg->battery); - power_supply_unregister(pchg->charger); -} - static void lp8788_charger_event(struct work_struct *work) { struct lp8788_charger *pchg = @@ -666,18 +660,16 @@ static int lp8788_psy_register(struct platform_device *pdev, charger_cfg.supplied_to = battery_supplied_to; charger_cfg.num_supplicants = ARRAY_SIZE(battery_supplied_to); - pchg->charger = power_supply_register(&pdev->dev, - &lp8788_psy_charger_desc, - &charger_cfg); + pchg->charger = devm_power_supply_register(&pdev->dev, + &lp8788_psy_charger_desc, + &charger_cfg); if (IS_ERR(pchg->charger)) return -EPERM; - pchg->battery = power_supply_register(&pdev->dev, - &lp8788_psy_battery_desc, NULL); - if (IS_ERR(pchg->battery)) { - power_supply_unregister(pchg->charger); + pchg->battery = devm_power_supply_register(&pdev->dev, + &lp8788_psy_battery_desc, NULL); + if (IS_ERR(pchg->battery)) return -EPERM; - } return 0; } @@ -720,7 +712,6 @@ static void lp8788_charger_remove(struct platform_device *pdev) flush_work(&pchg->charger_work); lp8788_irq_unregister(pdev, pchg); - lp8788_psy_unregister(pchg); } static struct platform_driver lp8788_charger_driver = { From e90a67f618c4a1128c49b11ddec37d9f1728ff5b Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:42 -0600 Subject: [PATCH 12/66] power: supply: pcf50633: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-11-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/pcf50633-charger.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/drivers/power/supply/pcf50633-charger.c b/drivers/power/supply/pcf50633-charger.c index 950e30917c63..0e980522fee5 100644 --- a/drivers/power/supply/pcf50633-charger.c +++ b/drivers/power/supply/pcf50633-charger.c @@ -404,9 +404,9 @@ static int pcf50633_mbc_probe(struct platform_device *pdev) psy_cfg.drv_data = mbc; /* Create power supplies */ - mbc->adapter = power_supply_register(&pdev->dev, - &pcf50633_mbc_adapter_desc, - &psy_cfg); + mbc->adapter = devm_power_supply_register(&pdev->dev, + &pcf50633_mbc_adapter_desc, + &psy_cfg); if (IS_ERR(mbc->adapter)) { dev_err(mbc->pcf->dev, "failed to register adapter\n"); return PTR_ERR(mbc->adapter); @@ -415,20 +415,19 @@ static int pcf50633_mbc_probe(struct platform_device *pdev) usb_psy_cfg = psy_cfg; usb_psy_cfg.attr_grp = pcf50633_mbc_sysfs_groups; - mbc->usb = power_supply_register(&pdev->dev, &pcf50633_mbc_usb_desc, - &usb_psy_cfg); + mbc->usb = devm_power_supply_register(&pdev->dev, + &pcf50633_mbc_usb_desc, + &usb_psy_cfg); if (IS_ERR(mbc->usb)) { dev_err(mbc->pcf->dev, "failed to register usb\n"); - power_supply_unregister(mbc->adapter); return PTR_ERR(mbc->usb); } - mbc->ac = power_supply_register(&pdev->dev, &pcf50633_mbc_ac_desc, - &psy_cfg); + mbc->ac = devm_power_supply_register(&pdev->dev, + &pcf50633_mbc_ac_desc, + &psy_cfg); if (IS_ERR(mbc->ac)) { dev_err(mbc->pcf->dev, "failed to register ac\n"); - power_supply_unregister(mbc->adapter); - power_supply_unregister(mbc->usb); return PTR_ERR(mbc->ac); } @@ -449,10 +448,6 @@ static void pcf50633_mbc_remove(struct platform_device *pdev) /* Remove IRQ handlers */ for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++) pcf50633_free_irq(mbc->pcf, mbc_irq_handlers[i]); - - power_supply_unregister(mbc->usb); - power_supply_unregister(mbc->adapter); - power_supply_unregister(mbc->ac); } static struct platform_driver pcf50633_mbc_driver = { From 3a93da231c12bb153224bbbdd3d9a83da9e0ba33 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:43 -0600 Subject: [PATCH 13/66] power: supply: rt5033: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-12-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/rt5033_battery.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/power/supply/rt5033_battery.c b/drivers/power/supply/rt5033_battery.c index d90b96df8e73..32eafe2c00af 100644 --- a/drivers/power/supply/rt5033_battery.c +++ b/drivers/power/supply/rt5033_battery.c @@ -159,12 +159,12 @@ static int rt5033_battery_probe(struct i2c_client *client) return -EINVAL; } - i2c_set_clientdata(client, battery); psy_cfg.of_node = client->dev.of_node; psy_cfg.drv_data = battery; - battery->psy = power_supply_register(&client->dev, - &rt5033_battery_desc, &psy_cfg); + battery->psy = devm_power_supply_register(&client->dev, + &rt5033_battery_desc, + &psy_cfg); if (IS_ERR(battery->psy)) return dev_err_probe(&client->dev, PTR_ERR(battery->psy), "Failed to register power supply\n"); @@ -172,13 +172,6 @@ static int rt5033_battery_probe(struct i2c_client *client) return 0; } -static void rt5033_battery_remove(struct i2c_client *client) -{ - struct rt5033_battery *battery = i2c_get_clientdata(client); - - power_supply_unregister(battery->psy); -} - static const struct i2c_device_id rt5033_battery_id[] = { { "rt5033-battery", }, { } @@ -197,7 +190,6 @@ static struct i2c_driver rt5033_battery_driver = { .of_match_table = rt5033_battery_of_match, }, .probe = rt5033_battery_probe, - .remove = rt5033_battery_remove, .id_table = rt5033_battery_id, }; module_i2c_driver(rt5033_battery_driver); From 503920abb586c3e355a19c680089ff5b33d97262 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:44 -0600 Subject: [PATCH 14/66] power: supply: tps65090: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-13-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/tps65090-charger.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/power/supply/tps65090-charger.c b/drivers/power/supply/tps65090-charger.c index c59197d2aa87..d41595764caa 100644 --- a/drivers/power/supply/tps65090-charger.c +++ b/drivers/power/supply/tps65090-charger.c @@ -262,7 +262,7 @@ static int tps65090_charger_probe(struct platform_device *pdev) psy_cfg.of_node = pdev->dev.of_node; psy_cfg.drv_data = cdata; - cdata->ac = power_supply_register(&pdev->dev, &tps65090_charger_desc, + cdata->ac = devm_power_supply_register(&pdev->dev, &tps65090_charger_desc, &psy_cfg); if (IS_ERR(cdata->ac)) { dev_err(&pdev->dev, "failed: power supply register\n"); @@ -277,7 +277,7 @@ static int tps65090_charger_probe(struct platform_device *pdev) ret = tps65090_config_charger(cdata); if (ret < 0) { dev_err(&pdev->dev, "charger config failed, err %d\n", ret); - goto fail_unregister_supply; + return ret; } /* Check for charger presence */ @@ -286,14 +286,14 @@ static int tps65090_charger_probe(struct platform_device *pdev) if (ret < 0) { dev_err(cdata->dev, "%s(): Error in reading reg 0x%x", __func__, TPS65090_REG_CG_STATUS1); - goto fail_unregister_supply; + return ret; } if (status1 != 0) { ret = tps65090_enable_charging(cdata); if (ret < 0) { dev_err(cdata->dev, "error enabling charger\n"); - goto fail_unregister_supply; + return ret; } cdata->ac_online = 1; power_supply_changed(cdata->ac); @@ -306,7 +306,7 @@ static int tps65090_charger_probe(struct platform_device *pdev) dev_err(cdata->dev, "Unable to register irq %d err %d\n", irq, ret); - goto fail_unregister_supply; + return ret; } } else { cdata->poll_task = kthread_run(tps65090_charger_poll_task, @@ -316,16 +316,11 @@ static int tps65090_charger_probe(struct platform_device *pdev) ret = PTR_ERR(cdata->poll_task); dev_err(cdata->dev, "Unable to run kthread err %d\n", ret); - goto fail_unregister_supply; + return ret; } } return 0; - -fail_unregister_supply: - power_supply_unregister(cdata->ac); - - return ret; } static void tps65090_charger_remove(struct platform_device *pdev) @@ -334,7 +329,6 @@ static void tps65090_charger_remove(struct platform_device *pdev) if (cdata->irq == -ENXIO) kthread_stop(cdata->poll_task); - power_supply_unregister(cdata->ac); } static const struct of_device_id of_tps65090_charger_match[] = { From aa0c8959dac7207e3b7b25bcb01730bff9c61713 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:45 -0600 Subject: [PATCH 15/66] power: supply: wm831x: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-14-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/wm831x_backup.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/power/supply/wm831x_backup.c b/drivers/power/supply/wm831x_backup.c index 1a7265660ade..9673fcf7f3af 100644 --- a/drivers/power/supply/wm831x_backup.c +++ b/drivers/power/supply/wm831x_backup.c @@ -171,7 +171,6 @@ static int wm831x_backup_probe(struct platform_device *pdev) return -ENOMEM; devdata->wm831x = wm831x; - platform_set_drvdata(pdev, devdata); /* We ignore configuration failures since we can still read * back the status without enabling the charger (which may @@ -191,22 +190,14 @@ static int wm831x_backup_probe(struct platform_device *pdev) devdata->backup_desc.properties = wm831x_backup_props; devdata->backup_desc.num_properties = ARRAY_SIZE(wm831x_backup_props); devdata->backup_desc.get_property = wm831x_backup_get_prop; - devdata->backup = power_supply_register(&pdev->dev, - &devdata->backup_desc, NULL); + devdata->backup = devm_power_supply_register(&pdev->dev, + &devdata->backup_desc, NULL); return PTR_ERR_OR_ZERO(devdata->backup); } -static void wm831x_backup_remove(struct platform_device *pdev) -{ - struct wm831x_backup *devdata = platform_get_drvdata(pdev); - - power_supply_unregister(devdata->backup); -} - static struct platform_driver wm831x_backup_driver = { .probe = wm831x_backup_probe, - .remove_new = wm831x_backup_remove, .driver = { .name = "wm831x-backup", }, From f2a7667c6cc09431575a286ec87e823fddd4dd41 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:46 -0600 Subject: [PATCH 16/66] power: supply: wm831x: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-15-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/wm831x_power.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/drivers/power/supply/wm831x_power.c b/drivers/power/supply/wm831x_power.c index e49b01ee5f3e..d56e499ac59f 100644 --- a/drivers/power/supply/wm831x_power.c +++ b/drivers/power/supply/wm831x_power.c @@ -570,8 +570,9 @@ static int wm831x_power_probe(struct platform_device *pdev) power->wall_desc.properties = wm831x_wall_props; power->wall_desc.num_properties = ARRAY_SIZE(wm831x_wall_props); power->wall_desc.get_property = wm831x_wall_get_prop; - power->wall = power_supply_register(&pdev->dev, &power->wall_desc, - NULL); + power->wall = devm_power_supply_register(&pdev->dev, + &power->wall_desc, + NULL); if (IS_ERR(power->wall)) { ret = PTR_ERR(power->wall); goto err; @@ -582,7 +583,9 @@ static int wm831x_power_probe(struct platform_device *pdev) power->usb_desc.properties = wm831x_usb_props; power->usb_desc.num_properties = ARRAY_SIZE(wm831x_usb_props); power->usb_desc.get_property = wm831x_usb_get_prop; - power->usb = power_supply_register(&pdev->dev, &power->usb_desc, NULL); + power->usb = devm_power_supply_register(&pdev->dev, + &power->usb_desc, + NULL); if (IS_ERR(power->usb)) { ret = PTR_ERR(power->usb); goto err_wall; @@ -599,9 +602,9 @@ static int wm831x_power_probe(struct platform_device *pdev) power->battery_desc.num_properties = ARRAY_SIZE(wm831x_bat_props); power->battery_desc.get_property = wm831x_bat_get_prop; power->battery_desc.use_for_apm = 1; - power->battery = power_supply_register(&pdev->dev, - &power->battery_desc, - NULL); + power->battery = devm_power_supply_register(&pdev->dev, + &power->battery_desc, + NULL); if (IS_ERR(power->battery)) { ret = PTR_ERR(power->battery); goto err_usb; @@ -684,12 +687,8 @@ err_syslo: irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "SYSLO")); free_irq(irq, power); err_battery: - if (power->have_battery) - power_supply_unregister(power->battery); err_usb: - power_supply_unregister(power->usb); err_wall: - power_supply_unregister(power->wall); err: return ret; } @@ -717,11 +716,6 @@ static void wm831x_power_remove(struct platform_device *pdev) irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "SYSLO")); free_irq(irq, wm831x_power); - - if (wm831x_power->have_battery) - power_supply_unregister(wm831x_power->battery); - power_supply_unregister(wm831x_power->wall); - power_supply_unregister(wm831x_power->usb); } static struct platform_driver wm831x_power_driver = { From 9115c677071a09cf51cace59c33ed71ec61bdfec Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:48 -0600 Subject: [PATCH 17/66] power: supply: da9150: Use devm_iio_channel_get() helper Use the device lifecycle managed get function. This helps prevent mistakes like releasing out of order in cleanup functions and forgetting to release on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-17-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/da9150-charger.c | 57 +++++++-------------------- 1 file changed, 14 insertions(+), 43 deletions(-) diff --git a/drivers/power/supply/da9150-charger.c b/drivers/power/supply/da9150-charger.c index 37db9e4ed7f3..77e2d42382e4 100644 --- a/drivers/power/supply/da9150-charger.c +++ b/drivers/power/supply/da9150-charger.c @@ -521,36 +521,26 @@ static int da9150_charger_probe(struct platform_device *pdev) charger->dev = dev; /* Acquire ADC channels */ - charger->ibus_chan = iio_channel_get(dev, "CHAN_IBUS"); - if (IS_ERR(charger->ibus_chan)) { - ret = PTR_ERR(charger->ibus_chan); - goto ibus_chan_fail; - } + charger->ibus_chan = devm_iio_channel_get(dev, "CHAN_IBUS"); + if (IS_ERR(charger->ibus_chan)) + return PTR_ERR(charger->ibus_chan); - charger->vbus_chan = iio_channel_get(dev, "CHAN_VBUS"); - if (IS_ERR(charger->vbus_chan)) { - ret = PTR_ERR(charger->vbus_chan); - goto vbus_chan_fail; - } + charger->vbus_chan = devm_iio_channel_get(dev, "CHAN_VBUS"); + if (IS_ERR(charger->vbus_chan)) + return PTR_ERR(charger->vbus_chan); - charger->tjunc_chan = iio_channel_get(dev, "CHAN_TJUNC"); - if (IS_ERR(charger->tjunc_chan)) { - ret = PTR_ERR(charger->tjunc_chan); - goto tjunc_chan_fail; - } + charger->tjunc_chan = devm_iio_channel_get(dev, "CHAN_TJUNC"); + if (IS_ERR(charger->tjunc_chan)) + return PTR_ERR(charger->tjunc_chan); - charger->vbat_chan = iio_channel_get(dev, "CHAN_VBAT"); - if (IS_ERR(charger->vbat_chan)) { - ret = PTR_ERR(charger->vbat_chan); - goto vbat_chan_fail; - } + charger->vbat_chan = devm_iio_channel_get(dev, "CHAN_VBAT"); + if (IS_ERR(charger->vbat_chan)) + return PTR_ERR(charger->vbat_chan); /* Register power supplies */ charger->usb = power_supply_register(dev, &usb_desc, NULL); - if (IS_ERR(charger->usb)) { - ret = PTR_ERR(charger->usb); - goto usb_fail; - } + if (IS_ERR(charger->usb)) + return PTR_ERR(charger->usb); charger->battery = power_supply_register(dev, &battery_desc, NULL); if (IS_ERR(charger->battery)) { @@ -619,19 +609,6 @@ chg_irq_fail: battery_fail: power_supply_unregister(charger->usb); -usb_fail: - iio_channel_release(charger->vbat_chan); - -vbat_chan_fail: - iio_channel_release(charger->tjunc_chan); - -tjunc_chan_fail: - iio_channel_release(charger->vbus_chan); - -vbus_chan_fail: - iio_channel_release(charger->ibus_chan); - -ibus_chan_fail: return ret; } @@ -659,12 +636,6 @@ static void da9150_charger_remove(struct platform_device *pdev) power_supply_unregister(charger->battery); power_supply_unregister(charger->usb); - - /* Release ADC channels */ - iio_channel_release(charger->ibus_chan); - iio_channel_release(charger->vbus_chan); - iio_channel_release(charger->tjunc_chan); - iio_channel_release(charger->vbat_chan); } static struct platform_driver da9150_charger_driver = { From 077c1df8456f97d89e4880ba503d8ddf6af5be12 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:49 -0600 Subject: [PATCH 18/66] power: supply: da9150: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-18-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/da9150-charger.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/power/supply/da9150-charger.c b/drivers/power/supply/da9150-charger.c index 77e2d42382e4..b13cecd84f58 100644 --- a/drivers/power/supply/da9150-charger.c +++ b/drivers/power/supply/da9150-charger.c @@ -538,15 +538,13 @@ static int da9150_charger_probe(struct platform_device *pdev) return PTR_ERR(charger->vbat_chan); /* Register power supplies */ - charger->usb = power_supply_register(dev, &usb_desc, NULL); + charger->usb = devm_power_supply_register(dev, &usb_desc, NULL); if (IS_ERR(charger->usb)) return PTR_ERR(charger->usb); - charger->battery = power_supply_register(dev, &battery_desc, NULL); - if (IS_ERR(charger->battery)) { - ret = PTR_ERR(charger->battery); - goto battery_fail; - } + charger->battery = devm_power_supply_register(dev, &battery_desc, NULL); + if (IS_ERR(charger->battery)) + return PTR_ERR(charger->battery); /* Get initial online supply */ reg = da9150_reg_read(da9150, DA9150_STATUS_H); @@ -606,8 +604,6 @@ tjunc_irq_fail: chg_irq_fail: if (!IS_ERR_OR_NULL(charger->usb_phy)) usb_unregister_notifier(charger->usb_phy, &charger->otg_nb); -battery_fail: - power_supply_unregister(charger->usb); return ret; } @@ -633,9 +629,6 @@ static void da9150_charger_remove(struct platform_device *pdev) if (!IS_ERR_OR_NULL(charger->usb_phy)) usb_unregister_notifier(charger->usb_phy, &charger->otg_nb); cancel_work_sync(&charger->otg_work); - - power_supply_unregister(charger->battery); - power_supply_unregister(charger->usb); } static struct platform_driver da9150_charger_driver = { From a16dc57e97558dcff7c422b3abec4f9880e8272b Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:50 -0600 Subject: [PATCH 19/66] power: supply: rx51: Use devm_iio_channel_get() helper Use the device lifecycle managed get function. This helps prevent mistakes like releasing out of order in cleanup functions and forgetting to release on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-19-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/rx51_battery.c | 45 +++++++---------------------- 1 file changed, 11 insertions(+), 34 deletions(-) diff --git a/drivers/power/supply/rx51_battery.c b/drivers/power/supply/rx51_battery.c index e2bfc81f0fd9..d532c670661b 100644 --- a/drivers/power/supply/rx51_battery.c +++ b/drivers/power/supply/rx51_battery.c @@ -192,7 +192,6 @@ static int rx51_battery_probe(struct platform_device *pdev) { struct power_supply_config psy_cfg = {}; struct rx51_device_info *di; - int ret; di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL); if (!di) @@ -209,41 +208,23 @@ static int rx51_battery_probe(struct platform_device *pdev) psy_cfg.drv_data = di; - di->channel_temp = iio_channel_get(di->dev, "temp"); - if (IS_ERR(di->channel_temp)) { - ret = PTR_ERR(di->channel_temp); - goto error; - } + di->channel_temp = devm_iio_channel_get(di->dev, "temp"); + if (IS_ERR(di->channel_temp)) + return PTR_ERR(di->channel_temp); - di->channel_bsi = iio_channel_get(di->dev, "bsi"); - if (IS_ERR(di->channel_bsi)) { - ret = PTR_ERR(di->channel_bsi); - goto error_channel_temp; - } + di->channel_bsi = devm_iio_channel_get(di->dev, "bsi"); + if (IS_ERR(di->channel_bsi)) + return PTR_ERR(di->channel_bsi); - di->channel_vbat = iio_channel_get(di->dev, "vbat"); - if (IS_ERR(di->channel_vbat)) { - ret = PTR_ERR(di->channel_vbat); - goto error_channel_bsi; - } + di->channel_vbat = devm_iio_channel_get(di->dev, "vbat"); + if (IS_ERR(di->channel_vbat)) + return PTR_ERR(di->channel_vbat); di->bat = power_supply_register(di->dev, &di->bat_desc, &psy_cfg); - if (IS_ERR(di->bat)) { - ret = PTR_ERR(di->bat); - goto error_channel_vbat; - } + if (IS_ERR(di->bat)) + return PTR_ERR(di->bat); return 0; - -error_channel_vbat: - iio_channel_release(di->channel_vbat); -error_channel_bsi: - iio_channel_release(di->channel_bsi); -error_channel_temp: - iio_channel_release(di->channel_temp); -error: - - return ret; } static void rx51_battery_remove(struct platform_device *pdev) @@ -251,10 +232,6 @@ static void rx51_battery_remove(struct platform_device *pdev) struct rx51_device_info *di = platform_get_drvdata(pdev); power_supply_unregister(di->bat); - - iio_channel_release(di->channel_vbat); - iio_channel_release(di->channel_bsi); - iio_channel_release(di->channel_temp); } #ifdef CONFIG_OF From 4cb372a0ca220fff4a3878c4d1239af3e057e7cc Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:51 -0600 Subject: [PATCH 20/66] power: supply: rx51: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-20-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/rx51_battery.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/power/supply/rx51_battery.c b/drivers/power/supply/rx51_battery.c index d532c670661b..7cdcd415e868 100644 --- a/drivers/power/supply/rx51_battery.c +++ b/drivers/power/supply/rx51_battery.c @@ -197,8 +197,6 @@ static int rx51_battery_probe(struct platform_device *pdev) if (!di) return -ENOMEM; - platform_set_drvdata(pdev, di); - di->dev = &pdev->dev; di->bat_desc.name = "rx51-battery"; di->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY; @@ -220,20 +218,13 @@ static int rx51_battery_probe(struct platform_device *pdev) if (IS_ERR(di->channel_vbat)) return PTR_ERR(di->channel_vbat); - di->bat = power_supply_register(di->dev, &di->bat_desc, &psy_cfg); + di->bat = devm_power_supply_register(di->dev, &di->bat_desc, &psy_cfg); if (IS_ERR(di->bat)) return PTR_ERR(di->bat); return 0; } -static void rx51_battery_remove(struct platform_device *pdev) -{ - struct rx51_device_info *di = platform_get_drvdata(pdev); - - power_supply_unregister(di->bat); -} - #ifdef CONFIG_OF static const struct of_device_id n900_battery_of_match[] = { {.compatible = "nokia,n900-battery", }, @@ -244,7 +235,6 @@ MODULE_DEVICE_TABLE(of, n900_battery_of_match); static struct platform_driver rx51_battery_driver = { .probe = rx51_battery_probe, - .remove_new = rx51_battery_remove, .driver = { .name = "rx51-battery", .of_match_table = of_match_ptr(n900_battery_of_match), From 8ac675344280a406835f03746594345209f2c1ae Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:52 -0600 Subject: [PATCH 21/66] power: supply: twl4030_madc: Use devm_iio_channel_get() helper Use the device lifecycle managed get function. This helps prevent mistakes like releasing out of order in cleanup functions and forgetting to release on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-21-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/twl4030_madc_battery.c | 44 ++++++--------------- 1 file changed, 11 insertions(+), 33 deletions(-) diff --git a/drivers/power/supply/twl4030_madc_battery.c b/drivers/power/supply/twl4030_madc_battery.c index 33106476bea2..cd9e94134ab2 100644 --- a/drivers/power/supply/twl4030_madc_battery.c +++ b/drivers/power/supply/twl4030_madc_battery.c @@ -188,30 +188,23 @@ static int twl4030_madc_battery_probe(struct platform_device *pdev) struct twl4030_madc_battery *twl4030_madc_bat; struct twl4030_madc_bat_platform_data *pdata = pdev->dev.platform_data; struct power_supply_config psy_cfg = {}; - int ret = 0; twl4030_madc_bat = devm_kzalloc(&pdev->dev, sizeof(*twl4030_madc_bat), GFP_KERNEL); if (!twl4030_madc_bat) return -ENOMEM; - twl4030_madc_bat->channel_temp = iio_channel_get(&pdev->dev, "temp"); - if (IS_ERR(twl4030_madc_bat->channel_temp)) { - ret = PTR_ERR(twl4030_madc_bat->channel_temp); - goto err; - } + twl4030_madc_bat->channel_temp = devm_iio_channel_get(&pdev->dev, "temp"); + if (IS_ERR(twl4030_madc_bat->channel_temp)) + return PTR_ERR(twl4030_madc_bat->channel_temp); - twl4030_madc_bat->channel_ichg = iio_channel_get(&pdev->dev, "ichg"); - if (IS_ERR(twl4030_madc_bat->channel_ichg)) { - ret = PTR_ERR(twl4030_madc_bat->channel_ichg); - goto err_temp; - } + twl4030_madc_bat->channel_ichg = devm_iio_channel_get(&pdev->dev, "ichg"); + if (IS_ERR(twl4030_madc_bat->channel_ichg)) + return PTR_ERR(twl4030_madc_bat->channel_ichg); - twl4030_madc_bat->channel_vbat = iio_channel_get(&pdev->dev, "vbat"); - if (IS_ERR(twl4030_madc_bat->channel_vbat)) { - ret = PTR_ERR(twl4030_madc_bat->channel_vbat); - goto err_ichg; - } + twl4030_madc_bat->channel_vbat = devm_iio_channel_get(&pdev->dev, "vbat"); + if (IS_ERR(twl4030_madc_bat->channel_vbat)) + return PTR_ERR(twl4030_madc_bat->channel_vbat); /* sort charging and discharging calibration data */ sort(pdata->charging, pdata->charging_size, @@ -227,21 +220,10 @@ static int twl4030_madc_battery_probe(struct platform_device *pdev) twl4030_madc_bat->psy = power_supply_register(&pdev->dev, &twl4030_madc_bat_desc, &psy_cfg); - if (IS_ERR(twl4030_madc_bat->psy)) { - ret = PTR_ERR(twl4030_madc_bat->psy); - goto err_vbat; - } + if (IS_ERR(twl4030_madc_bat->psy)) + return PTR_ERR(twl4030_madc_bat->psy); return 0; - -err_vbat: - iio_channel_release(twl4030_madc_bat->channel_vbat); -err_ichg: - iio_channel_release(twl4030_madc_bat->channel_ichg); -err_temp: - iio_channel_release(twl4030_madc_bat->channel_temp); -err: - return ret; } static void twl4030_madc_battery_remove(struct platform_device *pdev) @@ -249,10 +231,6 @@ static void twl4030_madc_battery_remove(struct platform_device *pdev) struct twl4030_madc_battery *bat = platform_get_drvdata(pdev); power_supply_unregister(bat->psy); - - iio_channel_release(bat->channel_vbat); - iio_channel_release(bat->channel_ichg); - iio_channel_release(bat->channel_temp); } static struct platform_driver twl4030_madc_battery_driver = { From 4c5d387d79a65355b73e526cbf5754a9dcd5377b Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Tue, 23 Jan 2024 10:36:53 -0600 Subject: [PATCH 22/66] power: supply: twl4030_madc: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240123163653.384385-22-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/twl4030_madc_battery.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/power/supply/twl4030_madc_battery.c b/drivers/power/supply/twl4030_madc_battery.c index cd9e94134ab2..3935162e350b 100644 --- a/drivers/power/supply/twl4030_madc_battery.c +++ b/drivers/power/supply/twl4030_madc_battery.c @@ -215,30 +215,21 @@ static int twl4030_madc_battery_probe(struct platform_device *pdev) twl4030_cmp, NULL); twl4030_madc_bat->pdata = pdata; - platform_set_drvdata(pdev, twl4030_madc_bat); psy_cfg.drv_data = twl4030_madc_bat; - twl4030_madc_bat->psy = power_supply_register(&pdev->dev, - &twl4030_madc_bat_desc, - &psy_cfg); + twl4030_madc_bat->psy = devm_power_supply_register(&pdev->dev, + &twl4030_madc_bat_desc, + &psy_cfg); if (IS_ERR(twl4030_madc_bat->psy)) return PTR_ERR(twl4030_madc_bat->psy); return 0; } -static void twl4030_madc_battery_remove(struct platform_device *pdev) -{ - struct twl4030_madc_battery *bat = platform_get_drvdata(pdev); - - power_supply_unregister(bat->psy); -} - static struct platform_driver twl4030_madc_battery_driver = { .driver = { .name = "twl4030_madc_battery", }, .probe = twl4030_madc_battery_probe, - .remove_new = twl4030_madc_battery_remove, }; module_platform_driver(twl4030_madc_battery_driver); From 99ae075684be3a84a9c20d9541259221d2c01fc8 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 29 Jan 2024 13:02:43 -0600 Subject: [PATCH 23/66] power: supply: max14577: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240129190246.73067-2-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/max14577_charger.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/power/supply/max14577_charger.c b/drivers/power/supply/max14577_charger.c index 7c23fa89ea19..b28c04157709 100644 --- a/drivers/power/supply/max14577_charger.c +++ b/drivers/power/supply/max14577_charger.c @@ -586,8 +586,9 @@ static int max14577_charger_probe(struct platform_device *pdev) } psy_cfg.drv_data = chg; - chg->charger = power_supply_register(&pdev->dev, &max14577_charger_desc, - &psy_cfg); + chg->charger = devm_power_supply_register(&pdev->dev, + &max14577_charger_desc, + &psy_cfg); if (IS_ERR(chg->charger)) { dev_err(&pdev->dev, "failed: power supply register\n"); ret = PTR_ERR(chg->charger); @@ -608,10 +609,7 @@ err: static void max14577_charger_remove(struct platform_device *pdev) { - struct max14577_charger *chg = platform_get_drvdata(pdev); - device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer); - power_supply_unregister(chg->charger); } static const struct platform_device_id max14577_charger_id[] = { From aed93a83a01211270feed78aa5dd5f2d2c76ff82 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 29 Jan 2024 13:02:44 -0600 Subject: [PATCH 24/66] power: supply: max77693: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240129190246.73067-3-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/max77693_charger.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/power/supply/max77693_charger.c b/drivers/power/supply/max77693_charger.c index d0157e63b8b5..2001e12c9f7d 100644 --- a/drivers/power/supply/max77693_charger.c +++ b/drivers/power/supply/max77693_charger.c @@ -709,9 +709,9 @@ static int max77693_charger_probe(struct platform_device *pdev) goto err; } - chg->charger = power_supply_register(&pdev->dev, - &max77693_charger_desc, - &psy_cfg); + chg->charger = devm_power_supply_register(&pdev->dev, + &max77693_charger_desc, + &psy_cfg); if (IS_ERR(chg->charger)) { dev_err(&pdev->dev, "failed: power supply register\n"); ret = PTR_ERR(chg->charger); @@ -730,13 +730,9 @@ err: static void max77693_charger_remove(struct platform_device *pdev) { - struct max77693_charger *chg = platform_get_drvdata(pdev); - device_remove_file(&pdev->dev, &dev_attr_top_off_timer); device_remove_file(&pdev->dev, &dev_attr_top_off_threshold_current); device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer); - - power_supply_unregister(chg->charger); } static const struct platform_device_id max77693_charger_id[] = { From 478a253e466570c4f02cbd7c9386f29dffe4375d Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 29 Jan 2024 13:02:45 -0600 Subject: [PATCH 25/66] power: supply: max8925: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240129190246.73067-4-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/max8925_power.c | 37 ++++++++-------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/drivers/power/supply/max8925_power.c b/drivers/power/supply/max8925_power.c index 4a2d6894f94e..621a006d52a9 100644 --- a/drivers/power/supply/max8925_power.c +++ b/drivers/power/supply/max8925_power.c @@ -507,7 +507,6 @@ static int max8925_power_probe(struct platform_device *pdev) struct power_supply_config psy_cfg = {}; /* Only for ac and usb */ struct max8925_power_pdata *pdata = NULL; struct max8925_power_info *info; - int ret; pdata = max8925_power_dt_init(pdev); if (!pdata) { @@ -528,25 +527,19 @@ static int max8925_power_probe(struct platform_device *pdev) psy_cfg.supplied_to = pdata->supplied_to; psy_cfg.num_supplicants = pdata->num_supplicants; - info->ac = power_supply_register(&pdev->dev, &ac_desc, &psy_cfg); - if (IS_ERR(info->ac)) { - ret = PTR_ERR(info->ac); - goto out; - } + info->ac = devm_power_supply_register(&pdev->dev, &ac_desc, &psy_cfg); + if (IS_ERR(info->ac)) + return PTR_ERR(info->ac); info->ac->dev.parent = &pdev->dev; - info->usb = power_supply_register(&pdev->dev, &usb_desc, &psy_cfg); - if (IS_ERR(info->usb)) { - ret = PTR_ERR(info->usb); - goto out_unregister_ac; - } + info->usb = devm_power_supply_register(&pdev->dev, &usb_desc, &psy_cfg); + if (IS_ERR(info->usb)) + return PTR_ERR(info->usb); info->usb->dev.parent = &pdev->dev; - info->battery = power_supply_register(&pdev->dev, &battery_desc, NULL); - if (IS_ERR(info->battery)) { - ret = PTR_ERR(info->battery); - goto out_unregister_usb; - } + info->battery = devm_power_supply_register(&pdev->dev, &battery_desc, NULL); + if (IS_ERR(info->battery)) + return PTR_ERR(info->battery); info->battery->dev.parent = &pdev->dev; info->batt_detect = pdata->batt_detect; @@ -558,24 +551,14 @@ static int max8925_power_probe(struct platform_device *pdev) max8925_init_charger(chip, info); return 0; -out_unregister_usb: - power_supply_unregister(info->usb); -out_unregister_ac: - power_supply_unregister(info->ac); -out: - return ret; } static void max8925_power_remove(struct platform_device *pdev) { struct max8925_power_info *info = platform_get_drvdata(pdev); - if (info) { - power_supply_unregister(info->ac); - power_supply_unregister(info->usb); - power_supply_unregister(info->battery); + if (info) max8925_deinit_charger(info); - } } static struct platform_driver max8925_power_driver = { From cad1e6df54ca6231a3d1217bc4231d1a7eadbc0c Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 29 Jan 2024 13:02:46 -0600 Subject: [PATCH 26/66] power: supply: wm8350: Use devm_power_supply_register() helper Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240129190246.73067-5-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/wm8350_power.c | 30 +++++++---------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/drivers/power/supply/wm8350_power.c b/drivers/power/supply/wm8350_power.c index f23b4f5343bc..3f79ab6f6abf 100644 --- a/drivers/power/supply/wm8350_power.c +++ b/drivers/power/supply/wm8350_power.c @@ -540,22 +540,17 @@ static int wm8350_power_probe(struct platform_device *pdev) struct wm8350_charger_policy *policy = power->policy; int ret; - power->ac = power_supply_register(&pdev->dev, &wm8350_ac_desc, NULL); + power->ac = devm_power_supply_register(&pdev->dev, &wm8350_ac_desc, NULL); if (IS_ERR(power->ac)) return PTR_ERR(power->ac); - power->battery = power_supply_register(&pdev->dev, &wm8350_battery_desc, - NULL); - if (IS_ERR(power->battery)) { - ret = PTR_ERR(power->battery); - goto battery_failed; - } + power->battery = devm_power_supply_register(&pdev->dev, &wm8350_battery_desc, NULL); + if (IS_ERR(power->battery)) + return PTR_ERR(power->battery); - power->usb = power_supply_register(&pdev->dev, &wm8350_usb_desc, NULL); - if (IS_ERR(power->usb)) { - ret = PTR_ERR(power->usb); - goto usb_failed; - } + power->usb = devm_power_supply_register(&pdev->dev, &wm8350_usb_desc, NULL); + if (IS_ERR(power->usb)) + return PTR_ERR(power->usb); ret = device_create_file(&pdev->dev, &dev_attr_charger_state); if (ret < 0) @@ -569,26 +564,15 @@ static int wm8350_power_probe(struct platform_device *pdev) wm8350_reg_lock(wm8350); } - return ret; - -usb_failed: - power_supply_unregister(power->battery); -battery_failed: - power_supply_unregister(power->ac); - return ret; } static void wm8350_power_remove(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); - struct wm8350_power *power = &wm8350->power; free_charger_irq(wm8350); device_remove_file(&pdev->dev, &dev_attr_charger_state); - power_supply_unregister(power->battery); - power_supply_unregister(power->ac); - power_supply_unregister(power->usb); } static struct platform_driver wm8350_power_driver = { From bec924d27a1fda74ec9ae9a1bae1e32723e32bcb Mon Sep 17 00:00:00 2001 From: Aren Moynihan Date: Tue, 30 Jan 2024 15:27:57 -0500 Subject: [PATCH 27/66] power: supply: axp20x_usb_power: replace current_max with input_current_limit The current_max property is supposed to be read-only, and represent the maximum current the supply can provide. input_current_limit is the limit that is currently set, which is what we have here. When determining what value to write to the register, we need to pick a reasonable value if the requested limit doesn't exactly match one supported by the hardware. If the requested limit is less than the lowest value we can set, round up to the lowest value. Otherwise round down to the nearest value supported by hardware. Also add a dev field to the axp20x_usb_power struct, so we can use dev_dbg and dev_err in more places. Signed-off-by: Aren Moynihan Link: https://lore.kernel.org/r/20240130203714.3020464-2-aren@peacevolution.org Signed-off-by: Sebastian Reichel --- drivers/power/supply/axp20x_usb_power.c | 29 +++++++++++++++---------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c index e23308ad4cc7..f7f2ac2b7dae 100644 --- a/drivers/power/supply/axp20x_usb_power.c +++ b/drivers/power/supply/axp20x_usb_power.c @@ -59,6 +59,7 @@ struct axp_data { }; struct axp20x_usb_power { + struct device *dev; struct regmap *regmap; struct regmap_field *curr_lim_fld; struct regmap_field *vbus_valid_bit; @@ -160,7 +161,7 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, val->intval = ret * 1700; /* 1 step = 1.7 mV */ return 0; - case POWER_SUPPLY_PROP_CURRENT_MAX: + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: ret = regmap_field_read(power->curr_lim_fld, &v); if (ret) return ret; @@ -256,19 +257,24 @@ static int axp20x_usb_power_set_voltage_min(struct axp20x_usb_power *power, return -EINVAL; } -static int axp20x_usb_power_set_current_max(struct axp20x_usb_power *power, int intval) +static int axp20x_usb_power_set_input_current_limit(struct axp20x_usb_power *power, + int intval) { + unsigned int reg; const unsigned int max = GENMASK(power->axp_data->curr_lim_fld.msb, power->axp_data->curr_lim_fld.lsb); if (intval == -1) return -EINVAL; - for (unsigned int i = 0; i <= max; ++i) - if (power->axp_data->curr_lim_table[i] == intval) - return regmap_field_write(power->curr_lim_fld, i); + for (reg = max - 1; reg > 0; reg--) + if (power->axp_data->curr_lim_table[reg] <= intval) + break; - return -EINVAL; + dev_dbg(power->dev, "setting input current limit reg to %d (%d uA), requested %d uA", + reg, power->axp_data->curr_lim_table[reg], intval); + + return regmap_field_write(power->curr_lim_fld, reg); } static int axp20x_usb_power_set_property(struct power_supply *psy, @@ -287,8 +293,8 @@ static int axp20x_usb_power_set_property(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_MIN: return axp20x_usb_power_set_voltage_min(power, val->intval); - case POWER_SUPPLY_PROP_CURRENT_MAX: - return axp20x_usb_power_set_current_max(power, val->intval); + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + return axp20x_usb_power_set_input_current_limit(power, val->intval); default: return -EINVAL; @@ -313,7 +319,7 @@ static int axp20x_usb_power_prop_writeable(struct power_supply *psy, return power->vbus_disable_bit != NULL; return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN || - psp == POWER_SUPPLY_PROP_CURRENT_MAX; + psp == POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT; } static enum power_supply_property axp20x_usb_power_properties[] = { @@ -322,7 +328,7 @@ static enum power_supply_property axp20x_usb_power_properties[] = { POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_VOLTAGE_MIN, POWER_SUPPLY_PROP_VOLTAGE_NOW, - POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, POWER_SUPPLY_PROP_CURRENT_NOW, }; @@ -331,7 +337,7 @@ static enum power_supply_property axp22x_usb_power_properties[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_VOLTAGE_MIN, - POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, }; static const struct power_supply_desc axp20x_usb_power_desc = { @@ -558,6 +564,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) platform_set_drvdata(pdev, power); + power->dev = &pdev->dev; power->axp_data = axp_data; power->regmap = axp20x->regmap; power->num_irqs = axp_data->num_irq_names; From b02fbd830edf9f2cce076d93b787827aac1e402a Mon Sep 17 00:00:00 2001 From: Aren Moynihan Date: Tue, 30 Jan 2024 15:27:58 -0500 Subject: [PATCH 28/66] power: supply: axp20x_usb_power: use correct register for input current limit On the axp803 and axp813 chips register 0x30 bits 0-1 is the default current limit that gets applied after the pmic detects a CDP or DCP port. The correct field to set is 0x35 bits 4-7. This field only has nine values (out of the 16 possible if it used all the bits), so introduce a field size variable to take that into account. Signed-off-by: Aren Moynihan Link: https://lore.kernel.org/r/20240130203714.3020464-3-aren@peacevolution.org Signed-off-by: Sebastian Reichel --- drivers/power/supply/axp20x_usb_power.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c index f7f2ac2b7dae..923121b23d5f 100644 --- a/drivers/power/supply/axp20x_usb_power.c +++ b/drivers/power/supply/axp20x_usb_power.c @@ -50,6 +50,7 @@ struct axp_data { const char * const *irq_names; unsigned int num_irq_names; const int *curr_lim_table; + int curr_lim_table_size; struct reg_field curr_lim_fld; struct reg_field vbus_valid_bit; struct reg_field vbus_mon_bit; @@ -166,7 +167,11 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, if (ret) return ret; - val->intval = power->axp_data->curr_lim_table[v]; + if (v < power->axp_data->curr_lim_table_size) + val->intval = power->axp_data->curr_lim_table[v]; + else + val->intval = power->axp_data->curr_lim_table[ + power->axp_data->curr_lim_table_size - 1]; return 0; case POWER_SUPPLY_PROP_CURRENT_NOW: if (IS_ENABLED(CONFIG_AXP20X_ADC)) { @@ -261,8 +266,7 @@ static int axp20x_usb_power_set_input_current_limit(struct axp20x_usb_power *pow int intval) { unsigned int reg; - const unsigned int max = GENMASK(power->axp_data->curr_lim_fld.msb, - power->axp_data->curr_lim_fld.lsb); + const unsigned int max = power->axp_data->curr_lim_table_size; if (intval == -1) return -EINVAL; @@ -394,10 +398,15 @@ static int axp221_usb_curr_lim_table[] = { }; static int axp813_usb_curr_lim_table[] = { + 100000, + 500000, 900000, 1500000, 2000000, 2500000, + 3000000, + 3500000, + 4000000, }; static const struct axp_data axp192_data = { @@ -405,6 +414,7 @@ static const struct axp_data axp192_data = { .irq_names = axp20x_irq_names, .num_irq_names = ARRAY_SIZE(axp20x_irq_names), .curr_lim_table = axp192_usb_curr_lim_table, + .curr_lim_table_size = ARRAY_SIZE(axp192_usb_curr_lim_table), .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1), .vbus_valid_bit = REG_FIELD(AXP192_USB_OTG_STATUS, 2, 2), .vbus_mon_bit = REG_FIELD(AXP20X_VBUS_MON, 3, 3), @@ -415,6 +425,7 @@ static const struct axp_data axp202_data = { .irq_names = axp20x_irq_names, .num_irq_names = ARRAY_SIZE(axp20x_irq_names), .curr_lim_table = axp20x_usb_curr_lim_table, + .curr_lim_table_size = ARRAY_SIZE(axp20x_usb_curr_lim_table), .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1), .vbus_valid_bit = REG_FIELD(AXP20X_USB_OTG_STATUS, 2, 2), .vbus_mon_bit = REG_FIELD(AXP20X_VBUS_MON, 3, 3), @@ -425,6 +436,7 @@ static const struct axp_data axp221_data = { .irq_names = axp22x_irq_names, .num_irq_names = ARRAY_SIZE(axp22x_irq_names), .curr_lim_table = axp221_usb_curr_lim_table, + .curr_lim_table_size = ARRAY_SIZE(axp221_usb_curr_lim_table), .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1), .vbus_needs_polling = true, }; @@ -434,6 +446,7 @@ static const struct axp_data axp223_data = { .irq_names = axp22x_irq_names, .num_irq_names = ARRAY_SIZE(axp22x_irq_names), .curr_lim_table = axp20x_usb_curr_lim_table, + .curr_lim_table_size = ARRAY_SIZE(axp20x_usb_curr_lim_table), .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1), .vbus_needs_polling = true, }; @@ -443,7 +456,8 @@ static const struct axp_data axp813_data = { .irq_names = axp22x_irq_names, .num_irq_names = ARRAY_SIZE(axp22x_irq_names), .curr_lim_table = axp813_usb_curr_lim_table, - .curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1), + .curr_lim_table_size = ARRAY_SIZE(axp813_usb_curr_lim_table), + .curr_lim_fld = REG_FIELD(AXP22X_CHRG_CTRL3, 4, 7), .usb_bc_en_bit = REG_FIELD(AXP288_BC_GLOBAL, 0, 0), .vbus_disable_bit = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 7, 7), .vbus_needs_polling = true, From 06a807e6e5ffaa35327e85b386f00c8614f6caaa Mon Sep 17 00:00:00 2001 From: Aren Moynihan Date: Tue, 30 Jan 2024 15:27:59 -0500 Subject: [PATCH 29/66] power: supply: axp20x_usb_power: fix race condition with usb bc When input_current_limit is set while USB BC is in progress, the BC module will overwrite the value that was set when it finishes detection. Signed-off-by: Aren Moynihan Link: https://lore.kernel.org/r/20240130203714.3020464-4-aren@peacevolution.org Signed-off-by: Sebastian Reichel --- drivers/power/supply/axp20x_usb_power.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c index 923121b23d5f..ac5a3f126df6 100644 --- a/drivers/power/supply/axp20x_usb_power.c +++ b/drivers/power/supply/axp20x_usb_power.c @@ -117,6 +117,15 @@ static void axp20x_usb_power_poll_vbus(struct work_struct *work) if (val != power->old_status) power_supply_changed(power->supply); + if (power->usb_bc_en_bit && (val & AXP20X_PWR_STATUS_VBUS_PRESENT) != + (power->old_status & AXP20X_PWR_STATUS_VBUS_PRESENT)) { + dev_dbg(power->dev, "Cable status changed, re-enabling USB BC"); + ret = regmap_field_write(power->usb_bc_en_bit, 1); + if (ret) + dev_err(power->dev, "failed to enable USB BC: errno %d", + ret); + } + power->old_status = val; power->online = val & AXP20X_PWR_STATUS_VBUS_USED; @@ -265,12 +274,26 @@ static int axp20x_usb_power_set_voltage_min(struct axp20x_usb_power *power, static int axp20x_usb_power_set_input_current_limit(struct axp20x_usb_power *power, int intval) { + int ret; unsigned int reg; const unsigned int max = power->axp_data->curr_lim_table_size; if (intval == -1) return -EINVAL; + /* + * BC1.2 detection can cause a race condition if we try to set a current + * limit while it's in progress. When it finishes it will overwrite the + * current limit we just set. + */ + if (power->usb_bc_en_bit) { + dev_dbg(power->dev, + "disabling BC1.2 detection because current limit was set"); + ret = regmap_field_write(power->usb_bc_en_bit, 0); + if (ret) + return ret; + } + for (reg = max - 1; reg > 0; reg--) if (power->axp_data->curr_lim_table[reg] <= intval) break; From aa08a0d10f5e67ccf82229cfd3a3fd57f1dff3bd Mon Sep 17 00:00:00 2001 From: Aren Moynihan Date: Tue, 30 Jan 2024 15:28:00 -0500 Subject: [PATCH 30/66] power: supply: axp20x_usb_power: enable usb_type reporting The axp803 and axp813 chips can report the detected USB BC mode. SDP, CDP, and DCP are supported. Signed-off-by: Aren Moynihan Link: https://lore.kernel.org/r/20240130203714.3020464-5-aren@peacevolution.org Signed-off-by: Sebastian Reichel --- drivers/power/supply/axp20x_usb_power.c | 73 ++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c index ac5a3f126df6..dae7e5cfc54e 100644 --- a/drivers/power/supply/axp20x_usb_power.c +++ b/drivers/power/supply/axp20x_usb_power.c @@ -55,6 +55,7 @@ struct axp_data { struct reg_field vbus_valid_bit; struct reg_field vbus_mon_bit; struct reg_field usb_bc_en_bit; + struct reg_field usb_bc_det_fld; struct reg_field vbus_disable_bit; bool vbus_needs_polling: 1; }; @@ -66,6 +67,7 @@ struct axp20x_usb_power { struct regmap_field *vbus_valid_bit; struct regmap_field *vbus_mon_bit; struct regmap_field *usb_bc_en_bit; + struct regmap_field *usb_bc_det_fld; struct regmap_field *vbus_disable_bit; struct power_supply *supply; const struct axp_data *axp_data; @@ -134,6 +136,37 @@ out: mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME); } +static int axp20x_get_usb_type(struct axp20x_usb_power *power, + union power_supply_propval *val) +{ + unsigned int reg; + int ret; + + if (!power->usb_bc_det_fld) + return -EINVAL; + + ret = regmap_field_read(power->usb_bc_det_fld, ®); + if (ret) + return ret; + + switch (reg) { + case 1: + val->intval = POWER_SUPPLY_USB_TYPE_SDP; + break; + case 2: + val->intval = POWER_SUPPLY_USB_TYPE_CDP; + break; + case 3: + val->intval = POWER_SUPPLY_USB_TYPE_DCP; + break; + default: + val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN; + break; + } + + return 0; +} + static int axp20x_usb_power_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { @@ -204,6 +237,9 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, val->intval = ret * 375; /* 1 step = 0.375 mA */ return 0; + + case POWER_SUPPLY_PROP_USB_TYPE: + return axp20x_get_usb_type(power, val); default: break; } @@ -367,6 +403,22 @@ static enum power_supply_property axp22x_usb_power_properties[] = { POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, }; +static enum power_supply_property axp813_usb_power_properties[] = { + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_MIN, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_USB_TYPE, +}; + +static enum power_supply_usb_type axp813_usb_types[] = { + POWER_SUPPLY_USB_TYPE_SDP, + POWER_SUPPLY_USB_TYPE_DCP, + POWER_SUPPLY_USB_TYPE_CDP, + POWER_SUPPLY_USB_TYPE_UNKNOWN, +}; + static const struct power_supply_desc axp20x_usb_power_desc = { .name = "axp20x-usb", .type = POWER_SUPPLY_TYPE_USB, @@ -387,6 +439,18 @@ static const struct power_supply_desc axp22x_usb_power_desc = { .set_property = axp20x_usb_power_set_property, }; +static const struct power_supply_desc axp813_usb_power_desc = { + .name = "axp20x-usb", + .type = POWER_SUPPLY_TYPE_USB, + .properties = axp813_usb_power_properties, + .num_properties = ARRAY_SIZE(axp813_usb_power_properties), + .property_is_writeable = axp20x_usb_power_prop_writeable, + .get_property = axp20x_usb_power_get_property, + .set_property = axp20x_usb_power_set_property, + .usb_types = axp813_usb_types, + .num_usb_types = ARRAY_SIZE(axp813_usb_types), +}; + static const char * const axp20x_irq_names[] = { "VBUS_PLUGIN", "VBUS_REMOVAL", @@ -475,13 +539,14 @@ static const struct axp_data axp223_data = { }; static const struct axp_data axp813_data = { - .power_desc = &axp22x_usb_power_desc, + .power_desc = &axp813_usb_power_desc, .irq_names = axp22x_irq_names, .num_irq_names = ARRAY_SIZE(axp22x_irq_names), .curr_lim_table = axp813_usb_curr_lim_table, .curr_lim_table_size = ARRAY_SIZE(axp813_usb_curr_lim_table), .curr_lim_fld = REG_FIELD(AXP22X_CHRG_CTRL3, 4, 7), .usb_bc_en_bit = REG_FIELD(AXP288_BC_GLOBAL, 0, 0), + .usb_bc_det_fld = REG_FIELD(AXP288_BC_DET_STAT, 5, 7), .vbus_disable_bit = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 7, 7), .vbus_needs_polling = true, }; @@ -629,6 +694,12 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) if (ret) return ret; + ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap, + axp_data->usb_bc_det_fld, + &power->usb_bc_det_fld); + if (ret) + return ret; + ret = axp20x_regmap_field_alloc_optional(&pdev->dev, power->regmap, axp_data->vbus_disable_bit, &power->vbus_disable_bit); From f22e835028902b01915f584d2912cc25a397c84e Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:13 -0600 Subject: [PATCH 31/66] power: reset: atc260x-poweroff: Use devm_register_sys_off_handler(RESTART) Use device life-cycle managed register function to simplify probe and exit paths. Signed-off-by: Andrew Davis Reviewed-by: Cristian Ciocaltea Link: https://lore.kernel.org/r/20240212162831.67838-2-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/atc260x-poweroff.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/power/reset/atc260x-poweroff.c b/drivers/power/reset/atc260x-poweroff.c index b4aa50e9685e..ce2748d3282c 100644 --- a/drivers/power/reset/atc260x-poweroff.c +++ b/drivers/power/reset/atc260x-poweroff.c @@ -16,7 +16,6 @@ struct atc260x_pwrc { struct device *dev; struct regmap *regmap; - struct notifier_block restart_nb; int (*do_poweroff)(const struct atc260x_pwrc *pwrc, bool restart); }; @@ -172,11 +171,9 @@ static void atc260x_pwrc_pm_handler(void) WARN_ONCE(1, "Unable to power off system\n"); } -static int atc260x_pwrc_restart_handler(struct notifier_block *nb, - unsigned long mode, void *cmd) +static int atc260x_pwrc_restart_handler(struct sys_off_data *data) { - struct atc260x_pwrc *pwrc = container_of(nb, struct atc260x_pwrc, - restart_nb); + struct atc260x_pwrc *pwrc = data->cb_data; pwrc->do_poweroff(pwrc, true); return NOTIFY_DONE; @@ -194,8 +191,6 @@ static int atc260x_pwrc_probe(struct platform_device *pdev) priv->dev = &pdev->dev; priv->regmap = atc260x->regmap; - priv->restart_nb.notifier_call = atc260x_pwrc_restart_handler; - priv->restart_nb.priority = 192; switch (atc260x->ic_type) { case ATC2603C: @@ -225,7 +220,11 @@ static int atc260x_pwrc_probe(struct platform_device *pdev) dev_warn(priv->dev, "Poweroff callback already assigned\n"); } - ret = register_restart_handler(&priv->restart_nb); + ret = devm_register_sys_off_handler(priv->dev, + SYS_OFF_MODE_RESTART, + SYS_OFF_PRIO_HIGH, + atc260x_pwrc_restart_handler, + priv); if (ret) dev_err(priv->dev, "failed to register restart handler: %d\n", ret); @@ -241,8 +240,6 @@ static void atc260x_pwrc_remove(struct platform_device *pdev) pm_power_off = NULL; atc260x_pwrc_data = NULL; } - - unregister_restart_handler(&priv->restart_nb); } static struct platform_driver atc260x_pwrc_driver = { From ab1439b05168dc73539e78d8b3100a0336a83bca Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:14 -0600 Subject: [PATCH 32/66] power: reset: atc260x-poweroff: Use devm_register_sys_off_handler(POWER_OFF) Use device life-cycle managed register function to simplify probe and exit paths. Signed-off-by: Andrew Davis Reviewed-by: Cristian Ciocaltea Link: https://lore.kernel.org/r/20240212162831.67838-3-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/atc260x-poweroff.c | 38 ++++++++++---------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/drivers/power/reset/atc260x-poweroff.c b/drivers/power/reset/atc260x-poweroff.c index ce2748d3282c..e3e4621ccb1d 100644 --- a/drivers/power/reset/atc260x-poweroff.c +++ b/drivers/power/reset/atc260x-poweroff.c @@ -19,9 +19,6 @@ struct atc260x_pwrc { int (*do_poweroff)(const struct atc260x_pwrc *pwrc, bool restart); }; -/* Global variable needed only for pm_power_off */ -static struct atc260x_pwrc *atc260x_pwrc_data; - static int atc2603c_do_poweroff(const struct atc260x_pwrc *pwrc, bool restart) { int ret, deep_sleep = 0; @@ -164,11 +161,15 @@ static int atc2609a_init(const struct atc260x_pwrc *pwrc) return ret; } -static void atc260x_pwrc_pm_handler(void) +static int atc260x_pwrc_pm_handler(struct sys_off_data *data) { - atc260x_pwrc_data->do_poweroff(atc260x_pwrc_data, false); + struct atc260x_pwrc *pwrc = data->cb_data; + + pwrc->do_poweroff(pwrc, false); WARN_ONCE(1, "Unable to power off system\n"); + + return NOTIFY_DONE; } static int atc260x_pwrc_restart_handler(struct sys_off_data *data) @@ -211,14 +212,14 @@ static int atc260x_pwrc_probe(struct platform_device *pdev) if (ret) return ret; - platform_set_drvdata(pdev, priv); - - if (!pm_power_off) { - atc260x_pwrc_data = priv; - pm_power_off = atc260x_pwrc_pm_handler; - } else { - dev_warn(priv->dev, "Poweroff callback already assigned\n"); - } + ret = devm_register_sys_off_handler(priv->dev, + SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_DEFAULT, + atc260x_pwrc_pm_handler, + priv); + if (ret) + dev_err(priv->dev, "failed to register power-off handler: %d\n", + ret); ret = devm_register_sys_off_handler(priv->dev, SYS_OFF_MODE_RESTART, @@ -232,19 +233,8 @@ static int atc260x_pwrc_probe(struct platform_device *pdev) return ret; } -static void atc260x_pwrc_remove(struct platform_device *pdev) -{ - struct atc260x_pwrc *priv = platform_get_drvdata(pdev); - - if (atc260x_pwrc_data == priv) { - pm_power_off = NULL; - atc260x_pwrc_data = NULL; - } -} - static struct platform_driver atc260x_pwrc_driver = { .probe = atc260x_pwrc_probe, - .remove_new = atc260x_pwrc_remove, .driver = { .name = "atc260x-pwrc", }, From 7ddfd33c6ee58ee915d09177a7dbac2c5be7b536 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:15 -0600 Subject: [PATCH 33/66] power: reset: xgene-reboot: Use devm_platform_ioremap_resource() helper Use device life-cycle managed ioremap function to simplify probe and exit paths. While here add __iomem to the returned pointer to fix a sparse warning. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240212162831.67838-4-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/xgene-reboot.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/power/reset/xgene-reboot.c b/drivers/power/reset/xgene-reboot.c index c2e5a99940d3..6b545a83d888 100644 --- a/drivers/power/reset/xgene-reboot.c +++ b/drivers/power/reset/xgene-reboot.c @@ -22,7 +22,7 @@ struct xgene_reboot_context { struct device *dev; - void *csr; + void __iomem *csr; u32 mask; struct notifier_block restart_handler; }; @@ -54,7 +54,7 @@ static int xgene_reboot_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - ctx->csr = of_iomap(dev->of_node, 0); + ctx->csr = devm_platform_ioremap_resource(pdev, 0); if (!ctx->csr) { dev_err(dev, "can not map resource\n"); return -ENODEV; @@ -67,10 +67,8 @@ static int xgene_reboot_probe(struct platform_device *pdev) ctx->restart_handler.notifier_call = xgene_restart_handler; ctx->restart_handler.priority = 128; err = register_restart_handler(&ctx->restart_handler); - if (err) { - iounmap(ctx->csr); + if (err) dev_err(dev, "cannot register restart handler (err=%d)\n", err); - } return err; } From 6af1ee028537be0a43ce939eb8f5321096208667 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:16 -0600 Subject: [PATCH 34/66] power: reset: xgene-reboot: Use devm_register_sys_off_handler(RESTART) Use device life-cycle managed register function to simplify probe. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240212162831.67838-5-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/xgene-reboot.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/power/reset/xgene-reboot.c b/drivers/power/reset/xgene-reboot.c index 6b545a83d888..867162dfe7ea 100644 --- a/drivers/power/reset/xgene-reboot.c +++ b/drivers/power/reset/xgene-reboot.c @@ -24,15 +24,11 @@ struct xgene_reboot_context { struct device *dev; void __iomem *csr; u32 mask; - struct notifier_block restart_handler; }; -static int xgene_restart_handler(struct notifier_block *this, - unsigned long mode, void *cmd) +static int xgene_restart_handler(struct sys_off_data *data) { - struct xgene_reboot_context *ctx = - container_of(this, struct xgene_reboot_context, - restart_handler); + struct xgene_reboot_context *ctx = data->cb_data; /* Issue the reboot */ writel(ctx->mask, ctx->csr); @@ -64,9 +60,8 @@ static int xgene_reboot_probe(struct platform_device *pdev) ctx->mask = 0xFFFFFFFF; ctx->dev = dev; - ctx->restart_handler.notifier_call = xgene_restart_handler; - ctx->restart_handler.priority = 128; - err = register_restart_handler(&ctx->restart_handler); + err = devm_register_sys_off_handler(dev, SYS_OFF_MODE_RESTART, 128, + xgene_restart_handler, ctx); if (err) dev_err(dev, "cannot register restart handler (err=%d)\n", err); From e68b71812ebf385317c5bcf82674c109806be452 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:17 -0600 Subject: [PATCH 35/66] power: reset: tps65086-restart: Use devm_register_sys_off_handler(RESTART) Use device life-cycle managed register function to simplify probe and exit paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240212162831.67838-6-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/tps65086-restart.c | 35 ++++++-------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/drivers/power/reset/tps65086-restart.c b/drivers/power/reset/tps65086-restart.c index ee8e9f4b837e..82d7a761a038 100644 --- a/drivers/power/reset/tps65086-restart.c +++ b/drivers/power/reset/tps65086-restart.c @@ -10,15 +10,12 @@ #include struct tps65086_restart { - struct notifier_block handler; struct device *dev; }; -static int tps65086_restart_notify(struct notifier_block *this, - unsigned long mode, void *cmd) +static int tps65086_restart_notify(struct sys_off_data *data) { - struct tps65086_restart *tps65086_restart = - container_of(this, struct tps65086_restart, handler); + struct tps65086_restart *tps65086_restart = data->cb_data; struct tps65086 *tps65086 = dev_get_drvdata(tps65086_restart->dev->parent); int ret; @@ -46,13 +43,13 @@ static int tps65086_restart_probe(struct platform_device *pdev) if (!tps65086_restart) return -ENOMEM; - platform_set_drvdata(pdev, tps65086_restart); - - tps65086_restart->handler.notifier_call = tps65086_restart_notify; - tps65086_restart->handler.priority = 192; tps65086_restart->dev = &pdev->dev; - ret = register_restart_handler(&tps65086_restart->handler); + ret = devm_register_sys_off_handler(&pdev->dev, + SYS_OFF_MODE_RESTART, + SYS_OFF_PRIO_HIGH, + tps65086_restart_notify, + tps65086_restart); if (ret) { dev_err(&pdev->dev, "%s: cannot register restart handler: %d\n", __func__, ret); @@ -62,23 +59,6 @@ static int tps65086_restart_probe(struct platform_device *pdev) return 0; } -static void tps65086_restart_remove(struct platform_device *pdev) -{ - struct tps65086_restart *tps65086_restart = platform_get_drvdata(pdev); - int ret; - - ret = unregister_restart_handler(&tps65086_restart->handler); - if (ret) { - /* - * tps65086_restart_probe() registered the restart handler. So - * unregistering should work fine. Checking the error code - * shouldn't be needed, still doing it for completeness. - */ - dev_err(&pdev->dev, "%s: cannot unregister restart handler: %d\n", - __func__, ret); - } -} - static const struct platform_device_id tps65086_restart_id_table[] = { { "tps65086-reset", }, { /* sentinel */ } @@ -90,7 +70,6 @@ static struct platform_driver tps65086_restart_driver = { .name = "tps65086-restart", }, .probe = tps65086_restart_probe, - .remove_new = tps65086_restart_remove, .id_table = tps65086_restart_id_table, }; module_platform_driver(tps65086_restart_driver); From 11d2642e14ad022de13f261370ccddd33693c045 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:18 -0600 Subject: [PATCH 36/66] power: reset: tps65086-restart: Remove unneeded device data struct We only need one member of the struct tps65086_restart, pass that tps65086_restart_notify() directly. Remove that struct and its allocation. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240212162831.67838-7-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/tps65086-restart.c | 35 ++++++-------------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/drivers/power/reset/tps65086-restart.c b/drivers/power/reset/tps65086-restart.c index 82d7a761a038..6976dbcac74f 100644 --- a/drivers/power/reset/tps65086-restart.c +++ b/drivers/power/reset/tps65086-restart.c @@ -9,19 +9,14 @@ #include #include -struct tps65086_restart { - struct device *dev; -}; - static int tps65086_restart_notify(struct sys_off_data *data) { - struct tps65086_restart *tps65086_restart = data->cb_data; - struct tps65086 *tps65086 = dev_get_drvdata(tps65086_restart->dev->parent); + struct tps65086 *tps65086 = data->cb_data; int ret; ret = regmap_write(tps65086->regmap, TPS65086_FORCESHUTDN, 1); if (ret) { - dev_err(tps65086_restart->dev, "%s: error writing to tps65086 pmic: %d\n", + dev_err(tps65086->dev, "%s: error writing to tps65086 pmic: %d\n", __func__, ret); return NOTIFY_DONE; } @@ -36,27 +31,13 @@ static int tps65086_restart_notify(struct sys_off_data *data) static int tps65086_restart_probe(struct platform_device *pdev) { - struct tps65086_restart *tps65086_restart; - int ret; + struct tps65086 *tps65086 = dev_get_drvdata(pdev->dev.parent); - tps65086_restart = devm_kzalloc(&pdev->dev, sizeof(*tps65086_restart), GFP_KERNEL); - if (!tps65086_restart) - return -ENOMEM; - - tps65086_restart->dev = &pdev->dev; - - ret = devm_register_sys_off_handler(&pdev->dev, - SYS_OFF_MODE_RESTART, - SYS_OFF_PRIO_HIGH, - tps65086_restart_notify, - tps65086_restart); - if (ret) { - dev_err(&pdev->dev, "%s: cannot register restart handler: %d\n", - __func__, ret); - return -ENODEV; - } - - return 0; + return devm_register_sys_off_handler(&pdev->dev, + SYS_OFF_MODE_RESTART, + SYS_OFF_PRIO_HIGH, + tps65086_restart_notify, + tps65086); } static const struct platform_device_id tps65086_restart_id_table[] = { From 45079f206e635a08cba395a08dd3fd7629dbb24d Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:19 -0600 Subject: [PATCH 37/66] power: reset: brcm-kona-reset: Use devm_register_sys_off_handler(RESTART) Use device life-cycle managed register function to simplify probe. Signed-off-by: Andrew Davis Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/r/20240212162831.67838-8-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/brcm-kona-reset.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/power/reset/brcm-kona-reset.c b/drivers/power/reset/brcm-kona-reset.c index d05728b1db09..ee3f1bb97653 100644 --- a/drivers/power/reset/brcm-kona-reset.c +++ b/drivers/power/reset/brcm-kona-reset.c @@ -15,8 +15,7 @@ static void __iomem *kona_reset_base; -static int kona_reset_handler(struct notifier_block *this, - unsigned long mode, void *cmd) +static int kona_reset_handler(struct sys_off_data *data) { /* * A soft reset is triggered by writing a 0 to bit 0 of the soft reset @@ -31,18 +30,14 @@ static int kona_reset_handler(struct notifier_block *this, return NOTIFY_DONE; } -static struct notifier_block kona_reset_nb = { - .notifier_call = kona_reset_handler, - .priority = 128, -}; - static int kona_reset_probe(struct platform_device *pdev) { kona_reset_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(kona_reset_base)) return PTR_ERR(kona_reset_base); - return register_restart_handler(&kona_reset_nb); + return devm_register_sys_off_handler(&pdev->dev, SYS_OFF_MODE_RESTART, + 128, kona_reset_handler, NULL); } static const struct of_device_id of_match[] = { From ad8d7b8002a1d3a673f2d6f110b378d137f61037 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:20 -0600 Subject: [PATCH 38/66] power: reset: axxia-reset: Use devm_register_sys_off_handler(RESTART) Use device life-cycle managed register function to simplify probe. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240212162831.67838-9-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/axxia-reset.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/power/reset/axxia-reset.c b/drivers/power/reset/axxia-reset.c index 24946766760c..797bf6773860 100644 --- a/drivers/power/reset/axxia-reset.c +++ b/drivers/power/reset/axxia-reset.c @@ -26,11 +26,10 @@ #define SC_EFUSE_INT_STATUS 0x180c #define EFUSE_READ_DONE (1<<31) -static struct regmap *syscon; - -static int axxia_restart_handler(struct notifier_block *this, - unsigned long mode, void *cmd) +static int axxia_restart_handler(struct sys_off_data *data) { + struct regmap *syscon = data->cb_data; + /* Access Key (0xab) */ regmap_write(syscon, SC_CRIT_WRITE_KEY, 0xab); /* Select internal boot from 0xffff0000 */ @@ -44,14 +43,10 @@ static int axxia_restart_handler(struct notifier_block *this, return NOTIFY_DONE; } -static struct notifier_block axxia_restart_nb = { - .notifier_call = axxia_restart_handler, - .priority = 128, -}; - static int axxia_reset_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct regmap *syscon; int err; syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); @@ -60,7 +55,8 @@ static int axxia_reset_probe(struct platform_device *pdev) return PTR_ERR(syscon); } - err = register_restart_handler(&axxia_restart_nb); + err = devm_register_sys_off_handler(&pdev->dev, SYS_OFF_MODE_RESTART, + 128, axxia_restart_handler, syscon); if (err) dev_err(dev, "cannot register restart handler (err=%d)\n", err); From 0867276eb12230a5e94ec2b28eba718e76b77eb1 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:21 -0600 Subject: [PATCH 39/66] power: reset: rmobile-reset: Use devm_platform_ioremap_resource() helper Use device life-cycle managed ioremap function to simplify probe and exit paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240212162831.67838-10-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/rmobile-reset.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/power/reset/rmobile-reset.c b/drivers/power/reset/rmobile-reset.c index 5df9b41c68c7..29c17ed2d4de 100644 --- a/drivers/power/reset/rmobile-reset.c +++ b/drivers/power/reset/rmobile-reset.c @@ -41,28 +41,23 @@ static int rmobile_reset_probe(struct platform_device *pdev) { int error; - sysc_base2 = of_iomap(pdev->dev.of_node, 1); - if (!sysc_base2) - return -ENODEV; + sysc_base2 = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(sysc_base2)) + return PTR_ERR(sysc_base2); error = register_restart_handler(&rmobile_reset_nb); if (error) { dev_err(&pdev->dev, "cannot register restart handler (err=%d)\n", error); - goto fail_unmap; + return error; } return 0; - -fail_unmap: - iounmap(sysc_base2); - return error; } static void rmobile_reset_remove(struct platform_device *pdev) { unregister_restart_handler(&rmobile_reset_nb); - iounmap(sysc_base2); } static const struct of_device_id rmobile_reset_of_match[] = { From ba1188ea8be80a7bc091073792d404ab54b187b1 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:22 -0600 Subject: [PATCH 40/66] power: reset: rmobile-reset: Use devm_register_sys_off_handler(RESTART) Use device life-cycle managed register function to simplify probe and exit paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240212162831.67838-11-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/rmobile-reset.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/power/reset/rmobile-reset.c b/drivers/power/reset/rmobile-reset.c index 29c17ed2d4de..80265608c18e 100644 --- a/drivers/power/reset/rmobile-reset.c +++ b/drivers/power/reset/rmobile-reset.c @@ -21,22 +21,14 @@ static void __iomem *sysc_base2; -static int rmobile_reset_handler(struct notifier_block *this, - unsigned long mode, void *cmd) +static int rmobile_reset_handler(struct sys_off_data *data) { - pr_debug("%s %lu\n", __func__, mode); - /* Let's assume we have acquired the HPB semaphore */ writel(RESCNT2_PRES, sysc_base2 + RESCNT2); return NOTIFY_DONE; } -static struct notifier_block rmobile_reset_nb = { - .notifier_call = rmobile_reset_handler, - .priority = 192, -}; - static int rmobile_reset_probe(struct platform_device *pdev) { int error; @@ -45,7 +37,11 @@ static int rmobile_reset_probe(struct platform_device *pdev) if (IS_ERR(sysc_base2)) return PTR_ERR(sysc_base2); - error = register_restart_handler(&rmobile_reset_nb); + error = devm_register_sys_off_handler(&pdev->dev, + SYS_OFF_MODE_RESTART, + SYS_OFF_PRIO_HIGH, + rmobile_reset_handler, + NULL); if (error) { dev_err(&pdev->dev, "cannot register restart handler (err=%d)\n", error); @@ -55,11 +51,6 @@ static int rmobile_reset_probe(struct platform_device *pdev) return 0; } -static void rmobile_reset_remove(struct platform_device *pdev) -{ - unregister_restart_handler(&rmobile_reset_nb); -} - static const struct of_device_id rmobile_reset_of_match[] = { { .compatible = "renesas,sysc-rmobile", }, { /* sentinel */ } @@ -68,7 +59,6 @@ MODULE_DEVICE_TABLE(of, rmobile_reset_of_match); static struct platform_driver rmobile_reset_driver = { .probe = rmobile_reset_probe, - .remove_new = rmobile_reset_remove, .driver = { .name = "rmobile_reset", .of_match_table = rmobile_reset_of_match, From 6ab9137719a719f39e000aa62887ae25e1194815 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:23 -0600 Subject: [PATCH 41/66] power: reset: mt6323-poweroff: Use devm_register_sys_off_handler(POWER_OFF) Use device life-cycle managed register function to simplify probe and exit paths. Signed-off-by: Andrew Davis Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20240212162831.67838-12-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/mt6323-poweroff.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/power/reset/mt6323-poweroff.c b/drivers/power/reset/mt6323-poweroff.c index 57a63c0ab7fb..c663347547f9 100644 --- a/drivers/power/reset/mt6323-poweroff.c +++ b/drivers/power/reset/mt6323-poweroff.c @@ -14,6 +14,7 @@ #include #include #include +#include struct mt6323_pwrc { struct device *dev; @@ -21,11 +22,9 @@ struct mt6323_pwrc { u32 base; }; -static struct mt6323_pwrc *mt_pwrc; - -static void mt6323_do_pwroff(void) +static int mt6323_do_pwroff(struct sys_off_data *data) { - struct mt6323_pwrc *pwrc = mt_pwrc; + struct mt6323_pwrc *pwrc = data->cb_data; unsigned int val; int ret; @@ -44,6 +43,8 @@ static void mt6323_do_pwroff(void) mdelay(1000); WARN_ONCE(1, "Unable to power off system\n"); + + return NOTIFY_DONE; } static int mt6323_pwrc_probe(struct platform_device *pdev) @@ -51,6 +52,7 @@ static int mt6323_pwrc_probe(struct platform_device *pdev) struct mt6397_chip *mt6397_chip = dev_get_drvdata(pdev->dev.parent); struct mt6323_pwrc *pwrc; struct resource *res; + int ret; pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL); if (!pwrc) @@ -63,19 +65,18 @@ static int mt6323_pwrc_probe(struct platform_device *pdev) pwrc->base = res->start; pwrc->regmap = mt6397_chip->regmap; pwrc->dev = &pdev->dev; - mt_pwrc = pwrc; - pm_power_off = &mt6323_do_pwroff; + ret = devm_register_sys_off_handler(pwrc->dev, + SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_DEFAULT, + mt6323_do_pwroff, + pwrc); + if (ret) + return dev_err_probe(pwrc->dev, ret, "failed to register power-off handler\n"); return 0; } -static void mt6323_pwrc_remove(struct platform_device *pdev) -{ - if (pm_power_off == &mt6323_do_pwroff) - pm_power_off = NULL; -} - static const struct of_device_id mt6323_pwrc_dt_match[] = { { .compatible = "mediatek,mt6323-pwrc" }, {}, @@ -84,7 +85,6 @@ MODULE_DEVICE_TABLE(of, mt6323_pwrc_dt_match); static struct platform_driver mt6323_pwrc_driver = { .probe = mt6323_pwrc_probe, - .remove_new = mt6323_pwrc_remove, .driver = { .name = "mt6323-pwrc", .of_match_table = mt6323_pwrc_dt_match, From b5711ff9171325261a7d6406b3c2b3c7752b6b8a Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:24 -0600 Subject: [PATCH 42/66] power: reset: msm-poweroff: Use devm_register_sys_off_handler(POWER_OFF) Use this helper to register sys_off handler. Drivers should move away from setting pm_power_off directly as it only allows for one handler. The new way allows for trying multiple if the first one doesn't work. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240212162831.67838-13-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/msm-poweroff.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index d96d248a6e25..3bf0ea06c485 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -28,9 +28,11 @@ static struct notifier_block restart_nb = { .priority = 128, }; -static void do_msm_poweroff(void) +static int do_msm_poweroff(struct sys_off_data *data) { deassert_pshold(&restart_nb, 0, NULL); + + return NOTIFY_DONE; } static int msm_restart_probe(struct platform_device *pdev) @@ -41,7 +43,9 @@ static int msm_restart_probe(struct platform_device *pdev) register_restart_handler(&restart_nb); - pm_power_off = do_msm_poweroff; + devm_register_sys_off_handler(&pdev->dev, SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_DEFAULT, do_msm_poweroff, + NULL); return 0; } From 00ae86ebf893e0c89a7af6bfd270259e3ded93d1 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:25 -0600 Subject: [PATCH 43/66] power: reset: msm-poweroff: Use devm_register_sys_off_handler(RESTART) Use device life-cycle managed register function to simplify probe. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240212162831.67838-14-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/msm-poweroff.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index 3bf0ea06c485..c7eb6dc8e90a 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -14,23 +14,11 @@ #include static void __iomem *msm_ps_hold; -static int deassert_pshold(struct notifier_block *nb, unsigned long action, - void *data) -{ - writel(0, msm_ps_hold); - mdelay(10000); - - return NOTIFY_DONE; -} - -static struct notifier_block restart_nb = { - .notifier_call = deassert_pshold, - .priority = 128, -}; static int do_msm_poweroff(struct sys_off_data *data) { - deassert_pshold(&restart_nb, 0, NULL); + writel(0, msm_ps_hold); + mdelay(10000); return NOTIFY_DONE; } @@ -41,7 +29,8 @@ static int msm_restart_probe(struct platform_device *pdev) if (IS_ERR(msm_ps_hold)) return PTR_ERR(msm_ps_hold); - register_restart_handler(&restart_nb); + devm_register_sys_off_handler(&pdev->dev, SYS_OFF_MODE_RESTART, + 128, do_msm_poweroff, NULL); devm_register_sys_off_handler(&pdev->dev, SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_DEFAULT, do_msm_poweroff, From 77b61173c2d0ff42e5d609dc1fad137f1229f03b Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:26 -0600 Subject: [PATCH 44/66] power: reset: regulator-poweroff: Use devm_register_sys_off_handler(POWER_OFF) Use device life-cycle managed register function to simplify probe and exit paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240212162831.67838-15-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/regulator-poweroff.c | 36 +++++++++--------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/drivers/power/reset/regulator-poweroff.c b/drivers/power/reset/regulator-poweroff.c index 15160809c423..fed4978e3858 100644 --- a/drivers/power/reset/regulator-poweroff.c +++ b/drivers/power/reset/regulator-poweroff.c @@ -13,18 +13,15 @@ #include #include #include +#include #include #define TIMEOUT_MS 3000 -/* - * Hold configuration here, cannot be more than one instance of the driver - * since pm_power_off itself is global. - */ -static struct regulator *cpu_regulator; - -static void regulator_poweroff_do_poweroff(void) +static int regulator_poweroff_do_poweroff(struct sys_off_data *data) { + struct regulator *cpu_regulator = data->cb_data; + if (cpu_regulator && regulator_is_enabled(cpu_regulator)) regulator_force_disable(cpu_regulator); @@ -32,30 +29,24 @@ static void regulator_poweroff_do_poweroff(void) mdelay(TIMEOUT_MS); WARN_ON(1); + + return NOTIFY_DONE; } static int regulator_poweroff_probe(struct platform_device *pdev) { - /* If a pm_power_off function has already been added, leave it alone */ - if (pm_power_off != NULL) { - dev_err(&pdev->dev, - "%s: pm_power_off function already registered\n", - __func__); - return -EBUSY; - } + struct regulator *cpu_regulator; cpu_regulator = devm_regulator_get(&pdev->dev, "cpu"); if (IS_ERR(cpu_regulator)) return PTR_ERR(cpu_regulator); - pm_power_off = ®ulator_poweroff_do_poweroff; - return 0; -} - -static void regulator_poweroff_remove(struct platform_device *pdev) -{ - if (pm_power_off == ®ulator_poweroff_do_poweroff) - pm_power_off = NULL; + /* Set this handler to low priority to not override an existing handler */ + return devm_register_sys_off_handler(&pdev->dev, + SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_LOW, + regulator_poweroff_do_poweroff, + cpu_regulator); } static const struct of_device_id of_regulator_poweroff_match[] = { @@ -66,7 +57,6 @@ MODULE_DEVICE_TABLE(of, of_regulator_poweroff_match); static struct platform_driver regulator_poweroff_driver = { .probe = regulator_poweroff_probe, - .remove_new = regulator_poweroff_remove, .driver = { .name = "poweroff-regulator", .of_match_table = of_regulator_poweroff_match, From 348fde771ce7f5219a73750bd7a0d4c4497b1223 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:27 -0600 Subject: [PATCH 45/66] power: reset: as3722-poweroff: Use devm_register_sys_off_handler(POWER_OFF) Use device life-cycle managed register function to simplify probe and exit paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240212162831.67838-16-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/as3722-poweroff.c | 30 ++++++++++----------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/drivers/power/reset/as3722-poweroff.c b/drivers/power/reset/as3722-poweroff.c index ab3350ce2d62..bb26fa6fa67c 100644 --- a/drivers/power/reset/as3722-poweroff.c +++ b/drivers/power/reset/as3722-poweroff.c @@ -11,6 +11,7 @@ #include #include #include +#include #include struct as3722_poweroff { @@ -18,22 +19,18 @@ struct as3722_poweroff { struct as3722 *as3722; }; -static struct as3722_poweroff *as3722_pm_poweroff; - -static void as3722_pm_power_off(void) +static int as3722_pm_power_off(struct sys_off_data *data) { + struct as3722_poweroff *as3722_pm_poweroff = data->cb_data; int ret; - if (!as3722_pm_poweroff) { - pr_err("AS3722 poweroff is not initialised\n"); - return; - } - ret = as3722_update_bits(as3722_pm_poweroff->as3722, AS3722_RESET_CONTROL_REG, AS3722_POWER_OFF, AS3722_POWER_OFF); if (ret < 0) dev_err(as3722_pm_poweroff->dev, "RESET_CONTROL_REG update failed, %d\n", ret); + + return NOTIFY_DONE; } static int as3722_poweroff_probe(struct platform_device *pdev) @@ -54,26 +51,21 @@ static int as3722_poweroff_probe(struct platform_device *pdev) as3722_poweroff->as3722 = dev_get_drvdata(pdev->dev.parent); as3722_poweroff->dev = &pdev->dev; - as3722_pm_poweroff = as3722_poweroff; - if (!pm_power_off) - pm_power_off = as3722_pm_power_off; + + return devm_register_sys_off_handler(as3722_poweroff->dev, + SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_DEFAULT, + as3722_pm_power_off, + as3722_poweroff); return 0; } -static void as3722_poweroff_remove(struct platform_device *pdev) -{ - if (pm_power_off == as3722_pm_power_off) - pm_power_off = NULL; - as3722_pm_poweroff = NULL; -} - static struct platform_driver as3722_poweroff_driver = { .driver = { .name = "as3722-power-off", }, .probe = as3722_poweroff_probe, - .remove_new = as3722_poweroff_remove, }; module_platform_driver(as3722_poweroff_driver); From b6475c3f81c13d6d69113f69a668c96af3a5af51 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:28 -0600 Subject: [PATCH 46/66] power: reset: gemini-poweroff: Use devm_register_sys_off_handler(POWER_OFF) Use device life-cycle managed register function to simplify probe. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240212162831.67838-17-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/gemini-poweroff.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/power/reset/gemini-poweroff.c b/drivers/power/reset/gemini-poweroff.c index d309b610142c..06d6992dec89 100644 --- a/drivers/power/reset/gemini-poweroff.c +++ b/drivers/power/reset/gemini-poweroff.c @@ -70,12 +70,9 @@ static irqreturn_t gemini_powerbutton_interrupt(int irq, void *data) return IRQ_HANDLED; } -/* This callback needs this static local as it has void as argument */ -static struct gemini_powercon *gpw_poweroff; - -static void gemini_poweroff(void) +static int gemini_poweroff(struct sys_off_data *data) { - struct gemini_powercon *gpw = gpw_poweroff; + struct gemini_powercon *gpw = data->cb_data; u32 val; dev_crit(gpw->dev, "Gemini power off\n"); @@ -86,6 +83,8 @@ static void gemini_poweroff(void) val &= ~GEMINI_CTRL_ENABLE; val |= GEMINI_CTRL_SHUTDOWN; writel(val, gpw->base + GEMINI_PWC_CTRLREG); + + return NOTIFY_DONE; } static int gemini_poweroff_probe(struct platform_device *pdev) @@ -148,8 +147,11 @@ static int gemini_poweroff_probe(struct platform_device *pdev) if (ret) return ret; - pm_power_off = gemini_poweroff; - gpw_poweroff = gpw; + ret = devm_register_sys_off_handler(dev, SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_DEFAULT, + gemini_poweroff, gpw); + if (ret) + return ret; dev_info(dev, "Gemini poweroff driver registered\n"); From c3ede0b6f7dd345d8986cb69b861cadb9976782f Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:29 -0600 Subject: [PATCH 47/66] power: reset: restart-poweroff: Use devm_register_sys_off_handler(POWER_OFF) Use device life-cycle managed register function to simplify probe and exit paths. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240212162831.67838-18-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/restart-poweroff.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/drivers/power/reset/restart-poweroff.c b/drivers/power/reset/restart-poweroff.c index f4d6004793d3..fcd588f9ae9d 100644 --- a/drivers/power/reset/restart-poweroff.c +++ b/drivers/power/reset/restart-poweroff.c @@ -14,29 +14,21 @@ #include #include -static void restart_poweroff_do_poweroff(void) +static int restart_poweroff_do_poweroff(struct sys_off_data *data) { reboot_mode = REBOOT_HARD; machine_restart(NULL); + return NOTIFY_DONE; } static int restart_poweroff_probe(struct platform_device *pdev) { - /* If a pm_power_off function has already been added, leave it alone */ - if (pm_power_off != NULL) { - dev_err(&pdev->dev, - "pm_power_off function already registered"); - return -EBUSY; - } - - pm_power_off = &restart_poweroff_do_poweroff; - return 0; -} - -static void restart_poweroff_remove(struct platform_device *pdev) -{ - if (pm_power_off == &restart_poweroff_do_poweroff) - pm_power_off = NULL; + /* Set this handler to low priority to not override an existing handler */ + return devm_register_sys_off_handler(&pdev->dev, + SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_LOW, + restart_poweroff_do_poweroff, + NULL); } static const struct of_device_id of_restart_poweroff_match[] = { @@ -47,7 +39,6 @@ MODULE_DEVICE_TABLE(of, of_restart_poweroff_match); static struct platform_driver restart_poweroff_driver = { .probe = restart_poweroff_probe, - .remove_new = restart_poweroff_remove, .driver = { .name = "poweroff-restart", .of_match_table = of_restart_poweroff_match, From ffa212831289f15a92fe295a371157290619bb8f Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:30 -0600 Subject: [PATCH 48/66] power: reset: syscon-poweroff: Move device data into a struct Currently all these device data elements are top level global variables. Move these into a struct. This will be used in the next patch when the global variable usage is removed. Doing this in two steps makes the patches easier to read. Signed-off-by: Andrew Davis Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20240212162831.67838-19-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/syscon-poweroff.c | 40 ++++++++++++++++----------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/drivers/power/reset/syscon-poweroff.c b/drivers/power/reset/syscon-poweroff.c index 1b2ce7734260..19c8da997b4c 100644 --- a/drivers/power/reset/syscon-poweroff.c +++ b/drivers/power/reset/syscon-poweroff.c @@ -15,15 +15,19 @@ #include #include -static struct regmap *map; -static u32 offset; -static u32 value; -static u32 mask; +struct syscon_poweroff_data { + struct regmap *map; + u32 offset; + u32 value; + u32 mask; +}; + +static struct syscon_poweroff_data *data; static void syscon_poweroff(void) { /* Issue the poweroff */ - regmap_update_bits(map, offset, mask, value); + regmap_update_bits(data->map, data->offset, data->mask, data->value); mdelay(1000); @@ -35,22 +39,26 @@ static int syscon_poweroff_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int mask_err, value_err; - map = syscon_regmap_lookup_by_phandle(dev->of_node, "regmap"); - if (IS_ERR(map)) { - map = syscon_node_to_regmap(dev->parent->of_node); - if (IS_ERR(map)) { + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->map = syscon_regmap_lookup_by_phandle(dev->of_node, "regmap"); + if (IS_ERR(data->map)) { + data->map = syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(data->map)) { dev_err(dev, "unable to get syscon"); - return PTR_ERR(map); + return PTR_ERR(data->map); } } - if (of_property_read_u32(dev->of_node, "offset", &offset)) { + if (of_property_read_u32(dev->of_node, "offset", &data->offset)) { dev_err(dev, "unable to read 'offset'"); return -EINVAL; } - value_err = of_property_read_u32(dev->of_node, "value", &value); - mask_err = of_property_read_u32(dev->of_node, "mask", &mask); + value_err = of_property_read_u32(dev->of_node, "value", &data->value); + mask_err = of_property_read_u32(dev->of_node, "mask", &data->mask); if (value_err && mask_err) { dev_err(dev, "unable to read 'value' and 'mask'"); return -EINVAL; @@ -58,11 +66,11 @@ static int syscon_poweroff_probe(struct platform_device *pdev) if (value_err) { /* support old binding */ - value = mask; - mask = 0xFFFFFFFF; + data->value = data->mask; + data->mask = 0xFFFFFFFF; } else if (mask_err) { /* support value without mask*/ - mask = 0xFFFFFFFF; + data->mask = 0xFFFFFFFF; } if (pm_power_off) { From 14c5678720bdee7c5b582839a8dbcffd0c50de5c Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Mon, 12 Feb 2024 10:28:31 -0600 Subject: [PATCH 49/66] power: reset: syscon-poweroff: Use devm_register_sys_off_handler(POWER_OFF) Use device life-cycle managed register function to simplify probe and exit paths. This also makes our data struct per-device and not global, which allows for more than one instance of this device. Signed-off-by: Andrew Davis Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20240212162831.67838-20-afd@ti.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/syscon-poweroff.c | 30 ++++++++++----------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/drivers/power/reset/syscon-poweroff.c b/drivers/power/reset/syscon-poweroff.c index 19c8da997b4c..203936f4c544 100644 --- a/drivers/power/reset/syscon-poweroff.c +++ b/drivers/power/reset/syscon-poweroff.c @@ -13,6 +13,7 @@ #include #include #include +#include #include struct syscon_poweroff_data { @@ -22,21 +23,24 @@ struct syscon_poweroff_data { u32 mask; }; -static struct syscon_poweroff_data *data; - -static void syscon_poweroff(void) +static int syscon_poweroff(struct sys_off_data *off_data) { + struct syscon_poweroff_data *data = off_data->cb_data; + /* Issue the poweroff */ regmap_update_bits(data->map, data->offset, data->mask, data->value); mdelay(1000); pr_emerg("Unable to poweroff system\n"); + + return NOTIFY_DONE; } static int syscon_poweroff_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct syscon_poweroff_data *data; int mask_err, value_err; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); @@ -73,21 +77,10 @@ static int syscon_poweroff_probe(struct platform_device *pdev) data->mask = 0xFFFFFFFF; } - if (pm_power_off) { - dev_err(dev, "pm_power_off already claimed for %ps", - pm_power_off); - return -EBUSY; - } - - pm_power_off = syscon_poweroff; - - return 0; -} - -static void syscon_poweroff_remove(struct platform_device *pdev) -{ - if (pm_power_off == syscon_poweroff) - pm_power_off = NULL; + return devm_register_sys_off_handler(&pdev->dev, + SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_DEFAULT, + syscon_poweroff, data); } static const struct of_device_id syscon_poweroff_of_match[] = { @@ -97,7 +90,6 @@ static const struct of_device_id syscon_poweroff_of_match[] = { static struct platform_driver syscon_poweroff_driver = { .probe = syscon_poweroff_probe, - .remove_new = syscon_poweroff_remove, .driver = { .name = "syscon-poweroff", .of_match_table = syscon_poweroff_of_match, From a9b254892ce1a447b06c5019cbf0e9caeb48c138 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 12 Feb 2024 10:00:14 +0100 Subject: [PATCH 50/66] power: supply: axp288_fuel_gauge: Add STCK1A* Intel Compute Sticks to the deny-list Besides the existing STK1A* Cherry Trail based Intel Compute Sticks already on the deny-list, Intel also made Bay Trail based Compute Sticks which have a product name of STCK1A* and wich also report a non existing battery with a random battery charge. Instead of adding 3 new deny-list entries for the 3 variants of the STCK1A* sticks consolidate the 2 Cherry Trail STK1AW32SC and STK1A32SC variants into a single entry with a partial match for STK1A* and add a single new STCK1A* match for the Bay Trail variants. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20240212090014.13719-1-hdegoede@redhat.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/axp288_fuel_gauge.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c index 3be6f3b10ea4..967a26096485 100644 --- a/drivers/power/supply/axp288_fuel_gauge.c +++ b/drivers/power/supply/axp288_fuel_gauge.c @@ -550,18 +550,20 @@ static const struct dmi_system_id axp288_quirks[] = { .driver_data = (void *)AXP288_QUIRK_NO_BATTERY, }, { - /* Intel Cherry Trail Compute Stick, Windows version */ + /* Intel Bay Trail Compute Stick */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Intel"), - DMI_MATCH(DMI_PRODUCT_NAME, "STK1AW32SC"), + /* Partial match for STCK1A32WFC STCK1A32FC, STCK1A8LFC variants */ + DMI_MATCH(DMI_PRODUCT_NAME, "STCK1A"), }, .driver_data = (void *)AXP288_QUIRK_NO_BATTERY, }, { - /* Intel Cherry Trail Compute Stick, version without an OS */ + /* Intel Cherry Trail Compute Stick */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Intel"), - DMI_MATCH(DMI_PRODUCT_NAME, "STK1A32SC"), + /* Partial match for STK1AW32SC and STK1A32SC variants */ + DMI_MATCH(DMI_PRODUCT_NAME, "STK1A"), }, .driver_data = (void *)AXP288_QUIRK_NO_BATTERY, }, From 62f4b33bf2b966035420c3e211bfa37f697c4d1f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 20 Feb 2024 12:02:22 +0300 Subject: [PATCH 51/66] power: reset: xgene-reboot: Fix a NULL vs IS_ERR() test The devm_platform_ioremap_resource() function returns error points. It never returns NULL. Update the check accordingly. Fixes: 7ddfd33c6ee5 ("power: reset: xgene-reboot: Use devm_platform_ioremap_resource() helper") Signed-off-by: Dan Carpenter Acked-by: Andrew Davis Link: https://lore.kernel.org/r/fe1b90d0-7234-4e03-accc-69a119f6a7eb@moroto.mountain Signed-off-by: Sebastian Reichel --- drivers/power/reset/xgene-reboot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/reset/xgene-reboot.c b/drivers/power/reset/xgene-reboot.c index 867162dfe7ea..b5eee19bac42 100644 --- a/drivers/power/reset/xgene-reboot.c +++ b/drivers/power/reset/xgene-reboot.c @@ -51,9 +51,9 @@ static int xgene_reboot_probe(struct platform_device *pdev) return -ENOMEM; ctx->csr = devm_platform_ioremap_resource(pdev, 0); - if (!ctx->csr) { + if (IS_ERR(ctx->csr)) { dev_err(dev, "can not map resource\n"); - return -ENODEV; + return PTR_ERR(ctx->csr); } if (of_property_read_u32(dev->of_node, "mask", &ctx->mask)) From 6f005ab7f5814bcbb58154167c282f03fc35db6a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 20 Feb 2024 20:55:53 +0100 Subject: [PATCH 52/66] power: reset: rmobile-reset: Map correct MMIO resource The registers related to reset generation are located in the second register block. However, the conversion to device life-cycle managed ioremap function accidentally changed the mapping to the first register block. Fixes: 0867276eb12230a5 ("power: reset: rmobile-reset: Use devm_platform_ioremap_resource() helper") Signed-off-by: Geert Uytterhoeven Acked-by: Andrew Davis Link: https://lore.kernel.org/r/3b267fb1b303f63248934a1a77bee319e1c44879.1708458882.git.geert+renesas@glider.be Signed-off-by: Sebastian Reichel --- drivers/power/reset/rmobile-reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/reset/rmobile-reset.c b/drivers/power/reset/rmobile-reset.c index 80265608c18e..14682cd59e61 100644 --- a/drivers/power/reset/rmobile-reset.c +++ b/drivers/power/reset/rmobile-reset.c @@ -33,7 +33,7 @@ static int rmobile_reset_probe(struct platform_device *pdev) { int error; - sysc_base2 = devm_platform_ioremap_resource(pdev, 0); + sysc_base2 = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(sysc_base2)) return PTR_ERR(sysc_base2); From 9e6047c01159697cfd2f9b7788af9fe90fc7f544 Mon Sep 17 00:00:00 2001 From: Guoyi Zhang Date: Wed, 21 Feb 2024 16:34:25 +0800 Subject: [PATCH 53/66] power: supply: axp288_fuel_gauge: Deny ROCK Pi X The ROCK Pi X is a single board computer without batteries using the AXP288 PMIC where the EFI code does not disable the charger part of the PMIC causing us to report a discharging battery with a continuously consumed battery charge to userspace. Add it to the deny-list to avoid the bogus battery status reporting. Signed-off-by: Guoyi Zhang Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20240221083425.440108-1-kuoi@bioarchlinux.org Signed-off-by: Sebastian Reichel --- drivers/power/supply/axp288_fuel_gauge.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c index 967a26096485..95d9a35243c2 100644 --- a/drivers/power/supply/axp288_fuel_gauge.c +++ b/drivers/power/supply/axp288_fuel_gauge.c @@ -601,6 +601,14 @@ static const struct dmi_system_id axp288_quirks[] = { }, .driver_data = NULL, }, + { + /* Radxa ROCK Pi X Single Board Computer */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "ROCK Pi X"), + DMI_MATCH(DMI_BOARD_VENDOR, "Radxa"), + }, + .driver_data = (void *)AXP288_QUIRK_NO_BATTERY, + }, { /* * Various Ace PC/Meegopad/MinisForum/Wintel Mini-PCs/HDMI-sticks From 7b46b60944d77e361a727cd8ce46aec31c146e26 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 24 Feb 2024 17:15:41 -0300 Subject: [PATCH 54/66] power: supply: core: constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the power_supply_dev_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. In order to accomplish that, export power_supply_attr_group in power_supply.h and use it with the macro __ATTRIBUTE_GROUPS when defining power_supply_dev_type in power_supply_core.c. Therefore the attribute group is no longer static. Lastly, because power_supply_attr_groups is no longer dynamically associated to power_supply_dev_type in power_supply_init_attrs(), make the function receive zero arguments. Cc: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240224-device_cleanup-power-v2-1-465ff94b896c@marliere.net Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply.h | 4 +++- drivers/power/supply/power_supply_core.c | 8 ++++++-- drivers/power/supply/power_supply_sysfs.c | 11 ++--------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/power_supply.h index 645eee4d6b6a..232fdd8c1212 100644 --- a/drivers/power/supply/power_supply.h +++ b/drivers/power/supply/power_supply.h @@ -13,9 +13,11 @@ struct device; struct device_type; struct power_supply; +extern const struct attribute_group power_supply_attr_group; + #ifdef CONFIG_SYSFS -extern void power_supply_init_attrs(struct device_type *dev_type); +extern void power_supply_init_attrs(void); extern int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env); #else diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index ecef35ac3b7e..37dac7669090 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -31,7 +31,11 @@ EXPORT_SYMBOL_GPL(power_supply_class); static BLOCKING_NOTIFIER_HEAD(power_supply_notifier); -static struct device_type power_supply_dev_type; +__ATTRIBUTE_GROUPS(power_supply_attr); +static const struct device_type power_supply_dev_type = { + .name = "power_supply", + .groups = power_supply_attr_groups, +}; #define POWER_SUPPLY_DEFERRED_REGISTER_TIME msecs_to_jiffies(10) @@ -1623,7 +1627,7 @@ static int __init power_supply_class_init(void) return PTR_ERR(power_supply_class); power_supply_class->dev_uevent = power_supply_uevent; - power_supply_init_attrs(&power_supply_dev_type); + power_supply_init_attrs(); return 0; } diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 977611e16373..edb240450e38 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -389,22 +389,15 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj, return 0; } -static const struct attribute_group power_supply_attr_group = { +const struct attribute_group power_supply_attr_group = { .attrs = __power_supply_attrs, .is_visible = power_supply_attr_is_visible, }; -static const struct attribute_group *power_supply_attr_groups[] = { - &power_supply_attr_group, - NULL, -}; - -void power_supply_init_attrs(struct device_type *dev_type) +void power_supply_init_attrs(void) { int i; - dev_type->groups = power_supply_attr_groups; - for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++) { struct device_attribute *attr; From 3da8d71754d3c1aa0b72d74c8a324a4bc7fab473 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 26 Feb 2024 11:54:52 +0100 Subject: [PATCH 55/66] power: reset: rmobile-reset: Make sysc_base2 local The static global variable sysc_base2 is no longer used outside the probe method and the reset handler, so it can be converted to a local variable, and passed to the reset handler via its callback data. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/35f04935c48ae55dc562071e0a1d6fca65234a58.1708944642.git.geert+renesas@glider.be Signed-off-by: Sebastian Reichel --- drivers/power/reset/rmobile-reset.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/power/reset/rmobile-reset.c b/drivers/power/reset/rmobile-reset.c index 14682cd59e61..7dbc51c32b0e 100644 --- a/drivers/power/reset/rmobile-reset.c +++ b/drivers/power/reset/rmobile-reset.c @@ -19,10 +19,10 @@ /* Reset Control Register 2 */ #define RESCNT2_PRES 0x80000000 /* Soft power-on reset */ -static void __iomem *sysc_base2; - static int rmobile_reset_handler(struct sys_off_data *data) { + void __iomem *sysc_base2 = (void __iomem *)data->cb_data; + /* Let's assume we have acquired the HPB semaphore */ writel(RESCNT2_PRES, sysc_base2 + RESCNT2); @@ -31,6 +31,7 @@ static int rmobile_reset_handler(struct sys_off_data *data) static int rmobile_reset_probe(struct platform_device *pdev) { + void __iomem *sysc_base2; int error; sysc_base2 = devm_platform_ioremap_resource(pdev, 1); @@ -41,7 +42,7 @@ static int rmobile_reset_probe(struct platform_device *pdev) SYS_OFF_MODE_RESTART, SYS_OFF_PRIO_HIGH, rmobile_reset_handler, - NULL); + (__force void *)sysc_base2); if (error) { dev_err(&pdev->dev, "cannot register restart handler (err=%d)\n", error); From 8fbb11162504f2de167a8ccd2d2c55a849d2c5ea Mon Sep 17 00:00:00 2001 From: "Sicelo A. Mhlongo" Date: Mon, 26 Feb 2024 21:37:22 +0200 Subject: [PATCH 56/66] power: supply: bq27xxx: Report charge full state correctly When reporting the charging status, the existing code reports the battery as full only when the reported current flowing is exactly 0mA, which is unlikely in practice. Fix the reporting by giving priority to the battery's full state indication/flag. Tested on the Nokia N900 with bq27200 fuel gauge. Signed-off-by: Sicelo A. Mhlongo Link: https://lore.kernel.org/r/20240226193722.2173624-1-absicsz@gmail.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 363428530ee6..abca56834468 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -1828,17 +1828,14 @@ static int bq27xxx_battery_current_and_status( val_curr->intval = curr; if (val_status) { - if (curr > 0) { + if (bq27xxx_battery_is_full(di, flags)) + val_status->intval = POWER_SUPPLY_STATUS_FULL; + else if (curr > 0) val_status->intval = POWER_SUPPLY_STATUS_CHARGING; - } else if (curr < 0) { + else if (curr < 0) val_status->intval = POWER_SUPPLY_STATUS_DISCHARGING; - } else { - if (bq27xxx_battery_is_full(di, flags)) - val_status->intval = POWER_SUPPLY_STATUS_FULL; - else - val_status->intval = - POWER_SUPPLY_STATUS_NOT_CHARGING; - } + else + val_status->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; } return 0; From b683d738c0a1c4c8fcf83fdf5eb4c6ce3d5130c6 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 27 Feb 2024 13:34:42 -0700 Subject: [PATCH 57/66] power: supply: core: Fix power_supply_init_attrs() stub When building without CONFIG_SYSFS, there is an error because of a recent refactoring that failed to update the stub of power_supply_init_attrs(): drivers/power/supply/power_supply_core.c: In function 'power_supply_class_init': drivers/power/supply/power_supply_core.c:1630:9: error: too few arguments to function 'power_supply_init_attrs' 1630 | power_supply_init_attrs(); | ^~~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/power/supply/power_supply_core.c:25: drivers/power/supply/power_supply.h:25:20: note: declared here 25 | static inline void power_supply_init_attrs(struct device_type *dev_type) {} | ^~~~~~~~~~~~~~~~~~~~~~~ Update the stub function to take no parameters like the rest of the refactoring, which resolves the build error. Fixes: 7b46b60944d7 ("power: supply: core: constify the struct device_type usage") Signed-off-by: Nathan Chancellor Reviewed-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240227-fix-power_supply_init_attrs-stub-v1-1-43365e68d4b3@kernel.org Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/power_supply.h index 232fdd8c1212..7d05756398b9 100644 --- a/drivers/power/supply/power_supply.h +++ b/drivers/power/supply/power_supply.h @@ -22,7 +22,7 @@ extern int power_supply_uevent(const struct device *dev, struct kobj_uevent_env #else -static inline void power_supply_init_attrs(struct device_type *dev_type) {} +static inline void power_supply_init_attrs(void) {} #define power_supply_uevent NULL #endif /* CONFIG_SYSFS */ From ea4367c40c79a5f16cb0de8a94a6b72697d37f06 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Wed, 28 Feb 2024 10:46:28 -0300 Subject: [PATCH 58/66] power: supply: core: move power_supply_attr_group into #ifdef block When building with CONFIG_SYSFS=n, the build error below is triggered: ld: drivers/power/supply/power_supply_core.o:(.data+0x0): undefined reference to `power_supply_attr_group' The problem is that power_supply_attr_group is needed in power_supply_core.c but defined in power_supply_sysfs.c, which is only targeted with CONFIG_SYSFS=y. Therefore, move the extern declaration into the #ifdef block that checks for CONFIG_SYSFS, and define an empty static const struct otherwise. This is safe because the macro __ATRIBUTE_GROUPS in power_supply_core.c will expand into an empty attribute_group array. Cc: Greg Kroah-Hartman Reported-by: Nathan Chancellor Link: https://lore.kernel.org/all/20240227214916.GA3699076@dev-arch.thelio-3990X/ Fixes: 7b46b60944d7 ("power: supply: core: constify the struct device_type usage") Signed-off-by: Ricardo B. Marliere Tested-by: Nathan Chancellor # build Link: https://lore.kernel.org/r/20240228-device_cleanup-power-v1-1-52c0321c48e1@marliere.net Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/power_supply.h index 7d05756398b9..06749a534db4 100644 --- a/drivers/power/supply/power_supply.h +++ b/drivers/power/supply/power_supply.h @@ -13,16 +13,16 @@ struct device; struct device_type; struct power_supply; -extern const struct attribute_group power_supply_attr_group; - #ifdef CONFIG_SYSFS extern void power_supply_init_attrs(void); extern int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env); +extern const struct attribute_group power_supply_attr_group; #else static inline void power_supply_init_attrs(void) {} +static const struct attribute_group power_supply_attr_group; #define power_supply_uevent NULL #endif /* CONFIG_SYSFS */ From 9a451f1b028e116d037a93bf13eb8f8620994205 Mon Sep 17 00:00:00 2001 From: "Sicelo A. Mhlongo" Date: Thu, 29 Feb 2024 08:37:21 +0200 Subject: [PATCH 59/66] power: supply: bq2415x_charger: report online status Provide the Online property. This chip does not have specific flags to indicate the presence of an input voltage, but this is implied by all valid charging states. Fault states also only occur when VBUS is present, so set Online true for those as well. Signed-off-by: Sicelo A. Mhlongo Link: https://lore.kernel.org/r/20240229063721.2592069-2-absicsz@gmail.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq2415x_charger.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/power/supply/bq2415x_charger.c b/drivers/power/supply/bq2415x_charger.c index 6a4798a62588..25e28dac900d 100644 --- a/drivers/power/supply/bq2415x_charger.c +++ b/drivers/power/supply/bq2415x_charger.c @@ -991,6 +991,7 @@ static enum power_supply_property bq2415x_power_supply_props[] = { /* TODO: maybe add more power supply properties */ POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_ONLINE, }; static int bq2415x_power_supply_get_property(struct power_supply *psy, @@ -1017,6 +1018,15 @@ static int bq2415x_power_supply_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_MODEL_NAME: val->strval = bq->model; break; + case POWER_SUPPLY_PROP_ONLINE: + /* VBUS is present for all charging and fault states, + * except the 'Ready' state. + */ + ret = bq2415x_exec_command(bq, BQ2415X_CHARGE_STATUS); + if (ret < 0) + return ret; + val->intval = ret > 0; + break; default: return -EINVAL; } From 71c2cc5cbf686c2397f43cbcb51a31589bdcee7b Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Fri, 1 Mar 2024 14:46:15 -0300 Subject: [PATCH 60/66] power: supply: core: make power_supply_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the power_supply_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240301-class_cleanup-power-v1-1-97e0b7bf9c94@marliere.net Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_btemp.c | 2 +- drivers/power/supply/ab8500_chargalg.c | 2 +- drivers/power/supply/ab8500_charger.c | 2 +- drivers/power/supply/ab8500_fg.c | 2 +- drivers/power/supply/apm_power.c | 2 +- drivers/power/supply/power_supply_core.c | 39 +++++++++++++----------- include/linux/power_supply.h | 2 +- 7 files changed, 27 insertions(+), 24 deletions(-) diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c index 7905eba93dea..41dba40fffdf 100644 --- a/drivers/power/supply/ab8500_btemp.c +++ b/drivers/power/supply/ab8500_btemp.c @@ -617,7 +617,7 @@ static int ab8500_btemp_get_ext_psy_data(struct device *dev, void *data) */ static void ab8500_btemp_external_power_changed(struct power_supply *psy) { - class_for_each_device(power_supply_class, NULL, psy, + class_for_each_device(&power_supply_class, NULL, psy, ab8500_btemp_get_ext_psy_data); } diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index de912658facb..329ae784a72d 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -1231,7 +1231,7 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) int ret; /* Collect data from all power_supply class devices */ - class_for_each_device(power_supply_class, NULL, + class_for_each_device(&power_supply_class, NULL, di->chargalg_psy, ab8500_chargalg_get_ext_psy_data); ab8500_chargalg_end_of_charge(di); diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index d72f32c663bc..1c2b69bbed17 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -1949,7 +1949,7 @@ static void ab8500_charger_check_vbat_work(struct work_struct *work) struct ab8500_charger *di = container_of(work, struct ab8500_charger, check_vbat_work.work); - class_for_each_device(power_supply_class, NULL, + class_for_each_device(&power_supply_class, NULL, &di->usb_chg, ab8500_charger_get_ext_psy_data); /* First run old_vbat is 0. */ diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 8c593fbdd45a..e49e704023e1 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -2407,7 +2407,7 @@ out: */ static void ab8500_fg_external_power_changed(struct power_supply *psy) { - class_for_each_device(power_supply_class, NULL, psy, + class_for_each_device(&power_supply_class, NULL, psy, ab8500_fg_get_ext_psy_data); } diff --git a/drivers/power/supply/apm_power.c b/drivers/power/supply/apm_power.c index 9d1a7fbcaed4..034f28699977 100644 --- a/drivers/power/supply/apm_power.c +++ b/drivers/power/supply/apm_power.c @@ -79,7 +79,7 @@ static void find_main_battery(void) main_battery = NULL; bp.main = main_battery; - error = class_for_each_device(power_supply_class, NULL, &bp, + error = class_for_each_device(&power_supply_class, NULL, &bp, __find_main_battery); if (error) { main_battery = bp.main; diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 37dac7669090..4f27f17f8741 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -26,7 +26,10 @@ #include "samsung-sdi-battery.h" /* exported for the APM Power driver, APM emulation */ -struct class *power_supply_class; +const struct class power_supply_class = { + .name = "power_supply", + .dev_uevent = power_supply_uevent, +}; EXPORT_SYMBOL_GPL(power_supply_class); static BLOCKING_NOTIFIER_HEAD(power_supply_notifier); @@ -97,7 +100,7 @@ static void power_supply_changed_work(struct work_struct *work) if (likely(psy->changed)) { psy->changed = false; spin_unlock_irqrestore(&psy->changed_lock, flags); - class_for_each_device(power_supply_class, NULL, psy, + class_for_each_device(&power_supply_class, NULL, psy, __power_supply_changed_work); power_supply_update_leds(psy); blocking_notifier_call_chain(&power_supply_notifier, @@ -191,7 +194,7 @@ static int power_supply_populate_supplied_from(struct power_supply *psy) { int error; - error = class_for_each_device(power_supply_class, NULL, psy, + error = class_for_each_device(&power_supply_class, NULL, psy, __power_supply_populate_supplied_from); dev_dbg(&psy->dev, "%s %d\n", __func__, error); @@ -226,8 +229,8 @@ static int power_supply_find_supply_from_node(struct device_node *supply_node) * We return 0 if class_for_each_device() returned 1, -EPROBE_DEFER if * it returned 0, or error as returned by it. */ - error = class_for_each_device(power_supply_class, NULL, supply_node, - __power_supply_find_supply_from_node); + error = class_for_each_device(&power_supply_class, NULL, supply_node, + __power_supply_find_supply_from_node); return error ? (error == 1 ? 0 : error) : -EPROBE_DEFER; } @@ -333,7 +336,7 @@ int power_supply_am_i_supplied(struct power_supply *psy) struct psy_am_i_supplied_data data = { psy, 0 }; int error; - error = class_for_each_device(power_supply_class, NULL, &data, + error = class_for_each_device(&power_supply_class, NULL, &data, __power_supply_am_i_supplied); dev_dbg(&psy->dev, "%s count %u err %d\n", __func__, data.count, error); @@ -369,7 +372,7 @@ int power_supply_is_system_supplied(void) int error; unsigned int count = 0; - error = class_for_each_device(power_supply_class, NULL, &count, + error = class_for_each_device(&power_supply_class, NULL, &count, __power_supply_is_system_supplied); /* @@ -416,7 +419,7 @@ int power_supply_get_property_from_supplier(struct power_supply *psy, * This function is not intended for use with a supply with multiple * suppliers, we simply pick the first supply to report the psp. */ - ret = class_for_each_device(power_supply_class, NULL, &data, + ret = class_for_each_device(&power_supply_class, NULL, &data, __power_supply_get_supplier_property); if (ret < 0) return ret; @@ -462,8 +465,8 @@ static int power_supply_match_device_by_name(struct device *dev, const void *dat struct power_supply *power_supply_get_by_name(const char *name) { struct power_supply *psy = NULL; - struct device *dev = class_find_device(power_supply_class, NULL, name, - power_supply_match_device_by_name); + struct device *dev = class_find_device(&power_supply_class, NULL, name, + power_supply_match_device_by_name); if (dev) { psy = dev_get_drvdata(dev); @@ -519,8 +522,8 @@ struct power_supply *power_supply_get_by_phandle(struct device_node *np, if (!power_supply_np) return ERR_PTR(-ENODEV); - dev = class_find_device(power_supply_class, NULL, power_supply_np, - power_supply_match_device_node); + dev = class_find_device(&power_supply_class, NULL, power_supply_np, + power_supply_match_device_node); of_node_put(power_supply_np); @@ -1373,7 +1376,7 @@ __power_supply_register(struct device *parent, device_initialize(dev); - dev->class = power_supply_class; + dev->class = &power_supply_class; dev->type = &power_supply_dev_type; dev->parent = parent; dev->release = power_supply_dev_release; @@ -1621,12 +1624,12 @@ EXPORT_SYMBOL_GPL(power_supply_get_drvdata); static int __init power_supply_class_init(void) { - power_supply_class = class_create("power_supply"); + int err; - if (IS_ERR(power_supply_class)) - return PTR_ERR(power_supply_class); + err = class_register(&power_supply_class); + if (err) + return err; - power_supply_class->dev_uevent = power_supply_uevent; power_supply_init_attrs(); return 0; @@ -1634,7 +1637,7 @@ static int __init power_supply_class_init(void) static void __exit power_supply_class_exit(void) { - class_destroy(power_supply_class); + class_unregister(&power_supply_class); } subsys_initcall(power_supply_class_init); diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index c0992a77feea..514f652de64d 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -895,7 +895,7 @@ extern int power_supply_powers(struct power_supply *psy, struct device *dev); extern void *power_supply_get_drvdata(struct power_supply *psy); /* For APM emulation, think legacy userspace. */ -extern struct class *power_supply_class; +extern const struct class power_supply_class; static inline bool power_supply_is_amp_property(enum power_supply_property psp) { From 68ade0976df7979eac5f1d46320ff798f5043af6 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Fri, 1 Mar 2024 23:58:26 +0100 Subject: [PATCH 61/66] power: supply: core: add power_supply_for_each_device() Introduce power_supply_for_each_device(), which is a wrapper for class_for_each_device() using the power_supply_class and going through all devices. This allows making the power_supply_class itself a local variable, so that drivers cannot mess with it and simplifies the code slightly. Reviewed-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240301-psy-class-cleanup-v1-1-aebe8c4b6b08@collabora.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_btemp.c | 3 +-- drivers/power/supply/ab8500_chargalg.c | 3 +-- drivers/power/supply/ab8500_charger.c | 3 +-- drivers/power/supply/ab8500_fg.c | 3 +-- drivers/power/supply/apm_power.c | 3 +-- drivers/power/supply/power_supply_core.c | 34 +++++++++++------------- include/linux/power_supply.h | 3 +-- 7 files changed, 22 insertions(+), 30 deletions(-) diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c index 41dba40fffdf..56f136b2d071 100644 --- a/drivers/power/supply/ab8500_btemp.c +++ b/drivers/power/supply/ab8500_btemp.c @@ -617,8 +617,7 @@ static int ab8500_btemp_get_ext_psy_data(struct device *dev, void *data) */ static void ab8500_btemp_external_power_changed(struct power_supply *psy) { - class_for_each_device(&power_supply_class, NULL, psy, - ab8500_btemp_get_ext_psy_data); + power_supply_for_each_device(psy, ab8500_btemp_get_ext_psy_data); } /* ab8500 btemp driver interrupts and their respective isr */ diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index 329ae784a72d..55ab7a28056e 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -1231,8 +1231,7 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) int ret; /* Collect data from all power_supply class devices */ - class_for_each_device(&power_supply_class, NULL, - di->chargalg_psy, ab8500_chargalg_get_ext_psy_data); + power_supply_for_each_device(di->chargalg_psy, ab8500_chargalg_get_ext_psy_data); ab8500_chargalg_end_of_charge(di); ab8500_chargalg_check_temp(di); diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index 1c2b69bbed17..9b34d1a60f66 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -1949,8 +1949,7 @@ static void ab8500_charger_check_vbat_work(struct work_struct *work) struct ab8500_charger *di = container_of(work, struct ab8500_charger, check_vbat_work.work); - class_for_each_device(&power_supply_class, NULL, - &di->usb_chg, ab8500_charger_get_ext_psy_data); + power_supply_for_each_device(&di->usb_chg, ab8500_charger_get_ext_psy_data); /* First run old_vbat is 0. */ if (di->old_vbat == 0) diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index e49e704023e1..2ccaf6116c09 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -2407,8 +2407,7 @@ out: */ static void ab8500_fg_external_power_changed(struct power_supply *psy) { - class_for_each_device(&power_supply_class, NULL, psy, - ab8500_fg_get_ext_psy_data); + power_supply_for_each_device(psy, ab8500_fg_get_ext_psy_data); } /** diff --git a/drivers/power/supply/apm_power.c b/drivers/power/supply/apm_power.c index 034f28699977..8ef1b6f1f787 100644 --- a/drivers/power/supply/apm_power.c +++ b/drivers/power/supply/apm_power.c @@ -79,8 +79,7 @@ static void find_main_battery(void) main_battery = NULL; bp.main = main_battery; - error = class_for_each_device(&power_supply_class, NULL, &bp, - __find_main_battery); + error = power_supply_for_each_device(&bp, __find_main_battery); if (error) { main_battery = bp.main; return; diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 4f27f17f8741..0eb8a57dda70 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -25,12 +25,10 @@ #include "power_supply.h" #include "samsung-sdi-battery.h" -/* exported for the APM Power driver, APM emulation */ -const struct class power_supply_class = { +static const struct class power_supply_class = { .name = "power_supply", .dev_uevent = power_supply_uevent, }; -EXPORT_SYMBOL_GPL(power_supply_class); static BLOCKING_NOTIFIER_HEAD(power_supply_notifier); @@ -100,8 +98,7 @@ static void power_supply_changed_work(struct work_struct *work) if (likely(psy->changed)) { psy->changed = false; spin_unlock_irqrestore(&psy->changed_lock, flags); - class_for_each_device(&power_supply_class, NULL, psy, - __power_supply_changed_work); + power_supply_for_each_device(psy, __power_supply_changed_work); power_supply_update_leds(psy); blocking_notifier_call_chain(&power_supply_notifier, PSY_EVENT_PROP_CHANGED, psy); @@ -119,6 +116,12 @@ static void power_supply_changed_work(struct work_struct *work) spin_unlock_irqrestore(&psy->changed_lock, flags); } +int power_supply_for_each_device(void *data, int (*fn)(struct device *dev, void *data)) +{ + return class_for_each_device(&power_supply_class, NULL, data, fn); +} +EXPORT_SYMBOL_GPL(power_supply_for_each_device); + void power_supply_changed(struct power_supply *psy) { unsigned long flags; @@ -194,8 +197,7 @@ static int power_supply_populate_supplied_from(struct power_supply *psy) { int error; - error = class_for_each_device(&power_supply_class, NULL, psy, - __power_supply_populate_supplied_from); + error = power_supply_for_each_device(psy, __power_supply_populate_supplied_from); dev_dbg(&psy->dev, "%s %d\n", __func__, error); @@ -208,7 +210,7 @@ static int __power_supply_find_supply_from_node(struct device *dev, struct device_node *np = data; struct power_supply *epsy = dev_get_drvdata(dev); - /* returning non-zero breaks out of class_for_each_device loop */ + /* returning non-zero breaks out of power_supply_for_each_device loop */ if (epsy->of_node == np) return 1; @@ -220,17 +222,16 @@ static int power_supply_find_supply_from_node(struct device_node *supply_node) int error; /* - * class_for_each_device() either returns its own errors or values + * power_supply_for_each_device() either returns its own errors or values * returned by __power_supply_find_supply_from_node(). * * __power_supply_find_supply_from_node() will return 0 (no match) * or 1 (match). * - * We return 0 if class_for_each_device() returned 1, -EPROBE_DEFER if + * We return 0 if power_supply_for_each_device() returned 1, -EPROBE_DEFER if * it returned 0, or error as returned by it. */ - error = class_for_each_device(&power_supply_class, NULL, supply_node, - __power_supply_find_supply_from_node); + error = power_supply_for_each_device(supply_node, __power_supply_find_supply_from_node); return error ? (error == 1 ? 0 : error) : -EPROBE_DEFER; } @@ -336,8 +337,7 @@ int power_supply_am_i_supplied(struct power_supply *psy) struct psy_am_i_supplied_data data = { psy, 0 }; int error; - error = class_for_each_device(&power_supply_class, NULL, &data, - __power_supply_am_i_supplied); + error = power_supply_for_each_device(&data, __power_supply_am_i_supplied); dev_dbg(&psy->dev, "%s count %u err %d\n", __func__, data.count, error); @@ -372,8 +372,7 @@ int power_supply_is_system_supplied(void) int error; unsigned int count = 0; - error = class_for_each_device(&power_supply_class, NULL, &count, - __power_supply_is_system_supplied); + error = power_supply_for_each_device(&count, __power_supply_is_system_supplied); /* * If no system scope power class device was found at all, most probably we @@ -419,8 +418,7 @@ int power_supply_get_property_from_supplier(struct power_supply *psy, * This function is not intended for use with a supply with multiple * suppliers, we simply pick the first supply to report the psp. */ - ret = class_for_each_device(&power_supply_class, NULL, &data, - __power_supply_get_supplier_property); + ret = power_supply_for_each_device(&data, __power_supply_get_supplier_property); if (ret < 0) return ret; if (ret == 0) diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 514f652de64d..92dd205774ec 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -894,8 +894,7 @@ extern int power_supply_powers(struct power_supply *psy, struct device *dev); #define to_power_supply(device) container_of(device, struct power_supply, dev) extern void *power_supply_get_drvdata(struct power_supply *psy); -/* For APM emulation, think legacy userspace. */ -extern const struct class power_supply_class; +extern int power_supply_for_each_device(void *data, int (*fn)(struct device *dev, void *data)); static inline bool power_supply_is_amp_property(enum power_supply_property psp) { From ea1ec769d1f01a9900127e83e63dfdd77d096c8a Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Fri, 1 Mar 2024 23:58:27 +0100 Subject: [PATCH 62/66] power: supply: core: simplify power_supply_class_init Technically the sysfs attributes should be initialized before the class is registered, since that will use them. As a nice side effect this nicely simplifies the code, since it allows dropping the helper variable. Reviewed-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240301-psy-class-cleanup-v1-2-aebe8c4b6b08@collabora.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_core.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 0eb8a57dda70..4daea6ed8f1d 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -1622,15 +1622,8 @@ EXPORT_SYMBOL_GPL(power_supply_get_drvdata); static int __init power_supply_class_init(void) { - int err; - - err = class_register(&power_supply_class); - if (err) - return err; - power_supply_init_attrs(); - - return 0; + return class_register(&power_supply_class); } static void __exit power_supply_class_exit(void) From f107e6b82392a4d64507e219c57235d3fe09e9d7 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sun, 3 Mar 2024 13:30:50 -0300 Subject: [PATCH 63/66] power: supply: move power_supply_attr_groups definition back to sysfs As reported by the kernel test robot, 'power_supply_attr_group' is defined but not used when CONFIG_SYSFS is not set. Sebastian suggested that the correct fix implemented by this patch, instead of my attempt in commit ea4367c40c79 ("power: supply: core: move power_supply_attr_group into #ifdef block"), is to define power_supply_attr_groups in power_supply_sysfs.c and expose it in the power_supply.h header. For the case where CONFIG_SYSFS=n, define it as NULL. Suggested-by: Sebastian Reichel Fixes: ea4367c40c79 ("power: supply: core: move power_supply_attr_group into #ifdef block") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202403021518.SUQzk3oA-lkp@intel.com/ Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240303-class_cleanup-power-v2-1-e248b7128519@marliere.net Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply.h | 4 ++-- drivers/power/supply/power_supply_core.c | 1 - drivers/power/supply/power_supply_sysfs.c | 7 ++++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/power_supply.h index 06749a534db4..3cbafc58bdad 100644 --- a/drivers/power/supply/power_supply.h +++ b/drivers/power/supply/power_supply.h @@ -17,12 +17,12 @@ struct power_supply; extern void power_supply_init_attrs(void); extern int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env); -extern const struct attribute_group power_supply_attr_group; +extern const struct attribute_group *power_supply_attr_groups[]; #else static inline void power_supply_init_attrs(void) {} -static const struct attribute_group power_supply_attr_group; +#define power_supply_attr_groups NULL #define power_supply_uevent NULL #endif /* CONFIG_SYSFS */ diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 4daea6ed8f1d..fefe938c9342 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -32,7 +32,6 @@ static const struct class power_supply_class = { static BLOCKING_NOTIFIER_HEAD(power_supply_notifier); -__ATTRIBUTE_GROUPS(power_supply_attr); static const struct device_type power_supply_dev_type = { .name = "power_supply", .groups = power_supply_attr_groups, diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index edb240450e38..bf725cbb0d86 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -389,11 +389,16 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj, return 0; } -const struct attribute_group power_supply_attr_group = { +static const struct attribute_group power_supply_attr_group = { .attrs = __power_supply_attrs, .is_visible = power_supply_attr_is_visible, }; +const struct attribute_group *power_supply_attr_groups[] = { + &power_supply_attr_group, + NULL +}; + void power_supply_init_attrs(void) { int i; From cd38a0acca734a1117663d6f0da579d3965b6c93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sun, 3 Mar 2024 16:31:13 +0100 Subject: [PATCH 64/66] power: supply: mm8013: fix "not charging" detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The charge_behaviours property is meant as a control-knob that can be changed by the user. Page 23 of [0] which documents the flag CHG_INH as follows: CHG_INH : Charge Inhibit When the current is more than or equal to charge threshold current, charge inhibit temperature (upper/lower limit) :1 charge permission temperature or the current is less than charge threshold current :0 So this is pure read-only information which is better represented as POWER_SUPPLY_STATUS_NOT_CHARGING. [0] https://product.minebeamitsumi.com/en/product/category/ics/battery/fuel_gauge/parts/download/__icsFiles/afieldfile/2023/07/12/1_download_01_12.pdf Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20240303-power_supply-charge_behaviour_prop-v2-1-8ebb0a7c2409@weissschuh.net Fixes: e39257cde7e8 ("power: supply: mm8013: Add more properties") Signed-off-by: Sebastian Reichel --- drivers/power/supply/mm8013.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/power/supply/mm8013.c b/drivers/power/supply/mm8013.c index caa272b03564..20c1651ca38e 100644 --- a/drivers/power/supply/mm8013.c +++ b/drivers/power/supply/mm8013.c @@ -71,7 +71,6 @@ static int mm8013_checkdevice(struct mm8013_chip *chip) static enum power_supply_property mm8013_battery_props[] = { POWER_SUPPLY_PROP_CAPACITY, - POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_CHARGE_NOW, @@ -103,16 +102,6 @@ static int mm8013_get_property(struct power_supply *psy, val->intval = regval; break; - case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: - ret = regmap_read(chip->regmap, REG_FLAGS, ®val); - if (ret < 0) - return ret; - - if (regval & MM8013_FLAG_CHG_INH) - val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; - else - val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO; - break; case POWER_SUPPLY_PROP_CHARGE_FULL: ret = regmap_read(chip->regmap, REG_FULL_CHARGE_CAPACITY, ®val); if (ret < 0) @@ -187,6 +176,8 @@ static int mm8013_get_property(struct power_supply *psy, if (regval & MM8013_FLAG_DSG) val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + else if (regval & MM8013_FLAG_CHG_INH) + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; else if (regval & MM8013_FLAG_CHG) val->intval = POWER_SUPPLY_STATUS_CHARGING; else if (regval & MM8013_FLAG_FC) From 521d75b4174e9cbfad73e7d0ac34fd6461b542d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sun, 3 Mar 2024 16:31:14 +0100 Subject: [PATCH 65/66] power: supply: core: ease special formatting implementations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By moving the conditional into the default-branch of the switch new additions to the switch won't have to bypass the conditional. This makes it easier to implement those special cases like the upcoming change to the formatting of "charge_behaviour". Suggested-by: Hans de Goede Link: https://lore.kernel.org/lkml/53082075-852f-4698-b354-ed30e7fd2683@redhat.com/ Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20240303-power_supply-charge_behaviour_prop-v2-2-8ebb0a7c2409@weissschuh.net Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_sysfs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index bf725cbb0d86..9b461e997fcb 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -298,11 +298,6 @@ static ssize_t power_supply_show_property(struct device *dev, } } - if (ps_attr->text_values_len > 0 && - value.intval < ps_attr->text_values_len && value.intval >= 0) { - return sysfs_emit(buf, "%s\n", ps_attr->text_values[value.intval]); - } - switch (psp) { case POWER_SUPPLY_PROP_USB_TYPE: ret = power_supply_show_usb_type(dev, psy->desc, @@ -312,7 +307,12 @@ static ssize_t power_supply_show_property(struct device *dev, ret = sysfs_emit(buf, "%s\n", value.strval); break; default: - ret = sysfs_emit(buf, "%d\n", value.intval); + if (ps_attr->text_values_len > 0 && + value.intval < ps_attr->text_values_len && value.intval >= 0) { + ret = sysfs_emit(buf, "%s\n", ps_attr->text_values[value.intval]); + } else { + ret = sysfs_emit(buf, "%d\n", value.intval); + } } return ret; From 4e61f1e9d58fb0765f59f47d4d1f318b36c14d95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sun, 3 Mar 2024 16:31:15 +0100 Subject: [PATCH 66/66] power: supply: core: fix charge_behaviour formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This property is documented to have a special format which exposes all available behaviours and the currently active one at the same time. For this special format some helpers are provided. When the charge_behaviour property was added in 1b0b6cc8030d ("power: supply: add charge_behaviour attributes"), it did not update the default logic in in power_supply_sysfs.c to use the format helpers. Thus by default only the currently active behaviour is printed. This fixes the default logic to follow the documented format. There is currently only one in-tree drivers exposing charge behaviours - thinkpad_acpi, which is not affected by the change, as it directly uses the helpers and does not use the power_supply_sysfs.c logic. Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20240303-power_supply-charge_behaviour_prop-v2-3-8ebb0a7c2409@weissschuh.net Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_sysfs.c | 20 ++++++++++++++++++++ include/linux/power_supply.h | 1 + 2 files changed, 21 insertions(+) diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 9b461e997fcb..0d2c3724d0bc 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -271,6 +271,23 @@ static ssize_t power_supply_show_usb_type(struct device *dev, return count; } +static ssize_t power_supply_show_charge_behaviour(struct device *dev, + struct power_supply *psy, + union power_supply_propval *value, + char *buf) +{ + int ret; + + ret = power_supply_get_property(psy, + POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR, + value); + if (ret < 0) + return ret; + + return power_supply_charge_behaviour_show(dev, psy->desc->charge_behaviours, + value->intval, buf); +} + static ssize_t power_supply_show_property(struct device *dev, struct device_attribute *attr, char *buf) { @@ -303,6 +320,9 @@ static ssize_t power_supply_show_property(struct device *dev, ret = power_supply_show_usb_type(dev, psy->desc, &value, buf); break; + case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: + ret = power_supply_show_charge_behaviour(dev, psy, &value, buf); + break; case POWER_SUPPLY_PROP_MODEL_NAME ... POWER_SUPPLY_PROP_SERIAL_NUMBER: ret = sysfs_emit(buf, "%s\n", value.strval); break; diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 92dd205774ec..8e5705a56b85 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -242,6 +242,7 @@ struct power_supply_config { struct power_supply_desc { const char *name; enum power_supply_type type; + u8 charge_behaviours; const enum power_supply_usb_type *usb_types; size_t num_usb_types; const enum power_supply_property *properties;