Re: [PATCH v2 19/22] usb: chipidea: msm: Handle phy power states

2016-07-10 Thread Peter Chen
On Thu, Jul 07, 2016 at 03:21:10PM -0700, Stephen Boyd wrote:
> The ULPI phy on qcom platforms needs to be initialized and
> powered on after a USB reset and before we toggle the run/stop
> bit. Otherwise, the phy locks up and doesn't work properly. Hook
> the phy initialization into the RESET event and the phy power off
> into the STOPPED event.
> 
> Cc: Peter Chen 
> Cc: Greg Kroah-Hartman 
> ---
>  drivers/usb/chipidea/ci_hdrc_msm.c | 40 
> +++---
>  drivers/usb/chipidea/core.c|  8 ++--
>  drivers/usb/chipidea/host.c|  8 ++--
>  include/linux/usb/chipidea.h   |  2 +-
>  4 files changed, 33 insertions(+), 25 deletions(-)
> 
> diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c 
> b/drivers/usb/chipidea/ci_hdrc_msm.c
> index ab6a7713ee5c..5c486c15e043 100644
> --- a/drivers/usb/chipidea/ci_hdrc_msm.c
> +++ b/drivers/usb/chipidea/ci_hdrc_msm.c
> @@ -75,20 +75,33 @@ static const struct reset_control_ops 
> ci_hdrc_msm_reset_ops = {
>   .reset = ci_hdrc_msm_por_reset,
>  };
>  
> -static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
> +static int ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
>  {
>   struct device *dev = ci->dev->parent;
>   struct ci_hdrc_msm *msm_ci = dev_get_drvdata(dev);
> + int ret;
>  
>   switch (event) {
>   case CI_HDRC_CONTROLLER_RESET_EVENT:
>   dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n");
> +
> + hw_phymode_configure(ci);
>   if (msm_ci->secondary_phy) {
>   u32 val = readl_relaxed(msm_ci->base + HS_PHY_SEC_CTRL);
>   val |= HS_PHY_DIG_CLAMP_N;
>   writel_relaxed(val, msm_ci->base + HS_PHY_SEC_CTRL);
>   }
>  
> + ret = phy_init(ci->phy);
> + if (ret)
> + return ret;
> +
> + ret = phy_power_on(ci->phy);
> + if (ret) {
> + phy_exit(ci->phy);
> + return ret;
> + }
> +
>   /* use AHB transactor, allow posted data writes */
>   hw_write_id_reg(ci, HS_PHY_AHB_MODE, 0x, 0x8);
>  
> @@ -108,21 +121,18 @@ static void ci_hdrc_msm_notify_event(struct ci_hdrc 
> *ci, unsigned event)
>HSPHY_SESS_VLD_CTRL);
>  
>   }
> -
> - usb_phy_init(ci->usb_phy);
>   break;
>   case CI_HDRC_CONTROLLER_STOPPED_EVENT:
>   dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n");
> - /*
> -  * Put the phy in non-driving mode. Otherwise host
> -  * may not detect soft-disconnection.
> -  */
> - usb_phy_notify_disconnect(ci->usb_phy, USB_SPEED_UNKNOWN);
> + phy_power_off(ci->phy);
> + phy_exit(ci->phy);
>   break;
>   default:
>   dev_dbg(dev, "unknown ci_hdrc event\n");
>   break;
>   }
> +
> + return 0;
>  }
>  
>  static int ci_hdrc_msm_mux_phy(struct ci_hdrc_msm *ci,
> @@ -162,7 +172,6 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)
>  {
>   struct ci_hdrc_msm *ci;
>   struct platform_device *plat_ci;
> - struct usb_phy *phy;
>   struct clk *clk;
>   struct reset_control *reset;
>   struct resource *res;
> @@ -176,21 +185,12 @@ static int ci_hdrc_msm_probe(struct platform_device 
> *pdev)
>   return -ENOMEM;
>   platform_set_drvdata(pdev, ci);
>  
> - /*
> -  * OTG(PHY) driver takes care of PHY initialization, clock management,
> -  * powering up VBUS, mapping of registers address space and power
> -  * management.
> -  */
> - phy = devm_usb_get_phy_by_phandle(>dev, "usb-phy", 0);
> - if (IS_ERR(phy))
> - return PTR_ERR(phy);
> -
>   ci->pdata.name = "ci_hdrc_msm";
>   ci->pdata.capoffset = DEF_CAPOFFSET;
>   ci->pdata.flags = CI_HDRC_REGS_SHARED | CI_HDRC_DISABLE_STREAMING |
> -   CI_HDRC_OVERRIDE_AHB_BURST;
> +   CI_HDRC_OVERRIDE_AHB_BURST |
> +   CI_HDRC_OVERRIDE_PHY_CONTROL;
>   ci->pdata.notify_event = ci_hdrc_msm_notify_event;
> - ci->pdata.usb_phy = phy;
>  
>   reset = devm_reset_control_get(>dev, "core");
>   if (IS_ERR(reset))
> diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
> index f144e1bbcc82..0866c03d66df 100644
> --- a/drivers/usb/chipidea/core.c
> +++ b/drivers/usb/chipidea/core.c
> @@ -327,6 +327,7 @@ void hw_phymode_configure(struct ci_hdrc *ci)
>   hw_write(ci, OP_PORTSC, PORTSC_STS, PORTSC_STS);
>   }
>  }
> +EXPORT_SYMBOL_GPL(hw_phymode_configure);
>  
>  /**
>   * _ci_usb_phy_init: initialize phy taking in account both phy and usb_phy
> @@ -503,9 +504,12 @@ int hw_device_reset(struct ci_hdrc *ci)
>   

Re: [PATCH v2 19/22] usb: chipidea: msm: Handle phy power states

2016-07-10 Thread Peter Chen
On Thu, Jul 07, 2016 at 03:21:10PM -0700, Stephen Boyd wrote:
> The ULPI phy on qcom platforms needs to be initialized and
> powered on after a USB reset and before we toggle the run/stop
> bit. Otherwise, the phy locks up and doesn't work properly. Hook
> the phy initialization into the RESET event and the phy power off
> into the STOPPED event.
> 
> Cc: Peter Chen 
> Cc: Greg Kroah-Hartman 
> ---
>  drivers/usb/chipidea/ci_hdrc_msm.c | 40 
> +++---
>  drivers/usb/chipidea/core.c|  8 ++--
>  drivers/usb/chipidea/host.c|  8 ++--
>  include/linux/usb/chipidea.h   |  2 +-
>  4 files changed, 33 insertions(+), 25 deletions(-)
> 
> diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c 
> b/drivers/usb/chipidea/ci_hdrc_msm.c
> index ab6a7713ee5c..5c486c15e043 100644
> --- a/drivers/usb/chipidea/ci_hdrc_msm.c
> +++ b/drivers/usb/chipidea/ci_hdrc_msm.c
> @@ -75,20 +75,33 @@ static const struct reset_control_ops 
> ci_hdrc_msm_reset_ops = {
>   .reset = ci_hdrc_msm_por_reset,
>  };
>  
> -static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
> +static int ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
>  {
>   struct device *dev = ci->dev->parent;
>   struct ci_hdrc_msm *msm_ci = dev_get_drvdata(dev);
> + int ret;
>  
>   switch (event) {
>   case CI_HDRC_CONTROLLER_RESET_EVENT:
>   dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n");
> +
> + hw_phymode_configure(ci);
>   if (msm_ci->secondary_phy) {
>   u32 val = readl_relaxed(msm_ci->base + HS_PHY_SEC_CTRL);
>   val |= HS_PHY_DIG_CLAMP_N;
>   writel_relaxed(val, msm_ci->base + HS_PHY_SEC_CTRL);
>   }
>  
> + ret = phy_init(ci->phy);
> + if (ret)
> + return ret;
> +
> + ret = phy_power_on(ci->phy);
> + if (ret) {
> + phy_exit(ci->phy);
> + return ret;
> + }
> +
>   /* use AHB transactor, allow posted data writes */
>   hw_write_id_reg(ci, HS_PHY_AHB_MODE, 0x, 0x8);
>  
> @@ -108,21 +121,18 @@ static void ci_hdrc_msm_notify_event(struct ci_hdrc 
> *ci, unsigned event)
>HSPHY_SESS_VLD_CTRL);
>  
>   }
> -
> - usb_phy_init(ci->usb_phy);
>   break;
>   case CI_HDRC_CONTROLLER_STOPPED_EVENT:
>   dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n");
> - /*
> -  * Put the phy in non-driving mode. Otherwise host
> -  * may not detect soft-disconnection.
> -  */
> - usb_phy_notify_disconnect(ci->usb_phy, USB_SPEED_UNKNOWN);
> + phy_power_off(ci->phy);
> + phy_exit(ci->phy);
>   break;
>   default:
>   dev_dbg(dev, "unknown ci_hdrc event\n");
>   break;
>   }
> +
> + return 0;
>  }
>  
>  static int ci_hdrc_msm_mux_phy(struct ci_hdrc_msm *ci,
> @@ -162,7 +172,6 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)
>  {
>   struct ci_hdrc_msm *ci;
>   struct platform_device *plat_ci;
> - struct usb_phy *phy;
>   struct clk *clk;
>   struct reset_control *reset;
>   struct resource *res;
> @@ -176,21 +185,12 @@ static int ci_hdrc_msm_probe(struct platform_device 
> *pdev)
>   return -ENOMEM;
>   platform_set_drvdata(pdev, ci);
>  
> - /*
> -  * OTG(PHY) driver takes care of PHY initialization, clock management,
> -  * powering up VBUS, mapping of registers address space and power
> -  * management.
> -  */
> - phy = devm_usb_get_phy_by_phandle(>dev, "usb-phy", 0);
> - if (IS_ERR(phy))
> - return PTR_ERR(phy);
> -
>   ci->pdata.name = "ci_hdrc_msm";
>   ci->pdata.capoffset = DEF_CAPOFFSET;
>   ci->pdata.flags = CI_HDRC_REGS_SHARED | CI_HDRC_DISABLE_STREAMING |
> -   CI_HDRC_OVERRIDE_AHB_BURST;
> +   CI_HDRC_OVERRIDE_AHB_BURST |
> +   CI_HDRC_OVERRIDE_PHY_CONTROL;
>   ci->pdata.notify_event = ci_hdrc_msm_notify_event;
> - ci->pdata.usb_phy = phy;
>  
>   reset = devm_reset_control_get(>dev, "core");
>   if (IS_ERR(reset))
> diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
> index f144e1bbcc82..0866c03d66df 100644
> --- a/drivers/usb/chipidea/core.c
> +++ b/drivers/usb/chipidea/core.c
> @@ -327,6 +327,7 @@ void hw_phymode_configure(struct ci_hdrc *ci)
>   hw_write(ci, OP_PORTSC, PORTSC_STS, PORTSC_STS);
>   }
>  }
> +EXPORT_SYMBOL_GPL(hw_phymode_configure);
>  
>  /**
>   * _ci_usb_phy_init: initialize phy taking in account both phy and usb_phy
> @@ -503,9 +504,12 @@ int hw_device_reset(struct ci_hdrc *ci)
>   return ret;
>   }
>  
> - if 

[PATCH v2 19/22] usb: chipidea: msm: Handle phy power states

2016-07-07 Thread Stephen Boyd
The ULPI phy on qcom platforms needs to be initialized and
powered on after a USB reset and before we toggle the run/stop
bit. Otherwise, the phy locks up and doesn't work properly. Hook
the phy initialization into the RESET event and the phy power off
into the STOPPED event.

Cc: Peter Chen 
Cc: Greg Kroah-Hartman 
---
 drivers/usb/chipidea/ci_hdrc_msm.c | 40 +++---
 drivers/usb/chipidea/core.c|  8 ++--
 drivers/usb/chipidea/host.c|  8 ++--
 include/linux/usb/chipidea.h   |  2 +-
 4 files changed, 33 insertions(+), 25 deletions(-)

diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c 
b/drivers/usb/chipidea/ci_hdrc_msm.c
index ab6a7713ee5c..5c486c15e043 100644
--- a/drivers/usb/chipidea/ci_hdrc_msm.c
+++ b/drivers/usb/chipidea/ci_hdrc_msm.c
@@ -75,20 +75,33 @@ static const struct reset_control_ops ci_hdrc_msm_reset_ops 
= {
.reset = ci_hdrc_msm_por_reset,
 };
 
-static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
+static int ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
 {
struct device *dev = ci->dev->parent;
struct ci_hdrc_msm *msm_ci = dev_get_drvdata(dev);
+   int ret;
 
switch (event) {
case CI_HDRC_CONTROLLER_RESET_EVENT:
dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n");
+
+   hw_phymode_configure(ci);
if (msm_ci->secondary_phy) {
u32 val = readl_relaxed(msm_ci->base + HS_PHY_SEC_CTRL);
val |= HS_PHY_DIG_CLAMP_N;
writel_relaxed(val, msm_ci->base + HS_PHY_SEC_CTRL);
}
 
+   ret = phy_init(ci->phy);
+   if (ret)
+   return ret;
+
+   ret = phy_power_on(ci->phy);
+   if (ret) {
+   phy_exit(ci->phy);
+   return ret;
+   }
+
/* use AHB transactor, allow posted data writes */
hw_write_id_reg(ci, HS_PHY_AHB_MODE, 0x, 0x8);
 
