power: supply: twl4030-charger: add deferred probing for phy and iio
[sfrench/cifs-2.6.git] / drivers / power / supply / twl4030_charger.c
index 2f82d0e9ec1bf7eaf879a57faa3b1da14303d99c..9dff1b4b85fc3b362da95df884c80c4e959a7a27 100644 (file)
@@ -153,7 +153,7 @@ struct twl4030_bci {
 };
 
 /* strings for 'usb_mode' values */
-static char *modes[] = { "off", "auto", "continuous" };
+static const char *modes[] = { "off", "auto", "continuous" };
 
 /*
  * clear and set bits on an given register on a given module
@@ -624,63 +624,6 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
-/*
- * Provide "max_current" attribute in sysfs.
- */
-static ssize_t
-twl4030_bci_max_current_store(struct device *dev, struct device_attribute *attr,
-       const char *buf, size_t n)
-{
-       struct twl4030_bci *bci = dev_get_drvdata(dev->parent);
-       int cur = 0;
-       int status = 0;
-       status = kstrtoint(buf, 10, &cur);
-       if (status)
-               return status;
-       if (cur < 0)
-               return -EINVAL;
-       if (dev == &bci->ac->dev)
-               bci->ac_cur = cur;
-       else
-               bci->usb_cur_target = cur;
-
-       twl4030_charger_update_current(bci);
-       return n;
-}
-
-/*
- * sysfs max_current show
- */
-static ssize_t twl4030_bci_max_current_show(struct device *dev,
-       struct device_attribute *attr, char *buf)
-{
-       int status = 0;
-       int cur = -1;
-       u8 bcictl1;
-       struct twl4030_bci *bci = dev_get_drvdata(dev->parent);
-
-       if (dev == &bci->ac->dev) {
-               if (!bci->ac_is_active)
-                       cur = bci->ac_cur;
-       } else {
-               if (bci->ac_is_active)
-                       cur = bci->usb_cur_target;
-       }
-       if (cur < 0) {
-               cur = twl4030bci_read_adc_val(TWL4030_BCIIREF1);
-               if (cur < 0)
-                       return cur;
-               status = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1);
-               if (status < 0)
-                       return status;
-               cur = regval2ua(cur, bcictl1 & TWL4030_CGAIN);
-       }
-       return scnprintf(buf, PAGE_SIZE, "%u\n", cur);
-}
-
-static DEVICE_ATTR(max_current, 0644, twl4030_bci_max_current_show,
-                       twl4030_bci_max_current_store);
-
 static void twl4030_bci_usb_work(struct work_struct *data)
 {
        struct twl4030_bci *bci = container_of(data, struct twl4030_bci, work);
@@ -726,14 +669,10 @@ twl4030_bci_mode_store(struct device *dev, struct device_attribute *attr,
        int mode;
        int status;
 
-       if (sysfs_streq(buf, modes[0]))
-               mode = 0;
-       else if (sysfs_streq(buf, modes[1]))
-               mode = 1;
-       else if (sysfs_streq(buf, modes[2]))
-               mode = 2;
-       else
-               return -EINVAL;
+       mode = sysfs_match_string(modes, buf);
+       if (mode < 0)
+               return mode;
+
        if (dev == &bci->ac->dev) {
                if (mode == 2)
                        return -EINVAL;
@@ -1041,6 +980,39 @@ static int twl4030_bci_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, bci);
 
+       INIT_WORK(&bci->work, twl4030_bci_usb_work);
+       INIT_DELAYED_WORK(&bci->current_worker, twl4030_current_worker);
+
+       bci->channel_vac = devm_iio_channel_get(&pdev->dev, "vac");
+       if (IS_ERR(bci->channel_vac)) {
+               ret = PTR_ERR(bci->channel_vac);
+               if (ret == -EPROBE_DEFER)
+                       return ret;     /* iio not ready */
+               dev_warn(&pdev->dev, "could not request vac iio channel (%d)",
+                       ret);
+               bci->channel_vac = NULL;
+       }
+
+       if (bci->dev->of_node) {
+               struct device_node *phynode;
+
+               phynode = of_find_compatible_node(bci->dev->of_node->parent,
+                                                 NULL, "ti,twl4030-usb");
+               if (phynode) {
+                       bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
+                       bci->transceiver = devm_usb_get_phy_by_node(
+                               bci->dev, phynode, &bci->usb_nb);
+                       if (IS_ERR(bci->transceiver)) {
+                               ret = PTR_ERR(bci->transceiver);
+                               if (ret == -EPROBE_DEFER)
+                                       return ret;     /* phy not ready */
+                               dev_warn(&pdev->dev, "could not request transceiver (%d)",
+                                       ret);
+                               bci->transceiver = NULL;
+                       }
+               }
+       }
+
        bci->ac = devm_power_supply_register(&pdev->dev, &twl4030_bci_ac_desc,
                                             NULL);
        if (IS_ERR(bci->ac)) {
@@ -1074,26 +1046,6 @@ static int twl4030_bci_probe(struct platform_device *pdev)
                return ret;
        }
 
-       bci->channel_vac = iio_channel_get(&pdev->dev, "vac");
-       if (IS_ERR(bci->channel_vac)) {
-               bci->channel_vac = NULL;
-               dev_warn(&pdev->dev, "could not request vac iio channel");
-       }
-
-       INIT_WORK(&bci->work, twl4030_bci_usb_work);
-       INIT_DELAYED_WORK(&bci->current_worker, twl4030_current_worker);
-
-       bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
-       if (bci->dev->of_node) {
-               struct device_node *phynode;
-
-               phynode = of_find_compatible_node(bci->dev->of_node->parent,
-                                                 NULL, "ti,twl4030-usb");
-               if (phynode)
-                       bci->transceiver = devm_usb_get_phy_by_node(
-                               bci->dev, phynode, &bci->usb_nb);
-       }
-
        /* Enable interrupts now. */
        reg = ~(u32)(TWL4030_ICHGLOW | TWL4030_ICHGEOC | TWL4030_TBATOR2 |
                TWL4030_TBATOR1 | TWL4030_BATSTS);
@@ -1101,7 +1053,7 @@ static int twl4030_bci_probe(struct platform_device *pdev)
                               TWL4030_INTERRUPTS_BCIIMR1A);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to unmask interrupts: %d\n", ret);
-               goto fail;
+               return ret;
        }
 
        reg = ~(u32)(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV);
