阅读:1642回复:0
OTG Transceiver --- ISP1301 的驱动代码分析(一)
排版有些问题,请参考http://blog.csdn.net/zkami
Isp1301是philips的外部收发器, 完全支持USB2.0和OTG1.0a规范。能以12Mbit/s(full-speed)和1.5Mbit/s(low-speed)的速度发送和接收串行数据。支持I2C总线接口。本文分析linux-2.6中isp1301 driver的code (isp1301_omap.c) include/linux/usb/otg.h /* * the otg driver needs to interact with both device side and host side * usb controllers. it decides which controller is active at a given * moment, using the transceiver, ID signal, HNP and sometimes static * configuration information (including "board isn't wired for otg"). */ struct otg_transceiver { struct device *dev; const char *label; u8 default_a; enum usb_otg_state state; struct usb_bus *host; struct usb_gadget *gadget; /* to pass extra port status to the root hub */ u16 port_status; u16 port_change; /* bind/unbind the host controller */ int (*set_host)(struct otg_transceiver *otg, struct usb_bus *host); /* bind/unbind the peripheral controller */ int (*set_peripheral)(struct otg_transceiver *otg, struct usb_gadget *gadget); /* effective for B devices, ignored for A-peripheral */ int (*set_power)(struct otg_transceiver *otg, unsigned mA); /* for non-OTG B devices: set transceiver into suspend mode */ int (*set_suspend)(struct otg_transceiver *otg, int suspend); /* for B devices only: start session with A-Host */ int (*start_srp)(struct otg_transceiver *otg); /* start or continue HNP role switch */ int (*start_hnp)(struct otg_transceiver *otg); }; drivers/i2c/chips/isp1301_omap.c struct isp1301 { struct otg_transceiver otg; //继承了strcuct otg_transceiver 的所有特性和接口 struct i2c_client client; void (*i2c_release)(struct device *dev); int irq; u32 last_otg_ctrl; unsigned working:1; struct timer_list timer; /* use keventd context to change the state for us */ struct work_struct work; unsigned long todo; # define WORK_UPDATE_ISP 0 /* update ISP from OTG */ # define WORK_UPDATE_OTG 1 /* update OTG from ISP */ # define WORK_HOST_RESUME 4 /* resume host */ # define WORK_TIMER 6 /* timer fired */ # define WORK_STOP 7 /* don't resubmit */ }; 在booting的时侯首先调用isp1301_scan_bus ---> i2c_probe(bus, &addr_data, isp1301_probe)探测i2c总线设备,进而调用 /* no error returns, they'd just make bus scanning stop */ static int isp1301_probe(struct i2c_adapter *bus, int address, int kind) { //分配一个struct isp1301的对象,并初始化其中各项 struct isp1301 *isp = kzalloc(sizeof *isp, GFP_KERNEL); ... INIT_WORK(&isp->work, isp1301_work, isp); //初始化isp1301的工作队列 init_timer(&isp->timer); //初始化isp1301的定时器 isp->timer.function = isp1301_timer; isp->timer.data = (unsigned long) isp; isp->irq = -1; //探测是否是isp1301,如果是进行一些chip的初始化设置 ... status = otg_bind(isp); //注册omap_otg_driver isp->otg.set_host = isp1301_set_host, //将这个设备的角色设为host isp->otg.set_peripheral = isp1301_set_peripheral, //将这个设备的角色设为peripheral isp->otg.set_power = isp1301_set_power, //设置transceiver的电流 isp->otg.start_srp = isp1301_start_srp, //发起srp isp->otg.start_hnp = isp1301_start_hnp, //发起hnp update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE)); update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS)); ... } static int otg_bind(struct isp1301 *isp) { //注册一个platform_device,在omap_otg_init的时侯会注册一个platform_device //platform_device_register(&otg_device),这样在device与driver间进行匹配 platform_driver_register(&omap_otg_driver); ... //注册isp1301的中断处理程序 request_irq(otg_dev->resource[1].start, omap_otg_irq, SA_INTERRUPT, DRIVER_NAME, isp); ... } static int isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host) {//将这个设备的角色设为host isp->otg.host = host; //用struct usb_bus来抽象这个host设备 host_suspend(isp); //挂起host if (isp->otg.gadget) //如果这个设备角色还是peripheral return isp1301_otg_enable(isp); //重新使能这个isp1301,因为一个设备不可能即是host又是peripheral return 0; } static int isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget) {//将这个设备的角色设为peripheral,同isp1301_set_host() isp->otg.gadget = gadget; /* gadget driver 可以挂起直到 vbus_connect () */ if (isp->otg.host) return isp1301_otg_enable(isp); return 0; } static int isp1301_set_power(struct otg_transceiver *dev, unsigned mA) {//只有当设备角色是B PERIPHERAL时,才能设置transceiver的电流,大小是第二个参数 if (dev->state == OTG_STATE_B_PERIPHERAL) enable_vbus_draw(the_transceiver, mA); } static int isp1301_start_srp(struct otg_transceiver *dev) { otg_ctrl = OTG_CTRL_REG; otg_ctrl |= OTG_B_BUSREQ; otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK; OTG_CTRL_REG = otg_ctrl; isp->otg.state = OTG_STATE_B_SRP_INIT; } static int isp1301_start_hnp(struct otg_transceiver *dev) { 跟距isp->otg.state判断: (1) OTG_STATE_B_HOST: isp->otg.state=OTG_STATE_B_PERIPHERAL 接着挂起 (2) OTG_STATE_A_HOST: 调用者必须挂起,接着清A_BUSREQ标志 usb_gadget_vbus_connect(isp->otg.gadget) OTG_CTRL_REQ |= OTG_A_SETB_HNPEN (3) OTG_STATE_A_PERIPHERAL: 已经由B-HOST挂起初始化 } void isp1301_work(struct work_struct *work) {//由isp1301_timer定时调用 (1) WORK_UPDATE_ISP: 将state从otg engine传到isp1301 otg_update_isp(isp); (2) WORK_UPDATE_ISP: 将state从isp1301传到otg engine otg_update_OTG(isp); (3) WORK_HOST_RESUME: 根距isp->otg.state判断 host_resume(isp) } |
|