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