summaryrefslogtreecommitdiff
path: root/drivers/power/supply/abx500_chargalg.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power/supply/abx500_chargalg.c')
-rw-r--r--drivers/power/supply/abx500_chargalg.c116
1 files changed, 64 insertions, 52 deletions
diff --git a/drivers/power/supply/abx500_chargalg.c b/drivers/power/supply/abx500_chargalg.c
index f5b792243727..599684ce0e4b 100644
--- a/drivers/power/supply/abx500_chargalg.c
+++ b/drivers/power/supply/abx500_chargalg.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/component.h>
#include <linux/hrtimer.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@@ -1943,13 +1944,44 @@ static int __maybe_unused abx500_chargalg_suspend(struct device *dev)
return 0;
}
-static int abx500_chargalg_remove(struct platform_device *pdev)
+static char *supply_interface[] = {
+ "ab8500_fg",
+};
+
+static const struct power_supply_desc abx500_chargalg_desc = {
+ .name = "abx500_chargalg",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .properties = abx500_chargalg_props,
+ .num_properties = ARRAY_SIZE(abx500_chargalg_props),
+ .get_property = abx500_chargalg_get_property,
+ .external_power_changed = abx500_chargalg_external_power_changed,
+};
+
+static int abx500_chargalg_bind(struct device *dev, struct device *master,
+ void *data)
{
- struct abx500_chargalg *di = platform_get_drvdata(pdev);
+ struct abx500_chargalg *di = dev_get_drvdata(dev);
- /* sysfs interface to enable/disbale charging from user space */
- abx500_chargalg_sysfs_exit(di);
+ /* Create a work queue for the chargalg */
+ di->chargalg_wq = alloc_ordered_workqueue("abx500_chargalg_wq",
+ WQ_MEM_RECLAIM);
+ if (di->chargalg_wq == NULL) {
+ dev_err(di->dev, "failed to create work queue\n");
+ return -ENOMEM;
+ }
+
+ /* Run the charging algorithm */
+ queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, 0);
+
+ return 0;
+}
+static void abx500_chargalg_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct abx500_chargalg *di = dev_get_drvdata(dev);
+
+ /* Stop all timers and work */
hrtimer_cancel(&di->safety_timer);
hrtimer_cancel(&di->maintenance_timer);
@@ -1959,48 +1991,36 @@ static int abx500_chargalg_remove(struct platform_device *pdev)
/* Delete the work queue */
destroy_workqueue(di->chargalg_wq);
-
- power_supply_unregister(di->chargalg_psy);
-
- return 0;
+ flush_scheduled_work();
}
-static char *supply_interface[] = {
- "ab8500_fg",
-};
-
-static const struct power_supply_desc abx500_chargalg_desc = {
- .name = "abx500_chargalg",
- .type = POWER_SUPPLY_TYPE_BATTERY,
- .properties = abx500_chargalg_props,
- .num_properties = ARRAY_SIZE(abx500_chargalg_props),
- .get_property = abx500_chargalg_get_property,
- .external_power_changed = abx500_chargalg_external_power_changed,
+static const struct component_ops abx500_chargalg_component_ops = {
+ .bind = abx500_chargalg_bind,
+ .unbind = abx500_chargalg_unbind,
};
static int abx500_chargalg_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
struct power_supply_config psy_cfg = {};
struct abx500_chargalg *di;
int ret = 0;
- di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
- if (!di) {
- dev_err(&pdev->dev, "%s no mem for ab8500_chargalg\n", __func__);
+ di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
+ if (!di)
return -ENOMEM;
- }
di->bm = &ab8500_bm_data;
- ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
+ ret = ab8500_bm_of_probe(dev, np, di->bm);
if (ret) {
- dev_err(&pdev->dev, "failed to get battery information\n");
+ dev_err(dev, "failed to get battery information\n");
return ret;
}
/* get device struct and parent */
- di->dev = &pdev->dev;
+ di->dev = dev;
di->parent = dev_get_drvdata(pdev->dev.parent);
psy_cfg.supplied_to = supply_interface;
@@ -2016,14 +2036,6 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
di->maintenance_timer.function =
abx500_chargalg_maintenance_timer_expired;
- /* Create a work queue for the chargalg */
- di->chargalg_wq = alloc_ordered_workqueue("abx500_chargalg_wq",
- WQ_MEM_RECLAIM);
- if (di->chargalg_wq == NULL) {
- dev_err(di->dev, "failed to create work queue\n");
- return -ENOMEM;
- }
-
/* Init work for chargalg */
INIT_DEFERRABLE_WORK(&di->chargalg_periodic_work,
abx500_chargalg_periodic_work);
@@ -2037,12 +2049,12 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
di->chg_info.prev_conn_chg = -1;
/* Register chargalg power supply class */
- di->chargalg_psy = power_supply_register(di->dev, &abx500_chargalg_desc,
+ di->chargalg_psy = devm_power_supply_register(di->dev,
+ &abx500_chargalg_desc,
&psy_cfg);
if (IS_ERR(di->chargalg_psy)) {
dev_err(di->dev, "failed to register chargalg psy\n");
- ret = PTR_ERR(di->chargalg_psy);
- goto free_chargalg_wq;
+ return PTR_ERR(di->chargalg_psy);
}
platform_set_drvdata(pdev, di);
@@ -2051,21 +2063,24 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
ret = abx500_chargalg_sysfs_init(di);
if (ret) {
dev_err(di->dev, "failed to create sysfs entry\n");
- goto free_psy;
+ return ret;
}
di->curr_status.curr_step = CHARGALG_CURR_STEP_HIGH;
- /* Run the charging algorithm */
- queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, 0);
-
dev_info(di->dev, "probe success\n");
- return ret;
+ return component_add(dev, &abx500_chargalg_component_ops);
+}
-free_psy:
- power_supply_unregister(di->chargalg_psy);
-free_chargalg_wq:
- destroy_workqueue(di->chargalg_wq);
- return ret;
+static int abx500_chargalg_remove(struct platform_device *pdev)
+{
+ struct abx500_chargalg *di = platform_get_drvdata(pdev);
+
+ component_del(&pdev->dev, &abx500_chargalg_component_ops);
+
+ /* sysfs interface to enable/disable charging from user space */
+ abx500_chargalg_sysfs_exit(di);
+
+ return 0;
}
static SIMPLE_DEV_PM_OPS(abx500_chargalg_pm_ops, abx500_chargalg_suspend, abx500_chargalg_resume);
@@ -2075,7 +2090,7 @@ static const struct of_device_id ab8500_chargalg_match[] = {
{ },
};
-static struct platform_driver abx500_chargalg_driver = {
+struct platform_driver abx500_chargalg_driver = {
.probe = abx500_chargalg_probe,
.remove = abx500_chargalg_remove,
.driver = {
@@ -2084,9 +2099,6 @@ static struct platform_driver abx500_chargalg_driver = {
.pm = &abx500_chargalg_pm_ops,
},
};
-
-module_platform_driver(abx500_chargalg_driver);
-
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Johan Palsson, Karl Komierowski");
MODULE_ALIAS("platform:abx500-chargalg");