USB驅動之二控制器驅動(musb)

對於mtk和sprd的usb控制器驅動都是musb,qcom的是dwc2/dwc3,拿musb來學習下。

現在嵌入式設備USB都支持主從了,控制器也分爲兩部分,一部分是HCD,一部分是UDC。
OHCI(open host controller inferface)
UHCI(universal host controller interface)
EHCI(enhanced host controller interface)
Multipoint USB Highspeed Dual-Role Controller (MUSB HDRC) 

UDC(usb device controllerr/從)
HCD(host controller device/主)

struct usb_udc {
	struct usb_gadget_driver	*driver;
	struct usb_gadget		*gadget;
	struct device			dev;
	struct list_head		list;
	bool				vbus;
};
struct usb_hcd {
	...
	const struct hc_driver	*driver;	/* hw-specific hooks */
	...
}

某主板的dts中usb控制器描述

usb: usb@20200000 {
                                compatible = "sprd,usb";
                                reg = <0x20200000 0x2000>;
                                interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
                                interrupt-names = "mc";
                                clocks = <&clk_ap_ahb_gates 4>;
                                clock-names = "core_clk";
                                phy-type = "usb20_sprd_phy";
                                usb-phy = <&hsphy>;
                                phy-names = "usb";
};

static int musb_sprd_probe(struct platform_device *pdev){
    struct platform_device_info pinfo;    
    pinfo.name = "musb-hdrc";
    platform_device_register_full(&pinfo);
}

static const struct of_device_id usb_ids[] = {
	{ .compatible = "sprd,usb" },
	{}
};

static struct platform_driver musb_sprd_driver = {
	.driver = {
		.name = "musb-sprd",
		.of_match_table = usb_ids,
	},
	.probe = musb_sprd_probe,
	.remove = musb_sprd_remove,
};
#define MUSB_DRIVER_NAME "musb-hdrc"
const char musb_driver_name[] = MUSB_DRIVER_NAME;
static struct platform_driver musb_driver = {
    .driver = {
        .name        = (char *)musb_driver_name,
        .bus        = &platform_bus_type,
        .pm        = MUSB_DEV_PM_OPS,
    },
    .probe        = musb_probe,
};

module_platform_driver(musb_driver);

static int musb_probe(struct platform_device *pdev)
{
    struct device    *dev = &pdev->dev;
    int        irq = platform_get_irq_byname(pdev, "mc");
    struct resource    *iomem;
    void __iomem    *base;

    if (irq <= 0)
        return -ENODEV;

    iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    base = devm_ioremap_resource(dev, iomem);
    if (IS_ERR(base))
        return PTR_ERR(base);

    return musb_init_controller(dev, irq, base);
}

 分別註冊主從控制器

static int musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
{
    struct musb		*musb;
    musb = allocate_instance(dev, plat->config, ctrl);--->musb_host_alloc
    request_irq(nIrq, musb->isr, 0, dev_name(dev), musb)
    switch (musb->port_mode) {
        case MUSB_PORT_MODE_DUAL_ROLE://雙角色/主從
        musb_host_setup(musb, plat->power);//主
        musb_gadget_setup(musb);//從    
}

 

HCD的註冊過程

 

UDC的註冊過程

int musb_gadget_setup(struct musb *musb)
{
	int status;

	/* REVISIT minor race:  if (erroneously) setting up two
	 * musb peripherals at the same time, only the bus lock
	 * is probably held.
	 */

	musb->g.ops = &musb_gadget_operations;
	musb->g.max_speed = USB_SPEED_HIGH;
	musb->g.speed = USB_SPEED_UNKNOWN;
	musb->g.sg_supported	= true;

	MUSB_DEV_MODE(musb);
	musb->xceiv->otg->default_a = 0;
	musb->xceiv->otg->state = OTG_STATE_B_IDLE;

	/* this "gadget" abstracts/virtualizes the controller */
	musb->g.name = musb_driver_name;
#if IS_ENABLED(CONFIG_USB_MUSB_DUAL_ROLE)
	musb->g.is_otg = 1;
#elif IS_ENABLED(CONFIG_USB_MUSB_GADGET)
	musb->g.is_otg = 0;
#endif

	musb_g_init_endpoints(musb);

	musb->is_active = 0;
	musb_platform_try_idle(musb, 0);

	status = usb_add_gadget_udc(musb->controller, &musb->g);
	if (status)
		goto err;

	return 0;
err:
	musb->g.dev.parent = NULL;
	device_unregister(&musb->g.dev);
	return status;
}

/**
 * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
 * @parent: the parent device to this udc. Usually the controller driver's
 * device.
 * @gadget: the gadget to be added to the list.
 * @release: a gadget release function.
 *
 * Returns zero on success, negative errno otherwise.
 */
int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
		void (*release)(struct device *dev))
{
	struct usb_udc		*udc;
	int			ret = -ENOMEM;

	udc = kzalloc(sizeof(*udc), GFP_KERNEL);
	if (!udc)
		goto err1;

	dev_set_name(&gadget->dev, "gadget");
	INIT_WORK(&gadget->work, usb_gadget_state_work);
	gadget->dev.parent = parent;

#ifdef	CONFIG_HAS_DMA
	dma_set_coherent_mask(&gadget->dev, parent->coherent_dma_mask);
	gadget->dev.dma_parms = parent->dma_parms;
	gadget->dev.dma_mask = parent->dma_mask;
#endif

	if (release)
		gadget->dev.release = release;
	else
		gadget->dev.release = usb_udc_nop_release;

	ret = device_register(&gadget->dev);
	if (ret)
		goto err2;

	device_initialize(&udc->dev);
	udc->dev.release = usb_udc_release;
	udc->dev.class = udc_class;
	udc->dev.groups = usb_udc_attr_groups;
	udc->dev.parent = parent;
	ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
	if (ret)
		goto err3;

	udc->gadget = gadget;
	gadget->udc = udc;

	mutex_lock(&udc_lock);
	list_add_tail(&udc->list, &udc_list);

	ret = device_add(&udc->dev);
	if (ret)
		goto err4;

	ret = usb_charger_init(gadget);
	if (ret)
		goto err5;

	usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
	udc->vbus = true;

	mutex_unlock(&udc_lock);

	return 0;

err5:
	device_del(&udc->dev);
err4:
	list_del(&udc->list);
	mutex_unlock(&udc_lock);

err3:
	put_device(&udc->dev);
	device_del(&gadget->dev);

err2:
	put_device(&gadget->dev);
	kfree(udc);

err1:
	return ret;
}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);

/**
 * usb_add_gadget_udc - adds a new gadget to the udc class driver list
 * @parent: the parent device to this udc. Usually the controller
 * driver's device.
 * @gadget: the gadget to be added to the list
 *
 * Returns zero on success, negative errno otherwise.
 */
int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
{
	return usb_add_gadget_udc_release(parent, gadget, NULL);
}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc);

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章