Re: [PATCH] usb: xhci-plat: Add generic PHY support
From: Srinath Mannam
Date: Thu Jul 14 2016 - 04:39:13 EST
++ 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
>