drivers/usb/dwc3/dwc3-google.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/dwc3/dwc3-google.c
Extension
.c
Size
17307 bytes
Lines
628
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: implementation source
Status
source 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

struct dwc3_google {
	struct device		*dev;
	struct dwc3		dwc;
	struct clk_bulk_data	*clks;
	int			num_clks;
	struct reset_control_bulk_data rsts[DWC3_GOOGLE_MAX_RESETS];
	int			num_rsts;
	struct reset_control	*non_sticky_rst;
	struct device		*usb_psw_pd;
	struct device_link	*usb_psw_pd_dl;
	struct notifier_block	usb_psw_pd_nb;
	struct device		*usb_top_pd;
	struct device_link	*usb_top_pd_dl;
	struct regmap		*usb_cfg_regmap;
	unsigned int		host_cfg_offset;
	unsigned int		usbint_cfg_offset;
	int			hs_pme_irq;
	int			ss_pme_irq;
	bool			is_usb2only;
	bool			is_hibernation;
};

#define to_dwc3_google(d) container_of_const((d), struct dwc3_google, dwc)

static int dwc3_google_rst_init(struct dwc3_google *google)
{
	int ret;

	google->num_rsts = 4;
	google->rsts[0].id = "non_sticky";
	google->rsts[1].id = "sticky";
	google->rsts[2].id = "drd_bus";
	google->rsts[3].id = "top";

	ret = devm_reset_control_bulk_get_exclusive(google->dev,
						    google->num_rsts,
						    google->rsts);

	if (ret < 0)
		return ret;

	google->non_sticky_rst = google->rsts[0].rstc;

	return 0;
}

static int dwc3_google_set_pmu_state(struct dwc3_google *google, int state)
{
	u32 reg;
	int ret;

	regmap_read(google->usb_cfg_regmap,
		    google->host_cfg_offset + HOST_CFG1_OFFSET, &reg);

	reg &= ~HOST_CFG1_PM_POWER_STATE_REQUEST;
	reg |= (FIELD_PREP(HOST_CFG1_PM_POWER_STATE_REQUEST, state) |
		HOST_CFG1_PME_EN);
	regmap_write(google->usb_cfg_regmap,
		     google->host_cfg_offset + HOST_CFG1_OFFSET, reg);

	ret = regmap_read_poll_timeout(google->usb_cfg_regmap,
				       google->host_cfg_offset + HC_STATUS_OFFSET, reg,
				       (FIELD_GET(HC_STATUS_CURRENT_POWER_STATE_U2PMU,
						  reg) == state &&
					FIELD_GET(HC_STATUS_CURRENT_POWER_STATE_U3PMU,
						  reg) == state),
				       10, 10000);

	if (ret)
		dev_err(google->dev, "failed to set PMU state %d\n", state);

	return ret;
}

/*
 * Clear pme interrupts and report their status.
 * The hardware requires write-1 then write-0 sequence to clear the interrupt bits.
 */
static u32 dwc3_google_clear_pme_irqs(struct dwc3_google *google)
{
	u32 irq_status, reg_set, reg_clear;

	regmap_read(google->usb_cfg_regmap,
		    google->usbint_cfg_offset + USBINT_STATUS_OFFSET, &irq_status);

	irq_status &= (USBINT_STATUS_USBDRD_PME_GEN_U2P_INTR_STS_RAW |
		       USBINT_STATUS_USBDRD_PME_GEN_U3P_INTR_STS_RAW);
	if (!irq_status)
		return irq_status;

Annotation

Implementation Notes