hcd nonper channel problem & suspend when no device connect

This commit is contained in:
yangkai
2012-07-09 10:41:30 +08:00
parent 9d19ca3097
commit b61b9880f0
2 changed files with 56 additions and 19 deletions

View File

@@ -432,6 +432,10 @@ static void kill_all_urbs(dwc_otg_hcd_t *_hcd)
// kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_assigned);
// kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_queued);
}
extern void release_channel(dwc_otg_hcd_t *_hcd,
dwc_hc_t *_hc,
dwc_otg_qtd_t *_qtd,
dwc_otg_halt_status_e _halt_status);
/**
* HCD Callback function for disconnect of the HCD.
@@ -463,7 +467,7 @@ static int32_t dwc_otg_hcd_disconnect_cb( void *_p )
dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintmsk, intr.d32, 0);
dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintsts, intr.d32, 0);
del_timers(dwc_otg_hcd);
// del_timers(dwc_otg_hcd);
/*
* Turn off the vbus power only if the core has transitioned to device
@@ -523,10 +527,13 @@ static int32_t dwc_otg_hcd_disconnect_cb( void *_p )
hcchar.b.chdis = 1;
dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
}
#if 1
release_channel(dwc_otg_hcd, channel, NULL, DWC_OTG_HC_XFER_URB_DEQUEUE);
#else
dwc_otg_hc_cleanup(dwc_otg_hcd->core_if, channel);
list_add_tail(&channel->hc_list_entry,
&dwc_otg_hcd->free_hc_list);
#endif
}
}
}
@@ -556,11 +563,11 @@ void dwc_otg_hcd_connect_timeout( unsigned long _ptr )
*/
static void dwc_otg_hcd_start_connect_timer( dwc_otg_hcd_t *_hcd)
{
init_timer( &_hcd->conn_timer );
_hcd->conn_timer.function = dwc_otg_hcd_connect_timeout;
_hcd->conn_timer.data = (unsigned long)0;
_hcd->conn_timer.expires = jiffies + (HZ*10);
add_timer( &_hcd->conn_timer );
init_timer( &_hcd->conn_timer );
_hcd->conn_timer.function = dwc_otg_hcd_connect_timeout;
_hcd->conn_timer.data = (unsigned long)0;
_hcd->conn_timer.expires = jiffies + (HZ*10);
add_timer( &_hcd->conn_timer );
}
/**
@@ -572,7 +579,7 @@ static int32_t dwc_otg_hcd_session_start_cb( void *_p )
{
dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_p);
DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p);
dwc_otg_hcd_start_connect_timer( dwc_otg_hcd );
// dwc_otg_hcd_start_connect_timer( dwc_otg_hcd );
return 1;
}
@@ -599,6 +606,18 @@ static int32_t dwc_otg_phy_suspend_cb( void *_p, int suspend)
DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n");
}
#endif
#ifdef CONFIG_ARCH_RK30
unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON2);
if(suspend) {
*otg_phy_con1 = ((0x01<<2)<<16); // exit suspend.
DWC_DEBUGPL(DBG_PCDV, "enable usb phy\n");
}
else{
*otg_phy_con1 = 0x554|(0xfff<<16); // enter suspend.
udelay(3);
DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n");
}
#endif
return suspend;
}
@@ -661,7 +680,7 @@ static void dwc_otg_hcd_enable(struct work_struct *work)
dwc_otg_hcd->host_enabled = dwc_otg_hcd->host_setenable;
if(dwc_otg_hcd->host_setenable == 0) // enable -> disable
{
DWC_PRINT("disable host controller\n");
DWC_PRINT("%s, disable host controller\n", __func__);
#if 1
if (_core_if->hcd_cb && _core_if->hcd_cb->disconnect) {
_core_if->hcd_cb->disconnect( _core_if->hcd_cb->p );
@@ -679,7 +698,7 @@ static void dwc_otg_hcd_enable(struct work_struct *work)
}
else if(dwc_otg_hcd->host_setenable == 1)
{
DWC_PRINT("enable host controller\n");
DWC_PRINT("%s, enable host controller\n", __func__);
// clk_enable(otg_dev->phyclk);
// clk_enable(otg_dev->ahbclk);
if (_core_if->hcd_cb && _core_if->hcd_cb->suspend) {
@@ -701,7 +720,7 @@ static void dwc_otg_hcd_connect_detect(unsigned long pdata)
local_irq_save(flags);
// DWC_PRINT("%s %p, grfstatus 0x%x\n", __func__, dwc_otg_hcd, usbgrf_status& (7<<22));
// DWC_PRINT("%s hprt %x, grfstatus 0x%x\n", __func__, dwc_read_reg32(core_if->host_if->hprt0), usbgrf_status& (7<<22));
if(usbgrf_status & (7<<22)){
// usb device connected
dwc_otg_hcd->host_setenable = 1;
@@ -712,7 +731,10 @@ static void dwc_otg_hcd_connect_detect(unsigned long pdata)
dwc_otg_hcd->host_setenable = 0;
}
schedule_delayed_work(&dwc_otg_hcd->host_enable_work, jiffies);
if(dwc_otg_hcd->host_setenable != dwc_otg_hcd->host_enabled){
DWC_PRINT("%s schedule delaywork \n", __func__, dwc_read_reg32(core_if->host_if->hprt0), usbgrf_status& (7<<22));
schedule_delayed_work(&dwc_otg_hcd->host_enable_work, 8);
}
// dwc_otg_hcd->connect_detect_timer.expires = jiffies + (HZ<<1); /* 1 s */
mod_timer(&dwc_otg_hcd->connect_detect_timer,jiffies + (HZ<<1));
local_irq_restore(flags);
@@ -814,7 +836,7 @@ int __devinit dwc_otg_hcd_init(struct device *dev)
}
/* Initialize the Connection timeout timer. */
init_timer( &dwc_otg_hcd->conn_timer );
// init_timer( &dwc_otg_hcd->conn_timer );
/* Initialize reset tasklet. */
reset_tasklet.data = (unsigned long) dwc_otg_hcd;
@@ -999,7 +1021,7 @@ int __devinit host11_hcd_init(struct device *dev)
}
/* Initialize the Connection timeout timer. */
init_timer( &dwc_otg_hcd->conn_timer );
// init_timer( &dwc_otg_hcd->conn_timer );
/* Initialize reset tasklet. */
host11_reset_tasklet.data = (unsigned long) dwc_otg_hcd;
@@ -1082,6 +1104,19 @@ static int32_t host20_phy_suspend_cb( void *_p, int suspend)
}
*otg_phy_con1 = regval;
#endif
#ifdef CONFIG_ARCH_RK30
unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON2);
if(suspend) {
*otg_phy_con1 = ((0x01<<2)<<16); // exit suspend.
DWC_DEBUGPL(DBG_PCDV, "enable usb phy\n");
}
else{
*otg_phy_con1 = 0x554|(0xfff<<16); // enter suspend.
udelay(3);
DWC_DEBUGPL(DBG_PCDV, "disable usb phy\n");
}
#endif
return suspend;
}
@@ -1450,7 +1485,7 @@ void dwc_otg_hcd_free(struct usb_hcd *_hcd)
DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
del_timers(dwc_otg_hcd);
// del_timers(dwc_otg_hcd);
/* Free memory for QH/QTD lists */
qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
@@ -1683,7 +1718,6 @@ int dwc_otg_hcd_urb_dequeue(struct usb_hcd *_hcd, struct urb *_urb, int _status)
if (urb_qtd == qh->qtd_in_process) {
/* The QTD is in process (it has been assigned to a channel). */
if (dwc_otg_hcd->flags.b.port_connect_status) {
/*
* If still connected (i.e. in host mode), halt the
* channel so it can be used for other transfers. If
@@ -2947,7 +2981,8 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t *_hcd)
/* Process entries in the periodic ready list. */
qh_ptr = _hcd->periodic_sched_inactive.next;
while (qh_ptr != &_hcd->periodic_sched_inactive) {
while ((qh_ptr != &_hcd->periodic_sched_inactive)&&
!list_empty(&_hcd->free_hc_list)) {
qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry);
if(qh->qh_state != QH_READY){
qh_ptr = qh_ptr->next;

View File

@@ -359,7 +359,7 @@ int32_t dwc_otg_hcd_handle_port_intr (dwc_otg_hcd_t *_dwc_otg_hcd)
hprt0_modify.b.prtconndet = 1;
/* B-Device has connected, Delete the connection timer. */
del_timer( &_dwc_otg_hcd->conn_timer );
// del_timer( &_dwc_otg_hcd->conn_timer );
/* The Hub driver asserts a reset when it sees port connect
* status change flag */
@@ -813,7 +813,8 @@ update_isoc_urb_state(dwc_otg_hcd_t *_hcd,
* @param _halt_status Reason the channel is being released. This status
* determines the actions taken by this function.
*/
static void release_channel(dwc_otg_hcd_t *_hcd,
/*static */
void release_channel(dwc_otg_hcd_t *_hcd,
dwc_hc_t *_hc,
dwc_otg_qtd_t *_qtd,
dwc_otg_halt_status_e _halt_status)
@@ -863,6 +864,7 @@ static void release_channel(dwc_otg_hcd_t *_hcd,
* deactivated. Don't want to do anything except release the
* host channel and try to queue more transfers.
*/
continue_trans = 0;
goto cleanup;
case DWC_OTG_HC_XFER_NO_HALT_STATUS:
DWC_ERROR("%s: No halt_status, channel %d\n", __func__, _hc->hc_num);