linux-omap.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3 v3] AM35x: Add musb support
@ 2010-05-17 10:47 Ajay Kumar Gupta
       [not found] ` <1274093235-7616-1-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
  0 siblings, 1 reply; 6+ messages in thread
From: Ajay Kumar Gupta @ 2010-05-17 10:47 UTC (permalink / raw)
  To: linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-omap-u79uwXL29TY76Z2rM5mHXA,
	felipe.balbi-xNZwKgViW5gAvxtiuMwx3w, Ajay Kumar Gupta

AM35x has musb interface (version 1.8) and uses CPPI41 DMA engine.
It supports upto 500mA of power in host mode.

Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
---
Patch created against linus'tree + all musb patches in Greg's queue
and patches available in linux-omap/for-next branch.

 arch/arm/mach-omap2/board-am3517evm.c |   43 +++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/usb-musb.c        |    4 +++
 arch/arm/plat-omap/include/plat/usb.h |   21 ++++++++++++++++
 3 files changed, 68 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c
index af383a8..313559c 100644
--- a/arch/arm/mach-omap2/board-am3517evm.c
+++ b/arch/arm/mach-omap2/board-am3517evm.c
@@ -35,6 +35,7 @@
 #include <plat/control.h>
 #include <plat/usb.h>
 #include <plat/display.h>
+#include <plat/control.h>
 
 #include "mux.h"
 
@@ -375,6 +376,43 @@ static void __init am3517_evm_init_irq(void)
 	omap_gpio_init();
 }
 
+static struct omap_musb_board_data musb_board_data = {
+	.interface_type         = MUSB_INTERFACE_ULPI,
+	.mode                   = MUSB_OTG,
+	.power                  = 500,
+};
+
+static __init void am3517_evm_musb_init(void)
+{
+	u32 devconf2;
+
+	/*
+	 * Set up USB clock/mode in the DEVCONF2 register.
+	 */
+	devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
+
+	/* USB2.0 PHY reference clock is 13 MHz */
+	devconf2 &= ~CONF2_REFFREQ;
+	devconf2 |=  CONF2_REFFREQ_13MHZ;
+
+	/*
+	 * We have to override VBUS/ID signals when MUSB is configured into the
+	 * host-only mode -- ID pin will float if no cable is connected, so the
+	 * controller won't be able to drive VBUS thinking that it's a B-device.
+	 * Otherwise, we want to use the OTG mode and enable VBUS comparators.
+	 */
+	devconf2 &= ~CONF2_OTGMODE;
+#ifdef	CONFIG_USB_MUSB_HOST
+	devconf2 |=  CONF2_FORCE_HOST;
+#else
+	devconf2 |=  CONF2_SESENDEN | CONF2_VBDTCTEN;
+#endif
+
+	omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
+
+	usb_musb_init(&musb_board_data);
+}
+
 static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
 	.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
 #if defined(CONFIG_PANEL_SHARP_LQ043T1DG01) || \
@@ -393,6 +431,8 @@ static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
 
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
+	/* USB OTG DRVVBUS offset = 0x212 */
+	OMAP3_MUX(SAD2D_MCAD23, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
 	{ .reg_offset = OMAP_MUX_TERMINATOR },
 };
 #else
@@ -459,6 +499,9 @@ static void __init am3517_evm_init(void)
 				ARRAY_SIZE(am3517evm_i2c1_boardinfo));
 	/*Ethernet*/
 	am3517_evm_ethernet_init(&am3517_evm_emac_pdata);
+
+	/* MUSB */
+	am3517_evm_musb_init();
 }
 
 static void __init am3517_evm_map_io(void)
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index 3befddb..883795b 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -21,6 +21,7 @@
 #include <linux/usb/musb.h>
 
 #include <mach/irqs.h>
+#include <mach/am35xx.h>
 #include <plat/usb.h>
 
 #ifdef CONFIG_USB_MUSB_SOC
@@ -69,6 +70,9 @@ void __init usb_musb_init(struct omap_musb_board_data *board_data)
 {
 	if (cpu_is_omap243x()) {
 		musb_resources[0].start = OMAP243X_HS_BASE;
+	} else if (cpu_is_omap3517()) {
+		musb_resources[0].start = AM35XX_IPSS_USBOTGSS_BASE;
+		musb_resources[1].start = INT_35XX_USBOTG_IRQ;
 	} else if (cpu_is_omap34xx()) {
 		musb_resources[0].start = OMAP34XX_HSUSB_OTG_BASE;
 	} else if (cpu_is_omap44xx()) {
diff --git a/arch/arm/plat-omap/include/plat/usb.h b/arch/arm/plat-omap/include/plat/usb.h
index 60c734f..c7a019c 100644
--- a/arch/arm/plat-omap/include/plat/usb.h
+++ b/arch/arm/plat-omap/include/plat/usb.h
@@ -168,5 +168,26 @@ void omap_usb_init(struct omap_usb_config *pdata);
 #	define	USBT2TLL5PI		(1 << 17)
 #	define	USB0PUENACTLOI		(1 << 16)
 #	define	USBSTANDBYCTRL		(1 << 15)
+/* AM3517 */
+/* USB 2.0 PHY Control */
+#define CONF2_PHY_GPIOMODE	(1 << 23)
+#define CONF2_OTGMODE		(3 << 14)
+#define CONF2_NO_OVERRIDE	(0 << 14)
+#define CONF2_FORCE_HOST	(1 << 14)
+#define CONF2_FORCE_DEVICE	(2 << 14)
+#define CONF2_FORCE_HOST_VBUS_LOW (3 << 14)
+#define CONF2_SESENDEN		(1 << 13)
+#define CONF2_VBDTCTEN		(1 << 12)
+#define CONF2_REFFREQ_24MHZ	(2 << 8)
+#define CONF2_REFFREQ_26MHZ	(7 << 8)
+#define CONF2_REFFREQ_13MHZ	(6 << 8)
+#define CONF2_REFFREQ		(0xf << 8)
+#define CONF2_PHYCLKGD		(1 << 7)
+#define CONF2_VBUSSENSE		(1 << 6)
+#define CONF2_PHY_PLLON		(1 << 5)
+#define CONF2_RESET		(1 << 4)
+#define CONF2_PHYPWRDN		(1 << 3)
+#define CONF2_OTGPWRDN		(1 << 2)
+#define CONF2_DATPOL		(1 << 1)
 
 #endif	/* __ASM_ARCH_OMAP_USB_H */
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/3 v3] musb: add musb support for AM35x
       [not found] ` <1274093235-7616-1-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
