drivers/usb/musb/jz4740.c

Source file repositories/reference/linux-study-clean/drivers/usb/musb/jz4740.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/musb/jz4740.c
Extension
.c
Size
8677 bytes
Lines
339
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 jz4740_glue {
	struct platform_device	*pdev;
	struct musb		*musb;
	struct clk		*clk;
	struct usb_role_switch	*role_sw;
};

static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci)
{
	unsigned long	flags;
	irqreturn_t	retval = IRQ_NONE, retval_dma = IRQ_NONE;
	struct musb	*musb = __hci;

	if (IS_ENABLED(CONFIG_USB_INVENTRA_DMA) && musb->dma_controller)
		retval_dma = dma_controller_irq(irq, musb->dma_controller);

	spin_lock_irqsave(&musb->lock, flags);

	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);

	/*
	 * The controller is gadget only, the state of the host mode IRQ bits is
	 * undefined. Mask them to make sure that the musb driver core will
	 * never see them set
	 */
	musb->int_usb &= MUSB_INTR_SUSPEND | MUSB_INTR_RESUME |
			 MUSB_INTR_RESET | MUSB_INTR_SOF;

	if (musb->int_usb || musb->int_tx || musb->int_rx)
		retval = musb_interrupt(musb);

	spin_unlock_irqrestore(&musb->lock, flags);

	if (retval == IRQ_HANDLED || retval_dma == IRQ_HANDLED)
		return IRQ_HANDLED;

	return IRQ_NONE;
}

static const struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = {
	{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
	{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
	{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 64, },
};

static const struct musb_hdrc_config jz4740_musb_config = {
	/* Silicon does not implement USB OTG. */
	.multipoint	= 0,
	/* Max EPs scanned, driver will decide which EP can be used. */
	.num_eps	= 4,
	/* RAMbits needed to configure EPs from table */
	.ram_bits	= 9,
	.fifo_cfg	= jz4740_musb_fifo_cfg,
	.fifo_cfg_size	= ARRAY_SIZE(jz4740_musb_fifo_cfg),
};

static int jz4740_musb_role_switch_set(struct usb_role_switch *sw,
				       enum usb_role role)
{
	struct jz4740_glue *glue = usb_role_switch_get_drvdata(sw);
	struct usb_phy *phy = glue->musb->xceiv;

	if (!phy)
		return 0;

	switch (role) {
	case USB_ROLE_NONE:
		atomic_notifier_call_chain(&phy->notifier, USB_EVENT_NONE, phy);
		break;
	case USB_ROLE_DEVICE:
		atomic_notifier_call_chain(&phy->notifier, USB_EVENT_VBUS, phy);
		break;
	case USB_ROLE_HOST:
		atomic_notifier_call_chain(&phy->notifier, USB_EVENT_ID, phy);
		break;
	}

	return 0;
}

static int jz4740_musb_init(struct musb *musb)
{
	struct device *dev = musb->controller->parent;
	struct jz4740_glue *glue = dev_get_drvdata(dev);
	struct usb_role_switch_desc role_sw_desc = {
		.set = jz4740_musb_role_switch_set,
		.driver_data = glue,
		.fwnode = dev_fwnode(dev),

Annotation

Implementation Notes