diff mbox series

[v3,06/14] usb: dwc2: Add enter partial power down when port is suspended

Message ID 20210408094510.6C4E9A022E@mailhost.synopsys.com (mailing list archive)
State Accepted
Commit 22ff0c8e529ed3c3385f9807ec8efacf440c4c8e
Headers show
Series usb: dwc2: Fix Partial Power down issues. | expand

Commit Message

Artur Petrosyan April 8, 2021, 9:45 a.m. UTC
Adds flow of entering Partial Power Down in
"dwc2_port_suspend()" function when core receives suspend.

NOTE: Switch case statement is used for hibernation partial
power down and clock gating mode determination. In this patch
only Partial Power Down is implemented the Hibernation and
clock gating implementations are planned to be added.

Signed-off-by: Artur Petrosyan <Arthur.Petrosyan@synopsys.com>
---
 Changes in v3:
 - None
 Changes in v2:
 - None

 drivers/usb/dwc2/core.h |  5 +++--
 drivers/usb/dwc2/hcd.c  | 48 ++++++++++++++++++++++++++---------------
 2 files changed, 34 insertions(+), 19 deletions(-)

Comments

Minas Harutyunyan April 8, 2021, 1:39 p.m. UTC | #1
On 4/8/2021 1:45 PM, Artur Petrosyan wrote:
> Adds flow of entering Partial Power Down in
> "dwc2_port_suspend()" function when core receives suspend.
> 
> NOTE: Switch case statement is used for hibernation partial
> power down and clock gating mode determination. In this patch
> only Partial Power Down is implemented the Hibernation and
> clock gating implementations are planned to be added.
> 
> Signed-off-by: Artur Petrosyan <Arthur.Petrosyan@synopsys.com>

Acked-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>

> ---
>   Changes in v3:
>   - None
>   Changes in v2:
>   - None
> 
>   drivers/usb/dwc2/core.h |  5 +++--
>   drivers/usb/dwc2/hcd.c  | 48 ++++++++++++++++++++++++++---------------
>   2 files changed, 34 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
> index b7d99cf9e84c..76807abd753b 100644
> --- a/drivers/usb/dwc2/core.h
> +++ b/drivers/usb/dwc2/core.h
> @@ -1470,7 +1470,7 @@ void dwc2_hcd_connect(struct dwc2_hsotg *hsotg);
>   void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force);
>   void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
>   int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup);
> -void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex);
> +int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex);
>   void dwc2_port_resume(struct dwc2_hsotg *hsotg);
>   int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg);
>   int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
> @@ -1495,7 +1495,8 @@ static inline void dwc2_hcd_start(struct dwc2_hsotg *hsotg) {}
>   static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {}
>   static inline int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
>   { return 0; }
> -static inline void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) {}
> +static inline int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
> +{ return 0; }
>   static inline void dwc2_port_resume(struct dwc2_hsotg *hsotg) {}
>   static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
>   { return 0; }
> diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
> index f4247a66c2b2..e7fb0d5940bc 100644
> --- a/drivers/usb/dwc2/hcd.c
> +++ b/drivers/usb/dwc2/hcd.c
> @@ -3281,15 +3281,18 @@ static int dwc2_host_is_b_hnp_enabled(struct dwc2_hsotg *hsotg)
>    * @hsotg: Programming view of the DWC_otg controller
>    * @windex: The control request wIndex field
>    *
> + * Return: non-zero if failed to enter suspend mode for host.
> + *
>    * This function is for entering Host mode suspend.
>    * Must NOT be called with interrupt disabled or spinlock held.
>    */
> -void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
> +int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
>   {
>   	unsigned long flags;
>   	u32 hprt0;
>   	u32 pcgctl;
>   	u32 gotgctl;
> +	int ret = 0;
>   
>   	dev_dbg(hsotg->dev, "%s()\n", __func__);
>   
> @@ -3302,22 +3305,31 @@ void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
>   		hsotg->op_state = OTG_STATE_A_SUSPEND;
>   	}
>   
> -	hprt0 = dwc2_read_hprt0(hsotg);
> -	hprt0 |= HPRT0_SUSP;
> -	dwc2_writel(hsotg, hprt0, HPRT0);
> -
> -	hsotg->bus_suspended = true;
> -
> -	/*
> -	 * If power_down is supported, Phy clock will be suspended
> -	 * after registers are backuped.
> -	 */
> -	if (!hsotg->params.power_down) {
> -		/* Suspend the Phy Clock */
> -		pcgctl = dwc2_readl(hsotg, PCGCTL);
> -		pcgctl |= PCGCTL_STOPPCLK;
> -		dwc2_writel(hsotg, pcgctl, PCGCTL);
> -		udelay(10);
> +	switch (hsotg->params.power_down) {
> +	case DWC2_POWER_DOWN_PARAM_PARTIAL:
> +		ret = dwc2_enter_partial_power_down(hsotg);
> +		if (ret)
> +			dev_err(hsotg->dev,
> +				"enter partial_power_down failed.\n");
> +		break;
> +	case DWC2_POWER_DOWN_PARAM_HIBERNATION:
> +	case DWC2_POWER_DOWN_PARAM_NONE:
> +	default:
> +		hprt0 = dwc2_read_hprt0(hsotg);
> +		hprt0 |= HPRT0_SUSP;
> +		dwc2_writel(hsotg, hprt0, HPRT0);
> +		hsotg->bus_suspended = true;
> +		/*
> +		 * If power_down is supported, Phy clock will be suspended
> +		 * after registers are backuped.
> +		 */
> +		if (!hsotg->params.power_down) {
> +			/* Suspend the Phy Clock */
> +			pcgctl = dwc2_readl(hsotg, PCGCTL);
> +			pcgctl |= PCGCTL_STOPPCLK;
> +			dwc2_writel(hsotg, pcgctl, PCGCTL);
> +			udelay(10);
> +		}
>   	}
>   
>   	/* For HNP the bus must be suspended for at least 200ms */
> @@ -3332,6 +3344,8 @@ void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
>   	} else {
>   		spin_unlock_irqrestore(&hsotg->lock, flags);
>   	}
> +
> +	return ret;
>   }
>   
>   /**
>
diff mbox series

Patch

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index b7d99cf9e84c..76807abd753b 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -1470,7 +1470,7 @@  void dwc2_hcd_connect(struct dwc2_hsotg *hsotg);
 void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force);
 void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
 int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup);
-void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex);
+int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex);
 void dwc2_port_resume(struct dwc2_hsotg *hsotg);
 int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg);
 int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
@@ -1495,7 +1495,8 @@  static inline void dwc2_hcd_start(struct dwc2_hsotg *hsotg) {}
 static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {}
 static inline int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
 { return 0; }
-static inline void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) {}
+static inline int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
+{ return 0; }
 static inline void dwc2_port_resume(struct dwc2_hsotg *hsotg) {}
 static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
 { return 0; }
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index f4247a66c2b2..e7fb0d5940bc 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3281,15 +3281,18 @@  static int dwc2_host_is_b_hnp_enabled(struct dwc2_hsotg *hsotg)
  * @hsotg: Programming view of the DWC_otg controller
  * @windex: The control request wIndex field
  *
+ * Return: non-zero if failed to enter suspend mode for host.
+ *
  * This function is for entering Host mode suspend.
  * Must NOT be called with interrupt disabled or spinlock held.
  */
