musb_hdrc: Improve tusb clocking, add musb_platform_wakeup()
Subsystems (2)
A message that is not in the archive (sent off-list or not yet received): musb-2007-10-21
cover musb_hdrc: Improve tusb clocking, add musb_platform_wakeup()
Hi all,
Attached series improves cleans up musb_gadget_ep0 a bit, improves tusb clock handling, and introduces musb_platform_wakeup().
Tested on tusb.
BTW, regarding sending these patches upstream, I probably won't have time to prepare the series and do the necessary clean-up for next few weeks because of some work stuff I need to deal with.
Regards,
Tony
PATCH 1/6 musb_hdrc: Removed nestedness in musb_gadget_ep0
Return early to leave out one level of nestedness. No functional changes.
--- drivers/usb/musb/musb_gadget_ep0.c | 326 ++++++++++++++++++------------------ 1 files changed, 160 insertions(+), 166 deletions(-)
drivers/usb/musb/musb_gadget_ep0.c +160 -166
@@ -234,199 +234,193 @@ __acquires(musb->lock)const u8 recip = ctrlrequest->bRequestType &USB_RECIP_MASK ;/* the gadget driver handles everything except what we MUST handle */ -if ((ctrlrequest->bRequestType &USB_TYPE_MASK ) - ==USB_TYPE_STANDARD ) { -switch (ctrlrequest->bRequest) { -case USB_REQ_SET_ADDRESS : -/* change it after the status stage */ - musb->set_address = true; - musb->address = (u8) (ctrlrequest->wValue &0x7f ); +if ((ctrlrequest->bRequestType &USB_TYPE_MASK ) !=USB_TYPE_STANDARD ) { + handled =0 ; + goto out; + } + +switch (ctrlrequest->bRequest) { +case USB_REQ_SET_ADDRESS : +/* change it after the status stage */ + musb->set_address = true; + musb->address = (u8) (ctrlrequest->wValue &0x7f ); + handled =1 ; +break ; + +case USB_REQ_CLEAR_FEATURE : +switch (recip) { +case USB_RECIP_DEVICE : +if (ctrlrequest->wValue !=USB_DEVICE_REMOTE_WAKEUP ) +break ; + musb->may_wakeup =0 ; handled =1 ;break ; +case USB_RECIP_INTERFACE : +break ; +case USB_RECIP_ENDPOINT : + { +const u8 epnum = ctrlrequest->wIndex &0x0f ; +struct musb_ep *musb_ep; -case USB_REQ_CLEAR_FEATURE : -switch (recip) { -case USB_RECIP_DEVICE : -if (ctrlrequest->wValue - !=USB_DEVICE_REMOTE_WAKEUP ) -break ; - musb->may_wakeup =0 ; - handled =1 ; -break ; -case USB_RECIP_INTERFACE : -break ; -case USB_RECIP_ENDPOINT :{ -const u8 epnum = ctrlrequest->wIndex &0x0f ; -struct musb_ep *musb_ep; - -if (epnum ==0 - || epnum >=MUSB_C_NUM_EPS - || ctrlrequest->wValue - !=USB_ENDPOINT_HALT ) +if (epnum ==0 || epnum >=MUSB_C_NUM_EPS + || ctrlrequest->wValue !=USB_ENDPOINT_HALT )break ; -if (ctrlrequest->wIndex &USB_DIR_IN ) - musb_ep = &musb->endpoints[epnum].ep_in; -else - musb_ep = &musb->endpoints[epnum].ep_out; -if (!musb_ep->desc) -break ; +if (ctrlrequest->wIndex &USB_DIR_IN ) + musb_ep = &musb->endpoints[epnum].ep_in; +else + musb_ep = &musb->endpoints[epnum].ep_out; +if (!musb_ep->desc) +break ; -/* REVISIT do it directly, no locking games */ -spin_unlock (&musb->lock); -musb_gadget_set_halt (&musb_ep->end_point,0 ); -spin_lock (&musb->lock); +/* REVISIT do it directly, no locking games */ +spin_unlock (&musb->lock); +musb_gadget_set_halt (&musb_ep->end_point,0 ); +spin_lock (&musb->lock); -/* select ep0 again */ -musb_ep_select (mbase,0 ); - handled =1 ; - }break ; -default : -/* class, vendor, etc ... delegate */ - handled =0 ; -break ; - } +/* select ep0 again */ +musb_ep_select (mbase,0 ); + handled =1 ; + } +break ; +default : +/* class, vendor, etc ... delegate */ + handled =0 ;break ; + } +break ; -case USB_REQ_SET_FEATURE : -switch (recip) { -case USB_RECIP_DEVICE : - handled =1 ; -switch (ctrlrequest->wValue) { -case USB_DEVICE_REMOTE_WAKEUP : - musb->may_wakeup =1 ; -break ; -case USB_DEVICE_TEST_MODE : -if (musb->g.speed !=USB_SPEED_HIGH ) - goto stall; -if (ctrlrequest->wIndex &0xff ) - goto stall; - -switch (ctrlrequest->wIndex >>8 ) { -case 1 : -pr_debug ("TEST_J\n" ); -/* TEST_J */ - musb->test_mode_nr = -MUSB_TEST_J ; -break ; -case 2 : -/* TEST_K */ -pr_debug ("TEST_K\n" ); - musb->test_mode_nr = -MUSB_TEST_K ; -break ; -case 3 : -/* TEST_SE0_NAK */ -pr_debug ("TEST_SE0_NAK\n" ); - musb->test_mode_nr = -MUSB_TEST_SE0_NAK ; -break ; -case 4 : -/* TEST_PACKET */ -pr_debug ("TEST_PACKET\n" ); - musb->test_mode_nr = -MUSB_TEST_PACKET ; -break ; -default : - goto stall; - } - -/* enter test mode after irq */ -if (handled >0 ) - musb->test_mode = true; +case USB_REQ_SET_FEATURE : +switch (recip) { +case USB_RECIP_DEVICE : + handled =1 ; +switch (ctrlrequest->wValue) { +case USB_DEVICE_REMOTE_WAKEUP : + musb->may_wakeup =1 ; +break ; +case USB_DEVICE_TEST_MODE : +if (musb->g.speed !=USB_SPEED_HIGH ) + goto stall; +if (ctrlrequest->wIndex &0xff ) + goto stall; + +switch (ctrlrequest->wIndex >>8 ) { +case 1 : +pr_debug ("TEST_J\n" ); +/* TEST_J */ + musb->test_mode_nr =MUSB_TEST_J ;break ; -#ifdef CONFIG_USB_MUSB_OTG -case USB_DEVICE_B_HNP_ENABLE : -if (!musb->g.is_otg) - goto stall; - musb->g.b_hnp_enable =1 ; -musb_try_b_hnp_enable (musb); +case 2 : +/* TEST_K */ +pr_debug ("TEST_K\n" ); + musb->test_mode_nr =MUSB_TEST_K ;break ; -case USB_DEVICE_A_HNP_SUPPORT : -if (!musb->g.is_otg) - goto stall; - musb->g.a_hnp_support =1 ; +case 3 : +/* TEST_SE0_NAK */ +pr_debug ("TEST_SE0_NAK\n" ); + musb->test_mode_nr = +MUSB_TEST_SE0_NAK ;break ; -case USB_DEVICE_A_ALT_HNP_SUPPORT : -if (!musb->g.is_otg) - goto stall; - musb->g.a_alt_hnp_support =1 ; +case 4 : +/* TEST_PACKET */ +pr_debug ("TEST_PACKET\n" ); + musb->test_mode_nr =MUSB_TEST_PACKET ;break ; -#endif -stall:default : - handled = -EINVAL ; -break ; + goto stall; } -break ; -case USB_RECIP_INTERFACE : +/* enter test mode after irq */ +if (handled >0 ) + musb->test_mode = true; +break ; +#ifdef CONFIG_USB_MUSB_OTG +case USB_DEVICE_B_HNP_ENABLE : +if (!musb->g.is_otg) + goto stall; + musb->g.b_hnp_enable =1 ; +musb_try_b_hnp_enable (musb); +break ; +case USB_DEVICE_A_HNP_SUPPORT : +if (!musb->g.is_otg) + goto stall; + musb->g.a_hnp_support =1 ;break ; +case USB_DEVICE_A_ALT_HNP_SUPPORT : +if (!musb->g.is_otg) + goto stall; + musb->g.a_alt_hnp_support =1 ; +break ; +#endif +stall: +default : + handled = -EINVAL ; +break ; + } +break ; -case USB_RECIP_ENDPOINT :{ -const u8 epnum = - ctrlrequest->wIndex &0x0f ; -struct musb_ep *musb_ep; -struct musb_hw_ep *ep; -void __iomem *regs; -int is_in; -u16 csr; - -if (epnum ==0 - || epnum >=MUSB_C_NUM_EPS - || ctrlrequest->wValue - !=USB_ENDPOINT_HALT ) -break ; +case USB_RECIP_INTERFACE : +break ; - ep = musb->endpoints + epnum; - regs = ep->regs; - is_in = ctrlrequest->wIndex &USB_DIR_IN ; -if (is_in) - musb_ep = &ep->ep_in; -else - musb_ep = &ep->ep_out; -if (!musb_ep->desc) +case USB_RECIP_ENDPOINT : + { +const u8 epnum = ctrlrequest->wIndex &0x0f ; +struct musb_ep *musb_ep; +struct musb_hw_ep *ep; +void __iomem *regs; +int is_in; +u16 csr; + +if (epnum ==0 || epnum >=MUSB_C_NUM_EPS + || ctrlrequest->wValue !=USB_ENDPOINT_HALT )break ; -musb_ep_select (mbase, epnum); -if (is_in) { - csr =musb_readw (regs, -MUSB_TXCSR ); -if (csr &MUSB_TXCSR_FIFONOTEMPTY ) - csr |=MUSB_TXCSR_FLUSHFIFO ; - csr |=MUSB_TXCSR_P_SENDSTALL - |MUSB_TXCSR_CLRDATATOG - |MUSB_TXCSR_P_WZC_BITS ; -musb_writew (regs,MUSB_TXCSR , - csr); - }else { - csr =musb_readw (regs, -MUSB_RXCSR ); - csr |=MUSB_RXCSR_P_SENDSTALL - |MUSB_RXCSR_FLUSHFIFO - |MUSB_RXCSR_CLRDATATOG - |MUSB_TXCSR_P_WZC_BITS ; -musb_writew (regs,MUSB_RXCSR , - csr); - } - -/* select ep0 again */ -musb_ep_select (mbase,0 ); - handled =1 ; - }break ; - -default : -/* class, vendor, etc ... delegate */ - handled =0 ; + ep = musb->endpoints + epnum; + regs = ep->regs; + is_in = ctrlrequest->wIndex &USB_DIR_IN ; +if (is_in) + musb_ep = &ep->ep_in; +else + musb_ep = &ep->ep_out; +if (!musb_ep->desc)break ; + +musb_ep_select (mbase, epnum); +if (is_in) { + csr =musb_readw (regs,MUSB_TXCSR ); +if (csr &MUSB_TXCSR_FIFONOTEMPTY ) + csr |=MUSB_TXCSR_FLUSHFIFO ; + csr |=MUSB_TXCSR_P_SENDSTALL + |MUSB_TXCSR_CLRDATATOG + |MUSB_TXCSR_P_WZC_BITS ; +musb_writew (regs,MUSB_TXCSR , csr); + }else { + csr =musb_readw (regs,MUSB_RXCSR ); + csr |=MUSB_RXCSR_P_SENDSTALL + |MUSB_RXCSR_FLUSHFIFO + |MUSB_RXCSR_CLRDATATOG + |MUSB_TXCSR_P_WZC_BITS ; +musb_writew (regs,MUSB_RXCSR , csr); } -break ; + +/* select ep0 again */ +musb_ep_select (mbase,0 ); + handled =1 ; + } +break ; +default : -/* delegate SET_CONFIGURATION, etc */ +/* class, vendor, etc ... delegate */ handled =0 ; +break ; } - }else +break ; +default : +/* delegate SET_CONFIGURATION, etc */ handled =0 ; + } + +out:return handled; }
Signature · 1 line
1.5.2.5
PATCH 2/6 musb_hdrc: Move tusb PLL locking code into a separate function
This needs to be also called when changing L3 speed with cpufreq.
--- drivers/usb/musb/tusb6010.c | 30 ++++++++++++++++++------------ 1 files changed, 18 insertions(+), 12 deletions(-)
drivers/usb/musb/tusb6010.c +18 -12
@@ -316,6 +316,23 @@ static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)#define tusb_draw_power NULL#endif +/* There are issues re-locking the PLL on wakeup */ +static inline void tusb_lock_pll (struct musb *musb) +{ +void __iomem *tbase = musb->ctrl_base; +u32 reg; +int i; + +for (i =0xf7f7f7 ; i >0xf7f7f7 -1000 ; i--) { +musb_writel (tbase,TUSB_SCRATCH_PAD ,0 ); +musb_writel (tbase,TUSB_SCRATCH_PAD , i); + reg =musb_readl (tbase,TUSB_SCRATCH_PAD ); +if (reg == i) +break ; +DBG (6 ,"TUSB NOR not ready\n" ); + } +} +/* workaround for issue 13: change clock during chip idle * (to be fixed in rev3 silicon) ... symptoms include disconnect * or looping suspend/resume cycles
@@ -824,22 +841,11 @@ static irqreturn_t tusb_interrupt(int irq, void *__hci)/* Acknowledge wake-up source interrupts */ if (int_src &TUSB_INT_SRC_DEV_WAKEUP ) {u32 reg; -u32 i;if (tusb_get_revision (musb) ==TUSB_REV_30 )tusb_wbus_quirk (musb,0 ); -/* there are issues re-locking the PLL on wakeup ... */ - -/* work around issue 8 */ -for (i =0xf7f7f7 ; i >0xf7f7f7 -1000 ; i--) { -musb_writel (tbase,TUSB_SCRATCH_PAD ,0 ); -musb_writel (tbase,TUSB_SCRATCH_PAD , i); - reg =musb_readl (tbase,TUSB_SCRATCH_PAD ); -if (reg == i) -break ; -DBG (6 ,"TUSB NOR not ready\n" ); - } +tusb_lock_pll (musb);/* work around issue 13 (2nd half) */ tusb_set_clock_source (musb,1 );
Signature · 1 line
1.5.2.5
PATCH 3/6 musb_hdrc: Improve tusb clock handling
Do not disable clock until in tusb_allow_idle()
--- drivers/usb/musb/tusb6010.c | 20 +++++++++++++------- 1 files changed, 13 insertions(+), 7 deletions(-)
drivers/usb/musb/tusb6010.c +13 -7
@@ -277,13 +277,10 @@ static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)/* * Keep clock active when enabled. Note that this is not tied to * drawing VBUS, as with OTG mA can be less than musb->min_power. +* Note that peripheral osc_ck gets disabled in tusb_allow_idle(). */ -if (musb->set_clock) { -if (mA) +if (musb->set_clock && mA) musb->set_clock (musb->clock,1 ); -else - musb->set_clock (musb->clock,0 ); - }/* tps65030 seems to consume max 100mA, with maybe 60mA available * (measured on one board) for things other than tps and tusb.
@@ -342,6 +339,9 @@ static void tusb_set_clock_source(struct musb *musb, unsigned mode)void __iomem *tbase = musb->ctrl_base;u32 reg; +if (musb->set_clock && (mode ==1 )) + musb->set_clock (musb->clock,1 ); + reg =musb_readl (tbase,TUSB_PRCM_CONF ); reg &= ~TUSB_PRCM_CONF_SYS_CLKSEL (0x3 );
@@ -374,6 +374,9 @@ void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)tusb_wbus_quirk (musb,1 );tusb_set_clock_source (musb,0 ); +if ((musb_platform_get_vbus_status (musb) ==0 ) + && (musb->xceiv.state ==OTG_STATE_B_IDLE )) + musb->set_clock (musb->clock,0 ); wakeup_enables |=TUSB_PRCM_WNORCS ;musb_writel (tbase,TUSB_PRCM_WAKEUP_MASK , ~wakeup_enables);
@@ -587,8 +590,8 @@ static void tusb_source_power(struct musb *musb, int is_on) devctl &= ~MUSB_DEVCTL_SESSION ; conf &= ~TUSB_DEV_CONF_USB_HOST_MODE ; -if (musb->set_clock) - musb->set_clock (musb->clock,0 ); + +/* Host osc_ck gets released in tusb_allow_idle() */ } prcm &= ~(TUSB_PRCM_MNGMT_15_SW_EN |TUSB_PRCM_MNGMT_33_SW_EN );
@@ -984,6 +987,9 @@ void musb_platform_disable(struct musb *musb)del_timer (&musb_idle_timer); +if (musb->set_clock) + musb->set_clock (musb->clock,0 ); +if (is_dma_capable () && !dma_off) {printk (KERN_WARNING "%s %s: dma still active\n" , __FILE__, __FUNCTION__);
Signature · 1 line
1.5.2.5
PATCH 4/6 musb_hdrc: Allow more time for HNP as a_wait_bcon
Allow more time for HNP as a_wait_bcon
--- drivers/usb/musb/musb_core.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/usb/musb/musb_core.c +1 -1
@@ -668,7 +668,7 @@ static irqreturn_t musb_stage0_irq(struct musb * musb, u8 int_usb, otg_state_string(musb)); musb_otg_timer.data = (unsigned long )musb;mod_timer (&musb_otg_timer, jiffies - +msecs_to_jiffies (100 )); + +msecs_to_jiffies (2000 ));break ;case OTG_STATE_A_PERIPHERAL :musb_hnp_stop (musb);
Signature · 1 line
1.5.2.5
PATCH 5/6 musb_hdrc: Add musb_platform_wakeup()
If we access tusb registers when tusb is in idle mode, tusb registers may not be immediately available. In most cases an interrupt will wake the system, but at least sending SRP can fail tusb registers are accessed via sysfs.
--- drivers/usb/musb/musb_core.h | 2 ++ drivers/usb/musb/musb_gadget.c | 2 +- drivers/usb/musb/tusb6010.c | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 1 deletions(-)
drivers/usb/musb/musb_core.h +2 -0
@@ -477,10 +477,12 @@ extern void musb_platform_disable(struct musb *musb);extern void musb_hnp_stop (struct musb *musb);#ifdef CONFIG_USB_TUSB6010 +extern void musb_platform_wakeup (struct musb *musb);extern void musb_platform_try_idle (struct musb *musb,unsigned long timeout);extern int musb_platform_get_vbus_status (struct musb *musb);extern void musb_platform_set_mode (struct musb *musb,u8 musb_mode);#else +#define musb_platform_wakeup (x) do {} while (0)#define musb_platform_try_idle (x, y) do {} while (0)#define musb_platform_get_vbus_status (x) 0#define musb_platform_set_mode (x, y) do {} while (0)
drivers/usb/musb/musb_gadget.c +1 -1
@@ -1394,7 +1394,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)int retries;spin_lock_irqsave (&musb->lock, flags); - +musb_platform_wakeup (musb);switch (musb->xceiv.state) {case OTG_STATE_B_PERIPHERAL :/* NOTE: OTG state machine doesn't include B_SUSPENDED;
drivers/usb/musb/tusb6010.c +15 -0
@@ -359,6 +359,21 @@ static void tusb_set_clock_source(struct musb *musb, unsigned mode) }/* +* Wake-up tusb from idle. Caller must take care of locking. +*/ +void musb_platform_wakeup (struct musb *musb) +{ +void __iomem *tbase = musb->ctrl_base; +u32 int_src; + +tusb_lock_pll (musb); +tusb_set_clock_source (musb,1 ); + int_src =musb_readl (tbase,TUSB_INT_SRC ) & ~TUSB_INT_SRC_RESERVED_BITS ; +if (int_src &TUSB_INT_SRC_DEV_WAKEUP ) +musb_writel (tbase,TUSB_INT_SRC_CLEAR ,TUSB_INT_SRC_DEV_WAKEUP ); +} + +/* * Idle TUSB6010 until next wake-up event; NOR access always wakes. * Other code ensures that we idle unless we're connected _and_ the * USB link is not suspended ... and tells us the relevant wakeup
Signature · 1 line
1.5.2.5
PATCH 6/6 musb_hdrc: Handle b_host in musb_otg_timer_func()
Otherwise we get warnings about unhandled mode.
--- drivers/usb/musb/musb_core.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
drivers/usb/musb/musb_core.c +2 -0
@@ -310,6 +310,8 @@ void musb_otg_timer_func(unsigned long data)spin_lock_irqsave (&musb->lock, flags);switch (musb->xceiv.state) { +case OTG_STATE_B_HOST : +break ;case OTG_STATE_B_WAIT_ACON :DBG (1 ,"HNP: b_wait_acon timeout; back to b_peripheral\n" );musb_g_disconnect (musb);
Signature · 1 line
1.5.2.5