@@ -108,21 +121,18 @@ static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, 
unsigned event)
 HSPHY_SESS_VLD_CTRL);
 
}
-
-   usb_phy_init(ci->usb_phy);
break;
case CI_HDRC_CONTROLLER_STOPPED_EVENT:
dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n");
-   /*
-* Put the phy in non-driving mode. Otherwise host
-* may not detect soft-disconnection.
-*/
-   usb_phy_notify_disconnect(ci->usb_phy, USB_SPEED_UNKNOWN);
+   phy_power_off(ci->phy);
+   phy_exit(ci->phy);
break;
default:
dev_dbg(dev, "unknown ci_hdrc event\n");
break;
}
+
+   return 0;
 }
 
 static int ci_hdrc_msm_mux_phy(struct ci_hdrc_msm *ci,
@@ -162,7 +172,6 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)
 {
struct ci_hdrc_msm *ci;
struct platform_device *plat_ci;
-   struct usb_phy *phy;
struct clk *clk;
struct reset_control *reset;
struct resource *res;
@@ -176,21 +185,12 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, ci);
 
-   /*
-* OTG(PHY) driver takes care of PHY initialization, clock management,
-* powering up VBUS, mapping of registers address space and power
-* management.
-*/
-   phy = devm_usb_get_phy_by_phandle(>dev, "usb-phy", 0);
-   if (IS_ERR(phy))
-   return PTR_ERR(phy);
-
ci->pdata.name = "ci_hdrc_msm";
ci->pdata.capoffset = DEF_CAPOFFSET;
ci->pdata.flags = CI_HDRC_REGS_SHARED | CI_HDRC_DISABLE_STREAMING |
- CI_HDRC_OVERRIDE_AHB_BURST;
+ CI_HDRC_OVERRIDE_AHB_BURST |
+ CI_HDRC_OVERRIDE_PHY_CONTROL;
ci->pdata.notify_event = ci_hdrc_msm_notify_event;
-   ci->pdata.usb_phy = phy;
 
