int usb_otg_start( struct platform_device * pdev) { struct fsl_otg * p_otg; /*获得otg_transceiver结构 */ struct otg_transceiver * otg_trans = otg_get_transceiver( ) ; struct otg_fsm * fsm; volatile unsigned long * p; int status; struct resource * res; u32 temp; /*获得设备的私有数据*/ struct fsl_usb2_platform_data * pdata = pdev- > dev. platform_data; /* 使用container_of宏定义可以通过结构中一个变量的指针获得该结构首地址 */ p_otg = container_of( otg_trans, struct fsl_otg, otg) ; fsm = & p_otg- > fsm; /* Initialize the state machine structure with default values */ SET_OTG_STATE( otg_trans, OTG_STATE_UNDEFINED) ; fsm- > transceiver = & p_otg- > otg; /* We don't require predefined MEM/IRQ resource index */ /*获得设备的资源,是在设备注册时结构体里面的内容*/ res = platform_get_resource( pdev, IORESOURCE_MEM, 0) ; if ( ! res) return - ENXIO; /* We don't request_mem_region here to enable resource sharing * with host/device */ /*通过资源中获得的物理地址映射一个可以被驱动访问的虚拟地址指针*/ usb_dr_regs = ioremap( res- > start, sizeof ( struct usb_dr_mmap) ) ; /*将该指针保存到p_otg - > dr_mem_map中 */ p_otg- > dr_mem_map = ( struct usb_dr_mmap * ) usb_dr_regs; pdata- > regs = ( void * ) usb_dr_regs; /* request irq */ /*获得设备注册时候的中断并注册,在 OTG ID发生变化时触发中断,然后调用注册的中断例程函数,函数后面分析*/ p_otg- > irq = platform_get_irq( pdev, 0) ; status = request_irq( p_otg- > irq, fsl_otg_isr, IRQF_SHARED, driver_name, p_otg) ; if ( status) { dev_dbg( p_otg- > otg. dev, "can't get IRQ %d, error %d/n" , p_otg- > irq, status) ; iounmap( p_otg- > dr_mem_map) ; kfree( p_otg) ; return status; } if ( pdata- > platform_init & & pdata- > platform_init( pdev) ! = 0) return - EINVAL; /* Export DR controller resources */ /**************************************************/ int otg_set_resources(struct resource *resources) { otg_resources = resources; return 0; } 和otg_set_transceiver功能类似将设备资源保存到一个全局变量中 /**************************************************/ otg_set_resources( pdev- > resource) ; /*开始配置USB寄存器*/ /* stop the controller */ temp = readl( & p_otg- > dr_mem_map- > usbcmd) ; temp & = ~ USB_CMD_RUN_STOP; writel( temp, & p_otg- > dr_mem_map- > usbcmd) ; /* reset the controller */ temp = readl( & p_otg- > dr_mem_map- > usbcmd) ; temp | = USB_CMD_CTRL_RESET; writel( temp, & p_otg- > dr_mem_map- > usbcmd) ; /* wait reset completed */ while ( readl( & p_otg- > dr_mem_map- > usbcmd) & USB_CMD_CTRL_RESET) ; /* configure the VBUSHS as IDLE(both host and device) */ temp = USB_MODE_STREAM_DISABLE | ( pdata- > es ? USB_MODE_ES : 0) ; writel( temp, & p_otg- > dr_mem_map- > usbmode) ; /* configure PHY interface */ temp = readl( & p_otg- > dr_mem_map- > portsc) ; temp & = ~ ( PORTSC_PHY_TYPE_SEL | PORTSC_PTW) ; switch ( pdata- > phy_mode) { case FSL_USB2_PHY_ULPI: temp | = PORTSC_PTS_ULPI; break ; case FSL_USB2_PHY_UTMI_WIDE: temp | = PORTSC_PTW_16BIT; /* fall through */ case FSL_USB2_PHY_UTMI: temp | = PORTSC_PTS_UTMI; /* fall through */ default : break ; } writel( temp, & p_otg- > dr_mem_map- > portsc) ; if ( pdata- > have_sysif_regs) { /* configure control enable IO output, big endian register */ p = ( volatile unsigned long * ) ( & p_otg- > dr_mem_map- > control) ; temp = * p; temp | = USB_CTRL_IOENB; * p = temp; } /* disable all interrupt and clear all OTGSC status */ temp = readl( & p_otg- > dr_mem_map- > otgsc) ; temp & = ~ OTGSC_INTERRUPT_ENABLE_BITS_MASK; temp | = OTGSC_INTERRUPT_STATUS_BITS_MASK | OTGSC_CTRL_VBUS_DISCHARGE; writel( temp, & p_otg- > dr_mem_map- > otgsc) ; /* * The identification (id) input is FALSE when a Mini-A plug is inserted * in the devices Mini-AB receptacle. Otherwise, this input is TRUE. * Also: record initial state of ID pin */ if ( le32_to_cpu( p_otg- > dr_mem_map- > otgsc) & OTGSC_STS_USB_ID) { p_otg- > otg. state = OTG_STATE_UNDEFINED; p_otg- > fsm. id = 1; } else { p_otg- > otg. state = OTG_STATE_A_IDLE; p_otg- > fsm. id = 0; } DBG( "initial ID pin=%d/n" , p_otg- > fsm. id) ; /* enable OTG ID pin interrupt */ temp = readl( & p_otg- > dr_mem_map- > otgsc) ; temp | = OTGSC_INTR_USB_ID_EN; temp & = ~ ( OTGSC_CTRL_VBUS_DISCHARGE | OTGSC_INTR_1MS_TIMER_EN) ; writel( temp, & p_otg- > dr_mem_map- > otgsc) ; return 0; } |