drivers/misc/hisi_hikey_usb.c

Source file repositories/reference/linux-study-clean/drivers/misc/hisi_hikey_usb.c

File Facts

System
Linux kernel
Corpus path
drivers/misc/hisi_hikey_usb.c
Extension
.c
Size
7424 bytes
Lines
276
Domain
Driver Families
Bucket
drivers/misc
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 hisi_hikey_usb {
	struct device *dev;
	struct gpio_desc *otg_switch;
	struct gpio_desc *typec_vbus;
	struct gpio_desc *reset;

	struct regulator *regulator;

	struct usb_role_switch *hub_role_sw;

	struct usb_role_switch *dev_role_sw;
	enum usb_role role;

	struct mutex lock;
	struct work_struct work;

	struct notifier_block nb;
};

static void hub_power_ctrl(struct hisi_hikey_usb *hisi_hikey_usb, int value)
{
	int ret, status;

	if (!hisi_hikey_usb->regulator)
		return;

	status = regulator_is_enabled(hisi_hikey_usb->regulator);
	if (status == !!value)
		return;

	if (value)
		ret = regulator_enable(hisi_hikey_usb->regulator);
	else
		ret = regulator_disable(hisi_hikey_usb->regulator);

	if (ret)
		dev_err(hisi_hikey_usb->dev,
			"Can't switch regulator state to %s\n",
			str_enabled_disabled(value));
}

static void usb_switch_ctrl(struct hisi_hikey_usb *hisi_hikey_usb,
			    int switch_to)
{
	if (!hisi_hikey_usb->otg_switch)
		return;

	gpiod_set_value_cansleep(hisi_hikey_usb->otg_switch, switch_to);
}

static void usb_typec_power_ctrl(struct hisi_hikey_usb *hisi_hikey_usb,
				 int value)
{
	if (!hisi_hikey_usb->typec_vbus)
		return;

	gpiod_set_value_cansleep(hisi_hikey_usb->typec_vbus, value);
}

static void relay_set_role_switch(struct work_struct *work)
{
	struct hisi_hikey_usb *hisi_hikey_usb = container_of(work,
							struct hisi_hikey_usb,
							work);
	struct usb_role_switch *sw;
	enum usb_role role;

	if (!hisi_hikey_usb || !hisi_hikey_usb->dev_role_sw)
		return;

	mutex_lock(&hisi_hikey_usb->lock);
	switch (hisi_hikey_usb->role) {
	case USB_ROLE_NONE:
		usb_typec_power_ctrl(hisi_hikey_usb, TYPEC_VBUS_POWER_OFF);
		usb_switch_ctrl(hisi_hikey_usb, USB_SWITCH_TO_HUB);
		hub_power_ctrl(hisi_hikey_usb, HUB_VBUS_POWER_ON);
		break;
	case USB_ROLE_HOST:
		hub_power_ctrl(hisi_hikey_usb, HUB_VBUS_POWER_OFF);
		usb_switch_ctrl(hisi_hikey_usb, USB_SWITCH_TO_TYPEC);
		usb_typec_power_ctrl(hisi_hikey_usb, TYPEC_VBUS_POWER_ON);
		break;
	case USB_ROLE_DEVICE:
		hub_power_ctrl(hisi_hikey_usb, HUB_VBUS_POWER_OFF);
		usb_typec_power_ctrl(hisi_hikey_usb, TYPEC_VBUS_POWER_OFF);
		usb_switch_ctrl(hisi_hikey_usb, USB_SWITCH_TO_TYPEC);
		break;
	default:
		break;
	}

Annotation

Implementation Notes