reset = devm_reset_control_get(>dev, "core");
if (IS_ERR(reset))
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index f144e1bbcc82..0866c03d66df 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -327,6 +327,7 @@ void hw_phymode_configure(struct ci_hdrc *ci)
hw_write(ci, OP_PORTSC, PORTSC_STS, PORTSC_STS);
}
 }
+EXPORT_SYMBOL_GPL(hw_phymode_configure);
 
 /**
  * _ci_usb_phy_init: initialize phy taking in account both phy and usb_phy
@@ -503,9 +504,12 @@ int hw_device_reset(struct ci_hdrc *ci)
return ret;
}
 
-   if (ci->platdata->notify_event)
-   ci->platdata->notify_event(ci,
+   if (ci->platdata->notify_event) {
+   ret = 

[PATCH v2 19/22] usb: chipidea: msm: Handle phy power states

2016-07-07 Thread Stephen Boyd
The ULPI phy on qcom platforms needs to be initialized and
powered on after a USB reset and before we toggle the run/stop
bit. Otherwise, the phy locks up and doesn't work properly. Hook
the phy initialization into the RESET event and the phy power off
into the STOPPED event.

Cc: Peter Chen 
Cc: Greg Kroah-Hartman 
---
 drivers/usb/chipidea/ci_hdrc_msm.c | 40 +++---
 drivers/usb/chipidea/core.c|  8 ++--
 drivers/usb/chipidea/host.c|  8 ++--
 include/linux/usb/chipidea.h   |  2 +-
 4 files changed, 33 insertions(+), 25 deletions(-)

diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c 
b/drivers/usb/chipidea/ci_hdrc_msm.c
index ab6a7713ee5c..5c486c15e043 100644
--- a/drivers/usb/chipidea/ci_hdrc_msm.c
+++ b/drivers/usb/chipidea/ci_hdrc_msm.c
@@ -75,20 +75,33 @@ static const struct reset_control_ops ci_hdrc_msm_reset_ops 
= {
.reset = ci_hdrc_msm_por_reset,
 };
 
-static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
+static int ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
 {
struct device *dev = ci->dev->parent;
struct ci_hdrc_msm *msm_ci = dev_get_drvdata(dev);
+   int ret;
 
switch (event) {
case CI_HDRC_CONTROLLER_RESET_EVENT:
dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n");
+
+   hw_phymode_configure(ci);
if (msm_ci->secondary_phy) {
u32 val = readl_relaxed(msm_ci->base + HS_PHY_SEC_CTRL);
val |= HS_PHY_DIG_CLAMP_N;
writel_relaxed(val, msm_ci->base + HS_PHY_SEC_CTRL);
}
 
+   ret = phy_init(ci->phy);
+   if (ret)
+   return ret;
+
+   ret = phy_power_on(ci->phy);
+   if (ret) {
+   phy_exit(ci->phy);
+   return ret;
+   }
+
/* use AHB transactor, allow posted data writes */
hw_write_id_reg(ci, HS_PHY_AHB_MODE, 0x, 0x8);
 
