drivers/usb/dwc3/core.c

Source file repositories/reference/linux-study-clean/drivers/usb/dwc3/core.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/dwc3/core.c
Extension
.c
Size
73416 bytes
Lines
2870
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) {
			dev_err(dev,
				"Controller does not support host mode.\n");
			return -EINVAL;
		}
		mode = USB_DR_MODE_PERIPHERAL;
		break;
	case DWC3_GHWPARAMS0_MODE_HOST:
		if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
			dev_err(dev,
				"Controller does not support device mode.\n");
			return -EINVAL;
		}
		mode = USB_DR_MODE_HOST;
		break;
	default:
		if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
			mode = USB_DR_MODE_HOST;
		else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
			mode = USB_DR_MODE_PERIPHERAL;

		/*
		 * DWC_usb31 and DWC_usb3 v3.30a and higher do not support OTG
		 * mode. If the controller supports DRD but the dr_mode is not
		 * specified or set to OTG, then set the mode to peripheral.
		 */
		if (mode == USB_DR_MODE_OTG && !dwc->edev &&
		    (!IS_ENABLED(CONFIG_USB_ROLE_SWITCH) ||
		     !device_property_read_bool(dwc->dev, "usb-role-switch")) &&
		    !DWC3_VER_IS_PRIOR(DWC3, 330A))
			mode = USB_DR_MODE_PERIPHERAL;
	}

	if (mode != dwc->dr_mode) {
		dev_warn(dev,
			 "Configuration mismatch. dr_mode forced to %s\n",
			 mode == USB_DR_MODE_HOST ? "host" : "gadget");

		dwc->dr_mode = mode;
	}

	return 0;
}

void dwc3_enable_susphy(struct dwc3 *dwc, bool enable)
{
	u32 reg;
	int i;

	for (i = 0; i < dwc->num_usb3_ports; i++) {
		reg = dwc3_readl(dwc, DWC3_GUSB3PIPECTL(i));
		if (enable && !dwc->dis_u3_susphy_quirk)
			reg |= DWC3_GUSB3PIPECTL_SUSPHY;
		else
			reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;

		dwc3_writel(dwc, DWC3_GUSB3PIPECTL(i), reg);
	}

	for (i = 0; i < dwc->num_usb2_ports; i++) {
		reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(i));
		if (enable && !dwc->dis_u2_susphy_quirk)
			reg |= DWC3_GUSB2PHYCFG_SUSPHY;
		else
			reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;

		dwc3_writel(dwc, DWC3_GUSB2PHYCFG(i), reg);
	}
}
EXPORT_SYMBOL_GPL(dwc3_enable_susphy);

void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy)
{
	unsigned int hw_mode;
	u32 reg;

	reg = dwc3_readl(dwc, DWC3_GCTL);

	 /*
	  * For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE and
	  * GUSB2PHYCFG.SUSPHY should be cleared during mode switching,
	  * and they can be set after core initialization.
	  */
	hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
	if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && !ignore_susphy) {
		if (DWC3_GCTL_PRTCAP(reg) != mode)
			dwc3_enable_susphy(dwc, false);
	}

	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));

Annotation

Implementation Notes