-void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
+int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
 {
 	unsigned long flags;
 	u32 hprt0;
 	u32 pcgctl;
 	u32 gotgctl;
+	int ret = 0;
 
 	dev_dbg(hsotg->dev, "%s()\n", __func__);
 
@@ -3302,22 +3305,31 @@  void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
 		hsotg->op_state = OTG_STATE_A_SUSPEND;
 	}
 
-	hprt0 = dwc2_read_hprt0(hsotg);
-	hprt0 |= HPRT0_SUSP;
-	dwc2_writel(hsotg, hprt0, HPRT0);
-
-	hsotg->bus_suspended = true;
-
-	/*
-	 * If power_down is supported, Phy clock will be suspended
-	 * after registers are backuped.
-	 */
-	if (!hsotg->params.power_down) {
-		/* Suspend the Phy Clock */
-		pcgctl = dwc2_readl(hsotg, PCGCTL);
-		pcgctl |= PCGCTL_STOPPCLK;
-		dwc2_writel(hsotg, pcgctl, PCGCTL);
-		udelay(10);
+	switch (hsotg->params.power_down) {
+	case DWC2_POWER_DOWN_PARAM_PARTIAL:
+		ret = dwc2_enter_partial_power_down(hsotg);
+		if (ret)
+			dev_err(hsotg->dev,
+				"enter partial_power_down failed.\n");
+		break;
+	case DWC2_POWER_DOWN_PARAM_HIBERNATION:
+	case DWC2_POWER_DOWN_PARAM_NONE:
+	default:
+		hprt0 = dwc2_read_hprt0(hsotg);
+		hprt0 |= HPRT0_SUSP;
+		dwc2_writel(hsotg, hprt0, HPRT0);
+		hsotg->bus_suspended = true;
+		/*
+		 * If power_down is supported, Phy clock will be suspended
+		 * after registers are backuped.
+		 */
+		if (!hsotg->params.power_down) {
+			/* Suspend the Phy Clock */
+			pcgctl = dwc2_readl(hsotg, PCGCTL);
+			pcgctl |= PCGCTL_STOPPCLK;
+			dwc2_writel(hsotg, pcgctl, PCGCTL);
+			udelay(10);
+		}
 	}
 
 	/* For HNP the bus must be suspended for at least 200ms */
@@ -3332,6 +3344,8 @@  void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
 	} else {
 		spin_unlock_irqrestore(&hsotg->lock, flags);
 	}
+
+	return ret;
 }
 
 /**