drivers/usb/chipidea/otg.c

Source file repositories/reference/linux-study-clean/drivers/usb/chipidea/otg.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/chipidea/otg.c
Extension
.c
Size
6052 bytes
Lines
276
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

if (data & mask & OTGSC_BSVIE) {
			cable->enabled = true;
			data &= ~OTGSC_BSVIE;
		} else if (mask & OTGSC_BSVIE) {
			cable->enabled = false;
		}
	}

	cable = &ci->platdata->id_extcon;
	if (!IS_ERR(cable->edev) || ci->role_switch) {
		if (data & mask & OTGSC_IDIS)
			cable->changed = false;

		/* Don't enable id interrupt if using external notifier */
		if (data & mask & OTGSC_IDIE) {
			cable->enabled = true;
			data &= ~OTGSC_IDIE;
		} else if (mask & OTGSC_IDIE) {
			cable->enabled = false;
		}
	}

	hw_write(ci, OP_OTGSC, mask | OTGSC_INT_STATUS_BITS, data);
}

/**
 * ci_otg_role - pick role based on ID pin state
 * @ci: the controller
 */
enum ci_role ci_otg_role(struct ci_hdrc *ci)
{
	enum ci_role role = hw_read_otgsc(ci, OTGSC_ID)
		? CI_ROLE_GADGET
		: CI_ROLE_HOST;

	return role;
}

void ci_handle_vbus_change(struct ci_hdrc *ci)
{
	if (ci->role != CI_ROLE_GADGET)
		return;

	if (!ci->is_otg) {
		if (ci->platdata->flags & CI_HDRC_FORCE_VBUS_ACTIVE_ALWAYS)
			usb_gadget_vbus_connect(&ci->gadget);
		return;
	}

	if (hw_read_otgsc(ci, OTGSC_BSV) && !ci->vbus_active)
		usb_gadget_vbus_connect(&ci->gadget);
	else if (!hw_read_otgsc(ci, OTGSC_BSV) && ci->vbus_active)
		usb_gadget_vbus_disconnect(&ci->gadget);
}

/**
 * hw_wait_vbus_lower_bsv - When we switch to device mode, the vbus value
 *                          should be lower than OTGSC_BSV before connecting
 *                          to host.
 *
 * @ci: the controller
 *
 * This function returns an error code if timeout
 */
static int hw_wait_vbus_lower_bsv(struct ci_hdrc *ci)
{
	unsigned long elapse = jiffies + msecs_to_jiffies(5000);
	u32 mask = OTGSC_BSV;

	while (hw_read_otgsc(ci, mask)) {
		if (time_after(jiffies, elapse)) {
			dev_err(ci->dev, "timeout waiting for %08x in OTGSC\n",
					mask);
			return -ETIMEDOUT;
		}
		msleep(20);
	}

	return 0;
}

void ci_handle_id_switch(struct ci_hdrc *ci)
{
	enum ci_role role;

	mutex_lock(&ci->mutex);
	role = ci_otg_role(ci);
	if (role != ci->role) {
		dev_dbg(ci->dev, "switching from %s to %s\n",
			ci_role(ci)->name, ci->roles[role]->name);

Annotation

Implementation Notes