Merge branch 'parisc-4.8-1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller...
[cascardo/linux.git] / drivers / power / max8903_charger.c
index 17876ca..fdc73d6 100644 (file)
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <linux/power_supply.h>
 #include <linux/platform_device.h>
 #include <linux/power/max8903_charger.h>
 
 struct max8903_data {
-       struct max8903_pdata pdata;
+       struct max8903_pdata *pdata;
        struct device *dev;
        struct power_supply *psy;
        struct power_supply_desc psy_desc;
@@ -53,8 +56,8 @@ static int max8903_get_property(struct power_supply *psy,
        switch (psp) {
        case POWER_SUPPLY_PROP_STATUS:
                val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
-               if (data->pdata.chg) {
-                       if (gpio_get_value(data->pdata.chg) == 0)
+               if (gpio_is_valid(data->pdata->chg)) {
+                       if (gpio_get_value(data->pdata->chg) == 0)
                                val->intval = POWER_SUPPLY_STATUS_CHARGING;
                        else if (data->usb_in || data->ta_in)
                                val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
@@ -75,13 +78,14 @@ static int max8903_get_property(struct power_supply *psy,
        default:
                return -EINVAL;
        }
+
        return 0;
 }
 
 static irqreturn_t max8903_dcin(int irq, void *_data)
 {
        struct max8903_data *data = _data;
-       struct max8903_pdata *pdata = &data->pdata;
+       struct max8903_pdata *pdata = data->pdata;
        bool ta_in;
        enum power_supply_type old_type;
 
@@ -93,11 +97,11 @@ static irqreturn_t max8903_dcin(int irq, void *_data)
        data->ta_in = ta_in;
 
        /* Set Current-Limit-Mode 1:DC 0:USB */
-       if (pdata->dcm)
+       if (gpio_is_valid(pdata->dcm))
                gpio_set_value(pdata->dcm, ta_in ? 1 : 0);
 
        /* Charger Enable / Disable (cen is negated) */
-       if (pdata->cen)
+       if (gpio_is_valid(pdata->cen))
                gpio_set_value(pdata->cen, ta_in ? 0 :
                                (data->usb_in ? 0 : 1));
 
@@ -122,7 +126,7 @@ static irqreturn_t max8903_dcin(int irq, void *_data)
 static irqreturn_t max8903_usbin(int irq, void *_data)
 {
        struct max8903_data *data = _data;
-       struct max8903_pdata *pdata = &data->pdata;
+       struct max8903_pdata *pdata = data->pdata;
        bool usb_in;
        enum power_supply_type old_type;
 
@@ -136,7 +140,7 @@ static irqreturn_t max8903_usbin(int irq, void *_data)
        /* Do not touch Current-Limit-Mode */
 
        /* Charger Enable / Disable (cen is negated) */
-       if (pdata->cen)
+       if (gpio_is_valid(pdata->cen))
                gpio_set_value(pdata->cen, usb_in ? 0 :
                                (data->ta_in ? 0 : 1));
 
@@ -161,7 +165,7 @@ static irqreturn_t max8903_usbin(int irq, void *_data)
 static irqreturn_t max8903_fault(int irq, void *_data)
 {
        struct max8903_data *data = _data;
-       struct max8903_pdata *pdata = &data->pdata;
+       struct max8903_pdata *pdata = data->pdata;
        bool fault;
 
        fault = gpio_get_value(pdata->flt) ? false : true;
@@ -179,57 +183,109 @@ static irqreturn_t max8903_fault(int irq, void *_data)
        return IRQ_HANDLED;
 }
 
-static int max8903_probe(struct platform_device *pdev)
+static struct max8903_pdata *max8903_parse_dt_data(struct device *dev)
 {
-       struct max8903_data *data;
+       struct device_node *np = dev->of_node;
+       struct max8903_pdata *pdata = NULL;
+
+       if (!np)
+               return NULL;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return NULL;
+
+       pdata->dc_valid = false;
+       pdata->usb_valid = false;
+
+       pdata->cen = of_get_named_gpio(np, "cen-gpios", 0);
+       if (!gpio_is_valid(pdata->cen))
+               pdata->cen = -EINVAL;
+
+       pdata->chg = of_get_named_gpio(np, "chg-gpios", 0);
+       if (!gpio_is_valid(pdata->chg))
+               pdata->chg = -EINVAL;
+
+       pdata->flt = of_get_named_gpio(np, "flt-gpios", 0);
+       if (!gpio_is_valid(pdata->flt))
+               pdata->flt = -EINVAL;
+
+       pdata->usus = of_get_named_gpio(np, "usus-gpios", 0);
+       if (!gpio_is_valid(pdata->usus))
+               pdata->usus = -EINVAL;
+
+       pdata->dcm = of_get_named_gpio(np, "dcm-gpios", 0);
+       if (!gpio_is_valid(pdata->dcm))
+               pdata->dcm = -EINVAL;
+
+       pdata->dok = of_get_named_gpio(np, "dok-gpios", 0);
+       if (!gpio_is_valid(pdata->dok))
+               pdata->dok = -EINVAL;
+       else
+               pdata->dc_valid = true;
+
+       pdata->uok = of_get_named_gpio(np, "uok-gpios", 0);
+       if (!gpio_is_valid(pdata->uok))
+               pdata->uok = -EINVAL;
+       else
+               pdata->usb_valid = true;
+
+       return pdata;
+}
+
+static int max8903_setup_gpios(struct platform_device *pdev)
+{
+       struct max8903_data *data = platform_get_drvdata(pdev);
        struct device *dev = &pdev->dev;
        struct max8903_pdata *pdata = pdev->dev.platform_data;
-       struct power_supply_config psy_cfg = {};
        int ret = 0;
        int gpio;
        int ta_in = 0;
        int usb_in = 0;
 
-       data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL);
-       if (data == NULL) {
-               dev_err(dev, "Cannot allocate memory.\n");
-               return -ENOMEM;
-       }
-       memcpy(&data->pdata, pdata, sizeof(struct max8903_pdata));
-       data->dev = dev;
-       platform_set_drvdata(pdev, data);
-
-       if (pdata->dc_valid == false && pdata->usb_valid == false) {
-               dev_err(dev, "No valid power sources.\n");
-               return -EINVAL;
-       }
-
        if (pdata->dc_valid) {
-               if (pdata->dok && gpio_is_valid(pdata->dok) &&
-                               pdata->dcm && gpio_is_valid(pdata->dcm)) {
+               if (gpio_is_valid(pdata->dok)) {
+                       ret = devm_gpio_request(dev, pdata->dok,
+                                               data->psy_desc.name);
+                       if (ret) {
+                               dev_err(dev,
+                                       "Failed GPIO request for dok: %d err %d\n",
+                                       pdata->dok, ret);
+                               return ret;
+                       }
+
                        gpio = pdata->dok; /* PULL_UPed Interrupt */
                        ta_in = gpio_get_value(gpio) ? 0 : 1;
-
-                       gpio = pdata->dcm; /* Output */
-                       gpio_set_value(gpio, ta_in);
                } else {
-                       dev_err(dev, "When DC is wired, DOK and DCM should"
-                                       " be wired as well.\n");
+                       dev_err(dev, "When DC is wired, DOK should be wired as well.\n");
                        return -EINVAL;
                }
-       } else {
-               if (pdata->dcm) {
-                       if (gpio_is_valid(pdata->dcm))
-                               gpio_set_value(pdata->dcm, 0);
-                       else {
-                               dev_err(dev, "Invalid pin: dcm.\n");
-                               return -EINVAL;
-                       }
+       }
+
+       if (gpio_is_valid(pdata->dcm)) {
+               ret = devm_gpio_request(dev, pdata->dcm, data->psy_desc.name);
+               if (ret) {
+                       dev_err(dev,
+                               "Failed GPIO request for dcm: %d err %d\n",
+                               pdata->dcm, ret);
+                       return ret;
                }
+
+               gpio = pdata->dcm; /* Output */
+               gpio_set_value(gpio, ta_in);
        }
 
        if (pdata->usb_valid) {
-               if (pdata->uok && gpio_is_valid(pdata->uok)) {
+               if (gpio_is_valid(pdata->uok)) {
+                       ret = devm_gpio_request(dev, pdata->uok,
+                                               data->psy_desc.name);
+                       if (ret) {
+                               dev_err(dev,
+                                       "Failed GPIO request for uok: %d err %d\n",
+                                       pdata->uok, ret);
+                               return ret;
+                       }
+
                        gpio = pdata->uok;
                        usb_in = gpio_get_value(gpio) ? 0 : 1;
                } else {
@@ -239,33 +295,45 @@ static int max8903_probe(struct platform_device *pdev)
                }
        }
 
-       if (pdata->cen) {
-               if (gpio_is_valid(pdata->cen)) {
-                       gpio_set_value(pdata->cen, (ta_in || usb_in) ? 0 : 1);
-               } else {
-                       dev_err(dev, "Invalid pin: cen.\n");
-                       return -EINVAL;
+       if (gpio_is_valid(pdata->cen)) {
+               ret = devm_gpio_request(dev, pdata->cen, data->psy_desc.name);
+               if (ret) {
+                       dev_err(dev,
+                               "Failed GPIO request for cen: %d err %d\n",
+                               pdata->cen, ret);
+                       return ret;
                }
+
+               gpio_set_value(pdata->cen, (ta_in || usb_in) ? 0 : 1);
        }
 
-       if (pdata->chg) {
-               if (!gpio_is_valid(pdata->chg)) {
-                       dev_err(dev, "Invalid pin: chg.\n");
-                       return -EINVAL;
+       if (gpio_is_valid(pdata->chg)) {
+               ret = devm_gpio_request(dev, pdata->chg, data->psy_desc.name);
+               if (ret) {
+                       dev_err(dev,
+                               "Failed GPIO request for chg: %d err %d\n",
+                               pdata->chg, ret);
+                       return ret;
                }
        }
 
-       if (pdata->flt) {
-               if (!gpio_is_valid(pdata->flt)) {
-                       dev_err(dev, "Invalid pin: flt.\n");
-                       return -EINVAL;
+       if (gpio_is_valid(pdata->flt)) {
+               ret = devm_gpio_request(dev, pdata->flt, data->psy_desc.name);
+               if (ret) {
+                       dev_err(dev,
+                               "Failed GPIO request for flt: %d err %d\n",
+                               pdata->flt, ret);
+                       return ret;
                }
        }
 
-       if (pdata->usus) {
-               if (!gpio_is_valid(pdata->usus)) {
-                       dev_err(dev, "Invalid pin: usus.\n");
-                       return -EINVAL;
+       if (gpio_is_valid(pdata->usus)) {
+               ret = devm_gpio_request(dev, pdata->usus, data->psy_desc.name);
+               if (ret) {
+                       dev_err(dev,
+                               "Failed GPIO request for usus: %d err %d\n",
+                               pdata->usus, ret);
+                       return ret;
                }
        }
 
@@ -273,14 +341,52 @@ static int max8903_probe(struct platform_device *pdev)
        data->ta_in = ta_in;
        data->usb_in = usb_in;
 
+       return 0;
+}
+
+static int max8903_probe(struct platform_device *pdev)
+{
+       struct max8903_data *data;
+       struct device *dev = &pdev->dev;
+       struct max8903_pdata *pdata = pdev->dev.platform_data;
+       struct power_supply_config psy_cfg = {};
+       int ret = 0;
+
+       data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       if (IS_ENABLED(CONFIG_OF) && !pdata && dev->of_node)
+               pdata = max8903_parse_dt_data(dev);
+
+       if (!pdata) {
+               dev_err(dev, "No platform data.\n");
+               return -EINVAL;
+       }
+
+       pdev->dev.platform_data = pdata;
+       data->pdata = pdata;
+       data->dev = dev;
+       platform_set_drvdata(pdev, data);
+
+       if (pdata->dc_valid == false && pdata->usb_valid == false) {
+               dev_err(dev, "No valid power sources.\n");
+               return -EINVAL;
+       }
+
+       ret = max8903_setup_gpios(pdev);
+       if (ret)
+               return ret;
+
        data->psy_desc.name = "max8903_charger";
-       data->psy_desc.type = (ta_in) ? POWER_SUPPLY_TYPE_MAINS :
-                       ((usb_in) ? POWER_SUPPLY_TYPE_USB :
+       data->psy_desc.type = (data->ta_in) ? POWER_SUPPLY_TYPE_MAINS :
+                       ((data->usb_in) ? POWER_SUPPLY_TYPE_USB :
                         POWER_SUPPLY_TYPE_BATTERY);
        data->psy_desc.get_property = max8903_get_property;
        data->psy_desc.properties = max8903_charger_props;
        data->psy_desc.num_properties = ARRAY_SIZE(max8903_charger_props);
 
+       psy_cfg.of_node = dev->of_node;
        psy_cfg.drv_data = data;
 
        data->psy = devm_power_supply_register(dev, &data->psy_desc, &psy_cfg);
@@ -315,7 +421,7 @@ static int max8903_probe(struct platform_device *pdev)
                }
        }
 
-       if (pdata->flt) {
+       if (gpio_is_valid(pdata->flt)) {
                ret = devm_request_threaded_irq(dev, gpio_to_irq(pdata->flt),
                                        NULL, max8903_fault,
                                        IRQF_TRIGGER_FALLING |
@@ -331,10 +437,17 @@ static int max8903_probe(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id max8903_match_ids[] = {
+       { .compatible = "maxim,max8903", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, max8903_match_ids);
+
 static struct platform_driver max8903_driver = {
        .probe  = max8903_probe,
        .driver = {
                .name   = "max8903-charger",
+               .of_match_table = max8903_match_ids
        },
 };