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