usb: dwc2: Add host partial power down functions

For host mode Partial Power Down entering and exiting
separate functions are needed to implement the logic.
Earlier the logic was implemented in one function. Which was
confusing the readability. Also both host and device implementations
were in the same function.

- Added host partial power down functions which must be called
by dwc2_enter_partial_power_down()/dwc2_exit_partial_power_down()
functions.

Added function names:
dwc2_host_enter_partial_power_down()
dwc2_host_exit_partial_power_down()

NOTE: There is a checkpatch "CHECK" warning on "udelay(100)".
The delay is needed to properly exit gadget Partial Power Down
A delay less than 100 doesn't work.

Acked-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Signed-off-by: Artur Petrosyan <Arthur.Petrosyan@synopsys.com>
Link: https://lore.kernel.org/r/20210408094438.56CFBA022E@mailhost.synopsys.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Artur Petrosyan 2021-04-08 13:44:37 +04:00 committed by Greg Kroah-Hartman
parent be2b960e57
commit 9ce9e5ad17
2 changed files with 168 additions and 0 deletions

View File

@ -1474,6 +1474,9 @@ int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg);
int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
int rem_wakeup, int reset);
int dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg);
int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg,
int rem_wakeup, bool restore);
bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2);
static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg)
{ schedule_work(&hsotg->phy_reset_work); }
@ -1500,6 +1503,11 @@ static inline int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
static inline int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
int rem_wakeup, int reset)
{ return 0; }
static inline int dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg,
int rem_wakeup, bool restore)
{ return 0; }
static inline bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
{ return false; }
static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) {}

View File

@ -5607,3 +5607,163 @@ bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
/* No reason to keep the PHY powered, so allow poweroff */
return true;
}
/**
* dwc2_host_enter_partial_power_down() - Put controller in partial
* power down.
*
* @hsotg: Programming view of the DWC_otg controller
*
* Return: non-zero if failed to enter host partial power down.
*
* This function is for entering Host mode partial power down.
*/
int dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg)
{
u32 pcgcctl;
u32 hprt0;
int ret = 0;
dev_dbg(hsotg->dev, "Entering host partial power down started.\n");
/* Put this port in suspend mode. */
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 |= HPRT0_SUSP;
dwc2_writel(hsotg, hprt0, HPRT0);
udelay(5);
/* Wait for the HPRT0.PrtSusp register field to be set */
if (dwc2_hsotg_wait_bit_set(hsotg, HPRT0, HPRT0_SUSP, 3000))
dev_warn(hsotg->dev, "Suspend wasn't generated\n");
/* Backup all registers */
ret = dwc2_backup_global_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup global registers\n",
__func__);
return ret;
}
ret = dwc2_backup_host_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup host registers\n",
__func__);
return ret;
}
/*
* Clear any pending interrupts since dwc2 will not be able to
* clear them after entering partial_power_down.
*/
dwc2_writel(hsotg, 0xffffffff, GINTSTS);
/* Put the controller in low power state */
pcgcctl = dwc2_readl(hsotg, PCGCTL);
pcgcctl |= PCGCTL_PWRCLMP;
dwc2_writel(hsotg, pcgcctl, PCGCTL);
udelay(5);
pcgcctl |= PCGCTL_RSTPDWNMODULE;
dwc2_writel(hsotg, pcgcctl, PCGCTL);
udelay(5);
pcgcctl |= PCGCTL_STOPPCLK;
dwc2_writel(hsotg, pcgcctl, PCGCTL);
/* Set in_ppd flag to 1 as here core enters suspend. */
hsotg->in_ppd = 1;
hsotg->lx_state = DWC2_L2;
hsotg->bus_suspended = true;
dev_dbg(hsotg->dev, "Entering host partial power down completed.\n");
return ret;
}
/*
* dwc2_host_exit_partial_power_down() - Exit controller from host partial
* power down.
*
* @hsotg: Programming view of the DWC_otg controller
* @rem_wakeup: indicates whether resume is initiated by Reset.
* @restore: indicates whether need to restore the registers or not.
*
* Return: non-zero if failed to exit host partial power down.
*
* This function is for exiting from Host mode partial power down.
*/
int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg,
int rem_wakeup, bool restore)
{
u32 pcgcctl;
int ret = 0;
u32 hprt0;
dev_dbg(hsotg->dev, "Exiting host partial power down started.\n");
pcgcctl = dwc2_readl(hsotg, PCGCTL);
pcgcctl &= ~PCGCTL_STOPPCLK;
dwc2_writel(hsotg, pcgcctl, PCGCTL);
udelay(5);
pcgcctl = dwc2_readl(hsotg, PCGCTL);
pcgcctl &= ~PCGCTL_PWRCLMP;
dwc2_writel(hsotg, pcgcctl, PCGCTL);
udelay(5);
pcgcctl = dwc2_readl(hsotg, PCGCTL);
pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
dwc2_writel(hsotg, pcgcctl, PCGCTL);
udelay(100);
if (restore) {
ret = dwc2_restore_global_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore registers\n",
__func__);
return ret;
}
ret = dwc2_restore_host_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore host registers\n",
__func__);
return ret;
}
}
/* Drive resume signaling and exit suspend mode on the port. */
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 |= HPRT0_RES;
hprt0 &= ~HPRT0_SUSP;
dwc2_writel(hsotg, hprt0, HPRT0);
udelay(5);
if (!rem_wakeup) {
/* Stop driveing resume signaling on the port. */
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 &= ~HPRT0_RES;
dwc2_writel(hsotg, hprt0, HPRT0);
hsotg->bus_suspended = false;
} else {
/* Turn on the port power bit. */
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 |= HPRT0_PWR;
dwc2_writel(hsotg, hprt0, HPRT0);
/* Connect hcd. */
dwc2_hcd_connect(hsotg);
mod_timer(&hsotg->wkp_timer,
jiffies + msecs_to_jiffies(71));
}
/* Set lx_state to and in_ppd to 0 as here core exits from suspend. */
hsotg->in_ppd = 0;
hsotg->lx_state = DWC2_L0;
dev_dbg(hsotg->dev, "Exiting host partial power down completed.\n");
return ret;
}