forked from Minki/linux
usb: dwc2: Add device clock gating support functions
Added device clock gating support functions according programming guide. Moved "bus_suspended" flag to "dwc2_hsotg" struct because we need to set that flag while entering to clock gating in case when the driver is built in peripheral mode. Added function names: dwc2_gadget_enter_clock_gating() dwc2_gadget_exit_clock_gating() Acked-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com> Signed-off-by: Artur Petrosyan <Arthur.Petrosyan@synopsys.com> Link: https://lore.kernel.org/r/20210413073607.F41E8A0094@mailhost.synopsys.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
5367f82a21
commit
012466fc8c
@ -866,6 +866,7 @@ struct dwc2_hregs_backup {
|
||||
* @ll_hw_enabled: Status of low-level hardware resources.
|
||||
* @hibernated: True if core is hibernated
|
||||
* @in_ppd: True if core is partial power down mode.
|
||||
* @bus_suspended: True if bus is suspended
|
||||
* @reset_phy_on_wake: Quirk saying that we should assert PHY reset on a
|
||||
* remote wakeup.
|
||||
* @phy_off_for_suspend: Status of whether we turned the PHY off at suspend.
|
||||
@ -1023,7 +1024,6 @@ struct dwc2_hregs_backup {
|
||||
* a pointer to an array of register definitions, the
|
||||
* array size and the base address where the register bank
|
||||
* is to be found.
|
||||
* @bus_suspended: True if bus is suspended
|
||||
* @last_frame_num: Number of last frame. Range from 0 to 32768
|
||||
* @frame_num_array: Used only if CONFIG_USB_DWC2_TRACK_MISSED_SOFS is
|
||||
* defined, for missed SOFs tracking. Array holds that
|
||||
@ -1062,6 +1062,7 @@ struct dwc2_hsotg {
|
||||
unsigned int ll_hw_enabled:1;
|
||||
unsigned int hibernated:1;
|
||||
unsigned int in_ppd:1;
|
||||
bool bus_suspended;
|
||||
unsigned int reset_phy_on_wake:1;
|
||||
unsigned int need_phy_for_wake:1;
|
||||
unsigned int phy_off_for_suspend:1;
|
||||
@ -1145,7 +1146,6 @@ struct dwc2_hsotg {
|
||||
unsigned long hs_periodic_bitmap[
|
||||
DIV_ROUND_UP(DWC2_HS_SCHEDULE_US, BITS_PER_LONG)];
|
||||
u16 periodic_qh_count;
|
||||
bool bus_suspended;
|
||||
bool new_connection;
|
||||
|
||||
u16 last_frame_num;
|
||||
@ -1415,6 +1415,9 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
|
||||
int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg);
|
||||
int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
|
||||
bool restore);
|
||||
void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg);
|
||||
void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg,
|
||||
int rem_wakeup);
|
||||
int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg);
|
||||
int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg);
|
||||
int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg);
|
||||
@ -1453,6 +1456,9 @@ static inline int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg)
|
||||
static inline int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
|
||||
bool restore)
|
||||
{ return 0; }
|
||||
static inline void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg) {}
|
||||
static inline void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg,
|
||||
int rem_wakeup) {}
|
||||
static inline int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg)
|
||||
{ return 0; }
|
||||
static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg)
|
||||
|
@ -5483,3 +5483,74 @@ int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
|
||||
dev_dbg(hsotg->dev, "Exiting device partial Power Down completed.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc2_gadget_enter_clock_gating() - Put controller in clock gating.
|
||||
*
|
||||
* @hsotg: Programming view of the DWC_otg controller
|
||||
*
|
||||
* Return: non-zero if failed to enter device partial power down.
|
||||
*
|
||||
* This function is for entering device mode clock gating.
|
||||
*/
|
||||
void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
u32 pcgctl;
|
||||
|
||||
dev_dbg(hsotg->dev, "Entering device clock gating.\n");
|
||||
|
||||
/* Set the Phy Clock bit as suspend is received. */
|
||||
pcgctl = dwc2_readl(hsotg, PCGCTL);
|
||||
pcgctl |= PCGCTL_STOPPCLK;
|
||||
dwc2_writel(hsotg, pcgctl, PCGCTL);
|
||||
udelay(5);
|
||||
|
||||
/* Set the Gate hclk as suspend is received. */
|
||||
pcgctl = dwc2_readl(hsotg, PCGCTL);
|
||||
pcgctl |= PCGCTL_GATEHCLK;
|
||||
dwc2_writel(hsotg, pcgctl, PCGCTL);
|
||||
udelay(5);
|
||||
|
||||
hsotg->lx_state = DWC2_L2;
|
||||
hsotg->bus_suspended = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* dwc2_gadget_exit_clock_gating() - Exit controller from device clock gating.
|
||||
*
|
||||
* @hsotg: Programming view of the DWC_otg controller
|
||||
* @rem_wakeup: indicates whether remote wake up is enabled.
|
||||
*
|
||||
* This function is for exiting from device mode clock gating.
|
||||
*/
|
||||
void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup)
|
||||
{
|
||||
u32 pcgctl;
|
||||
u32 dctl;
|
||||
|
||||
dev_dbg(hsotg->dev, "Exiting device clock gating.\n");
|
||||
|
||||
/* Clear the Gate hclk. */
|
||||
pcgctl = dwc2_readl(hsotg, PCGCTL);
|
||||
pcgctl &= ~PCGCTL_GATEHCLK;
|
||||
dwc2_writel(hsotg, pcgctl, PCGCTL);
|
||||
udelay(5);
|
||||
|
||||
/* Phy Clock bit. */
|
||||
pcgctl = dwc2_readl(hsotg, PCGCTL);
|
||||
pcgctl &= ~PCGCTL_STOPPCLK;
|
||||
dwc2_writel(hsotg, pcgctl, PCGCTL);
|
||||
udelay(5);
|
||||
|
||||
if (rem_wakeup) {
|
||||
/* Set Remote Wakeup Signaling */
|
||||
dctl = dwc2_readl(hsotg, DCTL);
|
||||
dctl |= DCTL_RMTWKUPSIG;
|
||||
dwc2_writel(hsotg, dctl, DCTL);
|
||||
}
|
||||
|
||||
/* Change to L0 state */
|
||||
call_gadget(hsotg, resume);
|
||||
hsotg->lx_state = DWC2_L0;
|
||||
hsotg->bus_suspended = false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user