@@ -108,21 +121,18 @@ static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, 
unsigned event)
 HSPHY_SESS_VLD_CTRL);
 
}
-
-   usb_phy_init(ci->usb_phy);
break;
case CI_HDRC_CONTROLLER_STOPPED_EVENT:
dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n");
-   /*
-* Put the phy in non-driving mode. Otherwise host
-* may not detect soft-disconnection.
-*/
-   usb_phy_notify_disconnect(ci->usb_phy, USB_SPEED_UNKNOWN);
+   phy_power_off(ci->phy);
+   phy_exit(ci->phy);
break;
default:
dev_dbg(dev, "unknown ci_hdrc event\n");
break;
}
+
+   return 0;
 }
 
 static int ci_hdrc_msm_mux_phy(struct ci_hdrc_msm *ci,
@@ -162,7 +172,6 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)
 {
struct ci_hdrc_msm *ci;
struct platform_device *plat_ci;
-   struct usb_phy *phy;
struct clk *clk;
struct reset_control *reset;
struct resource *res;
@@ -176,21 +185,12 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, ci);
 
-   /*
-* OTG(PHY) driver takes care of PHY initialization, clock management,
-* powering up VBUS, mapping of registers address space and power
-* management.
-*/
-   phy = devm_usb_get_phy_by_phandle(>dev, "usb-phy", 0);
-   if (IS_ERR(phy))
-   return PTR_ERR(phy);
-
ci->pdata.name = "ci_hdrc_msm";
ci->pdata.capoffset = DEF_CAPOFFSET;
ci->pdata.flags = CI_HDRC_REGS_SHARED | CI_HDRC_DISABLE_STREAMING |
- CI_HDRC_OVERRIDE_AHB_BURST;
+ CI_HDRC_OVERRIDE_AHB_BURST |
+ CI_HDRC_OVERRIDE_PHY_CONTROL;
ci->pdata.notify_event = ci_hdrc_msm_notify_event;
-   ci->pdata.usb_phy = phy;
 
reset = devm_reset_control_get(>dev, "core");
if (IS_ERR(reset))
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index f144e1bbcc82..0866c03d66df 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -327,6 +327,7 @@ void hw_phymode_configure(struct ci_hdrc *ci)
hw_write(ci, OP_PORTSC, PORTSC_STS, PORTSC_STS);
}
 }
+EXPORT_SYMBOL_GPL(hw_phymode_configure);
 
 /**
  * _ci_usb_phy_init: initialize phy taking in account both phy and usb_phy
@@ -503,9 +504,12 @@ int hw_device_reset(struct ci_hdrc *ci)
return ret;
}
 
-   if (ci->platdata->notify_event)
-   ci->platdata->notify_event(ci,
+   if (ci->platdata->notify_event) {
+   ret = ci->platdata->notify_event(ci,