summaryrefslogtreecommitdiffstats
path: root/drivers/power/supply/ab8500_btemp.c
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2021-05-23 00:50:39 +0200
committerSebastian Reichel <sre@kernel.org>2021-06-03 18:40:15 +0200
commit1c1f13a006ed0d71bb5664c8b7e3e77a28da3beb (patch)
tree2e1cc7e00fb9baff932c51571bda3b1f91521863 /drivers/power/supply/ab8500_btemp.c
parent94233f11f8b6be9dd78f66cca162de66b7b66ae6 (diff)
downloadlinux-1c1f13a006ed0d71bb5664c8b7e3e77a28da3beb.tar.bz2
power: supply: ab8500: Move to componentized binding
The driver has problems with the different components of the charging code racing with each other to probe(). This results in all four subdrivers populating battery information to ascertain that it is populated for their own needs for example. Fix this by using component probing and thus expressing to the kernel that these are dependent components. The probes can happen in any order and will only acquire resources such as state container, regulators and interrupts and initialize the data structures, but no execution happens until the .bind() callback is called. The charging driver is the main component and binds first, then bind in order the three subcomponents: ab8500-fg, ab8500-btemp and ab8500-chargalg. Do some housekeeping while we are moving the code around. Like use devm_* for IRQs so as to cut down on some boilerplate. Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Diffstat (limited to 'drivers/power/supply/ab8500_btemp.c')
-rw-r--r--drivers/power/supply/ab8500_btemp.c118
1 files changed, 51 insertions, 67 deletions
diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c
index fdfcd59fc43e..3598b5a748e7 100644
--- a/drivers/power/supply/ab8500_btemp.c
+++ b/drivers/power/supply/ab8500_btemp.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/component.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/slab.h>
@@ -932,26 +933,6 @@ static int __maybe_unused ab8500_btemp_suspend(struct device *dev)
return 0;
}
-static int ab8500_btemp_remove(struct platform_device *pdev)
-{
- struct ab8500_btemp *di = platform_get_drvdata(pdev);
- int i, irq;
-
- /* Disable interrupts */
- for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) {
- irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
- free_irq(irq, di);
- }
-
- /* Delete the work queue */
- destroy_workqueue(di->btemp_wq);
-
- flush_scheduled_work();
- power_supply_unregister(di->btemp_psy);
-
- return 0;
-}
-
static char *supply_interface[] = {
"ab8500_chargalg",
"ab8500_fg",
@@ -966,6 +947,40 @@ static const struct power_supply_desc ab8500_btemp_desc = {
.external_power_changed = ab8500_btemp_external_power_changed,
};
+static int ab8500_btemp_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct ab8500_btemp *di = dev_get_drvdata(dev);
+
+ /* Create a work queue for the btemp */
+ di->btemp_wq =
+ alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM, 0);
+ if (di->btemp_wq == NULL) {
+ dev_err(dev, "failed to create work queue\n");
+ return -ENOMEM;
+ }
+
+ /* Kick off periodic temperature measurements */
+ ab8500_btemp_periodic(di, true);
+
+ return 0;
+}
+
+static void ab8500_btemp_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct ab8500_btemp *di = dev_get_drvdata(dev);
+
+ /* Delete the work queue */
+ destroy_workqueue(di->btemp_wq);
+ flush_scheduled_work();
+}
+
+static const struct component_ops ab8500_btemp_component_ops = {
+ .bind = ab8500_btemp_bind,
+ .unbind = ab8500_btemp_unbind,
+};
+
static int ab8500_btemp_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -1011,14 +1026,6 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface);
psy_cfg.drv_data = di;
- /* Create a work queue for the btemp */
- di->btemp_wq =
- alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM, 0);
- if (di->btemp_wq == NULL) {
- dev_err(dev, "failed to create work queue\n");
- return -ENOMEM;
- }
-
/* Init work for measuring temperature periodically */
INIT_DEFERRABLE_WORK(&di->btemp_periodic_work,
ab8500_btemp_periodic_work);
@@ -1031,7 +1038,7 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
AB8500_BTEMP_HIGH_TH, &val);
if (ret < 0) {
dev_err(dev, "%s ab8500 read failed\n", __func__);
- goto free_btemp_wq;
+ return ret;
}
switch (val) {
case BTEMP_HIGH_TH_57_0:
@@ -1050,30 +1057,28 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
}
/* Register BTEMP power supply class */
- di->btemp_psy = power_supply_register(dev, &ab8500_btemp_desc,
- &psy_cfg);
+ di->btemp_psy = devm_power_supply_register(dev, &ab8500_btemp_desc,
+ &psy_cfg);
if (IS_ERR(di->btemp_psy)) {
dev_err(dev, "failed to register BTEMP psy\n");
- ret = PTR_ERR(di->btemp_psy);
- goto free_btemp_wq;
+ return PTR_ERR(di->btemp_psy);
}
/* Register interrupts */
for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) {
irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
- if (irq < 0) {
- ret = irq;
- goto free_irq;
- }
+ if (irq < 0)
+ return irq;
- ret = request_threaded_irq(irq, NULL, ab8500_btemp_irq[i].isr,
+ ret = devm_request_threaded_irq(dev, irq, NULL,
+ ab8500_btemp_irq[i].isr,
IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
ab8500_btemp_irq[i].name, di);
if (ret) {
dev_err(dev, "failed to request %s IRQ %d: %d\n"
, ab8500_btemp_irq[i].name, irq, ret);
- goto free_irq;
+ return ret;
}
dev_dbg(dev, "Requested %s IRQ %d: %d\n",
ab8500_btemp_irq[i].name, irq, ret);
@@ -1081,23 +1086,16 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, di);
- /* Kick off periodic temperature measurements */
- ab8500_btemp_periodic(di, true);
list_add_tail(&di->node, &ab8500_btemp_list);
- return ret;
+ return component_add(dev, &ab8500_btemp_component_ops);
+}
-free_irq:
- /* We also have to free all successfully registered irqs */
- for (i = i - 1; i >= 0; i--) {
- irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
- free_irq(irq, di);
- }
+static int ab8500_btemp_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &ab8500_btemp_component_ops);
- power_supply_unregister(di->btemp_psy);
-free_btemp_wq:
- destroy_workqueue(di->btemp_wq);
- return ret;
+ return 0;
}
static SIMPLE_DEV_PM_OPS(ab8500_btemp_pm_ops, ab8500_btemp_suspend, ab8500_btemp_resume);
@@ -1107,7 +1105,7 @@ static const struct of_device_id ab8500_btemp_match[] = {
{ },
};
-static struct platform_driver ab8500_btemp_driver = {
+struct platform_driver ab8500_btemp_driver = {
.probe = ab8500_btemp_probe,
.remove = ab8500_btemp_remove,
.driver = {
@@ -1116,20 +1114,6 @@ static struct platform_driver ab8500_btemp_driver = {
.pm = &ab8500_btemp_pm_ops,
},
};
-
-static int __init ab8500_btemp_init(void)
-{
- return platform_driver_register(&ab8500_btemp_driver);
-}
-
-static void __exit ab8500_btemp_exit(void)
-{
- platform_driver_unregister(&ab8500_btemp_driver);
-}
-
-device_initcall(ab8500_btemp_init);
-module_exit(ab8500_btemp_exit);
-
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy");
MODULE_ALIAS("platform:ab8500-btemp");