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