Skip to contentSkip to conversation

musb_hdrc: Improve tusb clocking, add musb_platform_wakeup()

PATCH New Tony Lindgren 1 participant 7 messages Oct 21, 2007 1 message not in the archive

Subsystems (2)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): musb-2007-10-21

#1 lore raw

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

#2 lore raw

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
index 3529359..82222e0 100644
@@ -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
#3 lore raw

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
index 3008b6d..85afdd2 100644
@@ -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
#4 lore raw

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
index 85afdd2..c3285ac 100644
@@ -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
#5 lore raw

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
index 33774a6..29732a8 100644
@@ -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
#6 lore raw

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
index 332d39d..1ea0849 100644
@@ -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
index 0fb9635..4b25b0a 100644
@@ -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
index c3285ac..7cbd50c 100644
@@ -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
#7 lore raw

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
index 29732a8..4a2c85a 100644
@@ -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