++ Felipe Balbi Thanks & Regards, Srinath Mannam. On Thu, Jul 14, 2016 at 2:03 PM, Srinath Mannam <srinath.mannam@xxxxxxxxxxxx> wrote: > Generic phy support added in xhci platform driver. > In the case of multiple phys to the xhci controller, this approach > is helpful to pass multiple phandles to xhci platform driver from > xhci device node. > > Signed-off-by: Srinath Mannam <srinath.mannam@xxxxxxxxxxxx> > Reviewed-by: Ray Jui <ray.jui@xxxxxxxxxxxx> > Reviewed-by: Scott Branden <scott.branden@xxxxxxxxxxxx> > > diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c > index 676ea45..c734e2e 100644 > --- a/drivers/usb/host/xhci-plat.c > +++ b/drivers/usb/host/xhci-plat.c > @@ -15,6 +15,7 @@ > #include <linux/dma-mapping.h> > #include <linux/module.h> > #include <linux/of.h> > +#include <linux/phy/phy.h> > #include <linux/platform_device.h> > #include <linux/usb/phy.h> > #include <linux/slab.h> > @@ -84,6 +85,52 @@ static int xhci_plat_start(struct usb_hcd *hcd) > return xhci_run(hcd); > } > > +static int xhci_platform_phy_on(struct usb_hcd *hcd) > +{ > + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); > + int ret, phy_num; > + > + if (hcd->usb_phy) { > + ret = usb_phy_init(hcd->usb_phy); > + if (ret) > + return ret; > + } > + for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { > + ret = phy_init(priv->phys[phy_num]); > + if (ret) > + goto err_exit_phy; > + ret = phy_power_on(priv->phys[phy_num]); > + if (ret) { > + phy_exit(priv->phys[phy_num]); > + goto err_exit_phy; > + } > + } > + > + return 0; > + > +err_exit_phy: > + while (--phy_num >= 0) { > + phy_power_off(priv->phys[phy_num]); > + phy_exit(priv->phys[phy_num]); > + } > + > + return ret; > +} > + > +static void xhci_platform_phy_off(struct usb_hcd *hcd) > +{ > + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); > + int phy_num; > + > + if (hcd->usb_phy) > + usb_phy_shutdown(hcd->usb_phy); > + > + for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { > + phy_power_off(priv->phys[phy_num]); > + phy_exit(priv->phys[phy_num]); > + } > +} > + > #ifdef CONFIG_OF > static const struct xhci_plat_priv xhci_plat_marvell_armada = { > .init_quirk = xhci_mvebu_mbus_init_quirk, > @@ -146,8 +193,9 @@ static int xhci_plat_probe(struct platform_device *pdev) > struct resource *res; > struct usb_hcd *hcd; > struct clk *clk; > + struct xhci_plat_priv *priv; > int ret; > - int irq; > + int irq, phy_num; > > if (usb_disabled()) > return -ENODEV; > @@ -199,10 +247,10 @@ static int xhci_plat_probe(struct platform_device *pdev) > } > > xhci = hcd_to_xhci(hcd); > + priv = hcd_to_xhci_priv(hcd); > match = of_match_node(usb_xhci_of_match, node); > if (match) { > const struct xhci_plat_priv *priv_match = match->data; > - struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); > > /* Just copy data for now */ > if (priv_match) > @@ -233,12 +281,32 @@ static int xhci_plat_probe(struct platform_device *pdev) > if (ret == -EPROBE_DEFER) > goto put_usb3_hcd; > hcd->usb_phy = NULL; > - } else { > - ret = usb_phy_init(hcd->usb_phy); > - if (ret) > + } > + > + priv->num_phys = of_count_phandle_with_args(pdev->dev.of_node, > + "phys", "#phy-cells"); > + > + if (priv->num_phys > 0) { > + priv->phys = devm_kcalloc(&pdev->dev, priv->num_phys, > + sizeof(struct phy *), GFP_KERNEL); > + if (!priv->phys) > + return -ENOMEM; > + } else > + priv->num_phys = 0; > + > + for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { > + priv->phys[phy_num] = devm_of_phy_get_by_index( > + &pdev->dev, pdev->dev.of_node, phy_num); > + if (IS_ERR(priv->phys[phy_num])) { > + ret = PTR_ERR(priv->phys[phy_num]); > goto put_usb3_hcd; > + } > } > > + ret = xhci_platform_phy_on(hcd); > + if (ret < 0) > + goto put_usb3_hcd; > + > ret = usb_add_hcd(hcd, irq, IRQF_SHARED); > if (ret) > goto disable_usb_phy; > @@ -254,7 +322,7 @@ dealloc_usb2_hcd: > usb_remove_hcd(hcd); > > disable_usb_phy: > - usb_phy_shutdown(hcd->usb_phy); > + xhci_platform_phy_off(hcd); > > put_usb3_hcd: > usb_put_hcd(xhci->shared_hcd); > @@ -276,7 +344,7 @@ static int xhci_plat_remove(struct platform_device *dev) > struct clk *clk = xhci->clk; > > usb_remove_hcd(xhci->shared_hcd); > - usb_phy_shutdown(hcd->usb_phy); > + xhci_platform_phy_off(hcd); > > usb_remove_hcd(hcd); > usb_put_hcd(xhci->shared_hcd); > diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h > index 9af0cb4..1fe9c21 100644 > --- a/drivers/usb/host/xhci-plat.h > +++ b/drivers/usb/host/xhci-plat.h > @@ -15,6 +15,8 @@ > > struct xhci_plat_priv { > const char *firmware_name; > + struct phy **phys; > + int num_phys; > void (*plat_start)(struct usb_hcd *); > int (*init_quirk)(struct usb_hcd *); > }; > -- > 2.9.0 > -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html