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);

 

musb 中文翻译和英文文档.可以通过会话请求协议(SRP)发起USB流量,而双角色设备同时支持SRP和主机协商协议(HNP),并且可以根据需要担任主机或外设的角色。MUSBMHDRC还支持拆分事务,这反过来允许它支持使用带有USB 2.0集线器的全速度或低速设备。核心还包括支持在不使用时关闭便携式设备。 除了端点0之外,MUSBMHDRC是用户可配置的,可支持最多15个‘传输’端点和/或最多15个‘接收’端点。(对于IN事务和OUT事务使用这些端点取决于MUSBMHDRC是用作外设还是用作主机。当用作外设时,IN事务通过TX端点处理,OUT事务通过Rx端点处理。当用作主机时,IN事务通过Rx端点处理,OUT事务通过TX端点处理。)这些附加端点可以在软件中单独配置,以处理批量传输(这也允许它们处理中断传输)、同步传输或控制传输。此外,还可以动态地将端点分配给不同的目标设备函数——最大限度地同时支持设备的数量。 每个端点都需要一个FIFO与之关联。MUSBMHDRC有一个RAM接口,用于连接到用于所有端点FIFOs的同步单端口RAM的单个块。(RAM块本身需要由用户添加。) 端点0的FIFO需要为64字节深,并缓冲1个数据包。RAM接口可以根据其他端点FIFOs进行配置,它的大小可以从8到8192字节,可以缓冲1个或2个数据包。单独的FIFOs可以与每个端点相关联:或者,具有相同端点编号的TX端点和Rx端点可以配置为使用相同的FIFO,例如,如果它们永远不能同时活动,可以减少所需RAM块的大小。 MUSBMHDRC提供了一个32位同步CPU接口,设计用于连接AMBA AHB bus1。接口支持使用AHB总线运行在一个大范围的总线速度。AHB总线上的多层操作也被支持。通过添加合适的包装器/桥接器,MUSBMHDRC还可以很容易地连接到一系列其他标准总线。 还支持对端点FIFOs的DMA访问。 MUSBMHDRC提供了一个UTMI+ 3级兼容接口,用于连接到一个合适的USB高/全速收发器。包含了一个可选的ULPI链接包装器(musbhdrc /docs目录中包含的musbhdrc_ulpi_an.pdf文档中描述),用于连接到与ULPI兼容的物理。另一种接口也提供,允许使用USB 1.1与核心全速PHY,但仅为全速和低速事务。(此接口见8.1节)MUSBMHDRC提供发送和接收USB数据包所需的所有编码、解码、检查和重新请求——仅当端点数据已被成功传输时才中断CPU。 当充当主机时,MUSBMHDRC另外维护一个帧计数器,并自动调度SOF、同步、中断和批量传输。它还包括对在点对点通信中使用的会话请求和主机协商协议的支持,其细节在USB 2.0规范的USB on - go补充中给出。MUSBMHDRC提供了一系列的测试模式——主要是USB 2.0规范中描述的高速运行的四种测试模式。它还包括选项,允许它被迫进入全速模式,高速模式或主机模式。最后一个可能在帮助调试硬件PHY问题时有用。 提供了图形用户界面脚本,用于根据用户的需求配置核心。要使用的脚本取决于所选的CPU接口。请注意:在撰写本文时,内核仅在Verilog中可用。 本规范应与USB运行规范一起阅读,该规范还提供了电源要求、电压水平、连接器等细节。.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值