@@ -1111,14 +1063,10 @@ static int twl4030_bci_probe(struct platform_device *pdev)
                dev_warn(&pdev->dev, "failed to unmask interrupts: %d\n", ret);
 
        twl4030_charger_update_current(bci);
-       if (device_create_file(&bci->usb->dev, &dev_attr_max_current))
-               dev_warn(&pdev->dev, "could not create sysfs file\n");
        if (device_create_file(&bci->usb->dev, &dev_attr_mode))
                dev_warn(&pdev->dev, "could not create sysfs file\n");
        if (device_create_file(&bci->ac->dev, &dev_attr_mode))
                dev_warn(&pdev->dev, "could not create sysfs file\n");
-       if (device_create_file(&bci->ac->dev, &dev_attr_max_current))
-               dev_warn(&pdev->dev, "could not create sysfs file\n");
 
        twl4030_charger_enable_ac(bci, true);
        if (!IS_ERR_OR_NULL(bci->transceiver))
@@ -1134,10 +1082,6 @@ static int twl4030_bci_probe(struct platform_device *pdev)
                twl4030_charger_enable_backup(0, 0);
 
        return 0;
-fail:
-       iio_channel_release(bci->channel_vac);
-
-       return ret;
 }
 
 static int twl4030_bci_remove(struct platform_device *pdev)
@@ -1148,11 +1092,7 @@ static int twl4030_bci_remove(struct platform_device *pdev)
        twl4030_charger_enable_usb(bci, false);
        twl4030_charger_enable_backup(0, 0);
 
-       iio_channel_release(bci->channel_vac);
-
-       device_remove_file(&bci->usb->dev, &dev_attr_max_current);
        device_remove_file(&bci->usb->dev, &dev_attr_mode);
-       device_remove_file(&bci->ac->dev, &dev_attr_max_current);
        device_remove_file(&bci->ac->dev, &dev_attr_mode);
        /* mask interrupts */
        twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,