@ 2010-05-17 10:47   ` Ajay Kumar Gupta
  2010-05-17 10:47     ` [PATCH 3/3] musb: AM35x: Workaround for fifo read issue Ajay Kumar Gupta
  0 siblings, 1 reply; 6+ messages in thread
From: Ajay Kumar Gupta @ 2010-05-17 10:47 UTC (permalink / raw)
  To: linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-omap-u79uwXL29TY76Z2rM5mHXA,
	felipe.balbi-xNZwKgViW5gAvxtiuMwx3w, Ajay Kumar Gupta

AM35x has musb interface and uses CPPI4.1 DMA engine.
Current patch supports only PIO mode and there are on-going
discussions on location of CPPI4.1 DMA.

Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
---
Patch created against linus'tree + all musb patches in Greg's queue
Changes from v2:
	- fixed multipline comment style
	- Removed unneeded 'coremask' variable
	- Added 'break' instead of 'return'
	- Updated musb_platform_init signature
I had to use MACH_OMAP3517EVM as there is no ARCH_xxx config specific to
AM3517 platforms other than ARCH_OMAP3.

 drivers/usb/musb/Kconfig  |    4 +-
 drivers/usb/musb/Makefile |    4 +
 drivers/usb/musb/am3517.c |  517 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 523 insertions(+), 2 deletions(-)
 create mode 100644 drivers/usb/musb/am3517.c

diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 7fab721..68efecf 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -10,7 +10,7 @@ comment "Enable Host or Gadget support to see Inventra options"
 config USB_MUSB_HDRC
 	depends on (USB || USB_GADGET)
 	depends on (ARM || (BF54x && !BF544) || (BF52x && !BF522 && !BF523))
-	select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)
+	select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN || MACH_OMAP3517EVM)
 	select TWL4030_USB if MACH_OMAP_3430SDP
 	select USB_OTG_UTILS
 	tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
@@ -144,7 +144,7 @@ config USB_MUSB_HDRC_HCD
 config MUSB_PIO_ONLY
 	bool 'Disable DMA (always use PIO)'
 	depends on USB_MUSB_HDRC
-	default y if USB_TUSB6010
+	default USB_TUSB6010 || MACH_OMAP3517EVM
 	help
 	  All data is copied between memory and FIFO by the CPU.
 	  DMA controllers are ignored.
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 9705f71..ce57675 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -19,7 +19,11 @@ ifeq ($(CONFIG_ARCH_OMAP2430),y)
 endif
 
 ifeq ($(CONFIG_ARCH_OMAP3430),y)
+   ifeq ($(CONFIG_MACH_OMAP3517EVM),y)
+	musb_hdrc-objs  += am3517.o
+   else
 	musb_hdrc-objs	+= omap2430.o
+   endif
 endif
 
 ifeq ($(CONFIG_ARCH_OMAP4),y)
