Skip to content

Commit 09c9698

Browse files
jysnpsFelipe Balbi
authored andcommitted
usb: dwc2: Add functions to set and clear force mode
Added functions to set force mode for host and device. These functions will check the current mode and only force if needed thus avoiding unnecessary force mode delays. However clearing the mode is currently done unconditionally and with the delay in place. This is needed during the connector ID status change interrupt in order to ensure that the mode has changed properly. This preserves the old behavior only for this case. The warning comment about this is moved into the clear mode condition. Signed-off-by: John Youn <[email protected]> Signed-off-by: Felipe Balbi <[email protected]>
1 parent 263b7fb commit 09c9698

File tree

2 files changed

+127
-24
lines changed

2 files changed

+127
-24
lines changed

drivers/usb/dwc2/core.c

Lines changed: 125 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,114 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg)
519519
return 0;
520520
}
521521

522+
/*
523+
* Force the mode of the controller.
524+
*
525+
* Forcing the mode is needed for two cases:
526+
*
527+
* 1) If the dr_mode is set to either HOST or PERIPHERAL we force the
528+
* controller to stay in a particular mode regardless of ID pin
529+
* changes. We do this usually after a core reset.
530+
*
531+
* 2) During probe we want to read reset values of the hw
532+
* configuration registers that are only available in either host or
533+
* device mode. We may need to force the mode if the current mode does
534+
* not allow us to access the register in the mode that we want.
535+
*
536+
* In either case it only makes sense to force the mode if the
537+
* controller hardware is OTG capable.
538+
*
539+
* Checks are done in this function to determine whether doing a force
540+
* would be valid or not.
541+
*
542+
* If a force is done, it requires a 25ms delay to take effect.
543+
*
544+
* Returns true if the mode was forced.
545+
*/
546+
static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
547+
{
548+
u32 gusbcfg;
549+
u32 set;
550+
u32 clear;
551+
552+
dev_dbg(hsotg->dev, "Forcing mode to %s\n", host ? "host" : "device");
553+
554+
/*
555+
* Force mode has no effect if the hardware is not OTG.
556+
*/
557+
if (!dwc2_hw_is_otg(hsotg))
558+
return false;
559+
560+
/*
561+
* If dr_mode is either peripheral or host only, there is no
562+
* need to ever force the mode to the opposite mode.
563+
*/
564+
if (WARN_ON(host && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL))
565+
return false;
566+
567+
if (WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST))
568+
return false;
569+
570+
gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
571+
572+
set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE;
573+
clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE;
574+
575+
/*
576+
* If the force mode bit is already set, don't set it.
577+
*/
578+
if ((gusbcfg & set) && !(gusbcfg & clear))
579+
return false;
580+
581+
gusbcfg &= ~clear;
582+
gusbcfg |= set;
583+
dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
584+
585+
msleep(25);
586+
return true;
587+
}
588+
589+
/*
590+
* Clears the force mode bits.
591+
*/
592+
static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
593+
{
594+
u32 gusbcfg;
595+
596+
gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
597+
gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
598+
gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
599+
dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
600+
601+
/*
602+
* NOTE: This long sleep is _very_ important, otherwise the core will
603+
* not stay in host mode after a connector ID change!
604+
*/
605+
usleep_range(150000, 160000);
606+
}
607+
608+
/*
609+
* Sets or clears force mode based on the dr_mode parameter.
610+
*/
611+
void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
612+
{
613+
switch (hsotg->dr_mode) {
614+
case USB_DR_MODE_HOST:
615+
dwc2_force_mode(hsotg, true);
616+
break;
617+
case USB_DR_MODE_PERIPHERAL:
618+
dwc2_force_mode(hsotg, false);
619+
break;
620+
case USB_DR_MODE_OTG:
621+
dwc2_clear_force_mode(hsotg);
622+
break;
623+
default:
624+
dev_warn(hsotg->dev, "%s() Invalid dr_mode=%d\n",
625+
__func__, hsotg->dr_mode);
626+
break;
627+
}
628+
}
629+
522630
/*
523631
* Do core a soft reset of the core. Be careful with this because it
524632
* resets all the internal state machines of the core.
@@ -529,35 +637,12 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg)
529637
int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg)
530638
{
531639
int retval;
532-
u32 gusbcfg;
533640

534641
retval = dwc2_core_reset(hsotg);
535642
if (retval)
536643
return retval;
537644

538-
if (hsotg->dr_mode == USB_DR_MODE_HOST) {
539-
gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
540-
gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
541-
gusbcfg |= GUSBCFG_FORCEHOSTMODE;
542-
dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
543-
} else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) {
544-
gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
545-
gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
546-
gusbcfg |= GUSBCFG_FORCEDEVMODE;
547-
dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
548-
} else if (hsotg->dr_mode == USB_DR_MODE_OTG) {
549-
gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
550-
gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
551-
gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
552-
dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
553-
}
554-
555-
/*
556-
* NOTE: This long sleep is _very_ important, otherwise the core will
557-
* not stay in host mode after a connector ID change!
558-
*/
559-
usleep_range(150000, 160000);
560-
645+
dwc2_force_dr_mode(hsotg);
561646
return 0;
562647
}
563648

@@ -3117,6 +3202,22 @@ void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
31173202
dwc2_set_param_hibernation(hsotg, params->hibernation);
31183203
}
31193204

3205+
/*
3206+
* Forces either host or device mode if the controller is not
3207+
* currently in that mode.
3208+
*
3209+
* Returns true if the mode was forced.
3210+
*/
3211+
static bool dwc2_force_mode_if_needed(struct dwc2_hsotg *hsotg, bool host)
3212+
{
3213+
if (host && dwc2_is_host_mode(hsotg))
3214+
return false;
3215+
else if (!host && dwc2_is_device_mode(hsotg))
3216+
return false;
3217+
3218+
return dwc2_force_mode(hsotg, host);
3219+
}
3220+
31203221
/**
31213222
* During device initialization, read various hardware configuration
31223223
* registers and interpret the contents.

drivers/usb/dwc2/core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,8 @@ extern void dwc2_core_host_init(struct dwc2_hsotg *hsotg);
886886
extern int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg);
887887
extern int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore);
888888

889+
void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg);
890+
889891
/*
890892
* Host core Functions.
891893
* The following functions support managing the DWC_otg controller in host

0 commit comments

Comments
 (0)