OSDN Git Service

usb: bdc: Add support for USB phy
authorAl Cooper <alcooperx@gmail.com>
Wed, 19 Jul 2017 19:11:48 +0000 (15:11 -0400)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Tue, 15 Aug 2017 11:18:59 +0000 (14:18 +0300)
If a phy is specified in the device tree node, get it and use it.
This was based on a patch by:
"Srinath Mannam <srinath.mannam@broadcom.com>"

Signed-off-by: Al Cooper <alcooperx@gmail.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
drivers/usb/gadget/udc/bdc/bdc.h
drivers/usb/gadget/udc/bdc/bdc_core.c

index 67c5f23..6df0352 100644 (file)
@@ -413,6 +413,9 @@ struct bdc {
        /* device lock */
        spinlock_t      lock;
 
+       /* generic phy */
+       struct phy      **phys;
+       int num_phys;
        /* num of endpoints for a particular instantiation of IP */
        unsigned int num_eps;
        /*
index 2690b6f..7a8af4b 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
 #include <linux/of.h>
+#include <linux/phy/phy.h>
 #include <linux/moduleparam.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -445,6 +446,43 @@ static int bdc_hw_init(struct bdc *bdc)
        return 0;
 }
 
+static int bdc_phy_init(struct bdc *bdc)
+{
+       int phy_num;
+       int ret;
+
+       for (phy_num = 0; phy_num < bdc->num_phys; phy_num++) {
+               ret = phy_init(bdc->phys[phy_num]);
+               if (ret)
+                       goto err_exit_phy;
+               ret = phy_power_on(bdc->phys[phy_num]);
+               if (ret) {
+                       phy_exit(bdc->phys[phy_num]);
+                       goto err_exit_phy;
+               }
+       }
+
+       return 0;
+
+err_exit_phy:
+       while (--phy_num >= 0) {
+               phy_power_off(bdc->phys[phy_num]);
+               phy_exit(bdc->phys[phy_num]);
+       }
+
+       return ret;
+}
+
+static void bdc_phy_exit(struct bdc *bdc)
+{
+       int phy_num;
+
+       for (phy_num = 0; phy_num < bdc->num_phys; phy_num++) {
+               phy_power_off(bdc->phys[phy_num]);
+               phy_exit(bdc->phys[phy_num]);
+       }
+}
+
 static int bdc_probe(struct platform_device *pdev)
 {
        struct bdc *bdc;
@@ -454,6 +492,7 @@ static int bdc_probe(struct platform_device *pdev)
        u32 temp;
        struct device *dev = &pdev->dev;
        struct clk *clk;
+       int phy_num;
 
        dev_dbg(dev, "%s()\n", __func__);
 
@@ -492,6 +531,35 @@ static int bdc_probe(struct platform_device *pdev)
        bdc->dev = dev;
        dev_dbg(dev, "bdc->regs: %p irq=%d\n", bdc->regs, bdc->irq);
 
+       bdc->num_phys = of_count_phandle_with_args(dev->of_node,
+                                               "phys", "#phy-cells");
+       if (bdc->num_phys > 0) {
+               bdc->phys = devm_kcalloc(dev, bdc->num_phys,
+                                       sizeof(struct phy *), GFP_KERNEL);
+               if (!bdc->phys)
+                       return -ENOMEM;
+       } else {
+               bdc->num_phys = 0;
+       }
+       dev_info(dev, "Using %d phy(s)\n", bdc->num_phys);
+
+       for (phy_num = 0; phy_num < bdc->num_phys; phy_num++) {
+               bdc->phys[phy_num] = devm_of_phy_get_by_index(
+                       dev, dev->of_node, phy_num);
+               if (IS_ERR(bdc->phys[phy_num])) {
+                       ret = PTR_ERR(bdc->phys[phy_num]);
+                       dev_err(bdc->dev,
+                               "BDC phy specified but not found:%d\n", ret);
+                       return ret;
+               }
+       }
+
+       ret = bdc_phy_init(bdc);
+       if (ret) {
+               dev_err(bdc->dev, "BDC phy init failure:%d\n", ret);
+               return ret;
+       }
+
        temp = bdc_readl(bdc->regs, BDC_BDCCAP1);
        if ((temp & BDC_P64) &&
                        !dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) {
@@ -508,7 +576,7 @@ static int bdc_probe(struct platform_device *pdev)
        ret = bdc_hw_init(bdc);
        if (ret) {
                dev_err(dev, "BDC init failure:%d\n", ret);
-               return ret;
+               goto phycleanup;
        }
        ret = bdc_udc_init(bdc);
        if (ret) {
@@ -519,7 +587,8 @@ static int bdc_probe(struct platform_device *pdev)
 
 cleanup:
        bdc_hw_exit(bdc);
-
+phycleanup:
+       bdc_phy_exit(bdc);
        return ret;
 }
 
@@ -531,6 +600,7 @@ static int bdc_remove(struct platform_device *pdev)
        dev_dbg(bdc->dev, "%s ()\n", __func__);
        bdc_udc_exit(bdc);
        bdc_hw_exit(bdc);
+       bdc_phy_exit(bdc);
        clk_disable_unprepare(bdc->clk);
        return 0;
 }