diff --git a/drivers/usb/musb/am3517.c b/drivers/usb/musb/am3517.c
new file mode 100644
index 0000000..b74e664
--- /dev/null
+++ b/drivers/usb/musb/am3517.c
@@ -0,0 +1,517 @@
+/*
+ * Texas Instruments AM3517 "glue layer"
+ *
+ * Copyright (c) 2010, by Texas Instruments
+ *
+ * Based on the DA8xx "glue layer" code.
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (c) 2008, MontaVista Software, Inc. <source-Igf4POYTYCDQT0dZR+AlfA@public.gmane.org>
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <plat/control.h>
+#include <plat/usb.h>
+
+#include "musb_core.h"
+
+/*
+ * AM3517 specific definitions
+ */
+/* USB 2.0 OTG module registers */
+#define USB_REVISION_REG	0x00
+#define USB_CTRL_REG		0x04
+#define USB_STAT_REG		0x08
+#define USB_EMULATION_REG	0x0c
+/* 0x10 Reserved */
+#define USB_AUTOREQ_REG		0x14
+#define USB_SRP_FIX_TIME_REG	0x18
+#define USB_TEARDOWN_REG	0x1c
+#define EP_INTR_SRC_REG		0x20
+#define EP_INTR_SRC_SET_REG	0x24
+#define EP_INTR_SRC_CLEAR_REG	0x28
+#define EP_INTR_MASK_REG	0x2c
+#define EP_INTR_MASK_SET_REG	0x30
+#define EP_INTR_MASK_CLEAR_REG	0x34
+#define EP_INTR_SRC_MASKED_REG	0x38
+#define CORE_INTR_SRC_REG	0x40
+#define CORE_INTR_SRC_SET_REG	0x44
+#define CORE_INTR_SRC_CLEAR_REG	0x48
+#define CORE_INTR_MASK_REG	0x4c
+#define CORE_INTR_MASK_SET_REG	0x50
+#define CORE_INTR_MASK_CLEAR_REG 0x54
+#define CORE_INTR_SRC_MASKED_REG 0x58
+/* 0x5c Reserved */
+#define USB_END_OF_INTR_REG	0x60
+
+/* Control register bits */
+#define USB_SOFT_RESET_MASK	1
+
+/* USB interrupt register bits */
+#define USB_INTR_USB_SHIFT	16
+#define USB_INTR_USB_MASK	(0x1ff << USB_INTR_USB_SHIFT)
+#define USB_INTR_DRVVBUS	0x100
+#define USB_INTR_RX_SHIFT	16
+#define USB_INTR_TX_SHIFT	0
+#define AM3517_TX_EP_MASK	0xffff		/* EP0 + 15 Tx EPs */
+#define AM3517_RX_EP_MASK	0xfffe		/* 15 Rx EPs */
+#define AM3517_TX_INTR_MASK	(AM3517_TX_EP_MASK << USB_INTR_TX_SHIFT)
+#define AM3517_RX_INTR_MASK	(AM3517_RX_EP_MASK << USB_INTR_RX_SHIFT)
+
+#define USB_MENTOR_CORE_OFFSET	0x400
+
+static inline void phy_on(void)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(100);
+	u32 devconf2;
+
+	/*
+	 * Start the on-chip PHY and its PLL.
+	 */
+	devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
+
+	devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN |
+			CONF2_PHY_GPIOMODE);
+	devconf2 |= CONF2_PHY_PLLON | CONF2_DATPOL;
+
+	omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
+
+	DBG(1, "Waiting for PHY clock good...\n");
+	while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2)
+			& CONF2_PHYCLKGD)) {
+		cpu_relax();
+
+		if (time_after(jiffies, timeout)) {
+			DBG(1, "musb PHY clock good timed out\n");
+			break;
+		}
+	}
+}
+
+static inline void phy_off(void)
+{
+	u32 devconf2;
+
+	/*
+	 * Power down the on-chip PHY.
+	 */
+	devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
+
+	devconf2 &= ~CONF2_PHY_PLLON;
+	devconf2 |=  CONF2_PHYPWRDN | CONF2_OTGPWRDN;
+	omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
+}
+
+/*
+ * musb_platform_enable - enable interrupts
+ */
+void musb_platform_enable(struct musb *musb)
+{
+	void __iomem *reg_base = musb->ctrl_base;
+	u32 epmask;
+
+	/* Workaround: setup IRQs through both register sets. */
+	epmask = ((musb->epmask & AM3517_TX_EP_MASK) << USB_INTR_TX_SHIFT) |
+	       ((musb->epmask & AM3517_RX_EP_MASK) << USB_INTR_RX_SHIFT);
+
+	musb_writel(reg_base, EP_INTR_MASK_SET_REG, epmask);
+	musb_writel(reg_base, CORE_INTR_MASK_SET_REG, USB_INTR_USB_MASK);
+
+	/* Force the DRVVBUS IRQ so we can start polling for ID change. */
+	if (is_otg_enabled(musb))
+		musb_writel(reg_base, CORE_INTR_SRC_SET_REG,
+			    USB_INTR_DRVVBUS << USB_INTR_USB_SHIFT);
+}
+
+/*
+ * musb_platform_disable - disable HDRC and flush interrupts
+ */
+void musb_platform_disable(struct musb *musb)
+{
+	void __iomem *reg_base = musb->ctrl_base;
+
+	musb_writel(reg_base, CORE_INTR_MASK_CLEAR_REG, USB_INTR_USB_MASK);
+	musb_writel(reg_base, EP_INTR_MASK_CLEAR_REG,
+			 AM3517_TX_INTR_MASK | AM3517_RX_INTR_MASK);
+	musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
+	musb_writel(reg_base, USB_END_OF_INTR_REG, 0);
+}
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+#define portstate(stmt)		stmt
+#else
+#define portstate(stmt)
+#endif
+
+static void am3517_set_vbus(struct musb *musb, int is_on)
+{
+	WARN_ON(is_on && is_peripheral_active(musb));
+}
+
+#define	POLL_SECONDS	2
+
+static struct timer_list otg_workaround;
+
+static void otg_timer(unsigned long _musb)
+{
+	struct musb		*musb = (void *)_musb;
+	void __iomem		*mregs = musb->mregs;
+	u8			devctl;
+	unsigned long		flags;
+
+	/*
+	 * We poll because AM3517's won't expose several OTG-critical
+	 * status change events (from the transceiver) otherwise.
+	 */
+	devctl = musb_readb(mregs, MUSB_DEVCTL);
+	DBG(7, "Poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
+
+	spin_lock_irqsave(&musb->lock, flags);
+	switch (musb->xceiv->state) {
+	case OTG_STATE_A_WAIT_BCON:
+		devctl &= ~MUSB_DEVCTL_SESSION;
+		musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+		devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+		if (devctl & MUSB_DEVCTL_BDEVICE) {
+			musb->xceiv->state = OTG_STATE_B_IDLE;
+			MUSB_DEV_MODE(musb);
+		} else {
+			musb->xceiv->state = OTG_STATE_A_IDLE;
+			MUSB_HST_MODE(musb);
+		}
+		break;
+	case OTG_STATE_A_WAIT_VFALL:
+		musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+		musb_writel(musb->ctrl_base, CORE_INTR_SRC_SET_REG,
+			    MUSB_INTR_VBUSERROR << USB_INTR_USB_SHIFT);
+		break;
+	case OTG_STATE_B_IDLE:
+		if (!is_peripheral_enabled(musb))
+			break;
+
+		devctl = musb_readb(mregs, MUSB_DEVCTL);
+		if (devctl & MUSB_DEVCTL_BDEVICE)
+			mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+		else
+			musb->xceiv->state = OTG_STATE_A_IDLE;
+		break;
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+{
+	static unsigned long last_timer;
+
+	if (!is_otg_enabled(musb))
+		return;
+
+	if (timeout == 0)
+		timeout = jiffies + msecs_to_jiffies(3);
+
+	/* Never idle if active, or when VBUS timeout is not set as host */
+	if (musb->is_active || (musb->a_wait_bcon == 0 &&
+				musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
+		DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
+		del_timer(&otg_workaround);
+		last_timer = jiffies;
+		return;
+	}
+
+	if (time_after(last_timer, timeout) && timer_pending(&otg_workaround)) {
+		DBG(4, "Longer idle timer already pending, ignoring...\n");
+		return;
+	}
+	last_timer = timeout;
+
+	DBG(4, "%s inactive, starting idle timer for %u ms\n",
+	    otg_state_string(musb), jiffies_to_msecs(timeout - jiffies));
+	mod_timer(&otg_workaround, timeout);
+}
+
+static irqreturn_t am3517_interrupt(int irq, void *hci)
+{
+	struct musb  *musb = hci;
+	void __iomem *reg_base = musb->ctrl_base;
+	unsigned long flags;
+	irqreturn_t ret = IRQ_NONE;
+	u32 epintr, usbintr, lvl_intr;
+
+	spin_lock_irqsave(&musb->lock, flags);
+
+	/* Get endpoint interrupts */
+	epintr = musb_readl(reg_base, EP_INTR_SRC_MASKED_REG);
+
+	if (epintr) {
+		musb_writel(reg_base, EP_INTR_SRC_CLEAR_REG, epintr);
+
+		musb->int_rx =
+			(epintr & AM3517_RX_INTR_MASK) >> USB_INTR_RX_SHIFT;
+		musb->int_tx =
+			(epintr & AM3517_TX_INTR_MASK) >> USB_INTR_TX_SHIFT;
+	}
+
+	/* Get usb core interrupts */
+	usbintr = musb_readl(reg_base, CORE_INTR_SRC_MASKED_REG);
+	if (!usbintr && !epintr)
+		goto eoi;
+
+	if (usbintr) {
+		musb_writel(reg_base, CORE_INTR_SRC_CLEAR_REG, usbintr);
+
+		musb->int_usb =
+			(usbintr & USB_INTR_USB_MASK) >> USB_INTR_USB_SHIFT;
+	}
+	/*
+	 * DRVVBUS IRQs are the only proxy we have (a very poor one!) for
+	 * AM3517's missing ID change IRQ.  We need an ID change IRQ to
+	 * switch appropriately between halves of the OTG state machine.
+	 * Managing DEVCTL.SESSION per Mentor docs requires that we know its
+	 * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
+	 * Also, DRVVBUS pulses for SRP (but not at 5V) ...
+	 */
+	if (usbintr & (USB_INTR_DRVVBUS << USB_INTR_USB_SHIFT)) {
+		int drvvbus = musb_readl(reg_base, USB_STAT_REG);
+		void __iomem *mregs = musb->mregs;
+		u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
+		int err;
+
+		err = is_host_enabled(musb) && (musb->int_usb &
+						MUSB_INTR_VBUSERROR);
+		if (err) {
+			/*
+			 * The Mentor core doesn't debounce VBUS as needed
+			 * to cope with device connect current spikes. This
+			 * means it's not uncommon for bus-powered devices
+			 * to get VBUS errors during enumeration.
+			 *
+			 * This is a workaround, but newer RTL from Mentor
+			 * seems to allow a better one: "re"-starting sessions
+			 * without waiting for VBUS to stop registering in
+			 * devctl.
+			 */
+			musb->int_usb &= ~MUSB_INTR_VBUSERROR;
+			musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+			mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+			WARNING("VBUS error workaround (delay coming)\n");
+		} else if (is_host_enabled(musb) && drvvbus) {
+			musb->is_active = 1;
+			MUSB_HST_MODE(musb);
+			musb->xceiv->default_a = 1;
+			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+			portstate(musb->port1_status |= USB_PORT_STAT_POWER);
+			del_timer(&otg_workaround);
+		} else {
+			musb->is_active = 0;
+			MUSB_DEV_MODE(musb);
+			musb->xceiv->default_a = 0;
+			musb->xceiv->state = OTG_STATE_B_IDLE;
+			portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
+		}
+
+		/* NOTE: this must complete power-on within 100 ms. */
+		DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
+				drvvbus ? "on" : "off",
+				otg_state_string(musb),
+				err ? " ERROR" : "",
+				devctl);
+		ret = IRQ_HANDLED;
+	}
+
+	if (musb->int_tx || musb->int_rx || musb->int_usb)
+		ret |= musb_interrupt(musb);
+
+ eoi:
+	/* EOI needs to be written for the IRQ to be re-asserted. */
+	if (ret == IRQ_HANDLED || epintr || usbintr) {
+		/* clear level interrupt */
+		lvl_intr = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+		lvl_intr |= AM35XX_USBOTGSS_INT_CLR;
+		omap_ctrl_writel(lvl_intr, AM35XX_CONTROL_LVL_INTR_CLEAR);
+		/* write EOI */
+		musb_writel(reg_base, USB_END_OF_INTR_REG, 0);
+	}
+
+	/* Poll for ID change */
+	if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
+		mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+	return ret;
+}
+
+int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+{
+	u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
+
+	devconf2 &= ~CONF2_OTGMODE;
+	switch (musb_mode) {
+#ifdef	CONFIG_USB_MUSB_HDRC_HCD
+	case MUSB_HOST:		/* Force VBUS valid, ID = 0 */
+		devconf2 |= CONF2_FORCE_HOST;
+		break;
+#endif
+#ifdef	CONFIG_USB_GADGET_MUSB_HDRC
+	case MUSB_PERIPHERAL:	/* Force VBUS valid, ID = 1 */
+		devconf2 |= CONF2_FORCE_DEVICE;
+		break;
+#endif
+#ifdef	CONFIG_USB_MUSB_OTG
+	case MUSB_OTG:		/* Don't override the VBUS/ID comparators */
+		devconf2 |= CONF2_NO_OVERRIDE;
+		break;
+#endif
+	default:
+		DBG(2, "Trying to set unsupported mode %u\n", musb_mode);
+	}
+
+	omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
+	return 0;
+}
+
+int __init musb_platform_init(struct musb *musb, void *board_data)
+{
+	void __iomem *reg_base = musb->ctrl_base;
+	struct clk              *otg_fck;
+	u32 rev, lvl_intr, sw_reset;
+
+	musb->mregs += USB_MENTOR_CORE_OFFSET;
+
+	if (musb->set_clock)
+		musb->set_clock(musb->clock, 1);
+	else
+		clk_enable(musb->clock);
+	DBG(2, "usbotg_ck=%lud\n", clk_get_rate(musb->clock));
+
+	otg_fck = clk_get(musb->controller, "fck");
+	clk_enable(otg_fck);
+	DBG(2, "usbotg_phy_ck=%lud\n", clk_get_rate(otg_fck));
+
+	/* Returns zero if e.g. not clocked */
+	rev = musb_readl(reg_base, USB_REVISION_REG);
+	if (!rev)
+		return -ENODEV;
+
+	usb_nop_xceiv_register();
+	musb->xceiv = otg_get_transceiver();
+	if (!musb->xceiv)
+		return -ENODEV;
+
+	if (is_host_enabled(musb))
+		setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
+
+	musb->board_set_vbus = am3517_set_vbus;
+
+	/* Global reset */
+	sw_reset = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
+
+	sw_reset |= AM35XX_USBOTGSS_SW_RST;
+	omap_ctrl_writel(sw_reset, AM35XX_CONTROL_IP_SW_RESET);
+
+	sw_reset &= ~AM35XX_USBOTGSS_SW_RST;
+	omap_ctrl_writel(sw_reset, AM35XX_CONTROL_IP_SW_RESET);
+
+	/* Reset the controller */
+	musb_writel(reg_base, USB_CTRL_REG, USB_SOFT_RESET_MASK);
+
+	/* Start the on-chip PHY and its PLL. */
+	phy_on();
+
+	msleep(5);
+
+	musb->isr = am3517_interrupt;
+
+	/* clear level interrupt */
+	lvl_intr = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+	lvl_intr |= AM35XX_USBOTGSS_INT_CLR;
+	omap_ctrl_writel(lvl_intr, AM35XX_CONTROL_LVL_INTR_CLEAR);
+	return 0;
+}
+
+int musb_platform_exit(struct musb *musb)
+{
+	struct clk *otg_fck = clk_get(musb->controller, "fck");
+
+	if (is_host_enabled(musb))
+		del_timer_sync(&otg_workaround);
+
+	/* Delay to avoid problems with module reload... */
+	if (is_host_enabled(musb) && musb->xceiv->default_a) {
+		u8 devctl, warn = 0;
+		int delay;
+
+		/*
+		 * If there's no peripheral connected, VBUS can take a
+		 * long time to fall...
+		 */
+		for (delay = 30; delay > 0; delay--) {
+			devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+			if (!(devctl & MUSB_DEVCTL_VBUS))
+				goto done;
+			if ((devctl & MUSB_DEVCTL_VBUS) != warn) {
+				warn = devctl & MUSB_DEVCTL_VBUS;
+				DBG(1, "VBUS %d\n",
+					warn >> MUSB_DEVCTL_VBUS_SHIFT);
+			}
+			msleep(1000);
+		}
+
+		/* In OTG mode, another host might be connected... */
+		DBG(1, "VBUS off timeout (devctl %02x)\n", devctl);
+	}
+done:
+	phy_off();
+
+	usb_nop_xceiv_unregister();
+
+	if (musb->set_clock)
+		musb->set_clock(musb->clock, 0);
+	else
+		clk_disable(musb->clock);
+
+	if (otg_fck) {
+		clk_put(otg_fck);
+		clk_disable(otg_fck);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+void musb_platform_save_context(struct musb_context_registers
+		*musb_context)
+{
+	phy_off();
+}
+
+void musb_platform_restore_context(struct musb_context_registers
+		*musb_context)
+{
+	phy_on();
+}
+#endif
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/3] musb: AM35x: Workaround for fifo read issue
  2010-05-17 10:47   ` [PATCH 2/3 v3] musb: add musb support for AM35x Ajay Kumar Gupta
@ 2010-05-17 10:47     ` Ajay Kumar Gupta
  2010-05-18  9:59       ` Sergei Shtylyov
  0 siblings, 1 reply; 6+ messages in thread
From: Ajay Kumar Gupta @ 2010-05-17 10:47 UTC (permalink / raw)
  To: linux-usb; +Cc: linux-omap, felipe.balbi, Ajay Kumar Gupta

AM35x supports only 32bit read operations so we need to have
workaround for 8bit and 16bit read operations.

Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com>
---
Patch created against linus'tree + all musb patches in Greg's queue
Changes from v2:
	- fixed multipline comment style
 drivers/usb/musb/am3517.c    |   31 +++++++++++++++++++++++++++++++
 drivers/usb/musb/musb_core.c |    2 ++
 2 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/musb/am3517.c b/drivers/usb/musb/am3517.c
index b74e664..c68c784 100644
--- a/drivers/usb/musb/am3517.c
+++ b/drivers/usb/musb/am3517.c
@@ -515,3 +515,34 @@ void musb_platform_restore_context(struct musb_context_registers
 	phy_on();
 }
 #endif
+
+/* AM35x supports only 32bit read operation */
+void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
+{
+	void __iomem *fifo = hw_ep->fifo;
+	u32		val;
+	int		i;
+
+	/* Read for 32bit-aligned destination address */
+	if ((likely((0x03 & (unsigned long) dst) == 0)) && len >= 4) {
+		readsl(fifo, dst, len >> 2);
+		dst += (len & ~0x03);
+		len &= 0x03;
+	}
+	/*
+	 * Now read the rest 1 to 3 bytes or complete length if
+	 * unaligned address.
+	 */
+	if (len > 4) {
+		for (i = 0; i < (len >> 2); i++) {
+			val = musb_readl(fifo, 0);
+			memcpy(dst, &val, 4);
+			dst += 4;
+		}
+		len %= 4;
+	}
+	if (len > 0) {
+		val = musb_readl(fifo, 0);
+		memcpy(dst, &val, len);
+	}
+}
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 4093f6d..9c59a8e 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -262,6 +262,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
 	}
 }
 
+#if !defined(CONFIG_MACH_OMAP3517EVM)
 /*
  * Unload an endpoint's FIFO
  */
@@ -299,6 +300,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
 		readsb(fifo, dst, len);
 	}
 }
+#endif
 
 #endif	/* normal PIO */
 
-- 
1.6.2.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/3] musb: AM35x: Workaround for fifo read issue
  2010-05-17 10:47     ` [PATCH 3/3] musb: AM35x: Workaround for fifo read issue Ajay Kumar Gupta
@ 2010-05-18  9:59       ` Sergei Shtylyov
       [not found]         ` <4BF26511.2060705-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
  0 siblings, 1 reply; 6+ messages in thread
From: Sergei Shtylyov @ 2010-05-18  9:59 UTC (permalink / raw)
  To: Ajay Kumar Gupta; +Cc: linux-usb, linux-omap, felipe.balbi

Hello.

Ajay Kumar Gupta wrote:

> AM35x supports only 32bit read operations so we need to have
> workaround for 8bit and 16bit read operations.

> Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com>
> ---
> Patch created against linus'tree + all musb patches in Greg's queue
> Changes from v2:
> 	- fixed multipline comment style
>  drivers/usb/musb/am3517.c    |   31 +++++++++++++++++++++++++++++++
>  drivers/usb/musb/musb_core.c |    2 ++
>  2 files changed, 33 insertions(+), 0 deletions(-)

> diff --git a/drivers/usb/musb/am3517.c b/drivers/usb/musb/am3517.c
> index b74e664..c68c784 100644
> --- a/drivers/usb/musb/am3517.c
> +++ b/drivers/usb/musb/am3517.c
> @@ -515,3 +515,34 @@ void musb_platform_restore_context(struct musb_context_registers
>  	phy_on();
>  }
>  #endif
> +
> +/* AM35x supports only 32bit read operation */
> +void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
> +{
> +	void __iomem *fifo = hw_ep->fifo;
> +	u32		val;
> +	int		i;
> +
> +	/* Read for 32bit-aligned destination address */
> +	if ((likely((0x03 & (unsigned long) dst) == 0)) && len >= 4) {

    You don't need to put likely() in parens.

> +		readsl(fifo, dst, len >> 2);
> +		dst += (len & ~0x03);

    You don't need parens here as well.

> +		len &= 0x03;
> +	}
> +	/*
> +	 * Now read the rest 1 to 3 bytes or complete length if
> +	 * unaligned address.
> +	 */
> +	if (len > 4) {
> +		for (i = 0; i < (len >> 2); i++) {
> +			val = musb_readl(fifo, 0);
> +			memcpy(dst, &val, 4);

    Can't you do away with memcpy() here?

> +			dst += 4;
> +		}
> +		len %= 4;
> +	}
> +	if (len > 0) {
> +		val = musb_readl(fifo, 0);
> +		memcpy(dst, &val, len);
> +	}
> +}

WBR, Sergei

^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [PATCH 3/3] musb: AM35x: Workaround for fifo read issue
       [not found]         ` <4BF26511.2060705-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
@ 2010-05-18 10:11           ` Gupta, Ajay Kumar
  2010-05-18 10:26             ` Gupta, Ajay Kumar
  0 siblings, 1 reply; 6+ messages in thread
From: Gupta, Ajay Kumar @ 2010-05-18 10:11 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-omap-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	felipe.balbi-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org

Hi,
> Ajay Kumar Gupta wrote:
> 
> > AM35x supports only 32bit read operations so we need to have
> > workaround for 8bit and 16bit read operations.
> 
> > Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
> > ---
> > Patch created against linus'tree + all musb patches in Greg's queue
> > Changes from v2:
> > 	- fixed multipline comment style
> >  drivers/usb/musb/am3517.c    |   31 +++++++++++++++++++++++++++++++
> >  drivers/usb/musb/musb_core.c |    2 ++
> >  2 files changed, 33 insertions(+), 0 deletions(-)
> 
> > diff --git a/drivers/usb/musb/am3517.c b/drivers/usb/musb/am3517.c
> > index b74e664..c68c784 100644
> > --- a/drivers/usb/musb/am3517.c
> > +++ b/drivers/usb/musb/am3517.c
> > @@ -515,3 +515,34 @@ void musb_platform_restore_context(struct
> musb_context_registers
> >  	phy_on();
> >  }
> >  #endif
> > +
> > +/* AM35x supports only 32bit read operation */
> > +void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
> > +{
> > +	void __iomem *fifo = hw_ep->fifo;
> > +	u32		val;
> > +	int		i;
> > +
> > +	/* Read for 32bit-aligned destination address */
> > +	if ((likely((0x03 & (unsigned long) dst) == 0)) && len >= 4) {
> 
>     You don't need to put likely() in parens.

Ok.

> 
> > +		readsl(fifo, dst, len >> 2);
> > +		dst += (len & ~0x03);
> 
>     You don't need parens here as well.

Ok.

> 
> > +		len &= 0x03;
> > +	}
> > +	/*
> > +	 * Now read the rest 1 to 3 bytes or complete length if
> > +	 * unaligned address.
> > +	 */
> > +	if (len > 4) {
> > +		for (i = 0; i < (len >> 2); i++) {
> > +			val = musb_readl(fifo, 0);
> > +			memcpy(dst, &val, 4);
> 
>     Can't you do away with memcpy() here?
Are you asking for change below?

*(u32 *)dst = musb_readl(fifo, 0);

-Ajay
> 
> > +			dst += 4;
> > +		}
> > +		len %= 4;
> > +	}
> > +	if (len > 0) {
> > +		val = musb_readl(fifo, 0);
> > +		memcpy(dst, &val, len);
> > +	}
> > +}
> 
> WBR, Sergei
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [PATCH 3/3] musb: AM35x: Workaround for fifo read issue
  2010-05-18 10:11           ` Gupta, Ajay Kumar
@ 2010-05-18 10:26             ` Gupta, Ajay Kumar
  0 siblings, 0 replies; 6+ messages in thread
From: Gupta, Ajay Kumar @ 2010-05-18 10:26 UTC (permalink / raw)
  To: Gupta, Ajay Kumar, Sergei Shtylyov
  Cc: linux-usb@vger.kernel.org, linux-omap@vger.kernel.org,
	felipe.balbi@nokia.com

Hi,
> > Ajay Kumar Gupta wrote:
> >
> > > AM35x supports only 32bit read operations so we need to have
> > > workaround for 8bit and 16bit read operations.
> >
> > > Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com>
> > > ---
> > > Patch created against linus'tree + all musb patches in Greg's queue
> > > Changes from v2:
> > > 	- fixed multipline comment style
> > >  drivers/usb/musb/am3517.c    |   31 +++++++++++++++++++++++++++++++
> > >  drivers/usb/musb/musb_core.c |    2 ++
> > >  2 files changed, 33 insertions(+), 0 deletions(-)
> >
> > > diff --git a/drivers/usb/musb/am3517.c b/drivers/usb/musb/am3517.c
> > > index b74e664..c68c784 100644
> > > --- a/drivers/usb/musb/am3517.c
> > > +++ b/drivers/usb/musb/am3517.c
> > > @@ -515,3 +515,34 @@ void musb_platform_restore_context(struct
> > musb_context_registers
> > >  	phy_on();
> > >  }
> > >  #endif
> > > +
> > > +/* AM35x supports only 32bit read operation */
> > > +void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
> > > +{
> > > +	void __iomem *fifo = hw_ep->fifo;
> > > +	u32		val;
> > > +	int		i;
> > > +
> > > +	/* Read for 32bit-aligned destination address */
> > > +	if ((likely((0x03 & (unsigned long) dst) == 0)) && len >= 4) {
> >
> >     You don't need to put likely() in parens.
> 
> Ok.
> 
> >
> > > +		readsl(fifo, dst, len >> 2);
> > > +		dst += (len & ~0x03);
> >
> >     You don't need parens here as well.
> 
> Ok.
> 
> >
> > > +		len &= 0x03;
> > > +	}
> > > +	/*
> > > +	 * Now read the rest 1 to 3 bytes or complete length if
> > > +	 * unaligned address.
> > > +	 */
> > > +	if (len > 4) {
> > > +		for (i = 0; i < (len >> 2); i++) {
> > > +			val = musb_readl(fifo, 0);
> > > +			memcpy(dst, &val, 4);
> >
> >     Can't you do away with memcpy() here?
> Are you asking for change below?
> *(u32 *)dst = musb_readl(fifo, 0);

This one is safe and works but the other memcpy (below one) would
not be safe to replace as the length would be 1 to 3 bytes.

-Ajay
> > > +			dst += 4;
> > > +		}
> > > +		len %= 4;
> > > +	}
> > > +	if (len > 0) {
> > > +		val = musb_readl(fifo, 0);
> > > +		memcpy(dst, &val, len);
> > > +	}
> > > +}
> >
> > WBR, Sergei
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-05-18 10:26 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-05-17 10:47 [PATCH 1/3 v3] AM35x: Add musb support Ajay Kumar Gupta
     [not found] ` <1274093235-7616-1-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
2010-05-17 10:47   ` [PATCH 2/3 v3] musb: add musb support for AM35x Ajay Kumar Gupta
2010-05-17 10:47     ` [PATCH 3/3] musb: AM35x: Workaround for fifo read issue Ajay Kumar Gupta
2010-05-18  9:59       ` Sergei Shtylyov
     [not found]         ` <4BF26511.2060705-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
2010-05-18 10:11           ` Gupta, Ajay Kumar
2010-05-18 10:26             ` Gupta, Ajay Kumar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).