]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/power/bq2415x_charger.c
video: mxc: ldb: sanitize error messages
[karo-tx-linux.git] / drivers / power / bq2415x_charger.c
index df893dd1447d1534695ace9405e4783ec49fd79d..79a37f6d3307290f6cc12cc9be2d818087ab2c7e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * bq2415x charger driver
  *
- * Copyright (C) 2011-2012  Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (C) 2011-2013  Pali Rohár <pali.rohar@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -170,6 +170,8 @@ struct bq2415x_device {
        struct bq2415x_platform_data init_data;
        struct power_supply charger;
        struct delayed_work work;
+       struct power_supply *notify_psy;
+       struct notifier_block nb;
        enum bq2415x_mode reported_mode;/* mode reported by hook function */
        enum bq2415x_mode mode;         /* current configured mode */
        enum bq2415x_chip chip;
@@ -795,24 +797,53 @@ static int bq2415x_set_mode(struct bq2415x_device *bq, enum bq2415x_mode mode)
 
 }
 
-/* hook function called by other driver which set reported mode */
-static void bq2415x_hook_function(enum bq2415x_mode mode, void *data)
+static int bq2415x_notifier_call(struct notifier_block *nb,
+               unsigned long val, void *v)
 {
-       struct bq2415x_device *bq = data;
+       struct bq2415x_device *bq =
+               container_of(nb, struct bq2415x_device, nb);
+       struct power_supply *psy = v;
+       enum bq2415x_mode mode;
+       union power_supply_propval prop;
+       int ret;
+       int mA;
 
-       if (!bq)
-               return;
+       if (val != PSY_EVENT_PROP_CHANGED)
+               return NOTIFY_OK;
+
+       if (psy != bq->notify_psy)
+               return NOTIFY_OK;
+
+       dev_dbg(bq->dev, "notifier call was called\n");
+
+       ret = psy->get_property(psy, POWER_SUPPLY_PROP_CURRENT_MAX, &prop);
+       if (ret != 0)
+               return NOTIFY_OK;
+
+       mA = prop.intval;
+
+       if (mA == 0)
+               mode = BQ2415X_MODE_OFF;
+       else if (mA < 500)
+               mode = BQ2415X_MODE_NONE;
+       else if (mA < 1800)
+               mode = BQ2415X_MODE_HOST_CHARGER;
+       else
+               mode = BQ2415X_MODE_DEDICATED_CHARGER;
+
+       if (bq->reported_mode == mode)
+               return NOTIFY_OK;
 
-       dev_dbg(bq->dev, "hook function was called\n");
        bq->reported_mode = mode;
 
        /* if automode is not enabled do not tell about reported_mode */
        if (bq->automode < 1)
-               return;
+               return NOTIFY_OK;
 
        sysfs_notify(&bq->charger.dev->kobj, NULL, "reported_mode");
        bq2415x_set_mode(bq, bq->reported_mode);
 
+       return NOTIFY_OK;
 }
 
 /**** timer functions ****/
@@ -1512,9 +1543,11 @@ static int bq2415x_probe(struct i2c_client *client,
        int num;
        char *name;
        struct bq2415x_device *bq;
+       struct device_node *np = client->dev.of_node;
+       struct bq2415x_platform_data *pdata = client->dev.platform_data;
 
-       if (!client->dev.platform_data) {
-               dev_err(&client->dev, "platform data not set\n");
+       if (!np && !pdata) {
+               dev_err(&client->dev, "platform data missing\n");
                return -ENODEV;
        }
 
@@ -1539,6 +1572,17 @@ static int bq2415x_probe(struct i2c_client *client,
                goto error_2;
        }
 
+       if (np) {
+               bq->notify_psy = power_supply_get_by_phandle(np, "ti,usb-charger-detection");
+
+               if (!bq->notify_psy)
+                       return -EPROBE_DEFER;
+       }
+       else if (pdata->notify_device)
+               bq->notify_psy = power_supply_get_by_name(pdata->notify_device);
+       else
+               bq->notify_psy = NULL;
+
        i2c_set_clientdata(client, bq);
 
        bq->id = num;
@@ -1550,8 +1594,34 @@ static int bq2415x_probe(struct i2c_client *client,
        bq->autotimer = 0;
        bq->automode = 0;
 
-       memcpy(&bq->init_data, client->dev.platform_data,
-                       sizeof(bq->init_data));
+       if (np) {
+               ret = of_property_read_u32(np, "ti,current-limit",
+                               &bq->init_data.current_limit);
+               if (ret)
+                       return ret;
+               ret = of_property_read_u32(np, "ti,weak-battery-voltage",
+                               &bq->init_data.weak_battery_voltage);
+               if (ret)
+                       return ret;
+               ret = of_property_read_u32(np, "ti,battery-regulation-voltage",
+                               &bq->init_data.battery_regulation_voltage);
+               if (ret)
+                       return ret;
+               ret = of_property_read_u32(np, "ti,charge-current",
+                               &bq->init_data.charge_current);
+               if (ret)
+                       return ret;
+               ret = of_property_read_u32(np, "ti,termination-current",
+                               &bq->init_data.termination_current);
+               if (ret)
+                       return ret;
+               ret = of_property_read_u32(np, "ti,resistor-sense",
+                               &bq->init_data.resistor_sense);
+               if (ret)
+                       return ret;
+       } else {
+               memcpy(&bq->init_data, pdata, sizeof(bq->init_data));
+       }
 
        bq2415x_reset_chip(bq);
 
@@ -1573,16 +1643,20 @@ static int bq2415x_probe(struct i2c_client *client,
                goto error_4;
        }
 
-       if (bq->init_data.set_mode_hook) {
-               if (bq->init_data.set_mode_hook(
-                               bq2415x_hook_function, bq)) {
-                       bq->automode = 1;
-                       bq2415x_set_mode(bq, bq->reported_mode);
-                       dev_info(bq->dev, "automode enabled\n");
-               } else {
-                       bq->automode = -1;
-                       dev_info(bq->dev, "automode failed\n");
+       if (bq->notify_psy) {
+               bq->nb.notifier_call = bq2415x_notifier_call;
+               ret = power_supply_reg_notifier(&bq->nb);
+               if (ret) {
+                       dev_err(bq->dev, "failed to reg notifier: %d\n", ret);
+                       goto error_5;
                }
+
+               /* Query for initial reported_mode and set it */
+               bq2415x_notifier_call(&bq->nb, PSY_EVENT_PROP_CHANGED, bq->notify_psy);
+               bq2415x_set_mode(bq, bq->reported_mode);
+
+               bq->automode = 1;
+               dev_info(bq->dev, "automode enabled\n");
        } else {
                bq->automode = -1;
                dev_info(bq->dev, "automode not supported\n");
@@ -1594,6 +1668,7 @@ static int bq2415x_probe(struct i2c_client *client,
        dev_info(bq->dev, "driver registered\n");
        return 0;
 
+error_5:
 error_4:
        bq2415x_sysfs_exit(bq);
 error_3:
@@ -1614,8 +1689,8 @@ static int bq2415x_remove(struct i2c_client *client)
 {
        struct bq2415x_device *bq = i2c_get_clientdata(client);
 
-       if (bq->init_data.set_mode_hook)
-               bq->init_data.set_mode_hook(NULL, NULL);
+       if (bq->notify_psy)
+               power_supply_unreg_notifier(&bq->nb);
 
        bq2415x_sysfs_exit(bq);
        bq2415x_power_supply_exit(bq);