diff options
Diffstat (limited to 'drivers/usb/musb')
35 files changed, 6560 insertions, 2738 deletions
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 341a37a469b..06cc5d6ea68 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -3,17 +3,10 @@  # for silicon based on Mentor Graphics INVENTRA designs  # -comment "Enable Host or Gadget support to see Inventra options" -	depends on !USB && USB_GADGET=n -  # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller  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 TWL4030_USB if MACH_OMAP_3430SDP -	select USB_OTG_UTILS  	tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' +	depends on (USB || USB_GADGET)  	help  	  Say Y here if your system has a dual role high speed USB  	  controller based on the Mentor Graphics silicon IP.  Then @@ -21,7 +14,7 @@ config USB_MUSB_HDRC  	  it's being used with, including the USB peripheral role,  	  or the USB host role, or both. -	  Texas Instruments familiies using this IP include DaVinci +	  Texas Instruments families using this IP include DaVinci  	  (35x, 644x ...), OMAP 243x, OMAP 3, and TUSB 6010.  	  Analog Devices parts using this IP include Blackfin BF54x, @@ -30,172 +23,144 @@ config USB_MUSB_HDRC  	  If you do not know what this is, please say N.  	  To compile this driver as a module, choose M here; the -	  module will be called "musb_hdrc". +	  module will be called "musb-hdrc". -config USB_MUSB_SOC -	boolean -	depends on USB_MUSB_HDRC -	default y if ARCH_DAVINCI -	default y if ARCH_OMAP2430 -	default y if ARCH_OMAP3 -	default y if ARCH_OMAP4 -	default y if (BF54x && !BF544) -	default y if (BF52x && !BF522 && !BF523) +if USB_MUSB_HDRC -comment "DaVinci 35x and 644x USB support" -	depends on USB_MUSB_HDRC && ARCH_DAVINCI_DMx +choice +	bool "MUSB Mode Selection" +	default USB_MUSB_DUAL_ROLE if (USB && USB_GADGET) +	default USB_MUSB_HOST if (USB && !USB_GADGET) +	default USB_MUSB_GADGET if (!USB && USB_GADGET) -comment "DA8xx/OMAP-L1x USB support" -	depends on USB_MUSB_HDRC && ARCH_DAVINCI_DA8XX +config USB_MUSB_HOST +	bool "Host only mode" +	depends on USB=y || USB=USB_MUSB_HDRC +	help +	  Select this when you want to use MUSB in host mode only, +	  thereby the gadget feature will be regressed. -comment "OMAP 243x high speed USB support" -	depends on USB_MUSB_HDRC && ARCH_OMAP2430 +config USB_MUSB_GADGET +	bool "Gadget only mode" +	depends on USB_GADGET=y || USB_GADGET=USB_MUSB_HDRC +	depends on HAS_DMA +	help +	  Select this when you want to use MUSB in gadget mode only, +	  thereby the host feature will be regressed. -comment "OMAP 343x high speed USB support" -	depends on USB_MUSB_HDRC && ARCH_OMAP3 +config USB_MUSB_DUAL_ROLE +	bool "Dual Role mode" +	depends on ((USB=y || USB=USB_MUSB_HDRC) && (USB_GADGET=y || USB_GADGET=USB_MUSB_HDRC)) +	depends on HAS_DMA +	help +	  This is the default mode of working of MUSB controller where +	  both host and gadget features are enabled. -comment "OMAP 44xx high speed USB support" -	depends on USB_MUSB_HDRC && ARCH_OMAP4 +endchoice -comment "Blackfin high speed USB Support" -	depends on USB_MUSB_HDRC && ((BF54x && !BF544) || (BF52x && !BF522 && !BF523)) +choice +	prompt "Platform Glue Layer" -config USB_MUSB_AM35X -	bool -	depends on USB_MUSB_HDRC && !ARCH_OMAP2430 && !ARCH_OMAP4 -	select NOP_USB_XCEIV -	default MACH_OMAP3517EVM -	help -	  Select this option if your platform is based on AM35x. As -	  AM35x has an updated MUSB with CPPI4.1 DMA so this config -	  is introduced to differentiate musb ip between OMAP3x and -	  AM35x platforms. - -config USB_TUSB6010 -	boolean "TUSB 6010 support" -	depends on USB_MUSB_HDRC && !USB_MUSB_SOC -	select NOP_USB_XCEIV -	default y -	help -	  The TUSB 6010 chip, from Texas Instruments, connects a discrete -	  HDRC core using a 16-bit parallel bus (NOR flash style) or VLYNQ -	  (a high speed serial link).  It can use system-specific external -	  DMA controllers. +config USB_MUSB_DAVINCI +	tristate "DaVinci" +	depends on ARCH_DAVINCI_DMx +	depends on BROKEN -choice -	prompt "Driver Mode" -	depends on USB_MUSB_HDRC -	help -	  Dual-Role devices can support both host and peripheral roles, -	  as well as a the special "OTG Device" role which can switch -	  between both roles as needed. +config USB_MUSB_DA8XX +	tristate "DA8xx/OMAP-L1x" +	depends on ARCH_DAVINCI_DA8XX +	depends on BROKEN -# use USB_MUSB_HDRC_HCD not USB_MUSB_HOST to #ifdef host side support; -# OTG needs both roles, not just USB_MUSB_HOST. -config USB_MUSB_HOST -	depends on USB -	bool "USB Host" -	help -	  Say Y here if your system supports the USB host role. -	  If it has a USB "A" (rectangular), "Mini-A" (uncommon), -	  or "Mini-AB" connector, it supports the host role. -	  (With a "Mini-AB" connector, you should enable USB OTG.) - -# use USB_GADGET_MUSB_HDRC not USB_MUSB_PERIPHERAL to #ifdef peripheral -# side support ... OTG needs both roles -config USB_MUSB_PERIPHERAL -	depends on USB_GADGET -	bool "USB Peripheral (gadget stack)" -	select USB_GADGET_MUSB_HDRC -	help -	  Say Y here if your system supports the USB peripheral role. -	  If it has a USB "B" (squarish), "Mini-B", or "Mini-AB" -	  connector, it supports the peripheral role. -	  (With a "Mini-AB" connector, you should enable USB OTG.) - -config USB_MUSB_OTG -	depends on USB && USB_GADGET && PM && EXPERIMENTAL -	bool "Both host and peripheral:  USB OTG (On The Go) Device" -	select USB_GADGET_MUSB_HDRC -	select USB_OTG -	help -	   The most notable feature of USB OTG is support for a -	   "Dual-Role" device, which can act as either a device -	   or a host.  The initial role choice can be changed -	   later, when two dual-role devices talk to each other. +config USB_MUSB_TUSB6010 +	tristate "TUSB6010" -	   At this writing, the OTG support in this driver is incomplete, -	   omitting the mandatory HNP or SRP protocols.  However, some -	   of the cable based role switching works.  (That is, grounding -	   the ID pin switches the controller to host mode, while leaving -	   it floating leaves it in peripheral mode.) +config USB_MUSB_OMAP2PLUS +	tristate "OMAP2430 and onwards" +	depends on ARCH_OMAP2PLUS && USB +	select GENERIC_PHY -	   Select this if your system has a Mini-AB connector, or -	   to simplify certain kinds of configuration. +config USB_MUSB_AM35X +	tristate "AM35x" +	depends on ARCH_OMAP -	   To implement your OTG Targeted Peripherals List (TPL), enable -	   USB_OTG_WHITELIST and update "drivers/usb/core/otg_whitelist.h" -	   to match your requirements. +config USB_MUSB_DSPS +	tristate "TI DSPS platforms" +	select USB_MUSB_AM335X_CHILD +	depends on OF_IRQ -endchoice +config USB_MUSB_BLACKFIN +	tristate "Blackfin" +	depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523) + +config USB_MUSB_UX500 +	tristate "Ux500 platforms" -# enable peripheral support (including with OTG) -config USB_GADGET_MUSB_HDRC -	bool -	depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG) -#	default y -#	select USB_GADGET_DUALSPEED -#	select USB_GADGET_SELECTED +config USB_MUSB_JZ4740 +	tristate "JZ4740" +	depends on MACH_JZ4740 || COMPILE_TEST +	depends on USB_MUSB_GADGET +	depends on USB_OTG_BLACKLIST_HUB -# enables host support (including with OTG) -config USB_MUSB_HDRC_HCD -	bool -	depends on USB_MUSB_HDRC && (USB_MUSB_HOST || USB_MUSB_OTG) -	select USB_OTG if USB_GADGET_MUSB_HDRC -	default y +endchoice +config USB_MUSB_AM335X_CHILD +	tristate -config MUSB_PIO_ONLY -	bool 'Disable DMA (always use PIO)' -	depends on USB_MUSB_HDRC -	default USB_TUSB6010 || ARCH_DAVINCI_DA8XX || USB_MUSB_AM35X +choice +	prompt 'MUSB DMA mode' +	default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM || USB_MUSB_JZ4740 +	default USB_UX500_DMA if USB_MUSB_UX500 +	default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN +	default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI +	default USB_TUSB_OMAP_DMA if USB_MUSB_TUSB6010 +	default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X \ +				|| USB_MUSB_DSPS  	help -	  All data is copied between memory and FIFO by the CPU. -	  DMA controllers are ignored. +	  Unfortunately, only one option can be enabled here. Ideally one +	  should be able to build all these drivers into one kernel to +	  allow using DMA on multiplatform kernels. -	  Do not select 'n' here unless DMA support for your SOC or board -	  is unavailable (or unstable).  When DMA is enabled at compile time, -	  you can still disable it at run time using the "use_dma=n" module -	  parameter. +config USB_UX500_DMA +	bool 'ST Ericsson Ux500' +	depends on USB_MUSB_UX500 +	help +	  Enable DMA transfers on UX500 platforms.  config USB_INVENTRA_DMA -	bool -	depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY -	default ARCH_OMAP2430 || ARCH_OMAP3 || BLACKFIN || ARCH_OMAP4 +	bool 'Inventra' +	depends on USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN  	help  	  Enable DMA transfers using Mentor's engine.  config USB_TI_CPPI_DMA -	bool -	depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY -	default ARCH_DAVINCI +	bool 'TI CPPI (Davinci)' +	depends on USB_MUSB_DAVINCI  	help  	  Enable DMA transfers when TI CPPI DMA is available. +config USB_TI_CPPI41_DMA +	bool 'TI CPPI 4.1 (AM335x)' +	depends on ARCH_OMAP +	select TI_CPPI41 +  config USB_TUSB_OMAP_DMA -	bool -	depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY -	depends on USB_TUSB6010 +	bool 'TUSB 6010' +	depends on USB_MUSB_TUSB6010 = USB_MUSB_HDRC # both built-in or both modules  	depends on ARCH_OMAP -	default y  	help  	  Enable DMA transfers on TUSB 6010 when OMAP DMA is available. -config	USB_MUSB_DEBUG -	depends on USB_MUSB_HDRC -	bool "Enable debugging messages" -	default n +config MUSB_PIO_ONLY +	bool 'Disable DMA (always use PIO)'  	help -	  This enables musb debugging. To set the logging level use the debug -	  module parameter. Starting at level 3, per-transfer (urb, usb_request, -	  packet, or dma transfer) tracing may kick in. +	  All data is copied between memory and FIFO by the CPU. +	  DMA controllers are ignored. + +	  Do not choose this unless DMA support for your SOC or board +	  is unavailable (or unstable).  When DMA is enabled at compile time, +	  you can still disable it at run time using the "use_dma=n" module +	  parameter. + +endchoice + +endif # USB_MUSB_HDRC diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index ce164e8998d..ba495018b41 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -2,47 +2,35 @@  # for USB OTG silicon based on Mentor Graphics INVENTRA designs  # -ccflags-$(CONFIG_USB_MUSB_DEBUG) := -DDEBUG -  obj-$(CONFIG_USB_MUSB_HDRC) += musb_hdrc.o  musb_hdrc-y := musb_core.o -musb_hdrc-$(CONFIG_ARCH_DAVINCI_DMx)		+= davinci.o -musb_hdrc-$(CONFIG_ARCH_DAVINCI_DA8XX)		+= da8xx.o -musb_hdrc-$(CONFIG_USB_TUSB6010)		+= tusb6010.o -musb_hdrc-$(CONFIG_ARCH_OMAP2430)		+= omap2430.o -ifeq ($(CONFIG_USB_MUSB_AM35X),y) -	musb_hdrc-$(CONFIG_ARCH_OMAP3430)	+= am35x.o -else -	musb_hdrc-$(CONFIG_ARCH_OMAP3430)	+= omap2430.o -endif -musb_hdrc-$(CONFIG_ARCH_OMAP4)			+= omap2430.o -musb_hdrc-$(CONFIG_BF54x)			+= blackfin.o -musb_hdrc-$(CONFIG_BF52x)			+= blackfin.o -musb_hdrc-$(CONFIG_USB_GADGET_MUSB_HDRC)	+= musb_gadget_ep0.o musb_gadget.o -musb_hdrc-$(CONFIG_USB_MUSB_HDRC_HCD)		+= musb_virthub.o musb_host.o +musb_hdrc-$(CONFIG_USB_MUSB_HOST)$(CONFIG_USB_MUSB_DUAL_ROLE) += musb_virthub.o musb_host.o +musb_hdrc-$(CONFIG_USB_MUSB_GADGET)$(CONFIG_USB_MUSB_DUAL_ROLE) += musb_gadget_ep0.o musb_gadget.o  musb_hdrc-$(CONFIG_DEBUG_FS)			+= musb_debugfs.o +# Hardware Glue Layer +obj-$(CONFIG_USB_MUSB_OMAP2PLUS)		+= omap2430.o +obj-$(CONFIG_USB_MUSB_AM35X)			+= am35x.o +obj-$(CONFIG_USB_MUSB_DSPS)			+= musb_dsps.o +obj-$(CONFIG_USB_MUSB_TUSB6010)			+= tusb6010.o +obj-$(CONFIG_USB_MUSB_DAVINCI)			+= davinci.o +obj-$(CONFIG_USB_MUSB_DA8XX)			+= da8xx.o +obj-$(CONFIG_USB_MUSB_BLACKFIN)			+= blackfin.o +obj-$(CONFIG_USB_MUSB_UX500)			+= ux500.o +obj-$(CONFIG_USB_MUSB_JZ4740)			+= jz4740.o + + +obj-$(CONFIG_USB_MUSB_AM335X_CHILD)		+= musb_am335x.o +  # the kconfig must guarantee that only one of the  # possible I/O schemes will be enabled at a time ...  # PIO only, or DMA (several potential schemes).  # though PIO is always there to back up DMA, and for ep0 -ifneq ($(CONFIG_MUSB_PIO_ONLY),y) - -  ifeq ($(CONFIG_USB_INVENTRA_DMA),y) -    musb_hdrc-y			+= musbhsdma.o - -  else -    ifeq ($(CONFIG_USB_TI_CPPI_DMA),y) -      musb_hdrc-y		+= cppi_dma.o - -    else -      ifeq ($(CONFIG_USB_TUSB_OMAP_DMA),y) -	musb_hdrc-y		+= tusb6010_omap.o - -      endif -    endif -  endif -endif +musb_hdrc-$(CONFIG_USB_INVENTRA_DMA)		+= musbhsdma.o +musb_hdrc-$(CONFIG_USB_TI_CPPI_DMA)		+= cppi_dma.o +musb_hdrc-$(CONFIG_USB_TUSB_OMAP_DMA)		+= tusb6010_omap.o +musb_hdrc-$(CONFIG_USB_UX500_DMA)		+= ux500_dma.o +musb_hdrc-$(CONFIG_USB_TI_CPPI41_DMA)		+= musb_cppi41.o diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index b0aabf3a606..0a34dd85955 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -26,12 +26,14 @@   *   */ -#include <linux/init.h> +#include <linux/module.h>  #include <linux/clk.h> +#include <linux/err.h>  #include <linux/io.h> - -#include <plat/control.h> -#include <plat/usb.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/usb/usb_phy_generic.h> +#include <linux/platform_data/usb-omap.h>  #include "musb_core.h" @@ -80,51 +82,18 @@  #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); -	devconf2 |= CONF2_PHY_PLLON; - -	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); -} +struct am35x_glue { +	struct device		*dev; +	struct platform_device	*musb; +	struct platform_device	*phy; +	struct clk		*phy_clk; +	struct clk		*clk; +};  /* - * musb_platform_enable - enable interrupts + * am35x_musb_enable - enable interrupts   */ -void musb_platform_enable(struct musb *musb) +static void am35x_musb_enable(struct musb *musb)  {  	void __iomem *reg_base = musb->ctrl_base;  	u32 epmask; @@ -137,15 +106,14 @@ void musb_platform_enable(struct musb *musb)  	musb_writel(reg_base, CORE_INTR_MASK_SET_REG, AM35X_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, -			    AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT); +	musb_writel(reg_base, CORE_INTR_SRC_SET_REG, +			AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT);  }  /* - * musb_platform_disable - disable HDRC and flush interrupts + * am35x_musb_disable - disable HDRC and flush interrupts   */ -void musb_platform_disable(struct musb *musb) +static void am35x_musb_disable(struct musb *musb)  {  	void __iomem *reg_base = musb->ctrl_base; @@ -156,13 +124,9 @@ void musb_platform_disable(struct musb *musb)  	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 am35x_set_vbus(struct musb *musb, int is_on) +static void am35x_musb_set_vbus(struct musb *musb, int is_on)  {  	WARN_ON(is_on && is_peripheral_active(musb));  } @@ -183,7 +147,8 @@ static void otg_timer(unsigned long _musb)  	 * 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)); +	dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, +		usb_otg_state_string(musb->xceiv->state));  	spin_lock_irqsave(&musb->lock, flags);  	switch (musb->xceiv->state) { @@ -206,9 +171,6 @@ static void otg_timer(unsigned long _musb)  			    MUSB_INTR_VBUSERROR << AM35X_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); @@ -221,43 +183,46 @@ static void otg_timer(unsigned long _musb)  	spin_unlock_irqrestore(&musb->lock, flags);  } -void musb_platform_try_idle(struct musb *musb, unsigned long timeout) +static void am35x_musb_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)); +		dev_dbg(musb->controller, "%s active, deleting timer\n", +			usb_otg_state_string(musb->xceiv->state));  		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"); +		dev_dbg(musb->controller, "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)); +	dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", +		usb_otg_state_string(musb->xceiv->state), +		jiffies_to_msecs(timeout - jiffies));  	mod_timer(&otg_workaround, timeout);  } -static irqreturn_t am35x_interrupt(int irq, void *hci) +static irqreturn_t am35x_musb_interrupt(int irq, void *hci)  {  	struct musb  *musb = hci;  	void __iomem *reg_base = musb->ctrl_base; +	struct device *dev = musb->controller; +	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); +	struct omap_musb_board_data *data = plat->board_data; +	struct usb_otg *otg = musb->xceiv->otg;  	unsigned long flags;  	irqreturn_t ret = IRQ_NONE; -	u32 epintr, usbintr, lvl_intr; +	u32 epintr, usbintr;  	spin_lock_irqsave(&musb->lock, flags); @@ -298,8 +263,7 @@ static irqreturn_t am35x_interrupt(int irq, void *hci)  		u8 devctl = musb_readb(mregs, MUSB_DEVCTL);  		int err; -		err = is_host_enabled(musb) && (musb->int_usb & -						MUSB_INTR_VBUSERROR); +		err = musb->int_usb & MUSB_INTR_VBUSERROR;  		if (err) {  			/*  			 * The Mentor core doesn't debounce VBUS as needed @@ -316,29 +280,35 @@ static irqreturn_t am35x_interrupt(int irq, void *hci)  			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) { +		} else if (drvvbus) {  			MUSB_HST_MODE(musb); -			musb->xceiv->default_a = 1; +			otg->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; +			otg->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", +		dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",  				drvvbus ? "on" : "off", -				otg_state_string(musb), +				usb_otg_state_string(musb->xceiv->state),  				err ? " ERROR" : "",  				devctl);  		ret = IRQ_HANDLED;  	} +	/* Drop spurious RX and TX if device is disconnected */ +	if (musb->int_usb & MUSB_INTR_DISCONNECT) { +		musb->int_tx = 0; +		musb->int_rx = 0; +	} +  	if (musb->int_tx || musb->int_rx || musb->int_usb)  		ret |= musb_interrupt(musb); @@ -346,15 +316,14 @@ 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); +		if (data->clear_irq) +			data->clear_irq();  		/* 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) +	if (musb->xceiv->state == OTG_STATE_B_IDLE)  		mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);  	spin_unlock_irqrestore(&musb->lock, flags); @@ -362,137 +331,81 @@ eoi:  	return ret;  } -int musb_platform_set_mode(struct musb *musb, u8 musb_mode) +static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode)  { -	u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2); +	struct device *dev = musb->controller; +	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); +	struct omap_musb_board_data *data = plat->board_data; +	int     retval = 0; -	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); -	} +	if (data->set_mode) +		data->set_mode(musb_mode); +	else +		retval = -EIO; -	omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); -	return 0; +	return retval;  } -int __init musb_platform_init(struct musb *musb, void *board_data) +static int am35x_musb_init(struct musb *musb)  { +	struct device *dev = musb->controller; +	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); +	struct omap_musb_board_data *data = plat->board_data;  	void __iomem *reg_base = musb->ctrl_base; -	u32 rev, lvl_intr, sw_reset; -	int status; +	u32 rev;  	musb->mregs += USB_MENTOR_CORE_OFFSET; -	clk_enable(musb->clock); -	DBG(2, "musb->clock=%lud\n", clk_get_rate(musb->clock)); - -	musb->phy_clock = clk_get(musb->controller, "fck"); -	if (IS_ERR(musb->phy_clock)) { -		status = PTR_ERR(musb->phy_clock); -		goto exit0; -	} -	clk_enable(musb->phy_clock); -	DBG(2, "musb->phy_clock=%lud\n", clk_get_rate(musb->phy_clock)); -  	/* Returns zero if e.g. not clocked */  	rev = musb_readl(reg_base, USB_REVISION_REG); -	if (!rev) { -		status = -ENODEV; -		goto exit1; -	} - -	usb_nop_xceiv_register(); -	musb->xceiv = otg_get_transceiver(); -	if (!musb->xceiv) { -		status = -ENODEV; -		goto exit1; -	} - -	if (is_host_enabled(musb)) -		setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); +	if (!rev) +		return -ENODEV; -	musb->board_set_vbus = am35x_set_vbus; +	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); +	if (IS_ERR_OR_NULL(musb->xceiv)) +		return -EPROBE_DEFER; -	/* Global reset */ -	sw_reset = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); +	setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); -	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 musb */ +	if (data->reset) +		data->reset();  	/* Reset the controller */  	musb_writel(reg_base, USB_CTRL_REG, AM35X_SOFT_RESET_MASK);  	/* Start the on-chip PHY and its PLL. */ -	phy_on(); +	if (data->set_phy_power) +		data->set_phy_power(1);  	msleep(5); -	musb->isr = am35x_interrupt; +	musb->isr = am35x_musb_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); +	if (data->clear_irq) +		data->clear_irq(); +  	return 0; -exit1: -	clk_disable(musb->phy_clock); -	clk_put(musb->phy_clock); -exit0: -	clk_disable(musb->clock); -	return status;  } -int musb_platform_exit(struct musb *musb) +static int am35x_musb_exit(struct musb *musb)  { -	if (is_host_enabled(musb)) -		del_timer_sync(&otg_workaround); +	struct device *dev = musb->controller; +	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); +	struct omap_musb_board_data *data = plat->board_data; -	phy_off(); +	del_timer_sync(&otg_workaround); -	otg_put_transceiver(musb->xceiv); -	usb_nop_xceiv_unregister(); +	/* Shutdown the on-chip PHY and its PLL. */ +	if (data->set_phy_power) +		data->set_phy_power(0); -	clk_disable(musb->clock); - -	clk_disable(musb->phy_clock); -	clk_put(musb->phy_clock); +	usb_put_phy(musb->xceiv);  	return 0;  } -#ifdef CONFIG_PM -void musb_platform_save_context(struct musb *musb, -	struct musb_context_registers *musb_context) -{ -	phy_off(); -} - -void musb_platform_restore_context(struct musb *musb, -	struct musb_context_registers *musb_context) -{ -	phy_on(); -} -#endif -  /* AM35x supports only 32bit read operation */  void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)  { @@ -522,3 +435,189 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)  		memcpy(dst, &val, len);  	}  } + +static const struct musb_platform_ops am35x_ops = { +	.init		= am35x_musb_init, +	.exit		= am35x_musb_exit, + +	.enable		= am35x_musb_enable, +	.disable	= am35x_musb_disable, + +	.set_mode	= am35x_musb_set_mode, +	.try_idle	= am35x_musb_try_idle, + +	.set_vbus	= am35x_musb_set_vbus, +}; + +static const struct platform_device_info am35x_dev_info = { +	.name		= "musb-hdrc", +	.id		= PLATFORM_DEVID_AUTO, +	.dma_mask	= DMA_BIT_MASK(32), +}; + +static int am35x_probe(struct platform_device *pdev) +{ +	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev); +	struct platform_device		*musb; +	struct am35x_glue		*glue; +	struct platform_device_info	pinfo; +	struct clk			*phy_clk; +	struct clk			*clk; + +	int				ret = -ENOMEM; + +	glue = kzalloc(sizeof(*glue), GFP_KERNEL); +	if (!glue) { +		dev_err(&pdev->dev, "failed to allocate glue context\n"); +		goto err0; +	} + +	phy_clk = clk_get(&pdev->dev, "fck"); +	if (IS_ERR(phy_clk)) { +		dev_err(&pdev->dev, "failed to get PHY clock\n"); +		ret = PTR_ERR(phy_clk); +		goto err3; +	} + +	clk = clk_get(&pdev->dev, "ick"); +	if (IS_ERR(clk)) { +		dev_err(&pdev->dev, "failed to get clock\n"); +		ret = PTR_ERR(clk); +		goto err4; +	} + +	ret = clk_enable(phy_clk); +	if (ret) { +		dev_err(&pdev->dev, "failed to enable PHY clock\n"); +		goto err5; +	} + +	ret = clk_enable(clk); +	if (ret) { +		dev_err(&pdev->dev, "failed to enable clock\n"); +		goto err6; +	} + +	glue->dev			= &pdev->dev; +	glue->phy_clk			= phy_clk; +	glue->clk			= clk; + +	pdata->platform_ops		= &am35x_ops; + +	glue->phy = usb_phy_generic_register(); +	if (IS_ERR(glue->phy)) +		goto err7; +	platform_set_drvdata(pdev, glue); + +	pinfo = am35x_dev_info; +	pinfo.parent = &pdev->dev; +	pinfo.res = pdev->resource; +	pinfo.num_res = pdev->num_resources; +	pinfo.data = pdata; +	pinfo.size_data = sizeof(*pdata); + +	glue->musb = musb = platform_device_register_full(&pinfo); +	if (IS_ERR(musb)) { +		ret = PTR_ERR(musb); +		dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); +		goto err8; +	} + +	return 0; + +err8: +	usb_phy_generic_unregister(glue->phy); + +err7: +	clk_disable(clk); + +err6: +	clk_disable(phy_clk); + +err5: +	clk_put(clk); + +err4: +	clk_put(phy_clk); + +err3: +	kfree(glue); + +err0: +	return ret; +} + +static int am35x_remove(struct platform_device *pdev) +{ +	struct am35x_glue	*glue = platform_get_drvdata(pdev); + +	platform_device_unregister(glue->musb); +	usb_phy_generic_unregister(glue->phy); +	clk_disable(glue->clk); +	clk_disable(glue->phy_clk); +	clk_put(glue->clk); +	clk_put(glue->phy_clk); +	kfree(glue); + +	return 0; +} + +#ifdef CONFIG_PM +static int am35x_suspend(struct device *dev) +{ +	struct am35x_glue	*glue = dev_get_drvdata(dev); +	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); +	struct omap_musb_board_data *data = plat->board_data; + +	/* Shutdown the on-chip PHY and its PLL. */ +	if (data->set_phy_power) +		data->set_phy_power(0); + +	clk_disable(glue->phy_clk); +	clk_disable(glue->clk); + +	return 0; +} + +static int am35x_resume(struct device *dev) +{ +	struct am35x_glue	*glue = dev_get_drvdata(dev); +	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); +	struct omap_musb_board_data *data = plat->board_data; +	int			ret; + +	/* Start the on-chip PHY and its PLL. */ +	if (data->set_phy_power) +		data->set_phy_power(1); + +	ret = clk_enable(glue->phy_clk); +	if (ret) { +		dev_err(dev, "failed to enable PHY clock\n"); +		return ret; +	} + +	ret = clk_enable(glue->clk); +	if (ret) { +		dev_err(dev, "failed to enable clock\n"); +		return ret; +	} + +	return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(am35x_pm_ops, am35x_suspend, am35x_resume); + +static struct platform_driver am35x_driver = { +	.probe		= am35x_probe, +	.remove		= am35x_remove, +	.driver		= { +		.name	= "musb-am35x", +		.pm	= &am35x_pm_ops, +	}, +}; + +MODULE_DESCRIPTION("AM35x MUSB Glue Layer"); +MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>"); +MODULE_LICENSE("GPL v2"); +module_platform_driver(am35x_driver); diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index fcb5206a65b..d40d5f0b552 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -11,21 +11,34 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/sched.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/gpio.h>  #include <linux/io.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/prefetch.h> +#include <linux/usb/usb_phy_generic.h>  #include <asm/cacheflush.h>  #include "musb_core.h" +#include "musbhsdma.h"  #include "blackfin.h" +struct bfin_glue { +	struct device		*dev; +	struct platform_device	*musb; +	struct platform_device	*phy; +}; +#define glue_to_musb(g)		platform_get_drvdata(g->musb) +  /*   * Load an endpoint's FIFO   */  void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)  { +	struct musb *musb = hw_ep->musb;  	void __iomem *fifo = hw_ep->fifo;  	void __iomem *epio = hw_ep->regs;  	u8 epnum = hw_ep->epnum; @@ -34,7 +47,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)  	musb_writew(epio, MUSB_TXCOUNT, len); -	DBG(4, "TX ep%d fifo %p count %d buf %p, epio %p\n", +	dev_dbg(musb->controller, "TX ep%d fifo %p count %d buf %p, epio %p\n",  			hw_ep->epnum, fifo, len, src, epio);  	dump_fifo_data(src, len); @@ -64,7 +77,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)  		bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);  		SSYNC(); -		/* Wait for compelete */ +		/* Wait for complete */  		while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))  			cpu_relax(); @@ -89,6 +102,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)   */  void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)  { +	struct musb *musb = hw_ep->musb;  	void __iomem *fifo = hw_ep->fifo;  	u8 epnum = hw_ep->epnum; @@ -117,7 +131,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)  		bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);  		SSYNC(); -		/* Wait for compelete */ +		/* Wait for complete */  		while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))  			cpu_relax(); @@ -145,7 +159,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)  				*(dst + len - 1) = (u8)inw((unsigned long)fifo + 4);  		}  	} -	DBG(4, "%cX ep%d fifo %p count %d buf %p\n", +	dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n",  			'R', hw_ep->epnum, fifo, len, dst);  	dump_fifo_data(dst, len); @@ -171,8 +185,8 @@ static irqreturn_t blackfin_interrupt(int irq, void *__hci)  	}  	/* Start sampling ID pin, when plug is removed from MUSB */ -	if ((is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE -		|| musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) || +	if ((musb->xceiv->state == OTG_STATE_B_IDLE +		|| musb->xceiv->state == OTG_STATE_A_WAIT_BCON) ||  		(musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))) {  		mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);  		musb->a_wait_bcon = TIMER_DELAY; @@ -215,18 +229,13 @@ static void musb_conn_timer_handler(unsigned long _musb)  			val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;  			musb_writeb(musb->mregs, MUSB_INTRUSB, val); -			if (is_otg_enabled(musb)) -				musb->xceiv->state = OTG_STATE_B_IDLE; -			else -				musb_writeb(musb->mregs, MUSB_POWER, MUSB_POWER_HSENAB); +			musb->xceiv->state = OTG_STATE_B_IDLE;  		}  		mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);  		break;  	case OTG_STATE_B_IDLE: - -		if (!is_peripheral_enabled(musb)) -			break; -		/* Start a new session.  It seems that MUSB needs taking +		/* +		 * Start a new session.  It seems that MUSB needs taking  		 * some time to recognize the type of the plug inserted?  		 */  		val = musb_readw(musb->mregs, MUSB_DEVCTL); @@ -270,61 +279,75 @@ static void musb_conn_timer_handler(unsigned long _musb)  		}  		break;  	default: -		DBG(1, "%s state not handled\n", otg_state_string(musb)); +		dev_dbg(musb->controller, "%s state not handled\n", +			usb_otg_state_string(musb->xceiv->state));  		break;  	}  	spin_unlock_irqrestore(&musb->lock, flags); -	DBG(4, "state is %s\n", otg_state_string(musb)); +	dev_dbg(musb->controller, "state is %s\n", +		usb_otg_state_string(musb->xceiv->state));  } -void musb_platform_enable(struct musb *musb) +static void bfin_musb_enable(struct musb *musb)  { -	if (!is_otg_enabled(musb) && is_host_enabled(musb)) { -		mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); -		musb->a_wait_bcon = TIMER_DELAY; -	} +	/* REVISIT is this really correct ? */  } -void musb_platform_disable(struct musb *musb) +static void bfin_musb_disable(struct musb *musb)  {  } -static void bfin_set_vbus(struct musb *musb, int is_on) +static void bfin_musb_set_vbus(struct musb *musb, int is_on)  {  	int value = musb->config->gpio_vrsel_active;  	if (!is_on)  		value = !value;  	gpio_set_value(musb->config->gpio_vrsel, value); -	DBG(1, "VBUS %s, devctl %02x " +	dev_dbg(musb->controller, "VBUS %s, devctl %02x "  		/* otg %3x conf %08x prcm %08x */ "\n", -		otg_state_string(musb), +		usb_otg_state_string(musb->xceiv->state),  		musb_readb(musb->mregs, MUSB_DEVCTL));  } -static int bfin_set_power(struct otg_transceiver *x, unsigned mA) +static int bfin_musb_set_power(struct usb_phy *x, unsigned mA)  {  	return 0;  } -void musb_platform_try_idle(struct musb *musb, unsigned long timeout) +static int bfin_musb_vbus_status(struct musb *musb)  { -	if (!is_otg_enabled(musb) && is_host_enabled(musb)) -		mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); +	return 0;  } -int musb_platform_get_vbus_status(struct musb *musb) +static int bfin_musb_set_mode(struct musb *musb, u8 musb_mode)  { -	return 0; +	return -EIO;  } -int musb_platform_set_mode(struct musb *musb, u8 musb_mode) +static int bfin_musb_adjust_channel_params(struct dma_channel *channel, +				u16 packet_sz, u8 *mode, +				dma_addr_t *dma_addr, u32 *len)  { -	return -EIO; +	struct musb_dma_channel *musb_channel = channel->private_data; + +	/* +	 * Anomaly 05000450 might cause data corruption when using DMA +	 * MODE 1 transmits with short packet.  So to work around this, +	 * we truncate all MODE 1 transfers down to a multiple of the +	 * max packet size, and then do the last short packet transfer +	 * (if there is any) using MODE 0. +	 */ +	if (ANOMALY_05000450) { +		if (musb_channel->transmit && *mode == 1) +			*len = *len - (*len % packet_sz); +	} + +	return 0;  } -static void musb_platform_reg_init(struct musb *musb) +static void bfin_musb_reg_init(struct musb *musb)  {  	if (ANOMALY_05000346) {  		bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value); @@ -362,7 +385,7 @@ static void musb_platform_reg_init(struct musb *musb)  	SSYNC();  } -int __init musb_platform_init(struct musb *musb, void *board_data) +static int bfin_musb_init(struct musb *musb)  {  	/* @@ -379,32 +402,149 @@ int __init musb_platform_init(struct musb *musb, void *board_data)  	}  	gpio_direction_output(musb->config->gpio_vrsel, 0); -	usb_nop_xceiv_register(); -	musb->xceiv = otg_get_transceiver(); -	if (!musb->xceiv) { +	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); +	if (IS_ERR_OR_NULL(musb->xceiv)) {  		gpio_free(musb->config->gpio_vrsel); -		return -ENODEV; +		return -EPROBE_DEFER;  	} -	musb_platform_reg_init(musb); +	bfin_musb_reg_init(musb); -	if (is_host_enabled(musb)) { -		musb->board_set_vbus = bfin_set_vbus; -		setup_timer(&musb_conn_timer, -			musb_conn_timer_handler, (unsigned long) musb); -	} -	if (is_peripheral_enabled(musb)) -		musb->xceiv->set_power = bfin_set_power; +	setup_timer(&musb_conn_timer, musb_conn_timer_handler, +			(unsigned long) musb); + +	musb->xceiv->set_power = bfin_musb_set_power;  	musb->isr = blackfin_interrupt; +	musb->double_buffer_not_ok = true; + +	return 0; +} + +static int bfin_musb_exit(struct musb *musb) +{ +	gpio_free(musb->config->gpio_vrsel); +	usb_put_phy(musb->xceiv); + +	return 0; +} + +static const struct musb_platform_ops bfin_ops = { +	.init		= bfin_musb_init, +	.exit		= bfin_musb_exit, + +	.enable		= bfin_musb_enable, +	.disable	= bfin_musb_disable, + +	.set_mode	= bfin_musb_set_mode, + +	.vbus_status	= bfin_musb_vbus_status, +	.set_vbus	= bfin_musb_set_vbus, + +	.adjust_channel_params = bfin_musb_adjust_channel_params, +}; + +static u64 bfin_dmamask = DMA_BIT_MASK(32); + +static int bfin_probe(struct platform_device *pdev) +{ +	struct resource musb_resources[2]; +	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev); +	struct platform_device		*musb; +	struct bfin_glue		*glue; + +	int				ret = -ENOMEM; + +	glue = kzalloc(sizeof(*glue), GFP_KERNEL); +	if (!glue) { +		dev_err(&pdev->dev, "failed to allocate glue context\n"); +		goto err0; +	} + +	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); +	if (!musb) { +		dev_err(&pdev->dev, "failed to allocate musb device\n"); +		goto err1; +	} + +	musb->dev.parent		= &pdev->dev; +	musb->dev.dma_mask		= &bfin_dmamask; +	musb->dev.coherent_dma_mask	= bfin_dmamask; + +	glue->dev			= &pdev->dev; +	glue->musb			= musb; + +	pdata->platform_ops		= &bfin_ops; + +	glue->phy = usb_phy_generic_register(); +	if (IS_ERR(glue->phy)) +		goto err2; +	platform_set_drvdata(pdev, glue); + +	memset(musb_resources, 0x00, sizeof(*musb_resources) * +			ARRAY_SIZE(musb_resources)); + +	musb_resources[0].name = pdev->resource[0].name; +	musb_resources[0].start = pdev->resource[0].start; +	musb_resources[0].end = pdev->resource[0].end; +	musb_resources[0].flags = pdev->resource[0].flags; + +	musb_resources[1].name = pdev->resource[1].name; +	musb_resources[1].start = pdev->resource[1].start; +	musb_resources[1].end = pdev->resource[1].end; +	musb_resources[1].flags = pdev->resource[1].flags; + +	ret = platform_device_add_resources(musb, musb_resources, +			ARRAY_SIZE(musb_resources)); +	if (ret) { +		dev_err(&pdev->dev, "failed to add resources\n"); +		goto err3; +	} + +	ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); +	if (ret) { +		dev_err(&pdev->dev, "failed to add platform_data\n"); +		goto err3; +	} + +	ret = platform_device_add(musb); +	if (ret) { +		dev_err(&pdev->dev, "failed to register musb device\n"); +		goto err3; +	} + +	return 0; + +err3: +	usb_phy_generic_unregister(glue->phy); + +err2: +	platform_device_put(musb); + +err1: +	kfree(glue); + +err0: +	return ret; +} + +static int bfin_remove(struct platform_device *pdev) +{ +	struct bfin_glue		*glue = platform_get_drvdata(pdev); + +	platform_device_unregister(glue->musb); +	usb_phy_generic_unregister(glue->phy); +	kfree(glue);  	return 0;  }  #ifdef CONFIG_PM -void musb_platform_save_context(struct musb *musb, -			struct musb_context_registers *musb_context) +static int bfin_suspend(struct device *dev)  { +	struct bfin_glue	*glue = dev_get_drvdata(dev); +	struct musb		*musb = glue_to_musb(glue); +  	if (is_host_active(musb))  		/*  		 * During hibernate gpio_vrsel will change from high to low @@ -413,20 +553,33 @@ void musb_platform_save_context(struct musb *musb,  		 * wakeup event.  		 */  		gpio_set_value(musb->config->gpio_vrsel, 0); -} -void musb_platform_restore_context(struct musb *musb, -			struct musb_context_registers *musb_context) -{ -	musb_platform_reg_init(musb); +	return 0;  } -#endif -int musb_platform_exit(struct musb *musb) +static int bfin_resume(struct device *dev)  { -	gpio_free(musb->config->gpio_vrsel); +	struct bfin_glue	*glue = dev_get_drvdata(dev); +	struct musb		*musb = glue_to_musb(glue); + +	bfin_musb_reg_init(musb); -	otg_put_transceiver(musb->xceiv); -	usb_nop_xceiv_unregister();  	return 0;  } +#endif + +static SIMPLE_DEV_PM_OPS(bfin_pm_ops, bfin_suspend, bfin_resume); + +static struct platform_driver bfin_driver = { +	.probe		= bfin_probe, +	.remove		= __exit_p(bfin_remove), +	.driver		= { +		.name	= "musb-blackfin", +		.pm	= &bfin_pm_ops, +	}, +}; + +MODULE_DESCRIPTION("Blackfin MUSB Glue Layer"); +MODULE_AUTHOR("Bryan Wy <cooloney@kernel.org>"); +MODULE_LICENSE("GPL v2"); +module_platform_driver(bfin_driver); diff --git a/drivers/usb/musb/blackfin.h b/drivers/usb/musb/blackfin.h index bd9352a2ef2..c84dae546dc 100644 --- a/drivers/usb/musb/blackfin.h +++ b/drivers/usb/musb/blackfin.h @@ -47,7 +47,7 @@   * So, need to either use silicon v0.2+ or disable DMA mode in MUSB.   */  #if ANOMALY_05000380 && defined(CONFIG_BF52x) && \ -    defined(CONFIG_USB_MUSB_HDRC) && !defined(CONFIG_MUSB_PIO_ONLY) +	!defined(CONFIG_MUSB_PIO_ONLY)  # error "Please use PIO mode in MUSB driver on bf52x chip v0.0 and v0.1"  #endif diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index f5a65ff0ac2..904fb85d85a 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -6,6 +6,7 @@   * The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci.   */ +#include <linux/module.h>  #include <linux/platform_device.h>  #include <linux/slab.h>  #include <linux/usb.h> @@ -104,7 +105,7 @@ static void cppi_reset_tx(struct cppi_tx_stateram __iomem *tx, u32 ptr)  	musb_writel(&tx->tx_complete, 0, ptr);  } -static void __init cppi_pool_init(struct cppi *cppi, struct cppi_channel *c) +static void cppi_pool_init(struct cppi *cppi, struct cppi_channel *c)  {  	int	j; @@ -149,14 +150,11 @@ static void cppi_pool_free(struct cppi_channel *c)  	c->last_processed = NULL;  } -static int __init cppi_controller_start(struct dma_controller *c) +static void cppi_controller_start(struct cppi *controller)  { -	struct cppi	*controller;  	void __iomem	*tibase;  	int		i; -	controller = container_of(c, struct cppi, controller); -  	/* do whatever is necessary to start controller */  	for (i = 0; i < ARRAY_SIZE(controller->tx); i++) {  		controller->tx[i].transmit = true; @@ -211,8 +209,6 @@ static int __init cppi_controller_start(struct dma_controller *c)  	/* disable RNDIS mode, also host rx RNDIS autorequest */  	musb_writel(tibase, DAVINCI_RNDIS_REG, 0);  	musb_writel(tibase, DAVINCI_AUTOREQ_REG, 0); - -	return 0;  }  /* @@ -221,13 +217,13 @@ static int __init cppi_controller_start(struct dma_controller *c)   *  De-Init the DMA controller as necessary.   */ -static int cppi_controller_stop(struct dma_controller *c) +static void cppi_controller_stop(struct cppi *controller)  { -	struct cppi		*controller;  	void __iomem		*tibase;  	int			i; +	struct musb		*musb; -	controller = container_of(c, struct cppi, controller); +	musb = controller->musb;  	tibase = controller->tibase;  	/* DISABLE INDIVIDUAL CHANNEL Interrupts */ @@ -236,7 +232,7 @@ static int cppi_controller_stop(struct dma_controller *c)  	musb_writel(tibase, DAVINCI_RXCPPI_INTCLR_REG,  			DAVINCI_DMA_ALL_CHANNELS_ENABLE); -	DBG(1, "Tearing down RX and TX Channels\n"); +	dev_dbg(musb->controller, "Tearing down RX and TX Channels\n");  	for (i = 0; i < ARRAY_SIZE(controller->tx); i++) {  		/* FIXME restructure of txdma to use bds like rxdma */  		controller->tx[i].last_processed = NULL; @@ -252,8 +248,6 @@ static int cppi_controller_stop(struct dma_controller *c)  	/*disable tx/rx cppi */  	musb_writel(tibase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);  	musb_writel(tibase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE); - -	return 0;  }  /* While dma channel is allocated, we only want the core irqs active @@ -289,9 +283,11 @@ cppi_channel_allocate(struct dma_controller *c,  	u8			index;  	struct cppi_channel	*cppi_ch;  	void __iomem		*tibase; +	struct musb		*musb;  	controller = container_of(c, struct cppi, controller);  	tibase = controller->tibase; +	musb = controller->musb;  	/* ep0 doesn't use DMA; remember cppi indices are 0..N-1 */  	index = ep->epnum - 1; @@ -301,13 +297,13 @@ cppi_channel_allocate(struct dma_controller *c,  	 */  	if (transmit) {  		if (index >= ARRAY_SIZE(controller->tx)) { -			DBG(1, "no %cX%d CPPI channel\n", 'T', index); +			dev_dbg(musb->controller, "no %cX%d CPPI channel\n", 'T', index);  			return NULL;  		}  		cppi_ch = controller->tx + index;  	} else {  		if (index >= ARRAY_SIZE(controller->rx)) { -			DBG(1, "no %cX%d CPPI channel\n", 'R', index); +			dev_dbg(musb->controller, "no %cX%d CPPI channel\n", 'R', index);  			return NULL;  		}  		cppi_ch = controller->rx + index; @@ -318,13 +314,13 @@ cppi_channel_allocate(struct dma_controller *c,  	 * with the other DMA engine too  	 */  	if (cppi_ch->hw_ep) -		DBG(1, "re-allocating DMA%d %cX channel %p\n", +		dev_dbg(musb->controller, "re-allocating DMA%d %cX channel %p\n",  				index, transmit ? 'T' : 'R', cppi_ch);  	cppi_ch->hw_ep = ep;  	cppi_ch->channel.status = MUSB_DMA_STATUS_FREE;  	cppi_ch->channel.max_len = 0x7fffffff; -	DBG(4, "Allocate CPPI%d %cX\n", index, transmit ? 'T' : 'R'); +	dev_dbg(musb->controller, "Allocate CPPI%d %cX\n", index, transmit ? 'T' : 'R');  	return &cppi_ch->channel;  } @@ -339,7 +335,8 @@ static void cppi_channel_release(struct dma_channel *channel)  	c = container_of(channel, struct cppi_channel, channel);  	tibase = c->controller->tibase;  	if (!c->hw_ep) -		DBG(1, "releasing idle DMA channel %p\n", c); +		dev_dbg(c->controller->musb->controller, +			"releasing idle DMA channel %p\n", c);  	else if (!c->transmit)  		core_rxirq_enable(tibase, c->index + 1); @@ -357,10 +354,11 @@ cppi_dump_rx(int level, struct cppi_channel *c, const char *tag)  	musb_ep_select(base, c->index + 1); -	DBG(level, "RX DMA%d%s: %d left, csr %04x, " -			"%08x H%08x S%08x C%08x, " -			"B%08x L%08x %08x .. %08x" -			"\n", +	dev_dbg(c->controller->musb->controller, +		"RX DMA%d%s: %d left, csr %04x, " +		"%08x H%08x S%08x C%08x, " +		"B%08x L%08x %08x .. %08x" +		"\n",  		c->index, tag,  		musb_readl(c->controller->tibase,  			DAVINCI_RXCPPI_BUFCNT0_REG + 4 * c->index), @@ -387,10 +385,11 @@ cppi_dump_tx(int level, struct cppi_channel *c, const char *tag)  	musb_ep_select(base, c->index + 1); -	DBG(level, "TX DMA%d%s: csr %04x, " -			"H%08x S%08x C%08x %08x, " -			"F%08x L%08x .. %08x" -			"\n", +	dev_dbg(c->controller->musb->controller, +		"TX DMA%d%s: csr %04x, " +		"H%08x S%08x C%08x %08x, " +		"F%08x L%08x .. %08x" +		"\n",  		c->index, tag,  		musb_readw(c->hw_ep->regs, MUSB_TXCSR), @@ -427,7 +426,6 @@ cppi_rndis_update(struct cppi_channel *c, int is_rx,  	}  } -#ifdef CONFIG_USB_MUSB_DEBUG  static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd)  {  	pr_debug("RXBD/%s %08x: " @@ -436,21 +434,16 @@ static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd)  			bd->hw_next, bd->hw_bufp, bd->hw_off_len,  			bd->hw_options);  } -#endif  static void cppi_dump_rxq(int level, const char *tag, struct cppi_channel *rx)  { -#ifdef CONFIG_USB_MUSB_DEBUG  	struct cppi_descriptor	*bd; -	if (!_dbg_level(level)) -		return;  	cppi_dump_rx(level, rx, tag);  	if (rx->last_processed)  		cppi_dump_rxbd("last", rx->last_processed);  	for (bd = rx->head; bd; bd = bd->next)  		cppi_dump_rxbd("active", bd); -#endif  } @@ -506,7 +499,7 @@ static inline int cppi_autoreq_update(struct cppi_channel *rx,  		if (!(val & MUSB_RXCSR_H_REQPKT)) {  			val |= MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_H_WZC_BITS;  			musb_writew(regs, MUSB_RXCSR, val); -			/* flush writebufer */ +			/* flush writebuffer */  			val = musb_readw(regs, MUSB_RXCSR);  		}  	} @@ -597,12 +590,12 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)  		length = min(n_bds * maxpacket, length);  	} -	DBG(4, "TX DMA%d, pktSz %d %s bds %d dma 0x%x len %u\n", +	dev_dbg(musb->controller, "TX DMA%d, pktSz %d %s bds %d dma 0x%llx len %u\n",  			tx->index,  			maxpacket,  			rndis ? "rndis" : "transparent",  			n_bds, -			addr, length); +			(unsigned long long)addr, length);  	cppi_rndis_update(tx, 0, musb->ctrl_base, rndis); @@ -654,7 +647,7 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)  				bd->hw_options |= CPPI_ZERO_SET;  		} -		DBG(5, "TXBD %p: nxt %08x buf %08x len %04x opt %08x\n", +		dev_dbg(musb->controller, "TXBD %p: nxt %08x buf %08x len %04x opt %08x\n",  				bd, bd->hw_next, bd->hw_bufp,  				bd->hw_off_len, bd->hw_options); @@ -743,7 +736,7 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)   * So this module parameter lets the heuristic be disabled.  When using   * gadgetfs, the heuristic will probably need to be disabled.   */ -static int cppi_rx_rndis = 1; +static bool cppi_rx_rndis = 1;  module_param(cppi_rx_rndis, bool, 0);  MODULE_PARM_DESC(cppi_rx_rndis, "enable/disable RX RNDIS heuristic"); @@ -776,6 +769,7 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)  	void __iomem		*tibase = musb->ctrl_base;  	int			is_rndis = 0;  	struct cppi_rx_stateram	__iomem *rx_ram = rx->state_ram; +	struct cppi_descriptor	*d;  	if (onepacket) {  		/* almost every USB driver, host or peripheral side */ @@ -819,8 +813,8 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)  	length = min(n_bds * maxpacket, length); -	DBG(4, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) " -			"dma 0x%x len %u %u/%u\n", +	dev_dbg(musb->controller, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) " +			"dma 0x%llx len %u %u/%u\n",  			rx->index, maxpacket,  			onepacket  				? (is_rndis ? "rndis" : "onepacket") @@ -829,7 +823,8 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)  			musb_readl(tibase,  				DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4))  					& 0xffff, -			addr, length, rx->channel.actual_len, rx->buf_len); +			(unsigned long long)addr, length, +			rx->channel.actual_len, rx->buf_len);  	/* only queue one segment at a time, since the hardware prevents  	 * correct queue shutdown after unexpected short packets @@ -888,14 +883,8 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)  	bd->hw_options |= CPPI_SOP_SET;  	tail->hw_options |= CPPI_EOP_SET; -#ifdef CONFIG_USB_MUSB_DEBUG -	if (_dbg_level(5)) { -		struct cppi_descriptor	*d; - -		for (d = rx->head; d; d = d->next) -			cppi_dump_rxbd("S", d); -	} -#endif +	for (d = rx->head; d; d = d->next) +		cppi_dump_rxbd("S", d);  	/* in case the preceding transfer left some state... */  	tail = rx->last_processed; @@ -935,7 +924,7 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)  			DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4))  			& 0xffff;  	if (i < (2 + n_bds)) { -		DBG(2, "bufcnt%d underrun - %d (for %d)\n", +		dev_dbg(musb->controller, "bufcnt%d underrun - %d (for %d)\n",  					rx->index, i, n_bds);  		musb_writel(tibase,  			DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4), @@ -984,7 +973,7 @@ static int cppi_channel_program(struct dma_channel *ch,  		/* WARN_ON(1); */  		break;  	case MUSB_DMA_STATUS_UNKNOWN: -		DBG(1, "%cX DMA%d not allocated!\n", +		dev_dbg(musb->controller, "%cX DMA%d not allocated!\n",  				cppi_ch->transmit ? 'T' : 'R',  				cppi_ch->index);  		/* FALLTHROUGH */ @@ -1021,6 +1010,7 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)  	int				i;  	dma_addr_t			safe2ack;  	void __iomem			*regs = rx->hw_ep->regs; +	struct musb			*musb = cppi->musb;  	cppi_dump_rx(6, rx, "/K"); @@ -1039,9 +1029,9 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)  		if (!completed && (bd->hw_options & CPPI_OWN_SET))  			break; -		DBG(5, "C/RXBD %08x: nxt %08x buf %08x " +		dev_dbg(musb->controller, "C/RXBD %llx: nxt %08x buf %08x "  			"off.len %08x opt.len %08x (%d)\n", -			bd->dma, bd->hw_next, bd->hw_bufp, +			(unsigned long long)bd->dma, bd->hw_next, bd->hw_bufp,  			bd->hw_off_len, bd->hw_options,  			rx->channel.actual_len); @@ -1061,7 +1051,7 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)  			 * CPPI ignores those BDs even though OWN is still set.  			 */  			completed = true; -			DBG(3, "rx short %d/%d (%d)\n", +			dev_dbg(musb->controller, "rx short %d/%d (%d)\n",  					len, bd->buflen,  					rx->channel.actual_len);  		} @@ -1111,11 +1101,12 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)  		musb_ep_select(cppi->mregs, rx->index + 1);  		csr = musb_readw(regs, MUSB_RXCSR);  		if (csr & MUSB_RXCSR_DMAENAB) { -			DBG(4, "list%d %p/%p, last %08x%s, csr %04x\n", +			dev_dbg(musb->controller, "list%d %p/%p, last %llx%s, csr %04x\n",  				rx->index,  				rx->head, rx->tail,  				rx->last_processed -					? rx->last_processed->dma +					? (unsigned long long) +						rx->last_processed->dma  					: 0,  				completed ? ", completed" : "",  				csr); @@ -1167,10 +1158,13 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)  	tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);  	rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG); -	if (!tx && !rx) +	if (!tx && !rx) { +		if (cppi->irq) +			spin_unlock_irqrestore(&musb->lock, flags);  		return IRQ_NONE; +	} -	DBG(4, "CPPI IRQ Tx%x Rx%x\n", tx, rx); +	dev_dbg(musb->controller, "CPPI IRQ Tx%x Rx%x\n", tx, rx);  	/* process TX channels */  	for (index = 0; tx; tx = tx >> 1, index++) { @@ -1198,8 +1192,8 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)  		 * that needs to be acknowledged.  		 */  		if (NULL == bd) { -			DBG(1, "null BD\n"); -			tx_ram->tx_complete = 0; +			dev_dbg(musb->controller, "null BD\n"); +			musb_writel(&tx_ram->tx_complete, 0, 0);  			continue;  		} @@ -1213,7 +1207,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)  			if (bd->hw_options & CPPI_OWN_SET)  				break; -			DBG(5, "C/TXBD %p n %x b %x off %x opt %x\n", +			dev_dbg(musb->controller, "C/TXBD %p n %x b %x off %x opt %x\n",  					bd, bd->hw_next, bd->hw_bufp,  					bd->hw_off_len, bd->hw_options); @@ -1300,15 +1294,15 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)  	return IRQ_HANDLED;  } +EXPORT_SYMBOL_GPL(cppi_interrupt);  /* Instantiate a software object representing a DMA controller. */ -struct dma_controller *__init -dma_controller_create(struct musb *musb, void __iomem *mregs) +struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mregs)  {  	struct cppi		*controller;  	struct device		*dev = musb->controller;  	struct platform_device	*pdev = to_platform_device(dev); -	int			irq = platform_get_irq(pdev, 1); +	int			irq = platform_get_irq_byname(pdev, "dma");  	controller = kzalloc(sizeof *controller, GFP_KERNEL);  	if (!controller) @@ -1318,8 +1312,6 @@ dma_controller_create(struct musb *musb, void __iomem *mregs)  	controller->tibase = mregs - DAVINCI_BASE_OFFSET;  	controller->musb = musb; -	controller->controller.start = cppi_controller_start; -	controller->controller.stop = cppi_controller_stop;  	controller->controller.channel_alloc = cppi_channel_allocate;  	controller->controller.channel_release = cppi_channel_release;  	controller->controller.channel_program = cppi_channel_program; @@ -1348,6 +1340,7 @@ dma_controller_create(struct musb *musb, void __iomem *mregs)  		controller->irq = irq;  	} +	cppi_controller_start(controller);  	return &controller->controller;  } @@ -1360,6 +1353,8 @@ void dma_controller_destroy(struct dma_controller *c)  	cppi = container_of(c, struct cppi, controller); +	cppi_controller_stop(cppi); +  	if (cppi->irq)  		free_irq(cppi->irq, cppi->musb); @@ -1452,7 +1447,7 @@ static int cppi_channel_abort(struct dma_channel *channel)  		 *    compare mode by writing 1 to the tx_complete register.  		 */  		cppi_reset_tx(tx_ram, 1); -		cppi_ch->head = 0; +		cppi_ch->head = NULL;  		musb_writel(&tx_ram->tx_complete, 0, 1);  		cppi_dump_tx(5, cppi_ch, " (done teardown)"); diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 84427bebbf6..058775e647a 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -26,12 +26,16 @@   *   */ -#include <linux/init.h> +#include <linux/module.h>  #include <linux/clk.h> +#include <linux/err.h>  #include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/usb/usb_phy_generic.h>  #include <mach/da8xx.h> -#include <mach/usb.h> +#include <linux/platform_data/usb-davinci.h>  #include "musb_core.h" @@ -78,6 +82,13 @@  #define CFGCHIP2	IO_ADDRESS(DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP2_REG) +struct da8xx_glue { +	struct device		*dev; +	struct platform_device	*musb; +	struct platform_device	*phy; +	struct clk		*clk; +}; +  /*   * REVISIT (PM): we should be able to keep the PHY in low power mode most   * of the time (24 MHz oscillator and PLL off, etc.) by setting POWER.D0 @@ -131,9 +142,9 @@ static inline void phy_off(void)   */  /** - * musb_platform_enable - enable interrupts + * da8xx_musb_enable - enable interrupts   */ -void musb_platform_enable(struct musb *musb) +static void da8xx_musb_enable(struct musb *musb)  {  	void __iomem *reg_base = musb->ctrl_base;  	u32 mask; @@ -145,15 +156,14 @@ void musb_platform_enable(struct musb *musb)  	musb_writel(reg_base, DA8XX_USB_INTR_MASK_SET_REG, mask);  	/* Force the DRVVBUS IRQ so we can start polling for ID change. */ -	if (is_otg_enabled(musb)) -		musb_writel(reg_base, DA8XX_USB_INTR_SRC_SET_REG, -			    DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT); +	musb_writel(reg_base, DA8XX_USB_INTR_SRC_SET_REG, +			DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT);  }  /** - * musb_platform_disable - disable HDRC and flush interrupts + * da8xx_musb_disable - disable HDRC and flush interrupts   */ -void musb_platform_disable(struct musb *musb) +static void da8xx_musb_disable(struct musb *musb)  {  	void __iomem *reg_base = musb->ctrl_base; @@ -164,13 +174,9 @@ void musb_platform_disable(struct musb *musb)  	musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0);  } -#ifdef CONFIG_USB_MUSB_HDRC_HCD -#define portstate(stmt) 	stmt -#else -#define portstate(stmt) -#endif +#define portstate(stmt)		stmt -static void da8xx_set_vbus(struct musb *musb, int is_on) +static void da8xx_musb_set_vbus(struct musb *musb, int is_on)  {  	WARN_ON(is_on && is_peripheral_active(musb));  } @@ -191,7 +197,8 @@ static void otg_timer(unsigned long _musb)  	 * 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)); +	dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, +		usb_otg_state_string(musb->xceiv->state));  	spin_lock_irqsave(&musb->lock, flags);  	switch (musb->xceiv->state) { @@ -224,9 +231,6 @@ static void otg_timer(unsigned long _musb)  			    MUSB_INTR_VBUSERROR << DA8XX_INTR_USB_SHIFT);  		break;  	case OTG_STATE_B_IDLE: -		if (!is_peripheral_enabled(musb)) -			break; -  		/*  		 * There's no ID-changed IRQ, so we have no good way to tell  		 * when to switch to the A-Default state machine (by setting @@ -252,40 +256,40 @@ static void otg_timer(unsigned long _musb)  	spin_unlock_irqrestore(&musb->lock, flags);  } -void musb_platform_try_idle(struct musb *musb, unsigned long timeout) +static void da8xx_musb_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)); +		dev_dbg(musb->controller, "%s active, deleting timer\n", +			usb_otg_state_string(musb->xceiv->state));  		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"); +		dev_dbg(musb->controller, "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)); +	dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", +		usb_otg_state_string(musb->xceiv->state), +		jiffies_to_msecs(timeout - jiffies));  	mod_timer(&otg_workaround, timeout);  } -static irqreturn_t da8xx_interrupt(int irq, void *hci) +static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)  {  	struct musb		*musb = hci;  	void __iomem		*reg_base = musb->ctrl_base; +	struct usb_otg		*otg = musb->xceiv->otg;  	unsigned long		flags;  	irqreturn_t		ret = IRQ_NONE;  	u32			status; @@ -303,7 +307,7 @@ static irqreturn_t da8xx_interrupt(int irq, void *hci)  		goto eoi;  	musb_writel(reg_base, DA8XX_USB_INTR_SRC_CLEAR_REG, status); -	DBG(4, "USB IRQ %08x\n", status); +	dev_dbg(musb->controller, "USB IRQ %08x\n", status);  	musb->int_rx = (status & DA8XX_INTR_RX_MASK) >> DA8XX_INTR_RX_SHIFT;  	musb->int_tx = (status & DA8XX_INTR_TX_MASK) >> DA8XX_INTR_TX_SHIFT; @@ -323,8 +327,7 @@ static irqreturn_t da8xx_interrupt(int irq, void *hci)  		u8 devctl = musb_readb(mregs, MUSB_DEVCTL);  		int err; -		err = is_host_enabled(musb) && (musb->int_usb & -						MUSB_INTR_VBUSERROR); +		err = musb->int_usb & MUSB_INTR_VBUSERROR;  		if (err) {  			/*  			 * The Mentor core doesn't debounce VBUS as needed @@ -341,23 +344,23 @@ static irqreturn_t da8xx_interrupt(int irq, void *hci)  			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) { +		} else if (drvvbus) {  			MUSB_HST_MODE(musb); -			musb->xceiv->default_a = 1; +			otg->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; +			otg->default_a = 0;  			musb->xceiv->state = OTG_STATE_B_IDLE;  			portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);  		} -		DBG(2, "VBUS %s (%s)%s, devctl %02x\n", +		dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",  				drvvbus ? "on" : "off", -				otg_state_string(musb), +				usb_otg_state_string(musb->xceiv->state),  				err ? " ERROR" : "",  				devctl);  		ret = IRQ_HANDLED; @@ -372,7 +375,7 @@ static irqreturn_t da8xx_interrupt(int irq, void *hci)  		musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0);  	/* Poll for ID change */ -	if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE) +	if (musb->xceiv->state == OTG_STATE_B_IDLE)  		mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);  	spin_unlock_irqrestore(&musb->lock, flags); @@ -380,58 +383,49 @@ static irqreturn_t da8xx_interrupt(int irq, void *hci)  	return ret;  } -int musb_platform_set_mode(struct musb *musb, u8 musb_mode) +static int da8xx_musb_set_mode(struct musb *musb, u8 musb_mode)  {  	u32 cfgchip2 = __raw_readl(CFGCHIP2);  	cfgchip2 &= ~CFGCHIP2_OTGMODE;  	switch (musb_mode) { -#ifdef	CONFIG_USB_MUSB_HDRC_HCD  	case MUSB_HOST:		/* Force VBUS valid, ID = 0 */  		cfgchip2 |= CFGCHIP2_FORCE_HOST;  		break; -#endif -#ifdef	CONFIG_USB_GADGET_MUSB_HDRC  	case MUSB_PERIPHERAL:	/* Force VBUS valid, ID = 1 */  		cfgchip2 |= CFGCHIP2_FORCE_DEVICE;  		break; -#endif -#ifdef	CONFIG_USB_MUSB_OTG  	case MUSB_OTG:		/* Don't override the VBUS/ID comparators */  		cfgchip2 |= CFGCHIP2_NO_OVERRIDE;  		break; -#endif  	default: -		DBG(2, "Trying to set unsupported mode %u\n", musb_mode); +		dev_dbg(musb->controller, "Trying to set unsupported mode %u\n", musb_mode);  	}  	__raw_writel(cfgchip2, CFGCHIP2);  	return 0;  } -int __init musb_platform_init(struct musb *musb, void *board_data) +static int da8xx_musb_init(struct musb *musb)  {  	void __iomem *reg_base = musb->ctrl_base;  	u32 rev; +	int ret = -ENODEV;  	musb->mregs += DA8XX_MENTOR_CORE_OFFSET; -	clk_enable(musb->clock); -  	/* Returns zero if e.g. not clocked */  	rev = musb_readl(reg_base, DA8XX_USB_REVISION_REG);  	if (!rev)  		goto fail; -	usb_nop_xceiv_register(); -	musb->xceiv = otg_get_transceiver(); -	if (!musb->xceiv) +	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); +	if (IS_ERR_OR_NULL(musb->xceiv)) { +		ret = -EPROBE_DEFER;  		goto fail; +	} -	if (is_host_enabled(musb)) -		setup_timer(&otg_workaround, otg_timer, (unsigned long)musb); - -	musb->board_set_vbus = da8xx_set_vbus; +	setup_timer(&otg_workaround, otg_timer, (unsigned long)musb);  	/* Reset the controller */  	musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK); @@ -446,24 +440,151 @@ int __init musb_platform_init(struct musb *musb, void *board_data)  		 rev, __raw_readl(CFGCHIP2),  		 musb_readb(reg_base, DA8XX_USB_CTRL_REG)); -	musb->isr = da8xx_interrupt; +	musb->isr = da8xx_musb_interrupt;  	return 0;  fail: -	clk_disable(musb->clock); -	return -ENODEV; +	return ret;  } -int musb_platform_exit(struct musb *musb) +static int da8xx_musb_exit(struct musb *musb)  { -	if (is_host_enabled(musb)) -		del_timer_sync(&otg_workaround); +	del_timer_sync(&otg_workaround);  	phy_off(); -	otg_put_transceiver(musb->xceiv); -	usb_nop_xceiv_unregister(); +	usb_put_phy(musb->xceiv); -	clk_disable(musb->clock); +	return 0; +} + +static const struct musb_platform_ops da8xx_ops = { +	.init		= da8xx_musb_init, +	.exit		= da8xx_musb_exit, + +	.enable		= da8xx_musb_enable, +	.disable	= da8xx_musb_disable, + +	.set_mode	= da8xx_musb_set_mode, +	.try_idle	= da8xx_musb_try_idle, + +	.set_vbus	= da8xx_musb_set_vbus, +}; + +static const struct platform_device_info da8xx_dev_info = { +	.name		= "musb-hdrc", +	.id		= PLATFORM_DEVID_AUTO, +	.dma_mask	= DMA_BIT_MASK(32), +}; + +static int da8xx_probe(struct platform_device *pdev) +{ +	struct resource musb_resources[2]; +	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev); +	struct platform_device		*musb; +	struct da8xx_glue		*glue; +	struct platform_device_info	pinfo; +	struct clk			*clk; + +	int				ret = -ENOMEM; + +	glue = kzalloc(sizeof(*glue), GFP_KERNEL); +	if (!glue) { +		dev_err(&pdev->dev, "failed to allocate glue context\n"); +		goto err0; +	} + +	clk = clk_get(&pdev->dev, "usb20"); +	if (IS_ERR(clk)) { +		dev_err(&pdev->dev, "failed to get clock\n"); +		ret = PTR_ERR(clk); +		goto err3; +	} + +	ret = clk_enable(clk); +	if (ret) { +		dev_err(&pdev->dev, "failed to enable clock\n"); +		goto err4; +	} + +	glue->dev			= &pdev->dev; +	glue->clk			= clk; + +	pdata->platform_ops		= &da8xx_ops; + +	glue->phy = usb_phy_generic_register(); +	if (IS_ERR(glue->phy)) { +		ret = PTR_ERR(glue->phy); +		goto err5; +	} +	platform_set_drvdata(pdev, glue); + +	memset(musb_resources, 0x00, sizeof(*musb_resources) * +			ARRAY_SIZE(musb_resources)); + +	musb_resources[0].name = pdev->resource[0].name; +	musb_resources[0].start = pdev->resource[0].start; +	musb_resources[0].end = pdev->resource[0].end; +	musb_resources[0].flags = pdev->resource[0].flags; + +	musb_resources[1].name = pdev->resource[1].name; +	musb_resources[1].start = pdev->resource[1].start; +	musb_resources[1].end = pdev->resource[1].end; +	musb_resources[1].flags = pdev->resource[1].flags; + +	pinfo = da8xx_dev_info; +	pinfo.parent = &pdev->dev; +	pinfo.res = musb_resources; +	pinfo.num_res = ARRAY_SIZE(musb_resources); +	pinfo.data = pdata; +	pinfo.size_data = sizeof(*pdata); + +	glue->musb = musb = platform_device_register_full(&pinfo); +	if (IS_ERR(musb)) { +		ret = PTR_ERR(musb); +		dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); +		goto err6; +	} + +	return 0; + +err6: +	usb_phy_generic_unregister(glue->phy); + +err5: +	clk_disable(clk); + +err4: +	clk_put(clk); + +err3: +	kfree(glue); + +err0: +	return ret; +} + +static int da8xx_remove(struct platform_device *pdev) +{ +	struct da8xx_glue		*glue = platform_get_drvdata(pdev); + +	platform_device_unregister(glue->musb); +	usb_phy_generic_unregister(glue->phy); +	clk_disable(glue->clk); +	clk_put(glue->clk); +	kfree(glue);  	return 0;  } + +static struct platform_driver da8xx_driver = { +	.probe		= da8xx_probe, +	.remove		= da8xx_remove, +	.driver		= { +		.name	= "musb-da8xx", +	}, +}; + +MODULE_DESCRIPTION("DA8xx/OMAP-L1x MUSB Glue Layer"); +MODULE_AUTHOR("Sergei Shtylyov <sshtylyov@ru.mvista.com>"); +MODULE_LICENSE("GPL v2"); +module_platform_driver(da8xx_driver); diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 6e67629f50c..de8492b06e4 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -24,17 +24,18 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/sched.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/delay.h>  #include <linux/clk.h> +#include <linux/err.h>  #include <linux/io.h>  #include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/usb/usb_phy_generic.h> -#include <mach/hardware.h> -#include <mach/memory.h> -#include <mach/gpio.h>  #include <mach/cputype.h> +#include <mach/hardware.h>  #include <asm/mach-types.h> @@ -51,6 +52,12 @@  #define USB_PHY_CTRL	IO_ADDRESS(USBPHY_CTL_PADDR)  #define DM355_DEEPSLEEP	IO_ADDRESS(DM355_DEEPSLEEP_PADDR) +struct davinci_glue { +	struct device		*dev; +	struct platform_device	*musb; +	struct clk		*clk; +}; +  /* REVISIT (PM) we should be able to keep the PHY in low power mode most   * of the time (24 MHZ oscillator and PLL off, etc) by setting POWER.D0   * and, when in host mode, autosuspending idle root ports... PHYPLLON @@ -83,7 +90,7 @@ static inline void phy_off(void)  static int dma_off = 1; -void musb_platform_enable(struct musb *musb) +static void davinci_musb_enable(struct musb *musb)  {  	u32	tmp, old, val; @@ -108,15 +115,14 @@ void musb_platform_enable(struct musb *musb)  		dma_off = 0;  	/* force a DRVVBUS irq so we can start polling for ID change */ -	if (is_otg_enabled(musb)) -		musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG, +	musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,  			DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT);  }  /*   * Disable the HDRC and flush interrupts   */ -void musb_platform_disable(struct musb *musb) +static void davinci_musb_disable(struct musb *musb)  {  	/* because we don't set CTRLR.UINT, "important" to:  	 *  - not read/write INTRUSB/INTRUSBE @@ -135,12 +141,7 @@ void musb_platform_disable(struct musb *musb)  } -#ifdef CONFIG_USB_MUSB_HDRC_HCD  #define	portstate(stmt)		stmt -#else -#define	portstate(stmt) -#endif -  /*   * VBUS SWITCHING IS BOARD-SPECIFIC ... at least for the DM6446 EVM, @@ -167,7 +168,7 @@ static void evm_deferred_drvvbus(struct work_struct *ignored)  #endif	/* EVM */ -static void davinci_source_power(struct musb *musb, int is_on, int immediate) +static void davinci_musb_source_power(struct musb *musb, int is_on, int immediate)  {  #ifdef CONFIG_MACH_DAVINCI_EVM  	if (is_on) @@ -190,10 +191,10 @@ static void davinci_source_power(struct musb *musb, int is_on, int immediate)  #endif  } -static void davinci_set_vbus(struct musb *musb, int is_on) +static void davinci_musb_set_vbus(struct musb *musb, int is_on)  {  	WARN_ON(is_on && is_peripheral_active(musb)); -	davinci_source_power(musb, is_on, 0); +	davinci_musb_source_power(musb, is_on, 0);  } @@ -212,7 +213,8 @@ static void otg_timer(unsigned long _musb)  	* 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)); +	dev_dbg(musb->controller, "poll devctl %02x (%s)\n", devctl, +		usb_otg_state_string(musb->xceiv->state));  	spin_lock_irqsave(&musb->lock, flags);  	switch (musb->xceiv->state) { @@ -231,10 +233,8 @@ static void otg_timer(unsigned long _musb)  			MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT);  		break;  	case OTG_STATE_B_IDLE: -		if (!is_peripheral_enabled(musb)) -			break; - -		/* There's no ID-changed IRQ, so we have no good way to tell +		/* +		 * There's no ID-changed IRQ, so we have no good way to tell  		 * when to switch to the A-Default state machine (by setting  		 * the DEVCTL.SESSION flag).  		 * @@ -259,11 +259,12 @@ static void otg_timer(unsigned long _musb)  	spin_unlock_irqrestore(&musb->lock, flags);  } -static irqreturn_t davinci_interrupt(int irq, void *__hci) +static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)  {  	unsigned long	flags;  	irqreturn_t	retval = IRQ_NONE;  	struct musb	*musb = __hci; +	struct usb_otg	*otg = musb->xceiv->otg;  	void __iomem	*tibase = musb->ctrl_base;  	struct cppi	*cppi;  	u32		tmp; @@ -289,7 +290,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)  	/* ack and handle non-CPPI interrupts */  	tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG);  	musb_writel(tibase, DAVINCI_USB_INT_SRC_CLR_REG, tmp); -	DBG(4, "IRQ %08x\n", tmp); +	dev_dbg(musb->controller, "IRQ %08x\n", tmp);  	musb->int_rx = (tmp & DAVINCI_USB_RXINT_MASK)  			>> DAVINCI_USB_RXINT_SHIFT; @@ -311,8 +312,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)  		u8	devctl = musb_readb(mregs, MUSB_DEVCTL);  		int	err = musb->int_usb & MUSB_INTR_VBUSERROR; -		err = is_host_enabled(musb) -				&& (musb->int_usb & MUSB_INTR_VBUSERROR); +		err = 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 @@ -328,16 +328,16 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)  			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) { +		} else if (drvvbus) {  			MUSB_HST_MODE(musb); -			musb->xceiv->default_a = 1; +			otg->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; +			otg->default_a = 0;  			musb->xceiv->state = OTG_STATE_B_IDLE;  			portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);  		} @@ -345,10 +345,10 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)  		/* NOTE:  this must complete poweron within 100 msec  		 * (OTG_TIME_A_WAIT_VRISE) but we don't check for that.  		 */ -		davinci_source_power(musb, drvvbus, 0); -		DBG(2, "VBUS %s (%s)%s, devctl %02x\n", +		davinci_musb_source_power(musb, drvvbus, 0); +		dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",  				drvvbus ? "on" : "off", -				otg_state_string(musb), +				usb_otg_state_string(musb->xceiv->state),  				err ? " ERROR" : "",  				devctl);  		retval = IRQ_HANDLED; @@ -361,8 +361,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)  	musb_writel(tibase, DAVINCI_USB_EOI_REG, 0);  	/* poll for ID change */ -	if (is_otg_enabled(musb) -			&& musb->xceiv->state == OTG_STATE_B_IDLE) +	if (musb->xceiv->state == OTG_STATE_B_IDLE)  		mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);  	spin_unlock_irqrestore(&musb->lock, flags); @@ -370,36 +369,34 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)  	return retval;  } -int musb_platform_set_mode(struct musb *musb, u8 mode) +static int davinci_musb_set_mode(struct musb *musb, u8 mode)  {  	/* EVM can't do this (right?) */  	return -EIO;  } -int __init musb_platform_init(struct musb *musb, void *board_data) +static int davinci_musb_init(struct musb *musb)  {  	void __iomem	*tibase = musb->ctrl_base;  	u32		revision; +	int 		ret = -ENODEV; -	usb_nop_xceiv_register(); -	musb->xceiv = otg_get_transceiver(); -	if (!musb->xceiv) -		return -ENODEV; +	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); +	if (IS_ERR_OR_NULL(musb->xceiv)) { +		ret = -EPROBE_DEFER; +		goto unregister; +	}  	musb->mregs += DAVINCI_BASE_OFFSET; -	clk_enable(musb->clock); -  	/* returns zero if e.g. not clocked */  	revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);  	if (revision == 0)  		goto fail; -	if (is_host_enabled(musb)) -		setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); +	setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); -	musb->board_set_vbus = davinci_set_vbus; -	davinci_source_power(musb, 0, 1); +	davinci_musb_source_power(musb, 0, 1);  	/* dm355 EVM swaps D+/D- for signal integrity, and  	 * is clocked from the main 24 MHz crystal. @@ -418,12 +415,7 @@ int __init musb_platform_init(struct musb *musb, void *board_data)  	if (cpu_is_davinci_dm355()) {  		u32	deepsleep = __raw_readl(DM355_DEEPSLEEP); -		if (is_host_enabled(musb)) { -			deepsleep &= ~DRVVBUS_OVERRIDE; -		} else { -			deepsleep &= ~DRVVBUS_FORCE; -			deepsleep |= DRVVBUS_OVERRIDE; -		} +		deepsleep &= ~DRVVBUS_FORCE;  		__raw_writel(deepsleep, DM355_DEEPSLEEP);  	} @@ -440,21 +432,19 @@ int __init musb_platform_init(struct musb *musb, void *board_data)  		revision, __raw_readl(USB_PHY_CTRL),  		musb_readb(tibase, DAVINCI_USB_CTRL_REG)); -	musb->isr = davinci_interrupt; +	musb->isr = davinci_musb_interrupt;  	return 0;  fail: -	clk_disable(musb->clock); - -	otg_put_transceiver(musb->xceiv); -	usb_nop_xceiv_unregister(); -	return -ENODEV; +	usb_put_phy(musb->xceiv); +unregister: +	usb_phy_generic_unregister(); +	return ret;  } -int musb_platform_exit(struct musb *musb) +static int davinci_musb_exit(struct musb *musb)  { -	if (is_host_enabled(musb)) -		del_timer_sync(&otg_workaround); +	del_timer_sync(&otg_workaround);  	/* force VBUS off */  	if (cpu_is_davinci_dm355()) { @@ -465,10 +455,10 @@ int musb_platform_exit(struct musb *musb)  		__raw_writel(deepsleep, DM355_DEEPSLEEP);  	} -	davinci_source_power(musb, 0 /*off*/, 1); +	davinci_musb_source_power(musb, 0 /*off*/, 1);  	/* delay, to avoid problems with module reload */ -	if (is_host_enabled(musb) && musb->xceiv->default_a) { +	if (musb->xceiv->otg->default_a) {  		int	maxdelay = 30;  		u8	devctl, warn = 0; @@ -481,7 +471,7 @@ int musb_platform_exit(struct musb *musb)  				break;  			if ((devctl & MUSB_DEVCTL_VBUS) != warn) {  				warn = devctl & MUSB_DEVCTL_VBUS; -				DBG(1, "VBUS %d\n", +				dev_dbg(musb->controller, "VBUS %d\n",  					warn >> MUSB_DEVCTL_VBUS_SHIFT);  			}  			msleep(1000); @@ -490,15 +480,145 @@ int musb_platform_exit(struct musb *musb)  		/* in OTG mode, another host might be connected */  		if (devctl & MUSB_DEVCTL_VBUS) -			DBG(1, "VBUS off timeout (devctl %02x)\n", devctl); +			dev_dbg(musb->controller, "VBUS off timeout (devctl %02x)\n", devctl);  	}  	phy_off(); -	clk_disable(musb->clock); +	usb_put_phy(musb->xceiv); + +	return 0; +} + +static const struct musb_platform_ops davinci_ops = { +	.init		= davinci_musb_init, +	.exit		= davinci_musb_exit, + +	.enable		= davinci_musb_enable, +	.disable	= davinci_musb_disable, + +	.set_mode	= davinci_musb_set_mode, + +	.set_vbus	= davinci_musb_set_vbus, +}; + +static const struct platform_device_info davinci_dev_info = { +	.name		= "musb-hdrc", +	.id		= PLATFORM_DEVID_AUTO, +	.dma_mask	= DMA_BIT_MASK(32), +}; + +static int davinci_probe(struct platform_device *pdev) +{ +	struct resource			musb_resources[3]; +	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev); +	struct platform_device		*musb; +	struct davinci_glue		*glue; +	struct platform_device_info	pinfo; +	struct clk			*clk; + +	int				ret = -ENOMEM; + +	glue = kzalloc(sizeof(*glue), GFP_KERNEL); +	if (!glue) { +		dev_err(&pdev->dev, "failed to allocate glue context\n"); +		goto err0; +	} + +	clk = clk_get(&pdev->dev, "usb"); +	if (IS_ERR(clk)) { +		dev_err(&pdev->dev, "failed to get clock\n"); +		ret = PTR_ERR(clk); +		goto err3; +	} + +	ret = clk_enable(clk); +	if (ret) { +		dev_err(&pdev->dev, "failed to enable clock\n"); +		goto err4; +	} + +	glue->dev			= &pdev->dev; +	glue->clk			= clk; + +	pdata->platform_ops		= &davinci_ops; + +	usb_phy_generic_register(); +	platform_set_drvdata(pdev, glue); + +	memset(musb_resources, 0x00, sizeof(*musb_resources) * +			ARRAY_SIZE(musb_resources)); + +	musb_resources[0].name = pdev->resource[0].name; +	musb_resources[0].start = pdev->resource[0].start; +	musb_resources[0].end = pdev->resource[0].end; +	musb_resources[0].flags = pdev->resource[0].flags; + +	musb_resources[1].name = pdev->resource[1].name; +	musb_resources[1].start = pdev->resource[1].start; +	musb_resources[1].end = pdev->resource[1].end; +	musb_resources[1].flags = pdev->resource[1].flags; + +	/* +	 * For DM6467 3 resources are passed. A placeholder for the 3rd +	 * resource is always there, so it's safe to always copy it... +	 */ +	musb_resources[2].name = pdev->resource[2].name; +	musb_resources[2].start = pdev->resource[2].start; +	musb_resources[2].end = pdev->resource[2].end; +	musb_resources[2].flags = pdev->resource[2].flags; + +	pinfo = davinci_dev_info; +	pinfo.parent = &pdev->dev; +	pinfo.res = musb_resources; +	pinfo.num_res = ARRAY_SIZE(musb_resources); +	pinfo.data = pdata; +	pinfo.size_data = sizeof(*pdata); + +	glue->musb = musb = platform_device_register_full(&pinfo); +	if (IS_ERR(musb)) { +		ret = PTR_ERR(musb); +		dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); +		goto err5; +	} + +	return 0; + +err5: +	clk_disable(clk); + +err4: +	clk_put(clk); -	otg_put_transceiver(musb->xceiv); -	usb_nop_xceiv_unregister(); +err3: +	kfree(glue); + +err0: +	return ret; +} + +static int davinci_remove(struct platform_device *pdev) +{ +	struct davinci_glue		*glue = platform_get_drvdata(pdev); + +	platform_device_unregister(glue->musb); +	usb_phy_generic_unregister(); +	clk_disable(glue->clk); +	clk_put(glue->clk); +	kfree(glue);  	return 0;  } + +static struct platform_driver davinci_driver = { +	.probe		= davinci_probe, +	.remove		= davinci_remove, +	.driver		= { +		.name	= "musb-davinci", +	}, +}; + +MODULE_DESCRIPTION("DaVinci MUSB Glue Layer"); +MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); +MODULE_LICENSE("GPL v2"); +module_platform_driver(davinci_driver); diff --git a/drivers/usb/musb/davinci.h b/drivers/usb/musb/davinci.h index 046c84433ca..371baa0ee50 100644 --- a/drivers/usb/musb/davinci.h +++ b/drivers/usb/musb/davinci.h @@ -15,7 +15,7 @@   */  /* Integrated highspeed/otg PHY */ -#define USBPHY_CTL_PADDR	(DAVINCI_SYSTEM_MODULE_BASE + 0x34) +#define USBPHY_CTL_PADDR	0x01c40034  #define USBPHY_DATAPOL		BIT(11)	/* (dm355) switch D+/D- */  #define USBPHY_PHYCLKGD		BIT(8)  #define USBPHY_SESNDEN		BIT(7)	/* v(sess_end) comparator */ @@ -27,7 +27,7 @@  #define USBPHY_OTGPDWN		BIT(1)  #define USBPHY_PHYPDWN		BIT(0) -#define DM355_DEEPSLEEP_PADDR	(DAVINCI_SYSTEM_MODULE_BASE + 0x48) +#define DM355_DEEPSLEEP_PADDR	0x01c40048  #define DRVVBUS_FORCE		BIT(2)  #define DRVVBUS_OVERRIDE	BIT(1) diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c new file mode 100644 index 00000000000..5f30537f192 --- /dev/null +++ b/drivers/usb/musb/jz4740.c @@ -0,0 +1,201 @@ +/* + * Ingenic JZ4740 "glue layer" + * + * Copyright (C) 2013, Apelete Seketeli <apelete@seketeli.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include "musb_core.h" + +struct jz4740_glue { +	struct device           *dev; +	struct platform_device  *musb; +	struct clk		*clk; +}; + +static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci) +{ +	unsigned long   flags; +	irqreturn_t     retval = IRQ_NONE; +	struct musb     *musb = __hci; + +	spin_lock_irqsave(&musb->lock, flags); + +	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); +	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); +	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); + +	/* +	 * The controller is gadget only, the state of the host mode IRQ bits is +	 * undefined. Mask them to make sure that the musb driver core will +	 * never see them set +	 */ +	musb->int_usb &= MUSB_INTR_SUSPEND | MUSB_INTR_RESUME | +	    MUSB_INTR_RESET | MUSB_INTR_SOF; + +	if (musb->int_usb || musb->int_tx || musb->int_rx) +		retval = musb_interrupt(musb); + +	spin_unlock_irqrestore(&musb->lock, flags); + +	return retval; +} + +static struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = { +{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 64, }, +}; + +static struct musb_hdrc_config jz4740_musb_config = { +	/* Silicon does not implement USB OTG. */ +	.multipoint = 0, +	/* Max EPs scanned, driver will decide which EP can be used. */ +	.num_eps    = 4, +	/* RAMbits needed to configure EPs from table */ +	.ram_bits   = 9, +	.fifo_cfg = jz4740_musb_fifo_cfg, +	.fifo_cfg_size = ARRAY_SIZE(jz4740_musb_fifo_cfg), +}; + +static struct musb_hdrc_platform_data jz4740_musb_platform_data = { +	.mode   = MUSB_PERIPHERAL, +	.config = &jz4740_musb_config, +}; + +static int jz4740_musb_init(struct musb *musb) +{ +	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); +	if (!musb->xceiv) { +		pr_err("HS UDC: no transceiver configured\n"); +		return -ENODEV; +	} + +	/* Silicon does not implement ConfigData register. +	 * Set dyn_fifo to avoid reading EP config from hardware. +	 */ +	musb->dyn_fifo = true; + +	musb->isr = jz4740_musb_interrupt; + +	return 0; +} + +static int jz4740_musb_exit(struct musb *musb) +{ +	usb_put_phy(musb->xceiv); + +	return 0; +} + +static const struct musb_platform_ops jz4740_musb_ops = { +	.init		= jz4740_musb_init, +	.exit		= jz4740_musb_exit, +}; + +static int jz4740_probe(struct platform_device *pdev) +{ +	struct musb_hdrc_platform_data	*pdata = &jz4740_musb_platform_data; +	struct platform_device		*musb; +	struct jz4740_glue		*glue; +	struct clk                      *clk; +	int				ret; + +	glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); +	if (!glue) +		return -ENOMEM; + +	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); +	if (!musb) { +		dev_err(&pdev->dev, "failed to allocate musb device\n"); +		return -ENOMEM; +	} + +	clk = devm_clk_get(&pdev->dev, "udc"); +	if (IS_ERR(clk)) { +		dev_err(&pdev->dev, "failed to get clock\n"); +		ret = PTR_ERR(clk); +		goto err_platform_device_put; +	} + +	ret = clk_prepare_enable(clk); +	if (ret) { +		dev_err(&pdev->dev, "failed to enable clock\n"); +		goto err_platform_device_put; +	} + +	musb->dev.parent		= &pdev->dev; + +	glue->dev			= &pdev->dev; +	glue->musb			= musb; +	glue->clk			= clk; + +	pdata->platform_ops		= &jz4740_musb_ops; + +	platform_set_drvdata(pdev, glue); + +	ret = platform_device_add_resources(musb, pdev->resource, +					    pdev->num_resources); +	if (ret) { +		dev_err(&pdev->dev, "failed to add resources\n"); +		goto err_clk_disable; +	} + +	ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); +	if (ret) { +		dev_err(&pdev->dev, "failed to add platform_data\n"); +		goto err_clk_disable; +	} + +	ret = platform_device_add(musb); +	if (ret) { +		dev_err(&pdev->dev, "failed to register musb device\n"); +		goto err_clk_disable; +	} + +	return 0; + +err_clk_disable: +	clk_disable_unprepare(clk); +err_platform_device_put: +	platform_device_put(musb); +	return ret; +} + +static int jz4740_remove(struct platform_device *pdev) +{ +	struct jz4740_glue	*glue = platform_get_drvdata(pdev); + +	platform_device_unregister(glue->musb); +	clk_disable_unprepare(glue->clk); + +	return 0; +} + +static struct platform_driver jz4740_driver = { +	.probe		= jz4740_probe, +	.remove		= jz4740_remove, +	.driver		= { +		.name	= "musb-jz4740", +	}, +}; + +MODULE_DESCRIPTION("JZ4740 MUSB Glue Layer"); +MODULE_AUTHOR("Apelete Seketeli <apelete@seketeli.net>"); +MODULE_LICENSE("GPL v2"); +module_platform_driver(jz4740_driver); diff --git a/drivers/usb/musb/musb_am335x.c b/drivers/usb/musb/musb_am335x.c new file mode 100644 index 00000000000..1e58ed2361c --- /dev/null +++ b/drivers/usb/musb/musb_am335x.c @@ -0,0 +1,43 @@ +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/module.h> +#include <linux/of_platform.h> + +static int am335x_child_probe(struct platform_device *pdev) +{ +	int ret; + +	pm_runtime_enable(&pdev->dev); + +	ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); +	if (ret) +		goto err; + +	return 0; +err: +	pm_runtime_disable(&pdev->dev); +	return ret; +} + +static const struct of_device_id am335x_child_of_match[] = { +	{ .compatible = "ti,am33xx-usb" }, +	{  }, +}; +MODULE_DEVICE_TABLE(of, am335x_child_of_match); + +static struct platform_driver am335x_child_driver = { +	.probe		= am335x_child_probe, +	.driver         = { +		.name   = "am335x-usb-childs", +		.of_match_table	= am335x_child_of_match, +	}, +}; + +static int __init am335x_child_init(void) +{ +	return platform_driver_register(&am335x_child_driver); +} +module_init(am335x_child_init); + +MODULE_DESCRIPTION("AM33xx child devices"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index e6669fc3b80..eff3c5cf84f 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -83,7 +83,7 @@   * This gets many kinds of configuration information:   *	- Kconfig for everything user-configurable   *	- platform_device for addressing, irq, and platform_data - *	- platform_data is mostly for board-specific informarion + *	- platform_data is mostly for board-specific information   *	  (plus recentrly, SOC or family details)   *   * Most of the conditional compilation will (someday) vanish. @@ -93,32 +93,18 @@  #include <linux/kernel.h>  #include <linux/sched.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/kobject.h> +#include <linux/prefetch.h>  #include <linux/platform_device.h>  #include <linux/io.h> - -#ifdef	CONFIG_ARM -#include <mach/hardware.h> -#include <mach/memory.h> -#include <asm/mach-types.h> -#endif +#include <linux/dma-mapping.h>  #include "musb_core.h" - -#ifdef CONFIG_ARCH_DAVINCI -#include "davinci.h" -#endif -  #define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON) -unsigned musb_debug; -module_param_named(debug, musb_debug, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug message level. Default = 0"); -  #define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia"  #define DRIVER_DESC "Inventra Dual-Role USB Controller Driver" @@ -126,7 +112,7 @@ MODULE_PARM_DESC(debug, "Debug message level. Default = 0");  #define DRIVER_INFO DRIVER_DESC ", v" MUSB_VERSION -#define MUSB_DRIVER_NAME "musb_hdrc" +#define MUSB_DRIVER_NAME "musb-hdrc"  const char musb_driver_name[] = MUSB_DRIVER_NAME;  MODULE_DESCRIPTION(DRIVER_INFO); @@ -139,23 +125,21 @@ MODULE_ALIAS("platform:" MUSB_DRIVER_NAME);  static inline struct musb *dev_to_musb(struct device *dev)  { -#ifdef CONFIG_USB_MUSB_HDRC_HCD -	/* usbcore insists dev->driver_data is a "struct hcd *" */ -	return hcd_to_musb(dev_get_drvdata(dev)); -#else  	return dev_get_drvdata(dev); -#endif  }  /*-------------------------------------------------------------------------*/  #ifndef CONFIG_BLACKFIN -static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset) +static int musb_ulpi_read(struct usb_phy *phy, u32 offset)  { -	void __iomem *addr = otg->io_priv; +	void __iomem *addr = phy->io_priv;  	int	i = 0;  	u8	r;  	u8	power; +	int	ret; + +	pm_runtime_get_sync(phy->io_dev);  	/* Make sure the transceiver is not in low power mode */  	power = musb_readb(addr, MUSB_POWER); @@ -174,8 +158,8 @@ static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset)  				& MUSB_ULPI_REG_CMPLT)) {  		i++;  		if (i == 10000) { -			DBG(3, "ULPI read timed out\n"); -			return -ETIMEDOUT; +			ret = -ETIMEDOUT; +			goto out;  		}  	} @@ -183,16 +167,23 @@ static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset)  	r &= ~MUSB_ULPI_REG_CMPLT;  	musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r); -	return musb_readb(addr, MUSB_ULPI_REG_DATA); +	ret = musb_readb(addr, MUSB_ULPI_REG_DATA); + +out: +	pm_runtime_put(phy->io_dev); + +	return ret;  } -static int musb_ulpi_write(struct otg_transceiver *otg, -		u32 offset, u32 data) +static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data)  { -	void __iomem *addr = otg->io_priv; +	void __iomem *addr = phy->io_priv;  	int	i = 0;  	u8	r = 0;  	u8	power; +	int	ret = 0; + +	pm_runtime_get_sync(phy->io_dev);  	/* Make sure the transceiver is not in low power mode */  	power = musb_readb(addr, MUSB_POWER); @@ -207,8 +198,8 @@ static int musb_ulpi_write(struct otg_transceiver *otg,  				& MUSB_ULPI_REG_CMPLT)) {  		i++;  		if (i == 10000) { -			DBG(3, "ULPI write timed out\n"); -			return -ETIMEDOUT; +			ret = -ETIMEDOUT; +			goto out;  		}  	} @@ -216,32 +207,39 @@ static int musb_ulpi_write(struct otg_transceiver *otg,  	r &= ~MUSB_ULPI_REG_CMPLT;  	musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r); -	return 0; +out: +	pm_runtime_put(phy->io_dev); + +	return ret;  }  #else  #define musb_ulpi_read		NULL  #define musb_ulpi_write		NULL  #endif -static struct otg_io_access_ops musb_ulpi_access = { +static struct usb_phy_io_ops musb_ulpi_access = {  	.read = musb_ulpi_read,  	.write = musb_ulpi_write,  };  /*-------------------------------------------------------------------------*/ -#if !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN) +#if !defined(CONFIG_USB_MUSB_TUSB6010) && !defined(CONFIG_USB_MUSB_BLACKFIN)  /*   * Load an endpoint's FIFO   */  void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)  { +	struct musb *musb = hw_ep->musb;  	void __iomem *fifo = hw_ep->fifo; +	if (unlikely(len == 0)) +		return; +  	prefetch((u8 *)src); -	DBG(4, "%cX ep%d fifo %p count %d buf %p\n", +	dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n",  			'T', hw_ep->epnum, fifo, len, src);  	/* we can't assume unaligned reads work */ @@ -251,7 +249,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)  		/* best case is 32bit-aligned source address */  		if ((0x02 & (unsigned long) src) == 0) {  			if (len >= 4) { -				writesl(fifo, src + index, len >> 2); +				iowrite32_rep(fifo, src + index, len >> 2);  				index += len & ~0x03;  			}  			if (len & 0x02) { @@ -260,7 +258,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)  			}  		} else {  			if (len >= 2) { -				writesw(fifo, src + index, len >> 1); +				iowrite16_rep(fifo, src + index, len >> 1);  				index += len & ~0x01;  			}  		} @@ -268,7 +266,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)  			musb_writeb(fifo, 0, src[index]);  	} else  {  		/* byte aligned */ -		writesb(fifo, src, len); +		iowrite8_rep(fifo, src, len);  	}  } @@ -278,9 +276,13 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)   */  void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)  { +	struct musb *musb = hw_ep->musb;  	void __iomem *fifo = hw_ep->fifo; -	DBG(4, "%cX ep%d fifo %p count %d buf %p\n", +	if (unlikely(len == 0)) +		return; + +	dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n",  			'R', hw_ep->epnum, fifo, len, dst);  	/* we can't assume unaligned writes work */ @@ -290,7 +292,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)  		/* best case is 32bit-aligned destination address */  		if ((0x02 & (unsigned long) dst) == 0) {  			if (len >= 4) { -				readsl(fifo, dst, len >> 2); +				ioread32_rep(fifo, dst, len >> 2);  				index = len & ~0x03;  			}  			if (len & 0x02) { @@ -299,7 +301,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)  			}  		} else {  			if (len >= 2) { -				readsw(fifo, dst, len >> 1); +				ioread16_rep(fifo, dst, len >> 1);  				index = len & ~0x01;  			}  		} @@ -307,7 +309,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)  			dst[index] = musb_readb(fifo, 0);  	} else  {  		/* byte aligned */ -		readsb(fifo, dst, len); +		ioread8_rep(fifo, dst, len);  	}  }  #endif @@ -349,32 +351,10 @@ void musb_load_testpacket(struct musb *musb)  /*-------------------------------------------------------------------------*/ -const char *otg_state_string(struct musb *musb) -{ -	switch (musb->xceiv->state) { -	case OTG_STATE_A_IDLE:		return "a_idle"; -	case OTG_STATE_A_WAIT_VRISE:	return "a_wait_vrise"; -	case OTG_STATE_A_WAIT_BCON:	return "a_wait_bcon"; -	case OTG_STATE_A_HOST:		return "a_host"; -	case OTG_STATE_A_SUSPEND:	return "a_suspend"; -	case OTG_STATE_A_PERIPHERAL:	return "a_peripheral"; -	case OTG_STATE_A_WAIT_VFALL:	return "a_wait_vfall"; -	case OTG_STATE_A_VBUS_ERR:	return "a_vbus_err"; -	case OTG_STATE_B_IDLE:		return "b_idle"; -	case OTG_STATE_B_SRP_INIT:	return "b_srp_init"; -	case OTG_STATE_B_PERIPHERAL:	return "b_peripheral"; -	case OTG_STATE_B_WAIT_ACON:	return "b_wait_acon"; -	case OTG_STATE_B_HOST:		return "b_host"; -	default:			return "UNDEFINED"; -	} -} - -#ifdef	CONFIG_USB_MUSB_OTG -  /*   * Handles OTG hnp timeouts, such as b_ase0_brst   */ -void musb_otg_timer_func(unsigned long data) +static void musb_otg_timer_func(unsigned long data)  {  	struct musb	*musb = (struct musb *)data;  	unsigned long	flags; @@ -382,21 +362,22 @@ void musb_otg_timer_func(unsigned long data)  	spin_lock_irqsave(&musb->lock, flags);  	switch (musb->xceiv->state) {  	case OTG_STATE_B_WAIT_ACON: -		DBG(1, "HNP: b_wait_acon timeout; back to b_peripheral\n"); +		dev_dbg(musb->controller, "HNP: b_wait_acon timeout; back to b_peripheral\n");  		musb_g_disconnect(musb);  		musb->xceiv->state = OTG_STATE_B_PERIPHERAL;  		musb->is_active = 0;  		break;  	case OTG_STATE_A_SUSPEND:  	case OTG_STATE_A_WAIT_BCON: -		DBG(1, "HNP: %s timeout\n", otg_state_string(musb)); -		musb_set_vbus(musb, 0); +		dev_dbg(musb->controller, "HNP: %s timeout\n", +			usb_otg_state_string(musb->xceiv->state)); +		musb_platform_set_vbus(musb, 0);  		musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;  		break;  	default: -		DBG(1, "HNP: Unhandled mode %s\n", otg_state_string(musb)); +		dev_dbg(musb->controller, "HNP: Unhandled mode %s\n", +			usb_otg_state_string(musb->xceiv->state));  	} -	musb->ignore_disconnect = 0;  	spin_unlock_irqrestore(&musb->lock, flags);  } @@ -405,20 +386,23 @@ void musb_otg_timer_func(unsigned long data)   */  void musb_hnp_stop(struct musb *musb)  { -	struct usb_hcd	*hcd = musb_to_hcd(musb); +	struct usb_hcd	*hcd = musb->hcd;  	void __iomem	*mbase = musb->mregs;  	u8	reg; -	DBG(1, "HNP: stop from %s\n", otg_state_string(musb)); +	dev_dbg(musb->controller, "HNP: stop from %s\n", +			usb_otg_state_string(musb->xceiv->state));  	switch (musb->xceiv->state) {  	case OTG_STATE_A_PERIPHERAL:  		musb_g_disconnect(musb); -		DBG(1, "HNP: back to %s\n", otg_state_string(musb)); +		dev_dbg(musb->controller, "HNP: back to %s\n", +			usb_otg_state_string(musb->xceiv->state));  		break;  	case OTG_STATE_B_HOST: -		DBG(1, "HNP: Disabling HR\n"); -		hcd->self.is_b_host = 0; +		dev_dbg(musb->controller, "HNP: Disabling HR\n"); +		if (hcd) +			hcd->self.is_b_host = 0;  		musb->xceiv->state = OTG_STATE_B_PERIPHERAL;  		MUSB_DEV_MODE(musb);  		reg = musb_readb(mbase, MUSB_POWER); @@ -427,8 +411,8 @@ void musb_hnp_stop(struct musb *musb)  		/* REVISIT: Start SESSION_REQUEST here? */  		break;  	default: -		DBG(1, "HNP: Stopping in unknown state %s\n", -			otg_state_string(musb)); +		dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n", +			usb_otg_state_string(musb->xceiv->state));  	}  	/* @@ -439,8 +423,6 @@ void musb_hnp_stop(struct musb *musb)  	musb->port1_status &= ~(USB_PORT_STAT_C_CONNECTION << 16);  } -#endif -  /*   * Interrupt Service Routine to record USB "global" interrupts.   * Since these do not happen often and signify things of @@ -454,11 +436,11 @@ void musb_hnp_stop(struct musb *musb)   */  static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, -				u8 devctl, u8 power) +				u8 devctl)  {  	irqreturn_t handled = IRQ_NONE; -	DBG(3, "<== Power=%02x, DevCtl=%02x, int_usb=0x%x\n", power, devctl, +	dev_dbg(musb->controller, "<== DevCtl=%02x, int_usb=0x%x\n", devctl,  		int_usb);  	/* in host mode, the peripheral may issue remote wakeup. @@ -467,11 +449,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  	 */  	if (int_usb & MUSB_INTR_RESUME) {  		handled = IRQ_HANDLED; -		DBG(3, "RESUME (%s)\n", otg_state_string(musb)); +		dev_dbg(musb->controller, "RESUME (%s)\n", usb_otg_state_string(musb->xceiv->state));  		if (devctl & MUSB_DEVCTL_HM) { -#ifdef CONFIG_USB_MUSB_HDRC_HCD  			void __iomem *mbase = musb->mregs; +			u8 power;  			switch (musb->xceiv->state) {  			case OTG_STATE_A_SUSPEND: @@ -479,10 +461,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  				 * will stop RESUME signaling  				 */ +				power = musb_readb(musb->mregs, MUSB_POWER);  				if (power & MUSB_POWER_SUSPENDM) {  					/* spurious */  					musb->int_usb &= ~MUSB_INTR_SUSPEND; -					DBG(2, "Spurious SUSPENDM\n"); +					dev_dbg(musb->controller, "Spurious SUSPENDM\n");  					break;  				} @@ -494,11 +477,14 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  						(USB_PORT_STAT_C_SUSPEND << 16)  						| MUSB_PORT_STAT_RESUME;  				musb->rh_timer = jiffies -						+ msecs_to_jiffies(20); +						 + msecs_to_jiffies(20); +				schedule_delayed_work( +					&musb->finish_resume_work, +					msecs_to_jiffies(20));  				musb->xceiv->state = OTG_STATE_A_HOST;  				musb->is_active = 1; -				usb_hcd_resume_root_hub(musb_to_hcd(musb)); +				musb_host_resume_root_hub(musb);  				break;  			case OTG_STATE_B_WAIT_ACON:  				musb->xceiv->state = OTG_STATE_B_PERIPHERAL; @@ -508,19 +494,15 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  			default:  				WARNING("bogus %s RESUME (%s)\n",  					"host", -					otg_state_string(musb)); +					usb_otg_state_string(musb->xceiv->state));  			} -#endif  		} else {  			switch (musb->xceiv->state) { -#ifdef CONFIG_USB_MUSB_HDRC_HCD  			case OTG_STATE_A_SUSPEND:  				/* possibly DISCONNECT is upcoming */  				musb->xceiv->state = OTG_STATE_A_HOST; -				usb_hcd_resume_root_hub(musb_to_hcd(musb)); +				musb_host_resume_root_hub(musb);  				break; -#endif -#ifdef CONFIG_USB_GADGET_MUSB_HDRC  			case OTG_STATE_B_WAIT_ACON:  			case OTG_STATE_B_PERIPHERAL:  				/* disconnect while suspended?  we may @@ -538,27 +520,26 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  			case OTG_STATE_B_IDLE:  				musb->int_usb &= ~MUSB_INTR_SUSPEND;  				break; -#endif  			default:  				WARNING("bogus %s RESUME (%s)\n",  					"peripheral", -					otg_state_string(musb)); +					usb_otg_state_string(musb->xceiv->state));  			}  		}  	} -#ifdef CONFIG_USB_MUSB_HDRC_HCD  	/* see manual for the order of the tests */  	if (int_usb & MUSB_INTR_SESSREQ) {  		void __iomem *mbase = musb->mregs;  		if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS  				&& (devctl & MUSB_DEVCTL_BDEVICE)) { -			DBG(3, "SessReq while on B state\n"); +			dev_dbg(musb->controller, "SessReq while on B state\n");  			return IRQ_HANDLED;  		} -		DBG(1, "SESSION_REQUEST (%s)\n", otg_state_string(musb)); +		dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n", +			usb_otg_state_string(musb->xceiv->state));  		/* IRQ arrives from ID pin sense or (later, if VBUS power  		 * is removed) SRP.  responses are time critical: @@ -571,7 +552,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  		musb->ep0_stage = MUSB_EP0_START;  		musb->xceiv->state = OTG_STATE_A_IDLE;  		MUSB_HST_MODE(musb); -		musb_set_vbus(musb, 1); +		musb_platform_set_vbus(musb, 1);  		handled = IRQ_HANDLED;  	} @@ -622,8 +603,9 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  			break;  		} -		DBG(1, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n", -				otg_state_string(musb), +		dev_printk(ignore ? KERN_DEBUG : KERN_ERR, musb->controller, +				"VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n", +				usb_otg_state_string(musb->xceiv->state),  				devctl,  				({ char *s;  				switch (devctl & MUSB_DEVCTL_VBUS) { @@ -636,24 +618,22 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  				/* case 3 << MUSB_DEVCTL_VBUS_SHIFT: */  				default:  					s = "VALID"; break; -				}; s; }), +				} s; }),  				VBUSERR_RETRY_COUNT - musb->vbuserr_retry,  				musb->port1_status);  		/* go through A_WAIT_VFALL then start a new session */  		if (!ignore) -			musb_set_vbus(musb, 0); +			musb_platform_set_vbus(musb, 0);  		handled = IRQ_HANDLED;  	} -#endif  	if (int_usb & MUSB_INTR_SUSPEND) { -		DBG(1, "SUSPEND (%s) devctl %02x power %02x\n", -				otg_state_string(musb), devctl, power); +		dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x\n", +			usb_otg_state_string(musb->xceiv->state), devctl);  		handled = IRQ_HANDLED;  		switch (musb->xceiv->state) { -#ifdef	CONFIG_USB_MUSB_OTG  		case OTG_STATE_A_PERIPHERAL:  			/* We also come here if the cable is removed, since  			 * this silicon doesn't report ID-no-longer-grounded. @@ -663,29 +643,25 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  			 * undesired detour through A_WAIT_BCON.  			 */  			musb_hnp_stop(musb); -			usb_hcd_resume_root_hub(musb_to_hcd(musb)); +			musb_host_resume_root_hub(musb);  			musb_root_disconnect(musb);  			musb_platform_try_idle(musb, jiffies  					+ msecs_to_jiffies(musb->a_wait_bcon  						? : OTG_TIME_A_WAIT_BCON));  			break; -#endif  		case OTG_STATE_B_IDLE:  			if (!musb->is_active)  				break;  		case OTG_STATE_B_PERIPHERAL:  			musb_g_suspend(musb); -			musb->is_active = is_otg_enabled(musb) -					&& musb->xceiv->gadget->b_hnp_enable; +			musb->is_active = musb->g.b_hnp_enable;  			if (musb->is_active) { -#ifdef	CONFIG_USB_MUSB_OTG  				musb->xceiv->state = OTG_STATE_B_WAIT_ACON; -				DBG(1, "HNP: Setting timer for b_ase0_brst\n"); +				dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n");  				mod_timer(&musb->otg_timer, jiffies  					+ msecs_to_jiffies(  							OTG_TIME_B_ASE0_BRST)); -#endif  			}  			break;  		case OTG_STATE_A_WAIT_BCON: @@ -695,12 +671,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  			break;  		case OTG_STATE_A_HOST:  			musb->xceiv->state = OTG_STATE_A_SUSPEND; -			musb->is_active = is_otg_enabled(musb) -					&& musb->xceiv->host->b_hnp_enable; +			musb->is_active = musb->hcd->self.b_hnp_enable;  			break;  		case OTG_STATE_B_HOST:  			/* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */ -			DBG(1, "REVISIT: SUSPEND as B_HOST\n"); +			dev_dbg(musb->controller, "REVISIT: SUSPEND as B_HOST\n");  			break;  		default:  			/* "should not happen" */ @@ -709,25 +684,23 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  		}  	} -#ifdef CONFIG_USB_MUSB_HDRC_HCD  	if (int_usb & MUSB_INTR_CONNECT) { -		struct usb_hcd *hcd = musb_to_hcd(musb); +		struct usb_hcd *hcd = musb->hcd;  		handled = IRQ_HANDLED;  		musb->is_active = 1; -		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);  		musb->ep0_stage = MUSB_EP0_START; -#ifdef CONFIG_USB_MUSB_OTG  		/* flush endpoints when transitioning from Device Mode */  		if (is_peripheral_active(musb)) {  			/* REVISIT HNP; just force disconnect */  		} -		musb_writew(musb->mregs, MUSB_INTRTXE, musb->epmask); -		musb_writew(musb->mregs, MUSB_INTRRXE, musb->epmask & 0xfffe); +		musb->intrtxe = musb->epmask; +		musb_writew(musb->mregs, MUSB_INTRTXE, musb->intrtxe); +		musb->intrrxe = musb->epmask & 0xfffe; +		musb_writew(musb->mregs, MUSB_INTRRXE, musb->intrrxe);  		musb_writeb(musb->mregs, MUSB_INTRUSBE, 0xf7); -#endif  		musb->port1_status &= ~(USB_PORT_STAT_LOW_SPEED  					|USB_PORT_STAT_HIGH_SPEED  					|USB_PORT_STAT_ENABLE @@ -743,59 +716,51 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  		switch (musb->xceiv->state) {  		case OTG_STATE_B_PERIPHERAL:  			if (int_usb & MUSB_INTR_SUSPEND) { -				DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n"); +				dev_dbg(musb->controller, "HNP: SUSPEND+CONNECT, now b_host\n");  				int_usb &= ~MUSB_INTR_SUSPEND;  				goto b_host;  			} else -				DBG(1, "CONNECT as b_peripheral???\n"); +				dev_dbg(musb->controller, "CONNECT as b_peripheral???\n");  			break;  		case OTG_STATE_B_WAIT_ACON: -			DBG(1, "HNP: CONNECT, now b_host\n"); +			dev_dbg(musb->controller, "HNP: CONNECT, now b_host\n");  b_host:  			musb->xceiv->state = OTG_STATE_B_HOST; -			hcd->self.is_b_host = 1; -			musb->ignore_disconnect = 0; +			if (musb->hcd) +				musb->hcd->self.is_b_host = 1;  			del_timer(&musb->otg_timer);  			break;  		default:  			if ((devctl & MUSB_DEVCTL_VBUS)  					== (3 << MUSB_DEVCTL_VBUS_SHIFT)) {  				musb->xceiv->state = OTG_STATE_A_HOST; -				hcd->self.is_b_host = 0; +				if (hcd) +					hcd->self.is_b_host = 0;  			}  			break;  		} -		/* poke the root hub */ -		MUSB_HST_MODE(musb); -		if (hcd->status_urb) -			usb_hcd_poll_rh_status(hcd); -		else -			usb_hcd_resume_root_hub(hcd); +		musb_host_poke_root_hub(musb); -		DBG(1, "CONNECT (%s) devctl %02x\n", -				otg_state_string(musb), devctl); +		dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n", +				usb_otg_state_string(musb->xceiv->state), devctl);  	} -#endif	/* CONFIG_USB_MUSB_HDRC_HCD */ -	if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) { -		DBG(1, "DISCONNECT (%s) as %s, devctl %02x\n", -				otg_state_string(musb), +	if (int_usb & MUSB_INTR_DISCONNECT) { +		dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n", +				usb_otg_state_string(musb->xceiv->state),  				MUSB_MODE(musb), devctl);  		handled = IRQ_HANDLED;  		switch (musb->xceiv->state) { -#ifdef CONFIG_USB_MUSB_HDRC_HCD  		case OTG_STATE_A_HOST:  		case OTG_STATE_A_SUSPEND: -			usb_hcd_resume_root_hub(musb_to_hcd(musb)); +			musb_host_resume_root_hub(musb);  			musb_root_disconnect(musb); -			if (musb->a_wait_bcon != 0 && is_otg_enabled(musb)) +			if (musb->a_wait_bcon != 0)  				musb_platform_try_idle(musb, jiffies  					+ msecs_to_jiffies(musb->a_wait_bcon));  			break; -#endif	/* HOST */ -#ifdef CONFIG_USB_MUSB_OTG  		case OTG_STATE_B_HOST:  			/* REVISIT this behaves for "real disconnect"  			 * cases; make sure the other transitions from @@ -803,7 +768,8 @@ b_host:  			 * in hnp_stop() is currently not used...  			 */  			musb_root_disconnect(musb); -			musb_to_hcd(musb)->self.is_b_host = 0; +			if (musb->hcd) +				musb->hcd->self.is_b_host = 0;  			musb->xceiv->state = OTG_STATE_B_PERIPHERAL;  			MUSB_DEV_MODE(musb);  			musb_g_disconnect(musb); @@ -814,16 +780,13 @@ b_host:  			/* FALLTHROUGH */  		case OTG_STATE_B_WAIT_ACON:  			/* FALLTHROUGH */ -#endif	/* OTG */ -#ifdef CONFIG_USB_GADGET_MUSB_HDRC  		case OTG_STATE_B_PERIPHERAL:  		case OTG_STATE_B_IDLE:  			musb_g_disconnect(musb);  			break; -#endif	/* GADGET */  		default:  			WARNING("unhandled DISCONNECT transition (%s)\n", -				otg_state_string(musb)); +				usb_otg_state_string(musb->xceiv->state));  			break;  		}  	} @@ -833,7 +796,7 @@ b_host:  	 */  	if (int_usb & MUSB_INTR_RESET) {  		handled = IRQ_HANDLED; -		if (is_host_capable() && (devctl & MUSB_DEVCTL_HM) != 0) { +		if ((devctl & MUSB_DEVCTL_HM) != 0) {  			/*  			 * Looks like non-HS BABBLE can be ignored, but  			 * HS BABBLE is an error condition. For HS the solution @@ -842,43 +805,36 @@ b_host:  			 * stop the session.  			 */  			if (devctl & (MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV)) -				DBG(1, "BABBLE devctl: %02x\n", devctl); +				dev_dbg(musb->controller, "BABBLE devctl: %02x\n", devctl);  			else {  				ERR("Stopping host session -- babble\n");  				musb_writeb(musb->mregs, MUSB_DEVCTL, 0);  			} -		} else if (is_peripheral_capable()) { -			DBG(1, "BUS RESET as %s\n", otg_state_string(musb)); +		} else { +			dev_dbg(musb->controller, "BUS RESET as %s\n", +				usb_otg_state_string(musb->xceiv->state));  			switch (musb->xceiv->state) { -#ifdef CONFIG_USB_OTG  			case OTG_STATE_A_SUSPEND: -				/* We need to ignore disconnect on suspend -				 * otherwise tusb 2.0 won't reconnect after a -				 * power cycle, which breaks otg compliance. -				 */ -				musb->ignore_disconnect = 1;  				musb_g_reset(musb);  				/* FALLTHROUGH */  			case OTG_STATE_A_WAIT_BCON:	/* OPT TD.4.7-900ms */  				/* never use invalid T(a_wait_bcon) */ -				DBG(1, "HNP: in %s, %d msec timeout\n", -						otg_state_string(musb), -						TA_WAIT_BCON(musb)); +				dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n", +					usb_otg_state_string(musb->xceiv->state), +					TA_WAIT_BCON(musb));  				mod_timer(&musb->otg_timer, jiffies  					+ msecs_to_jiffies(TA_WAIT_BCON(musb)));  				break;  			case OTG_STATE_A_PERIPHERAL: -				musb->ignore_disconnect = 0;  				del_timer(&musb->otg_timer);  				musb_g_reset(musb);  				break;  			case OTG_STATE_B_WAIT_ACON: -				DBG(1, "HNP: RESET (%s), to b_peripheral\n", -					otg_state_string(musb)); +				dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n", +					usb_otg_state_string(musb->xceiv->state));  				musb->xceiv->state = OTG_STATE_B_PERIPHERAL;  				musb_g_reset(musb);  				break; -#endif  			case OTG_STATE_B_IDLE:  				musb->xceiv->state = OTG_STATE_B_PERIPHERAL;  				/* FALLTHROUGH */ @@ -886,12 +842,16 @@ b_host:  				musb_g_reset(musb);  				break;  			default: -				DBG(1, "Unhandled BUS RESET as %s\n", -					otg_state_string(musb)); +				dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n", +					usb_otg_state_string(musb->xceiv->state));  			}  		}  	} +	/* handle babble condition */ +	if (int_usb & MUSB_INTR_BABBLE && is_host_active(musb)) +		schedule_work(&musb->recover_work); +  #if 0  /* REVISIT ... this would be for multiplexing periodic endpoints, or   * supporting transfer phasing to prevent exceeding ISO bandwidth @@ -910,7 +870,7 @@ b_host:  		u8 epnum;  		u16 frame; -		DBG(6, "START_OF_FRAME\n"); +		dev_dbg(musb->controller, "START_OF_FRAME\n");  		handled = IRQ_HANDLED;  		/* start any periodic Tx transfers waiting for current frame */ @@ -944,79 +904,74 @@ b_host:  /*-------------------------------------------------------------------------*/ +static void musb_generic_disable(struct musb *musb) +{ +	void __iomem	*mbase = musb->mregs; +	u16	temp; + +	/* disable interrupts */ +	musb_writeb(mbase, MUSB_INTRUSBE, 0); +	musb->intrtxe = 0; +	musb_writew(mbase, MUSB_INTRTXE, 0); +	musb->intrrxe = 0; +	musb_writew(mbase, MUSB_INTRRXE, 0); + +	/* off */ +	musb_writeb(mbase, MUSB_DEVCTL, 0); + +	/*  flush pending interrupts */ +	temp = musb_readb(mbase, MUSB_INTRUSB); +	temp = musb_readw(mbase, MUSB_INTRTX); +	temp = musb_readw(mbase, MUSB_INTRRX); + +} +  /* -* Program the HDRC to start (enable interrupts, dma, etc.). -*/ + * Program the HDRC to start (enable interrupts, dma, etc.). + */  void musb_start(struct musb *musb)  { -	void __iomem	*regs = musb->mregs; -	u8		devctl = musb_readb(regs, MUSB_DEVCTL); +	void __iomem    *regs = musb->mregs; +	u8              devctl = musb_readb(regs, MUSB_DEVCTL); -	DBG(2, "<== devctl %02x\n", devctl); +	dev_dbg(musb->controller, "<== devctl %02x\n", devctl);  	/*  Set INT enable registers, enable interrupts */ -	musb_writew(regs, MUSB_INTRTXE, musb->epmask); -	musb_writew(regs, MUSB_INTRRXE, musb->epmask & 0xfffe); +	musb->intrtxe = musb->epmask; +	musb_writew(regs, MUSB_INTRTXE, musb->intrtxe); +	musb->intrrxe = musb->epmask & 0xfffe; +	musb_writew(regs, MUSB_INTRRXE, musb->intrrxe);  	musb_writeb(regs, MUSB_INTRUSBE, 0xf7);  	musb_writeb(regs, MUSB_TESTMODE, 0);  	/* put into basic highspeed mode and start session */  	musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE -						| MUSB_POWER_SOFTCONN -						| MUSB_POWER_HSENAB -						/* ENSUSPEND wedges tusb */ -						/* | MUSB_POWER_ENSUSPEND */ -						); +			| MUSB_POWER_HSENAB +			/* ENSUSPEND wedges tusb */ +			/* | MUSB_POWER_ENSUSPEND */ +		   );  	musb->is_active = 0;  	devctl = musb_readb(regs, MUSB_DEVCTL);  	devctl &= ~MUSB_DEVCTL_SESSION; -	if (is_otg_enabled(musb)) { -		/* session started after: -		 * (a) ID-grounded irq, host mode; -		 * (b) vbus present/connect IRQ, peripheral mode; -		 * (c) peripheral initiates, using SRP -		 */ -		if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) -			musb->is_active = 1; -		else -			devctl |= MUSB_DEVCTL_SESSION; - -	} else if (is_host_enabled(musb)) { -		/* assume ID pin is hard-wired to ground */ +	/* session started after: +	 * (a) ID-grounded irq, host mode; +	 * (b) vbus present/connect IRQ, peripheral mode; +	 * (c) peripheral initiates, using SRP +	 */ +	if (musb->port_mode != MUSB_PORT_MODE_HOST && +			(devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) { +		musb->is_active = 1; +	} else {  		devctl |= MUSB_DEVCTL_SESSION; - -	} else /* peripheral is enabled */ { -		if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) -			musb->is_active = 1;  	} +  	musb_platform_enable(musb);  	musb_writeb(regs, MUSB_DEVCTL, devctl);  } - -static void musb_generic_disable(struct musb *musb) -{ -	void __iomem	*mbase = musb->mregs; -	u16	temp; - -	/* disable interrupts */ -	musb_writeb(mbase, MUSB_INTRUSBE, 0); -	musb_writew(mbase, MUSB_INTRTXE, 0); -	musb_writew(mbase, MUSB_INTRRXE, 0); - -	/* off */ -	musb_writeb(mbase, MUSB_DEVCTL, 0); - -	/*  flush pending interrupts */ -	temp = musb_readb(mbase, MUSB_INTRUSB); -	temp = musb_readw(mbase, MUSB_INTRTX); -	temp = musb_readw(mbase, MUSB_INTRRX); - -} -  /*   * Make the HDRC stop (disable interrupts, etc.);   * reversible by musb_start @@ -1029,7 +984,7 @@ void musb_stop(struct musb *musb)  	/* stop IRQs, timers, ... */  	musb_platform_disable(musb);  	musb_generic_disable(musb); -	DBG(3, "HDRC disabled\n"); +	dev_dbg(musb->controller, "HDRC disabled\n");  	/* FIXME  	 *  - mark host and/or peripheral drivers unusable/inactive @@ -1046,18 +1001,20 @@ static void musb_shutdown(struct platform_device *pdev)  	struct musb	*musb = dev_to_musb(&pdev->dev);  	unsigned long	flags; +	pm_runtime_get_sync(musb->controller); + +	musb_host_cleanup(musb); +	musb_gadget_cleanup(musb); +  	spin_lock_irqsave(&musb->lock, flags);  	musb_platform_disable(musb);  	musb_generic_disable(musb); -	if (musb->clock) -		clk_put(musb->clock);  	spin_unlock_irqrestore(&musb->lock, flags); -	if (!is_otg_enabled(musb) && is_host_enabled(musb)) -		usb_remove_hcd(musb_to_hcd(musb));  	musb_writeb(musb->mregs, MUSB_DEVCTL, 0);  	musb_platform_exit(musb); +	pm_runtime_put(musb->controller);  	/* FIXME power down */  } @@ -1074,12 +1031,20 @@ static void musb_shutdown(struct platform_device *pdev)   * We don't currently use dynamic fifo setup capability to do anything   * more than selecting one of a bunch of predefined configurations.   */ -#if defined(CONFIG_USB_TUSB6010) || \ -	defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) \ -	|| defined(CONFIG_ARCH_OMAP4) -static ushort __initdata fifo_mode = 4; +#if defined(CONFIG_USB_MUSB_TUSB6010)			\ +	|| defined(CONFIG_USB_MUSB_TUSB6010_MODULE)	\ +	|| defined(CONFIG_USB_MUSB_OMAP2PLUS)		\ +	|| defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE)	\ +	|| defined(CONFIG_USB_MUSB_AM35X)		\ +	|| defined(CONFIG_USB_MUSB_AM35X_MODULE)	\ +	|| defined(CONFIG_USB_MUSB_DSPS)		\ +	|| defined(CONFIG_USB_MUSB_DSPS_MODULE) +static ushort fifo_mode = 4; +#elif defined(CONFIG_USB_MUSB_UX500)			\ +	|| defined(CONFIG_USB_MUSB_UX500_MODULE) +static ushort fifo_mode = 5;  #else -static ushort __initdata fifo_mode = 2; +static ushort fifo_mode = 2;  #endif  /* "modprobe ... fifo_mode=1" etc */ @@ -1092,7 +1057,7 @@ MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration");   */  /* mode 0 - fits in 2KB */ -static struct musb_fifo_cfg __initdata mode_0_cfg[] = { +static struct musb_fifo_cfg mode_0_cfg[] = {  { .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, },  { .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, },  { .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, }, @@ -1101,7 +1066,7 @@ static struct musb_fifo_cfg __initdata mode_0_cfg[] = {  };  /* mode 1 - fits in 4KB */ -static struct musb_fifo_cfg __initdata mode_1_cfg[] = { +static struct musb_fifo_cfg mode_1_cfg[] = {  { .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, .mode = BUF_DOUBLE, },  { .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, .mode = BUF_DOUBLE, },  { .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, .mode = BUF_DOUBLE, }, @@ -1110,7 +1075,7 @@ static struct musb_fifo_cfg __initdata mode_1_cfg[] = {  };  /* mode 2 - fits in 4KB */ -static struct musb_fifo_cfg __initdata mode_2_cfg[] = { +static struct musb_fifo_cfg mode_2_cfg[] = {  { .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, },  { .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, },  { .hw_ep_num = 2, .style = FIFO_TX,   .maxpacket = 512, }, @@ -1120,7 +1085,7 @@ static struct musb_fifo_cfg __initdata mode_2_cfg[] = {  };  /* mode 3 - fits in 4KB */ -static struct musb_fifo_cfg __initdata mode_3_cfg[] = { +static struct musb_fifo_cfg mode_3_cfg[] = {  { .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, .mode = BUF_DOUBLE, },  { .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, .mode = BUF_DOUBLE, },  { .hw_ep_num = 2, .style = FIFO_TX,   .maxpacket = 512, }, @@ -1130,7 +1095,7 @@ static struct musb_fifo_cfg __initdata mode_3_cfg[] = {  };  /* mode 4 - fits in 16KB */ -static struct musb_fifo_cfg __initdata mode_4_cfg[] = { +static struct musb_fifo_cfg mode_4_cfg[] = {  { .hw_ep_num =  1, .style = FIFO_TX,   .maxpacket = 512, },  { .hw_ep_num =  1, .style = FIFO_RX,   .maxpacket = 512, },  { .hw_ep_num =  2, .style = FIFO_TX,   .maxpacket = 512, }, @@ -1161,7 +1126,7 @@ static struct musb_fifo_cfg __initdata mode_4_cfg[] = {  };  /* mode 5 - fits in 8KB */ -static struct musb_fifo_cfg __initdata mode_5_cfg[] = { +static struct musb_fifo_cfg mode_5_cfg[] = {  { .hw_ep_num =  1, .style = FIFO_TX,   .maxpacket = 512, },  { .hw_ep_num =  1, .style = FIFO_RX,   .maxpacket = 512, },  { .hw_ep_num =  2, .style = FIFO_TX,   .maxpacket = 512, }, @@ -1197,7 +1162,7 @@ static struct musb_fifo_cfg __initdata mode_5_cfg[] = {   *   * returns negative errno or offset for next fifo.   */ -static int __init +static int  fifo_setup(struct musb *musb, struct musb_hw_ep  *hw_ep,  		const struct musb_fifo_cfg *cfg, u16 offset)  { @@ -1226,14 +1191,12 @@ fifo_setup(struct musb *musb, struct musb_hw_ep  *hw_ep,  	/* configure the FIFO */  	musb_writeb(mbase, MUSB_INDEX, hw_ep->epnum); -#ifdef CONFIG_USB_MUSB_HDRC_HCD  	/* EP0 reserved endpoint for control, bidirectional; -	 * EP1 reserved for bulk, two unidirection halves. +	 * EP1 reserved for bulk, two unidirectional halves.  	 */  	if (hw_ep->epnum == 1)  		musb->bulk_ep = hw_ep;  	/* REVISIT error check:  be sure ep0 can both rx and tx ... */ -#endif  	switch (cfg->style) {  	case FIFO_TX:  		musb_write_txfifosz(mbase, c_size); @@ -1270,11 +1233,11 @@ fifo_setup(struct musb *musb, struct musb_hw_ep  *hw_ep,  	return offset + (maxpacket << ((c_size & MUSB_FIFOSZ_DPB) ? 1 : 0));  } -static struct musb_fifo_cfg __initdata ep0_cfg = { +static struct musb_fifo_cfg ep0_cfg = {  	.style = FIFO_RXTX, .maxpacket = 64,  }; -static int __init ep_config_from_table(struct musb *musb) +static int ep_config_from_table(struct musb *musb)  {  	const struct musb_fifo_cfg	*cfg;  	unsigned		i, n; @@ -1341,7 +1304,7 @@ done:  		if (offset < 0) {  			pr_debug("%s: mem overrun, ep %d\n",  					musb_driver_name, epn); -			return -EINVAL; +			return offset;  		}  		epn++;  		musb->nr_endpoints = max(epn, musb->nr_endpoints); @@ -1352,12 +1315,10 @@ done:  			n + 1, musb->config->num_eps * 2 - 1,  			offset, (1 << (musb->config->ram_bits + 2))); -#ifdef CONFIG_USB_MUSB_HDRC_HCD  	if (!musb->bulk_ep) {  		pr_debug("%s: missing bulk\n", musb_driver_name);  		return -EINVAL;  	} -#endif  	return 0;  } @@ -1367,14 +1328,14 @@ done:   * ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false   * @param musb the controller   */ -static int __init ep_config_from_hw(struct musb *musb) +static int ep_config_from_hw(struct musb *musb)  {  	u8 epnum = 0;  	struct musb_hw_ep *hw_ep; -	void *mbase = musb->mregs; +	void __iomem *mbase = musb->mregs;  	int ret = 0; -	DBG(2, "<== static silicon ep config\n"); +	dev_dbg(musb->controller, "<== static silicon ep config\n");  	/* FIXME pick up ep0 maxpacket size */ @@ -1388,7 +1349,6 @@ static int __init ep_config_from_hw(struct musb *musb)  		/* FIXME set up hw_ep->{rx,tx}_double_buffered */ -#ifdef CONFIG_USB_MUSB_HDRC_HCD  		/* pick an RX/TX endpoint for bulk */  		if (hw_ep->max_packet_sz_tx < 512  				|| hw_ep->max_packet_sz_rx < 512) @@ -1400,15 +1360,12 @@ static int __init ep_config_from_hw(struct musb *musb)  		if (musb->bulk_ep)  			continue;  		musb->bulk_ep = hw_ep; -#endif  	} -#ifdef CONFIG_USB_MUSB_HDRC_HCD  	if (!musb->bulk_ep) {  		pr_debug("%s: missing bulk\n", musb_driver_name);  		return -EINVAL;  	} -#endif  	return 0;  } @@ -1418,7 +1375,7 @@ enum { MUSB_CONTROLLER_MHDRC, MUSB_CONTROLLER_HDRC, };  /* Initialize MUSB (M)HDRC part of the USB hardware subsystem;   * configure endpoints, or take their config from silicon   */ -static int __init musb_core_init(u16 musb_type, struct musb *musb) +static int musb_core_init(u16 musb_type, struct musb *musb)  {  	u8 reg;  	char *type; @@ -1464,13 +1421,11 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)  	} else {  		musb->is_multipoint = 0;  		type = ""; -#ifdef CONFIG_USB_MUSB_HDRC_HCD  #ifndef	CONFIG_USB_OTG_BLACKLIST_HUB  		printk(KERN_ERR  			"%s: kernel must blacklist external hubs\n",  			musb_driver_name);  #endif -#endif  	}  	/* log release info */ @@ -1501,7 +1456,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)  		struct musb_hw_ep	*hw_ep = musb->endpoints + i;  		hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase; -#ifdef CONFIG_USB_TUSB6010 +#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE)  		hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i);  		hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i);  		hw_ep->fifo_sync_va = @@ -1514,14 +1469,12 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)  #endif  		hw_ep->regs = MUSB_EP_OFFSET(i, 0) + mbase; -#ifdef CONFIG_USB_MUSB_HDRC_HCD  		hw_ep->target_regs = musb_read_target_reg_base(i, mbase);  		hw_ep->rx_reinit = 1;  		hw_ep->tx_reinit = 1; -#endif  		if (hw_ep->max_packet_sz_tx) { -			DBG(1, +			dev_dbg(musb->controller,  				"%s: hw_ep %d%s, %smax %d\n",  				musb_driver_name, i,  				hw_ep->is_shared_fifo ? "shared" : "tx", @@ -1530,7 +1483,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)  				hw_ep->max_packet_sz_tx);  		}  		if (hw_ep->max_packet_sz_rx && !hw_ep->is_shared_fifo) { -			DBG(1, +			dev_dbg(musb->controller,  				"%s: hw_ep %d%s, %smax %d\n",  				musb_driver_name, i,  				"rx", @@ -1539,7 +1492,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)  				hw_ep->max_packet_sz_rx);  		}  		if (!(hw_ep->max_packet_sz_tx || hw_ep->max_packet_sz_rx)) -			DBG(1, "hw_ep %d not configured\n", i); +			dev_dbg(musb->controller, "hw_ep %d not configured\n", i);  	}  	return 0; @@ -1547,33 +1500,6 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)  /*-------------------------------------------------------------------------*/ -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) || \ -	defined(CONFIG_ARCH_OMAP4) - -static irqreturn_t generic_interrupt(int irq, void *__hci) -{ -	unsigned long	flags; -	irqreturn_t	retval = IRQ_NONE; -	struct musb	*musb = __hci; - -	spin_lock_irqsave(&musb->lock, flags); - -	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); -	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); -	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); - -	if (musb->int_usb || musb->int_tx || musb->int_rx) -		retval = musb_interrupt(musb); - -	spin_unlock_irqrestore(&musb->lock, flags); - -	return retval; -} - -#else -#define generic_interrupt	NULL -#endif -  /*   * handle all the irqs defined by the HDRC core. for now we expect:  other   * irq sources (phy, dma, etc) will be handled first, musb->int_* values @@ -1584,31 +1510,22 @@ static irqreturn_t generic_interrupt(int irq, void *__hci)  irqreturn_t musb_interrupt(struct musb *musb)  {  	irqreturn_t	retval = IRQ_NONE; -	u8		devctl, power; +	u8		devctl;  	int		ep_num;  	u32		reg;  	devctl = musb_readb(musb->mregs, MUSB_DEVCTL); -	power = musb_readb(musb->mregs, MUSB_POWER); -	DBG(4, "** IRQ %s usb%04x tx%04x rx%04x\n", +	dev_dbg(musb->controller, "** IRQ %s usb%04x tx%04x rx%04x\n",  		(devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral",  		musb->int_usb, musb->int_tx, musb->int_rx); -#ifdef CONFIG_USB_GADGET_MUSB_HDRC -	if (is_otg_enabled(musb) || is_peripheral_enabled(musb)) -		if (!musb->gadget_driver) { -			DBG(5, "No gadget driver loaded\n"); -			return IRQ_HANDLED; -		} -#endif -  	/* the core can interrupt us for multiple reasons; docs have  	 * a generic interrupt flowchart to follow  	 */  	if (musb->int_usb)  		retval |= musb_stage0_irq(musb, musb->int_usb, -				devctl, power); +				devctl);  	/* "stage 1" is handling endpoint irqs */ @@ -1628,13 +1545,10 @@ irqreturn_t musb_interrupt(struct musb *musb)  			/* musb_ep_select(musb->mregs, ep_num); */  			/* REVISIT just retval = ep->rx_irq(...) */  			retval = IRQ_HANDLED; -			if (devctl & MUSB_DEVCTL_HM) { -				if (is_host_capable()) -					musb_host_rx(musb, ep_num); -			} else { -				if (is_peripheral_capable()) -					musb_g_rx(musb, ep_num); -			} +			if (devctl & MUSB_DEVCTL_HM) +				musb_host_rx(musb, ep_num); +			else +				musb_g_rx(musb, ep_num);  		}  		reg >>= 1; @@ -1649,13 +1563,10 @@ irqreturn_t musb_interrupt(struct musb *musb)  			/* musb_ep_select(musb->mregs, ep_num); */  			/* REVISIT just retval |= ep->tx_irq(...) */  			retval = IRQ_HANDLED; -			if (devctl & MUSB_DEVCTL_HM) { -				if (is_host_capable()) -					musb_host_tx(musb, ep_num); -			} else { -				if (is_peripheral_capable()) -					musb_g_tx(musb, ep_num); -			} +			if (devctl & MUSB_DEVCTL_HM) +				musb_host_tx(musb, ep_num); +			else +				musb_g_tx(musb, ep_num);  		}  		reg >>= 1;  		ep_num++; @@ -1663,10 +1574,10 @@ irqreturn_t musb_interrupt(struct musb *musb)  	return retval;  } - +EXPORT_SYMBOL_GPL(musb_interrupt);  #ifndef CONFIG_MUSB_PIO_ONLY -static int __initdata use_dma = 1; +static bool use_dma = 1;  /* "modprobe ... use_dma=0" etc */  module_param(use_dma, bool, 0); @@ -1691,25 +1602,20 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)  	} else {  		/* endpoints 1..15 */  		if (transmit) { -			if (devctl & MUSB_DEVCTL_HM) { -				if (is_host_capable()) -					musb_host_tx(musb, epnum); -			} else { -				if (is_peripheral_capable()) -					musb_g_tx(musb, epnum); -			} +			if (devctl & MUSB_DEVCTL_HM) +				musb_host_tx(musb, epnum); +			else +				musb_g_tx(musb, epnum);  		} else {  			/* receive */ -			if (devctl & MUSB_DEVCTL_HM) { -				if (is_host_capable()) -					musb_host_rx(musb, epnum); -			} else { -				if (is_peripheral_capable()) -					musb_g_rx(musb, epnum); -			} +			if (devctl & MUSB_DEVCTL_HM) +				musb_host_rx(musb, epnum); +			else +				musb_g_rx(musb, epnum);  		}  	}  } +EXPORT_SYMBOL_GPL(musb_dma_completion);  #else  #define use_dma			0 @@ -1717,8 +1623,6 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)  /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_SYSFS -  static ssize_t  musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)  { @@ -1727,7 +1631,7 @@ musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)  	int ret = -EINVAL;  	spin_lock_irqsave(&musb->lock, flags); -	ret = sprintf(buf, "%s\n", otg_state_string(musb)); +	ret = sprintf(buf, "%s\n", usb_otg_state_string(musb->xceiv->state));  	spin_unlock_irqrestore(&musb->lock, flags);  	return ret; @@ -1801,8 +1705,6 @@ musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf)  }  static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store); -#ifdef CONFIG_USB_GADGET_MUSB_HDRC -  /* Gadget drivers can't know that a host is connected so they might want   * to start SRP, but users can.  This allows userspace to trigger SRP.   */ @@ -1826,14 +1728,10 @@ musb_srp_store(struct device *dev, struct device_attribute *attr,  }  static DEVICE_ATTR(srp, 0644, NULL, musb_srp_store); -#endif /* CONFIG_USB_GADGET_MUSB_HDRC */ -  static struct attribute *musb_attributes[] = {  	&dev_attr_mode.attr,  	&dev_attr_vbus.attr, -#ifdef CONFIG_USB_GADGET_MUSB_HDRC  	&dev_attr_srp.attr, -#endif  	NULL  }; @@ -1841,56 +1739,67 @@ static const struct attribute_group musb_attr_group = {  	.attrs = musb_attributes,  }; -#endif	/* sysfs */ -  /* Only used to provide driver mode change events */  static void musb_irq_work(struct work_struct *data)  {  	struct musb *musb = container_of(data, struct musb, irq_work); -	static int old_state; -	if (musb->xceiv->state != old_state) { -		old_state = musb->xceiv->state; +	if (musb->xceiv->state != musb->xceiv_old_state) { +		musb->xceiv_old_state = musb->xceiv->state;  		sysfs_notify(&musb->controller->kobj, NULL, "mode");  	}  } +/* Recover from babble interrupt conditions */ +static void musb_recover_work(struct work_struct *data) +{ +	struct musb *musb = container_of(data, struct musb, recover_work); +	int status; + +	musb_platform_reset(musb); + +	usb_phy_vbus_off(musb->xceiv); +	udelay(100); + +	usb_phy_vbus_on(musb->xceiv); +	udelay(100); + +	/* +	 * When a babble condition occurs, the musb controller removes the +	 * session bit and the endpoint config is lost. +	 */ +	if (musb->dyn_fifo) +		status = ep_config_from_table(musb); +	else +		status = ep_config_from_hw(musb); + +	/* start the session again */ +	if (status == 0) +		musb_start(musb); +} +  /* --------------------------------------------------------------------------   * Init support   */ -static struct musb *__init -allocate_instance(struct device *dev, +static struct musb *allocate_instance(struct device *dev,  		struct musb_hdrc_config *config, void __iomem *mbase)  {  	struct musb		*musb;  	struct musb_hw_ep	*ep;  	int			epnum; -#ifdef CONFIG_USB_MUSB_HDRC_HCD -	struct usb_hcd	*hcd; +	int			ret; -	hcd = usb_create_hcd(&musb_hc_driver, dev, dev_name(dev)); -	if (!hcd) +	musb = devm_kzalloc(dev, sizeof(*musb), GFP_KERNEL); +	if (!musb)  		return NULL; -	/* usbcore sets dev->driver_data to hcd, and sometimes uses that... */ -	musb = hcd_to_musb(hcd);  	INIT_LIST_HEAD(&musb->control);  	INIT_LIST_HEAD(&musb->in_bulk);  	INIT_LIST_HEAD(&musb->out_bulk); -	hcd->uses_new_polling = 1; -  	musb->vbuserr_retry = VBUSERR_RETRY_COUNT;  	musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON; -#else -	musb = kzalloc(sizeof *musb, GFP_KERNEL); -	if (!musb) -		return NULL; -	dev_set_drvdata(dev, musb); - -#endif -  	musb->mregs = mbase;  	musb->ctrl_base = mbase;  	musb->nIrq = -ENODEV; @@ -1904,7 +1813,17 @@ allocate_instance(struct device *dev,  	}  	musb->controller = dev; + +	ret = musb_host_alloc(musb); +	if (ret < 0) +		goto err_free; + +	dev_set_drvdata(dev, musb); +  	return musb; + +err_free: +	return NULL;  }  static void musb_free(struct musb *musb) @@ -1918,43 +1837,44 @@ static void musb_free(struct musb *musb)  	sysfs_remove_group(&musb->controller->kobj, &musb_attr_group);  #endif -#ifdef CONFIG_USB_GADGET_MUSB_HDRC -	musb_gadget_cleanup(musb); -#endif -  	if (musb->nIrq >= 0) {  		if (musb->irq_wake)  			disable_irq_wake(musb->nIrq);  		free_irq(musb->nIrq, musb);  	} -	if (is_dma_capable() && musb->dma_controller) { -		struct dma_controller	*c = musb->dma_controller; -		(void) c->stop(c); -		dma_controller_destroy(c); -	} +	musb_host_free(musb); +} -#ifdef CONFIG_USB_MUSB_HDRC_HCD -	usb_put_hcd(musb_to_hcd(musb)); -#else -	kfree(musb); -#endif +static void musb_deassert_reset(struct work_struct *work) +{ +	struct musb *musb; +	unsigned long flags; + +	musb = container_of(work, struct musb, deassert_reset_work.work); + +	spin_lock_irqsave(&musb->lock, flags); + +	if (musb->port1_status & USB_PORT_STAT_RESET) +		musb_port_reset(musb, false); + +	spin_unlock_irqrestore(&musb->lock, flags);  }  /*   * Perform generic per-controller initialization.   * - * @pDevice: the controller (already clocked, etc) - * @nIrq: irq - * @mregs: virtual address of controller registers, + * @dev: the controller (already clocked, etc) + * @nIrq: IRQ number + * @ctrl: virtual address of controller registers,   *	not yet corrected for platform-specific offsets   */ -static int __init +static int  musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)  {  	int			status;  	struct musb		*musb; -	struct musb_hdrc_platform_data *plat = dev->platform_data; +	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);  	/* The driver might handle more features than the board; OK.  	 * Fail when the board needs a feature that's not enabled. @@ -1965,31 +1885,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)  		goto fail0;  	} -	switch (plat->mode) { -	case MUSB_HOST: -#ifdef CONFIG_USB_MUSB_HDRC_HCD -		break; -#else -		goto bad_config; -#endif -	case MUSB_PERIPHERAL: -#ifdef CONFIG_USB_GADGET_MUSB_HDRC -		break; -#else -		goto bad_config; -#endif -	case MUSB_OTG: -#ifdef CONFIG_USB_MUSB_OTG -		break; -#else -bad_config: -#endif -	default: -		dev_err(dev, "incompatible Kconfig role setting\n"); -		status = -EINVAL; -		goto fail0; -	} -  	/* allocate */  	musb = allocate_instance(dev, plat->config, ctrl);  	if (!musb) { @@ -1997,72 +1892,63 @@ bad_config:  		goto fail0;  	} +	pm_runtime_use_autosuspend(musb->controller); +	pm_runtime_set_autosuspend_delay(musb->controller, 200); +	pm_runtime_enable(musb->controller); +  	spin_lock_init(&musb->lock); -	musb->board_mode = plat->mode;  	musb->board_set_power = plat->set_power; -	musb->set_clock = plat->set_clock;  	musb->min_power = plat->min_power; - -	/* Clock usage is chip-specific ... functional clock (DaVinci, -	 * OMAP2430), or PHY ref (some TUSB6010 boards).  All this core -	 * code does is make sure a clock handle is available; platform -	 * code manages it during start/stop and suspend/resume. -	 */ -	if (plat->clock) { -		musb->clock = clk_get(dev, plat->clock); -		if (IS_ERR(musb->clock)) { -			status = PTR_ERR(musb->clock); -			musb->clock = NULL; -			goto fail1; -		} -	} +	musb->ops = plat->platform_ops; +	musb->port_mode = plat->mode;  	/* The musb_platform_init() call: -	 *   - adjusts musb->mregs and musb->isr if needed, -	 *   - may initialize an integrated tranceiver -	 *   - initializes musb->xceiv, usually by otg_get_transceiver() -	 *   - activates clocks. +	 *   - adjusts musb->mregs +	 *   - sets the musb->isr +	 *   - may initialize an integrated transceiver +	 *   - initializes musb->xceiv, usually by otg_get_phy()  	 *   - stops powering VBUS -	 *   - assigns musb->board_set_vbus if host mode is enabled  	 * -	 * There are various transciever configurations.  Blackfin, +	 * There are various transceiver configurations.  Blackfin,  	 * DaVinci, TUSB60x0, and others integrate them.  OMAP3 uses  	 * external/discrete ones in various flavors (twl4030 family,  	 * isp1504, non-OTG, etc) mostly hooking up through ULPI.  	 */ -	musb->isr = generic_interrupt; -	status = musb_platform_init(musb, plat->board_data); +	status = musb_platform_init(musb);  	if (status < 0) -		goto fail2; +		goto fail1;  	if (!musb->isr) {  		status = -ENODEV; -		goto fail3; +		goto fail2;  	}  	if (!musb->xceiv->io_ops) { +		musb->xceiv->io_dev = musb->controller;  		musb->xceiv->io_priv = musb->mregs;  		musb->xceiv->io_ops = &musb_ulpi_access;  	} -#ifndef CONFIG_MUSB_PIO_ONLY -	if (use_dma && dev->dma_mask) { -		struct dma_controller	*c; +	pm_runtime_get_sync(musb->controller); -		c = dma_controller_create(musb, musb->mregs); -		musb->dma_controller = c; -		if (c) -			(void) c->start(c); +	if (use_dma && dev->dma_mask) { +		musb->dma_controller = dma_controller_create(musb, musb->mregs); +		if (IS_ERR(musb->dma_controller)) { +			status = PTR_ERR(musb->dma_controller); +			goto fail2_5; +		}  	} -#endif -	/* ideally this would be abstracted in platform setup */ -	if (!is_dma_capable() || !musb->dma_controller) -		dev->dma_mask = NULL;  	/* be sure interrupts are disabled before connecting ISR */  	musb_platform_disable(musb);  	musb_generic_disable(musb); +	/* Init IRQ workqueue before request_irq */ +	INIT_WORK(&musb->irq_work, musb_irq_work); +	INIT_WORK(&musb->recover_work, musb_recover_work); +	INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); +	INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume); +  	/* setup musb parts of the core (especially endpoints) */  	status = musb_core_init(plat->config->multipoint  			? MUSB_CONTROLLER_MHDRC @@ -2070,12 +1956,7 @@ bad_config:  	if (status < 0)  		goto fail3; -#ifdef CONFIG_USB_MUSB_OTG  	setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb); -#endif - -	/* Init IRQ workqueue before request_irq */ -	INIT_WORK(&musb->irq_work, musb_irq_work);  	/* attach to the IRQ */  	if (request_irq(nIrq, musb->isr, 0, dev_name(dev), musb)) { @@ -2084,7 +1965,7 @@ bad_config:  		goto fail3;  	}  	musb->nIrq = nIrq; -/* FIXME this handles wakeup irqs wrong */ +	/* FIXME this handles wakeup irqs wrong */  	if (enable_irq_wake(nIrq) == 0) {  		musb->irq_wake = 1;  		device_init_wakeup(dev, 1); @@ -2092,56 +1973,50 @@ bad_config:  		musb->irq_wake = 0;  	} -	/* host side needs more setup */ -	if (is_host_enabled(musb)) { -		struct usb_hcd	*hcd = musb_to_hcd(musb); - -		otg_set_host(musb->xceiv, &hcd->self); - -		if (is_otg_enabled(musb)) -			hcd->self.otg_port = 1; -		musb->xceiv->host = &hcd->self; -		hcd->power_budget = 2 * (plat->power ? : 250); - -		/* program PHY to use external vBus if required */ -		if (plat->extvbus) { -			u8 busctl = musb_read_ulpi_buscontrol(musb->mregs); -			busctl |= MUSB_ULPI_USE_EXTVBUS; -			musb_write_ulpi_buscontrol(musb->mregs, busctl); -		} +	/* program PHY to use external vBus if required */ +	if (plat->extvbus) { +		u8 busctl = musb_read_ulpi_buscontrol(musb->mregs); +		busctl |= MUSB_ULPI_USE_EXTVBUS; +		musb_write_ulpi_buscontrol(musb->mregs, busctl);  	} -	/* For the host-only role, we can activate right away. -	 * (We expect the ID pin to be forcibly grounded!!) -	 * Otherwise, wait till the gadget driver hooks up. -	 */ -	if (!is_otg_enabled(musb) && is_host_enabled(musb)) { +	if (musb->xceiv->otg->default_a) {  		MUSB_HST_MODE(musb); -		musb->xceiv->default_a = 1;  		musb->xceiv->state = OTG_STATE_A_IDLE; - -		status = usb_add_hcd(musb_to_hcd(musb), -1, 0); - -		DBG(1, "%s mode, status %d, devctl %02x %c\n", -			"HOST", status, -			musb_readb(musb->mregs, MUSB_DEVCTL), -			(musb_readb(musb->mregs, MUSB_DEVCTL) -					& MUSB_DEVCTL_BDEVICE -				? 'B' : 'A')); - -	} else /* peripheral is enabled */ { +	} else {  		MUSB_DEV_MODE(musb); -		musb->xceiv->default_a = 0;  		musb->xceiv->state = OTG_STATE_B_IDLE; +	} +	switch (musb->port_mode) { +	case MUSB_PORT_MODE_HOST: +		status = musb_host_setup(musb, plat->power); +		if (status < 0) +			goto fail3; +		status = musb_platform_set_mode(musb, MUSB_HOST); +		break; +	case MUSB_PORT_MODE_GADGET:  		status = musb_gadget_setup(musb); - -		DBG(1, "%s mode, status %d, dev%02x\n", -			is_otg_enabled(musb) ? "OTG" : "PERIPHERAL", -			status, -			musb_readb(musb->mregs, MUSB_DEVCTL)); - +		if (status < 0) +			goto fail3; +		status = musb_platform_set_mode(musb, MUSB_PERIPHERAL); +		break; +	case MUSB_PORT_MODE_DUAL_ROLE: +		status = musb_host_setup(musb, plat->power); +		if (status < 0) +			goto fail3; +		status = musb_gadget_setup(musb); +		if (status) { +			musb_host_cleanup(musb); +			goto fail3; +		} +		status = musb_platform_set_mode(musb, MUSB_OTG); +		break; +	default: +		dev_err(dev, "unsupported port mode %d\n", musb->port_mode); +		break;  	} +  	if (status < 0)  		goto fail3; @@ -2149,23 +2024,11 @@ bad_config:  	if (status < 0)  		goto fail4; -#ifdef CONFIG_SYSFS  	status = sysfs_create_group(&musb->controller->kobj, &musb_attr_group);  	if (status)  		goto fail5; -#endif -	dev_info(dev, "USB %s mode controller at %p using %s, IRQ %d\n", -			({char *s; -			 switch (musb->board_mode) { -			 case MUSB_HOST:		s = "Host"; break; -			 case MUSB_PERIPHERAL:	s = "Peripheral"; break; -			 default:		s = "OTG"; break; -			 }; s; }), -			ctrl, -			(is_dma_capable() && musb->dma_controller) -			? "DMA" : "PIO", -			musb->nIrq); +	pm_runtime_put(musb->controller);  	return 0; @@ -2173,21 +2036,26 @@ fail5:  	musb_exit_debugfs(musb);  fail4: -	if (!is_otg_enabled(musb) && is_host_enabled(musb)) -		usb_remove_hcd(musb_to_hcd(musb)); -	else -		musb_gadget_cleanup(musb); +	musb_gadget_cleanup(musb); +	musb_host_cleanup(musb);  fail3: +	cancel_work_sync(&musb->irq_work); +	cancel_work_sync(&musb->recover_work); +	cancel_delayed_work_sync(&musb->finish_resume_work); +	cancel_delayed_work_sync(&musb->deassert_reset_work); +	if (musb->dma_controller) +		dma_controller_destroy(musb->dma_controller); +fail2_5: +	pm_runtime_put_sync(musb->controller); + +fail2:  	if (musb->irq_wake)  		device_init_wakeup(dev, 0);  	musb_platform_exit(musb); -fail2: -	if (musb->clock) -		clk_put(musb->clock); -  fail1: +	pm_runtime_disable(musb->controller);  	dev_err(musb->controller,  		"musb_init_controller failed with status %d\n", status); @@ -2204,44 +2072,28 @@ fail0:  /* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just   * bridge to a platform device; this driver then suffices.   */ - -#ifndef CONFIG_MUSB_PIO_ONLY -static u64	*orig_dma_mask; -#endif - -static int __init musb_probe(struct platform_device *pdev) +static int musb_probe(struct platform_device *pdev)  {  	struct device	*dev = &pdev->dev; -	int		irq = platform_get_irq(pdev, 0); -	int		status; +	int		irq = platform_get_irq_byname(pdev, "mc");  	struct resource	*iomem;  	void __iomem	*base;  	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!iomem || irq == 0) +	if (!iomem || irq <= 0)  		return -ENODEV; -	base = ioremap(iomem->start, resource_size(iomem)); -	if (!base) { -		dev_err(dev, "ioremap failed\n"); -		return -ENOMEM; -	} +	base = devm_ioremap_resource(dev, iomem); +	if (IS_ERR(base)) +		return PTR_ERR(base); -#ifndef CONFIG_MUSB_PIO_ONLY -	/* clobbered by use_dma=n */ -	orig_dma_mask = dev->dma_mask; -#endif -	status = musb_init_controller(dev, irq, base); -	if (status < 0) -		iounmap(base); - -	return status; +	return musb_init_controller(dev, irq, base);  } -static int __exit musb_remove(struct platform_device *pdev) +static int musb_remove(struct platform_device *pdev)  { -	struct musb	*musb = dev_to_musb(&pdev->dev); -	void __iomem	*ctrl_base = musb->ctrl_base; +	struct device	*dev = &pdev->dev; +	struct musb	*musb = dev_to_musb(dev);  	/* this gets called on rmmod.  	 *  - Host mode: host may still be active @@ -2251,164 +2103,180 @@ static int __exit musb_remove(struct platform_device *pdev)  	musb_exit_debugfs(musb);  	musb_shutdown(pdev); +	if (musb->dma_controller) +		dma_controller_destroy(musb->dma_controller); + +	cancel_work_sync(&musb->irq_work); +	cancel_work_sync(&musb->recover_work); +	cancel_delayed_work_sync(&musb->finish_resume_work); +	cancel_delayed_work_sync(&musb->deassert_reset_work);  	musb_free(musb); -	iounmap(ctrl_base); -	device_init_wakeup(&pdev->dev, 0); -#ifndef CONFIG_MUSB_PIO_ONLY -	pdev->dev.dma_mask = orig_dma_mask; -#endif +	device_init_wakeup(dev, 0);  	return 0;  }  #ifdef	CONFIG_PM -static struct musb_context_registers musb_context; - -void musb_save_context(struct musb *musb) +static void musb_save_context(struct musb *musb)  {  	int i;  	void __iomem *musb_base = musb->mregs;  	void __iomem *epio; -	if (is_host_enabled(musb)) { -		musb_context.frame = musb_readw(musb_base, MUSB_FRAME); -		musb_context.testmode = musb_readb(musb_base, MUSB_TESTMODE); -		musb_context.busctl = musb_read_ulpi_buscontrol(musb->mregs); -	} -	musb_context.power = musb_readb(musb_base, MUSB_POWER); -	musb_context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE); -	musb_context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE); -	musb_context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE); -	musb_context.index = musb_readb(musb_base, MUSB_INDEX); -	musb_context.devctl = musb_readb(musb_base, MUSB_DEVCTL); +	musb->context.frame = musb_readw(musb_base, MUSB_FRAME); +	musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE); +	musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs); +	musb->context.power = musb_readb(musb_base, MUSB_POWER); +	musb->context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE); +	musb->context.index = musb_readb(musb_base, MUSB_INDEX); +	musb->context.devctl = musb_readb(musb_base, MUSB_DEVCTL);  	for (i = 0; i < musb->config->num_eps; ++i) { -		epio = musb->endpoints[i].regs; -		musb_context.index_regs[i].txmaxp = +		struct musb_hw_ep	*hw_ep; + +		hw_ep = &musb->endpoints[i]; +		if (!hw_ep) +			continue; + +		epio = hw_ep->regs; +		if (!epio) +			continue; + +		musb_writeb(musb_base, MUSB_INDEX, i); +		musb->context.index_regs[i].txmaxp =  			musb_readw(epio, MUSB_TXMAXP); -		musb_context.index_regs[i].txcsr = +		musb->context.index_regs[i].txcsr =  			musb_readw(epio, MUSB_TXCSR); -		musb_context.index_regs[i].rxmaxp = +		musb->context.index_regs[i].rxmaxp =  			musb_readw(epio, MUSB_RXMAXP); -		musb_context.index_regs[i].rxcsr = +		musb->context.index_regs[i].rxcsr =  			musb_readw(epio, MUSB_RXCSR);  		if (musb->dyn_fifo) { -			musb_context.index_regs[i].txfifoadd = +			musb->context.index_regs[i].txfifoadd =  					musb_read_txfifoadd(musb_base); -			musb_context.index_regs[i].rxfifoadd = +			musb->context.index_regs[i].rxfifoadd =  					musb_read_rxfifoadd(musb_base); -			musb_context.index_regs[i].txfifosz = +			musb->context.index_regs[i].txfifosz =  					musb_read_txfifosz(musb_base); -			musb_context.index_regs[i].rxfifosz = +			musb->context.index_regs[i].rxfifosz =  					musb_read_rxfifosz(musb_base);  		} -		if (is_host_enabled(musb)) { -			musb_context.index_regs[i].txtype = -				musb_readb(epio, MUSB_TXTYPE); -			musb_context.index_regs[i].txinterval = -				musb_readb(epio, MUSB_TXINTERVAL); -			musb_context.index_regs[i].rxtype = -				musb_readb(epio, MUSB_RXTYPE); -			musb_context.index_regs[i].rxinterval = -				musb_readb(epio, MUSB_RXINTERVAL); - -			musb_context.index_regs[i].txfunaddr = -				musb_read_txfunaddr(musb_base, i); -			musb_context.index_regs[i].txhubaddr = -				musb_read_txhubaddr(musb_base, i); -			musb_context.index_regs[i].txhubport = -				musb_read_txhubport(musb_base, i); - -			musb_context.index_regs[i].rxfunaddr = -				musb_read_rxfunaddr(musb_base, i); -			musb_context.index_regs[i].rxhubaddr = -				musb_read_rxhubaddr(musb_base, i); -			musb_context.index_regs[i].rxhubport = -				musb_read_rxhubport(musb_base, i); -		} -	} -	musb_platform_save_context(musb, &musb_context); +		musb->context.index_regs[i].txtype = +			musb_readb(epio, MUSB_TXTYPE); +		musb->context.index_regs[i].txinterval = +			musb_readb(epio, MUSB_TXINTERVAL); +		musb->context.index_regs[i].rxtype = +			musb_readb(epio, MUSB_RXTYPE); +		musb->context.index_regs[i].rxinterval = +			musb_readb(epio, MUSB_RXINTERVAL); + +		musb->context.index_regs[i].txfunaddr = +			musb_read_txfunaddr(musb_base, i); +		musb->context.index_regs[i].txhubaddr = +			musb_read_txhubaddr(musb_base, i); +		musb->context.index_regs[i].txhubport = +			musb_read_txhubport(musb_base, i); + +		musb->context.index_regs[i].rxfunaddr = +			musb_read_rxfunaddr(musb_base, i); +		musb->context.index_regs[i].rxhubaddr = +			musb_read_rxhubaddr(musb_base, i); +		musb->context.index_regs[i].rxhubport = +			musb_read_rxhubport(musb_base, i); +	}  } -void musb_restore_context(struct musb *musb) +static void musb_restore_context(struct musb *musb)  {  	int i;  	void __iomem *musb_base = musb->mregs;  	void __iomem *ep_target_regs;  	void __iomem *epio; +	u8 power; -	musb_platform_restore_context(musb, &musb_context); +	musb_writew(musb_base, MUSB_FRAME, musb->context.frame); +	musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode); +	musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl); -	if (is_host_enabled(musb)) { -		musb_writew(musb_base, MUSB_FRAME, musb_context.frame); -		musb_writeb(musb_base, MUSB_TESTMODE, musb_context.testmode); -		musb_write_ulpi_buscontrol(musb->mregs, musb_context.busctl); -	} -	musb_writeb(musb_base, MUSB_POWER, musb_context.power); -	musb_writew(musb_base, MUSB_INTRTXE, musb_context.intrtxe); -	musb_writew(musb_base, MUSB_INTRRXE, musb_context.intrrxe); -	musb_writeb(musb_base, MUSB_INTRUSBE, musb_context.intrusbe); -	musb_writeb(musb_base, MUSB_DEVCTL, musb_context.devctl); +	/* Don't affect SUSPENDM/RESUME bits in POWER reg */ +	power = musb_readb(musb_base, MUSB_POWER); +	power &= MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME; +	musb->context.power &= ~(MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME); +	power |= musb->context.power; +	musb_writeb(musb_base, MUSB_POWER, power); + +	musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe); +	musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe); +	musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe); +	musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl);  	for (i = 0; i < musb->config->num_eps; ++i) { -		epio = musb->endpoints[i].regs; +		struct musb_hw_ep	*hw_ep; + +		hw_ep = &musb->endpoints[i]; +		if (!hw_ep) +			continue; + +		epio = hw_ep->regs; +		if (!epio) +			continue; + +		musb_writeb(musb_base, MUSB_INDEX, i);  		musb_writew(epio, MUSB_TXMAXP, -			musb_context.index_regs[i].txmaxp); +			musb->context.index_regs[i].txmaxp);  		musb_writew(epio, MUSB_TXCSR, -			musb_context.index_regs[i].txcsr); +			musb->context.index_regs[i].txcsr);  		musb_writew(epio, MUSB_RXMAXP, -			musb_context.index_regs[i].rxmaxp); +			musb->context.index_regs[i].rxmaxp);  		musb_writew(epio, MUSB_RXCSR, -			musb_context.index_regs[i].rxcsr); +			musb->context.index_regs[i].rxcsr);  		if (musb->dyn_fifo) {  			musb_write_txfifosz(musb_base, -				musb_context.index_regs[i].txfifosz); +				musb->context.index_regs[i].txfifosz);  			musb_write_rxfifosz(musb_base, -				musb_context.index_regs[i].rxfifosz); +				musb->context.index_regs[i].rxfifosz);  			musb_write_txfifoadd(musb_base, -				musb_context.index_regs[i].txfifoadd); +				musb->context.index_regs[i].txfifoadd);  			musb_write_rxfifoadd(musb_base, -				musb_context.index_regs[i].rxfifoadd); +				musb->context.index_regs[i].rxfifoadd);  		} -		if (is_host_enabled(musb)) { -			musb_writeb(epio, MUSB_TXTYPE, -				musb_context.index_regs[i].txtype); -			musb_writeb(epio, MUSB_TXINTERVAL, -				musb_context.index_regs[i].txinterval); -			musb_writeb(epio, MUSB_RXTYPE, -				musb_context.index_regs[i].rxtype); -			musb_writeb(epio, MUSB_RXINTERVAL, - -			musb_context.index_regs[i].rxinterval); -			musb_write_txfunaddr(musb_base, i, -				musb_context.index_regs[i].txfunaddr); -			musb_write_txhubaddr(musb_base, i, -				musb_context.index_regs[i].txhubaddr); -			musb_write_txhubport(musb_base, i, -				musb_context.index_regs[i].txhubport); - -			ep_target_regs = -				musb_read_target_reg_base(i, musb_base); - -			musb_write_rxfunaddr(ep_target_regs, -				musb_context.index_regs[i].rxfunaddr); -			musb_write_rxhubaddr(ep_target_regs, -				musb_context.index_regs[i].rxhubaddr); -			musb_write_rxhubport(ep_target_regs, -				musb_context.index_regs[i].rxhubport); -		} +		musb_writeb(epio, MUSB_TXTYPE, +				musb->context.index_regs[i].txtype); +		musb_writeb(epio, MUSB_TXINTERVAL, +				musb->context.index_regs[i].txinterval); +		musb_writeb(epio, MUSB_RXTYPE, +				musb->context.index_regs[i].rxtype); +		musb_writeb(epio, MUSB_RXINTERVAL, + +				musb->context.index_regs[i].rxinterval); +		musb_write_txfunaddr(musb_base, i, +				musb->context.index_regs[i].txfunaddr); +		musb_write_txhubaddr(musb_base, i, +				musb->context.index_regs[i].txhubaddr); +		musb_write_txhubport(musb_base, i, +				musb->context.index_regs[i].txhubport); + +		ep_target_regs = +			musb_read_target_reg_base(i, musb_base); + +		musb_write_rxfunaddr(ep_target_regs, +				musb->context.index_regs[i].rxfunaddr); +		musb_write_rxhubaddr(ep_target_regs, +				musb->context.index_regs[i].rxhubaddr); +		musb_write_rxhubport(ep_target_regs, +				musb->context.index_regs[i].rxhubport);  	} +	musb_writeb(musb_base, MUSB_INDEX, musb->context.index);  }  static int musb_suspend(struct device *dev)  { -	struct platform_device *pdev = to_platform_device(dev); +	struct musb	*musb = dev_to_musb(dev);  	unsigned long	flags; -	struct musb	*musb = dev_to_musb(&pdev->dev);  	spin_lock_irqsave(&musb->lock, flags); @@ -2424,40 +2292,64 @@ static int musb_suspend(struct device *dev)  	musb_save_context(musb); -	if (musb->clock) { -		if (musb->set_clock) -			musb->set_clock(musb->clock, 0); -		else -			clk_disable(musb->clock); -	}  	spin_unlock_irqrestore(&musb->lock, flags);  	return 0;  }  static int musb_resume_noirq(struct device *dev)  { -	struct platform_device *pdev = to_platform_device(dev); -	struct musb	*musb = dev_to_musb(&pdev->dev); +	struct musb	*musb = dev_to_musb(dev); -	if (musb->clock) { -		if (musb->set_clock) -			musb->set_clock(musb->clock, 1); -		else -			clk_enable(musb->clock); -	} +	/* +	 * For static cmos like DaVinci, register values were preserved +	 * unless for some reason the whole soc powered down or the USB +	 * module got reset through the PSC (vs just being disabled). +	 * +	 * For the DSPS glue layer though, a full register restore has to +	 * be done. As it shouldn't harm other platforms, we do it +	 * unconditionally. +	 */  	musb_restore_context(musb); -	/* for static cmos like DaVinci, register values were preserved -	 * unless for some reason the whole soc powered down or the USB -	 * module got reset through the PSC (vs just being disabled). +	return 0; +} + +static int musb_runtime_suspend(struct device *dev) +{ +	struct musb	*musb = dev_to_musb(dev); + +	musb_save_context(musb); + +	return 0; +} + +static int musb_runtime_resume(struct device *dev) +{ +	struct musb	*musb = dev_to_musb(dev); +	static int	first = 1; + +	/* +	 * When pm_runtime_get_sync called for the first time in driver +	 * init,  some of the structure is still not initialized which is +	 * used in restore function. But clock needs to be +	 * enabled before any register access, so +	 * pm_runtime_get_sync has to be called. +	 * Also context restore without save does not make +	 * any sense  	 */ +	if (!first) +		musb_restore_context(musb); +	first = 0; +  	return 0;  }  static const struct dev_pm_ops musb_dev_pm_ops = {  	.suspend	= musb_suspend,  	.resume_noirq	= musb_resume_noirq, +	.runtime_suspend = musb_runtime_suspend, +	.runtime_resume = musb_runtime_resume,  };  #define MUSB_DEV_PM_OPS (&musb_dev_pm_ops) @@ -2472,51 +2364,9 @@ static struct platform_driver musb_driver = {  		.owner		= THIS_MODULE,  		.pm		= MUSB_DEV_PM_OPS,  	}, -	.remove		= __exit_p(musb_remove), +	.probe		= musb_probe, +	.remove		= musb_remove,  	.shutdown	= musb_shutdown,  }; -/*-------------------------------------------------------------------------*/ - -static int __init musb_init(void) -{ -#ifdef CONFIG_USB_MUSB_HDRC_HCD -	if (usb_disabled()) -		return 0; -#endif - -	pr_info("%s: version " MUSB_VERSION ", " -#ifdef CONFIG_MUSB_PIO_ONLY -		"pio" -#elif defined(CONFIG_USB_TI_CPPI_DMA) -		"cppi-dma" -#elif defined(CONFIG_USB_INVENTRA_DMA) -		"musb-dma" -#elif defined(CONFIG_USB_TUSB_OMAP_DMA) -		"tusb-omap-dma" -#else -		"?dma?" -#endif -		", " -#ifdef CONFIG_USB_MUSB_OTG -		"otg (peripheral+host)" -#elif defined(CONFIG_USB_GADGET_MUSB_HDRC) -		"peripheral" -#elif defined(CONFIG_USB_MUSB_HDRC_HCD) -		"host" -#endif -		", debug=%d\n", -		musb_driver_name, musb_debug); -	return platform_driver_probe(&musb_driver, musb_probe); -} - -/* make us init after usbcore and i2c (transceivers, regulators, etc) - * and before usb gadget and host-side drivers start to register - */ -fs_initcall(musb_init); - -static void __exit musb_cleanup(void) -{ -	platform_driver_unregister(&musb_driver); -} -module_exit(musb_cleanup); +module_platform_driver(musb_driver); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index febaabcc2b3..d155a156f24 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -40,13 +40,14 @@  #include <linux/interrupt.h>  #include <linux/errno.h>  #include <linux/timer.h> -#include <linux/clk.h>  #include <linux/device.h>  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h>  #include <linux/usb.h>  #include <linux/usb/otg.h>  #include <linux/usb/musb.h> +#include <linux/phy/phy.h> +#include <linux/workqueue.h>  struct musb;  struct musb_hw_ep; @@ -72,99 +73,17 @@ struct musb_ep;  #include <linux/usb/hcd.h>  #include "musb_host.h" - - -#ifdef CONFIG_USB_MUSB_OTG - -#define	is_peripheral_enabled(musb)	((musb)->board_mode != MUSB_HOST) -#define	is_host_enabled(musb)		((musb)->board_mode != MUSB_PERIPHERAL) -#define	is_otg_enabled(musb)		((musb)->board_mode == MUSB_OTG) -  /* NOTE:  otg and peripheral-only state machines start at B_IDLE.   * OTG or host-only go to A_IDLE when ID is sensed.   */  #define is_peripheral_active(m)		(!(m)->is_host)  #define is_host_active(m)		((m)->is_host) -#else -#define	is_peripheral_enabled(musb)	is_peripheral_capable() -#define	is_host_enabled(musb)		is_host_capable() -#define	is_otg_enabled(musb)		0 - -#define	is_peripheral_active(musb)	is_peripheral_capable() -#define	is_host_active(musb)		is_host_capable() -#endif - -#if defined(CONFIG_USB_MUSB_OTG) || defined(CONFIG_USB_MUSB_PERIPHERAL) -/* for some reason, the "select USB_GADGET_MUSB_HDRC" doesn't always - * override that choice selection (often USB_GADGET_DUMMY_HCD). - */ -#ifndef CONFIG_USB_GADGET_MUSB_HDRC -#error bogus Kconfig output ... select CONFIG_USB_GADGET_MUSB_HDRC -#endif -#endif	/* need MUSB gadget selection */ - -#ifndef CONFIG_HAVE_CLK -/* Dummy stub for clk framework */ -#define clk_get(dev, id)	NULL -#define clk_put(clock)		do {} while (0) -#define clk_enable(clock)	do {} while (0) -#define clk_disable(clock)	do {} while (0) -#endif - -#ifdef CONFIG_PROC_FS -#include <linux/fs.h> -#define MUSB_CONFIG_PROC_FS -#endif - -/****************************** PERIPHERAL ROLE *****************************/ - -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - -#define	is_peripheral_capable()	(1) - -extern irqreturn_t musb_g_ep0_irq(struct musb *); -extern void musb_g_tx(struct musb *, u8); -extern void musb_g_rx(struct musb *, u8); -extern void musb_g_reset(struct musb *); -extern void musb_g_suspend(struct musb *); -extern void musb_g_resume(struct musb *); -extern void musb_g_wakeup(struct musb *); -extern void musb_g_disconnect(struct musb *); - -#else - -#define	is_peripheral_capable()	(0) - -static inline irqreturn_t musb_g_ep0_irq(struct musb *m) { return IRQ_NONE; } -static inline void musb_g_reset(struct musb *m) {} -static inline void musb_g_suspend(struct musb *m) {} -static inline void musb_g_resume(struct musb *m) {} -static inline void musb_g_wakeup(struct musb *m) {} -static inline void musb_g_disconnect(struct musb *m) {} - -#endif - -/****************************** HOST ROLE ***********************************/ - -#ifdef CONFIG_USB_MUSB_HDRC_HCD - -#define	is_host_capable()	(1) - -extern irqreturn_t musb_h_ep0_irq(struct musb *); -extern void musb_host_tx(struct musb *, u8); -extern void musb_host_rx(struct musb *, u8); - -#else - -#define	is_host_capable()	(0) - -static inline irqreturn_t musb_h_ep0_irq(struct musb *m) { return IRQ_NONE; } -static inline void musb_host_tx(struct musb *m, u8 e) {} -static inline void musb_host_rx(struct musb *m, u8 e) {} - -#endif - +enum { +	MUSB_PORT_MODE_HOST	= 1, +	MUSB_PORT_MODE_GADGET, +	MUSB_PORT_MODE_DUAL_ROLE, +};  /****************************** CONSTANTS ********************************/ @@ -212,8 +131,8 @@ enum musb_g_ep0_state {   * directly with the "flat" model, or after setting up an index register.   */ -#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_ARCH_OMAP2430) \ -		|| defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_BLACKFIN) \ +#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_SOC_OMAP2430) \ +		|| defined(CONFIG_SOC_OMAP3430) || defined(CONFIG_BLACKFIN) \  		|| defined(CONFIG_ARCH_OMAP4)  /* REVISIT indexed access seemed to   * misbehave (on DaVinci) for at least peripheral IN ... @@ -222,7 +141,8 @@ enum musb_g_ep0_state {  #endif  /* TUSB mapping: "flat" plus ep0 special cases */ -#if	defined(CONFIG_USB_TUSB6010) +#if defined(CONFIG_USB_MUSB_TUSB6010) || \ +	defined(CONFIG_USB_MUSB_TUSB6010_MODULE)  #define musb_ep_select(_mbase, _epnum) \  	musb_writeb((_mbase), MUSB_INDEX, (_epnum))  #define	MUSB_EP_OFFSET			MUSB_TUSB_OFFSET @@ -253,6 +173,35 @@ enum musb_g_ep0_state {  /******************************** TYPES *************************************/ +/** + * struct musb_platform_ops - Operations passed to musb_core by HW glue layer + * @init:	turns on clocks, sets up platform-specific registers, etc + * @exit:	undoes @init + * @set_mode:	forcefully changes operating mode + * @try_ilde:	tries to idle the IP + * @vbus_status: returns vbus status if possible + * @set_vbus:	forces vbus status + * @adjust_channel_params: pre check for standard dma channel_program func + */ +struct musb_platform_ops { +	int	(*init)(struct musb *musb); +	int	(*exit)(struct musb *musb); + +	void	(*enable)(struct musb *musb); +	void	(*disable)(struct musb *musb); + +	int	(*set_mode)(struct musb *musb, u8 mode); +	void	(*try_idle)(struct musb *musb, unsigned long timeout); +	void	(*reset)(struct musb *musb); + +	int	(*vbus_status)(struct musb *musb); +	void	(*set_vbus)(struct musb *musb, int on); + +	int	(*adjust_channel_params)(struct dma_channel *channel, +				u16 packet_sz, u8 *mode, +				dma_addr_t *dma_addr, u32 *len); +}; +  /*   * struct musb_hw_ep - endpoint hardware (bidirectional)   * @@ -263,7 +212,8 @@ struct musb_hw_ep {  	void __iomem		*fifo;  	void __iomem		*regs; -#ifdef CONFIG_USB_TUSB6010 +#if defined(CONFIG_USB_MUSB_TUSB6010) || \ +	defined(CONFIG_USB_MUSB_TUSB6010_MODULE)  	void __iomem		*conf;  #endif @@ -280,14 +230,14 @@ struct musb_hw_ep {  	struct dma_channel	*tx_channel;  	struct dma_channel	*rx_channel; -#ifdef CONFIG_USB_TUSB6010 +#if defined(CONFIG_USB_MUSB_TUSB6010) || \ +	defined(CONFIG_USB_MUSB_TUSB6010_MODULE)  	/* TUSB has "asynchronous" and "synchronous" dma modes */  	dma_addr_t		fifo_async;  	dma_addr_t		fifo_sync;  	void __iomem		*fifo_sync_va;  #endif -#ifdef CONFIG_USB_MUSB_HDRC_HCD  	void __iomem		*target_regs;  	/* currently scheduled peripheral endpoint */ @@ -296,51 +246,69 @@ struct musb_hw_ep {  	u8			rx_reinit;  	u8			tx_reinit; -#endif -#ifdef CONFIG_USB_GADGET_MUSB_HDRC  	/* peripheral side */  	struct musb_ep		ep_in;			/* TX */  	struct musb_ep		ep_out;			/* RX */ -#endif  }; -static inline struct usb_request *next_in_request(struct musb_hw_ep *hw_ep) +static inline struct musb_request *next_in_request(struct musb_hw_ep *hw_ep)  { -#ifdef CONFIG_USB_GADGET_MUSB_HDRC  	return next_request(&hw_ep->ep_in); -#else -	return NULL; -#endif  } -static inline struct usb_request *next_out_request(struct musb_hw_ep *hw_ep) +static inline struct musb_request *next_out_request(struct musb_hw_ep *hw_ep)  { -#ifdef CONFIG_USB_GADGET_MUSB_HDRC  	return next_request(&hw_ep->ep_out); -#else -	return NULL; -#endif  } +struct musb_csr_regs { +	/* FIFO registers */ +	u16 txmaxp, txcsr, rxmaxp, rxcsr; +	u16 rxfifoadd, txfifoadd; +	u8 txtype, txinterval, rxtype, rxinterval; +	u8 rxfifosz, txfifosz; +	u8 txfunaddr, txhubaddr, txhubport; +	u8 rxfunaddr, rxhubaddr, rxhubport; +}; + +struct musb_context_registers { + +	u8 power; +	u8 intrusbe; +	u16 frame; +	u8 index, testmode; + +	u8 devctl, busctl, misc; +	u32 otg_interfsel; + +	struct musb_csr_regs index_regs[MUSB_C_NUM_EPS]; +}; +  /*   * struct musb - Driver instance data.   */  struct musb {  	/* device lock */  	spinlock_t		lock; -	struct clk		*clock; -	struct clk		*phy_clock; + +	const struct musb_platform_ops *ops; +	struct musb_context_registers context; +  	irqreturn_t		(*isr)(int, void *);  	struct work_struct	irq_work; +	struct work_struct	recover_work; +	struct delayed_work	deassert_reset_work; +	struct delayed_work	finish_resume_work;  	u16			hwvers; +	u16			intrrxe; +	u16			intrtxe;  /* this hub status bit is reserved by USB 2.0 and not seen by usbcore */  #define MUSB_PORT_STAT_RESUME	(1 << 31)  	u32			port1_status; -#ifdef CONFIG_USB_MUSB_HDRC_HCD  	unsigned long		rh_timer;  	enum musb_h_ep0_state	ep0_stage; @@ -358,12 +326,7 @@ struct musb {  	struct list_head	out_bulk;	/* of musb_qh */  	struct timer_list	otg_timer; -#endif - -	/* called with IRQs blocked; ON/nonzero implies starting a session, -	 * and waiting at least a_wait_vrise_tmout. -	 */ -	void			(*board_set_vbus)(struct musb *, int is_on); +	struct notifier_block	nb;  	struct dma_controller	*dma_controller; @@ -371,10 +334,12 @@ struct musb {  	void __iomem		*ctrl_base;  	void __iomem		*mregs; -#ifdef CONFIG_USB_TUSB6010 +#if defined(CONFIG_USB_MUSB_TUSB6010) || \ +	defined(CONFIG_USB_MUSB_TUSB6010_MODULE)  	dma_addr_t		async;  	dma_addr_t		sync;  	void __iomem		*sync_va; +	u8			tusb_revision;  #endif  	/* passed down from chip/board specific irq handlers */ @@ -382,7 +347,8 @@ struct musb {  	u16			int_rx;  	u16			int_tx; -	struct otg_transceiver	*xceiv; +	struct usb_phy		*xceiv; +	struct phy		*phy;  	int nIrq;  	unsigned		irq_wake:1; @@ -395,13 +361,11 @@ struct musb {  	u16 epmask;  	u8 nr_endpoints; -	u8 board_mode;		/* enum musb_mode */  	int			(*board_set_power)(int state); -	int			(*set_clock)(struct clk *clk, int is_active); -  	u8			min_power;	/* vbus for periph, in mA/2 */ +	int			port_mode;	/* MUSB_PORT_MODE_* */  	bool			is_host;  	int			a_wait_bcon;	/* VBUS timeout in msecs */ @@ -411,7 +375,6 @@ struct musb {  	unsigned		is_active:1;  	unsigned is_multipoint:1; -	unsigned ignore_disconnect:1;	/* during bus resets */  	unsigned		hb_iso_rx:1;	/* high bandwidth iso rx? */  	unsigned		hb_iso_tx:1;	/* high bandwidth iso tx? */ @@ -425,7 +388,6 @@ struct musb {  #define	can_bulk_combine(musb,type) \  	(((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_combine) -#ifdef CONFIG_USB_GADGET_MUSB_HDRC  	/* is_suspended means USB B_PERIPHERAL suspend */  	unsigned		is_suspended:1; @@ -449,67 +411,33 @@ struct musb {  	enum musb_g_ep0_state	ep0_state;  	struct usb_gadget	g;			/* the gadget */  	struct usb_gadget_driver *gadget_driver;	/* its driver */ -#endif +	struct usb_hcd		*hcd;			/* the usb hcd */ + +	/* +	 * FIXME: Remove this flag. +	 * +	 * This is only added to allow Blackfin to work +	 * with current driver. For some unknown reason +	 * Blackfin doesn't work with double buffering +	 * and that's enabled by default. +	 * +	 * We added this flag to forcefully disable double +	 * buffering until we get it working. +	 */ +	unsigned                double_buffer_not_ok:1;  	struct musb_hdrc_config	*config; -#ifdef MUSB_CONFIG_PROC_FS -	struct proc_dir_entry *proc_entry; +	int			xceiv_old_state; +#ifdef CONFIG_DEBUG_FS +	struct dentry		*debugfs_root;  #endif  }; -#ifdef CONFIG_PM -struct musb_csr_regs { -	/* FIFO registers */ -	u16 txmaxp, txcsr, rxmaxp, rxcsr; -	u16 rxfifoadd, txfifoadd; -	u8 txtype, txinterval, rxtype, rxinterval; -	u8 rxfifosz, txfifosz; -	u8 txfunaddr, txhubaddr, txhubport; -	u8 rxfunaddr, rxhubaddr, rxhubport; -}; - -struct musb_context_registers { - -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \ -    defined(CONFIG_ARCH_OMAP4) -	u32 otg_sysconfig, otg_forcestandby; -#endif -	u8 power; -	u16 intrtxe, intrrxe; -	u8 intrusbe; -	u16 frame; -	u8 index, testmode; - -	u8 devctl, busctl, misc; - -	struct musb_csr_regs index_regs[MUSB_C_NUM_EPS]; -}; - -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \ -    defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_BLACKFIN) -extern void musb_platform_save_context(struct musb *musb, -		struct musb_context_registers *musb_context); -extern void musb_platform_restore_context(struct musb *musb, -		struct musb_context_registers *musb_context); -#else -#define musb_platform_save_context(m, x)	do {} while (0) -#define musb_platform_restore_context(m, x)	do {} while (0) -#endif - -#endif - -static inline void musb_set_vbus(struct musb *musb, int is_on) -{ -	musb->board_set_vbus(musb, is_on); -} - -#ifdef CONFIG_USB_GADGET_MUSB_HDRC  static inline struct musb *gadget_to_musb(struct usb_gadget *g)  {  	return container_of(g, struct musb, g);  } -#endif  #ifdef CONFIG_BLACKFIN  static inline int musb_read_fifosize(struct musb *musb, @@ -542,7 +470,7 @@ static inline void musb_configure_ep0(struct musb *musb)  static inline int musb_read_fifosize(struct musb *musb,  		struct musb_hw_ep *hw_ep, u8 epnum)  { -	void *mbase = musb->mregs; +	void __iomem *mbase = musb->mregs;  	u8 reg = 0;  	/* read from core using indexed model */ @@ -582,8 +510,8 @@ static inline void musb_configure_ep0(struct musb *musb)  extern const char musb_driver_name[]; -extern void musb_start(struct musb *musb);  extern void musb_stop(struct musb *musb); +extern void musb_start(struct musb *musb);  extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src);  extern void musb_read_fifo(struct musb_hw_ep *ep, u16 len, u8 *dst); @@ -592,29 +520,69 @@ extern void musb_load_testpacket(struct musb *);  extern irqreturn_t musb_interrupt(struct musb *); -extern void musb_platform_enable(struct musb *musb); -extern void musb_platform_disable(struct musb *musb); -  extern void musb_hnp_stop(struct musb *musb); -extern int musb_platform_set_mode(struct musb *musb, u8 musb_mode); +static inline void musb_platform_set_vbus(struct musb *musb, int is_on) +{ +	if (musb->ops->set_vbus) +		musb->ops->set_vbus(musb, is_on); +} -#if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN) || \ -	defined(CONFIG_ARCH_DAVINCI_DA8XX) || \ -	defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \ -	defined(CONFIG_ARCH_OMAP4) -extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout); -#else -#define musb_platform_try_idle(x, y)		do {} while (0) -#endif +static inline void musb_platform_enable(struct musb *musb) +{ +	if (musb->ops->enable) +		musb->ops->enable(musb); +} -#if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN) -extern int musb_platform_get_vbus_status(struct musb *musb); -#else -#define musb_platform_get_vbus_status(x)	0 -#endif +static inline void musb_platform_disable(struct musb *musb) +{ +	if (musb->ops->disable) +		musb->ops->disable(musb); +} + +static inline int musb_platform_set_mode(struct musb *musb, u8 mode) +{ +	if (!musb->ops->set_mode) +		return 0; + +	return musb->ops->set_mode(musb, mode); +} -extern int __init musb_platform_init(struct musb *musb, void *board_data); -extern int musb_platform_exit(struct musb *musb); +static inline void musb_platform_try_idle(struct musb *musb, +		unsigned long timeout) +{ +	if (musb->ops->try_idle) +		musb->ops->try_idle(musb, timeout); +} + +static inline void musb_platform_reset(struct musb *musb) +{ +	if (musb->ops->reset) +		musb->ops->reset(musb); +} + +static inline int musb_platform_get_vbus_status(struct musb *musb) +{ +	if (!musb->ops->vbus_status) +		return 0; + +	return musb->ops->vbus_status(musb); +} + +static inline int musb_platform_init(struct musb *musb) +{ +	if (!musb->ops->init) +		return -EINVAL; + +	return musb->ops->init(musb); +} + +static inline int musb_platform_exit(struct musb *musb) +{ +	if (!musb->ops->exit) +		return -EINVAL; + +	return musb->ops->exit(musb); +}  #endif	/* __MUSB_CORE_H__ */ diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c new file mode 100644 index 00000000000..5341bb223b7 --- /dev/null +++ b/drivers/usb/musb/musb_cppi41.c @@ -0,0 +1,744 @@ +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> +#include <linux/sizes.h> +#include <linux/platform_device.h> +#include <linux/of.h> + +#include "musb_core.h" + +#define RNDIS_REG(x) (0x80 + ((x - 1) * 4)) + +#define EP_MODE_AUTOREG_NONE		0 +#define EP_MODE_AUTOREG_ALL_NEOP	1 +#define EP_MODE_AUTOREG_ALWAYS		3 + +#define EP_MODE_DMA_TRANSPARENT		0 +#define EP_MODE_DMA_RNDIS		1 +#define EP_MODE_DMA_GEN_RNDIS		3 + +#define USB_CTRL_TX_MODE	0x70 +#define USB_CTRL_RX_MODE	0x74 +#define USB_CTRL_AUTOREQ	0xd0 +#define USB_TDOWN		0xd8 + +struct cppi41_dma_channel { +	struct dma_channel channel; +	struct cppi41_dma_controller *controller; +	struct musb_hw_ep *hw_ep; +	struct dma_chan *dc; +	dma_cookie_t cookie; +	u8 port_num; +	u8 is_tx; +	u8 is_allocated; +	u8 usb_toggle; + +	dma_addr_t buf_addr; +	u32 total_len; +	u32 prog_len; +	u32 transferred; +	u32 packet_sz; +	struct list_head tx_check; +	struct work_struct dma_completion; +}; + +#define MUSB_DMA_NUM_CHANNELS 15 + +struct cppi41_dma_controller { +	struct dma_controller controller; +	struct cppi41_dma_channel rx_channel[MUSB_DMA_NUM_CHANNELS]; +	struct cppi41_dma_channel tx_channel[MUSB_DMA_NUM_CHANNELS]; +	struct musb *musb; +	struct hrtimer early_tx; +	struct list_head early_tx_list; +	u32 rx_mode; +	u32 tx_mode; +	u32 auto_req; +}; + +static void save_rx_toggle(struct cppi41_dma_channel *cppi41_channel) +{ +	u16 csr; +	u8 toggle; + +	if (cppi41_channel->is_tx) +		return; +	if (!is_host_active(cppi41_channel->controller->musb)) +		return; + +	csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR); +	toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0; + +	cppi41_channel->usb_toggle = toggle; +} + +static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel) +{ +	u16 csr; +	u8 toggle; + +	if (cppi41_channel->is_tx) +		return; +	if (!is_host_active(cppi41_channel->controller->musb)) +		return; + +	csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR); +	toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0; + +	/* +	 * AM335x Advisory 1.0.13: Due to internal synchronisation error the +	 * data toggle may reset from DATA1 to DATA0 during receiving data from +	 * more than one endpoint. +	 */ +	if (!toggle && toggle == cppi41_channel->usb_toggle) { +		csr |= MUSB_RXCSR_H_DATATOGGLE | MUSB_RXCSR_H_WR_DATATOGGLE; +		musb_writew(cppi41_channel->hw_ep->regs, MUSB_RXCSR, csr); +		dev_dbg(cppi41_channel->controller->musb->controller, +				"Restoring DATA1 toggle.\n"); +	} + +	cppi41_channel->usb_toggle = toggle; +} + +static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep) +{ +	u8		epnum = hw_ep->epnum; +	struct musb	*musb = hw_ep->musb; +	void __iomem	*epio = musb->endpoints[epnum].regs; +	u16		csr; + +	csr = musb_readw(epio, MUSB_TXCSR); +	if (csr & MUSB_TXCSR_TXPKTRDY) +		return false; +	return true; +} + +static bool is_isoc(struct musb_hw_ep *hw_ep, bool in) +{ +	if (in && hw_ep->in_qh) { +		if (hw_ep->in_qh->type == USB_ENDPOINT_XFER_ISOC) +			return true; +	} else if (hw_ep->out_qh) { +		if (hw_ep->out_qh->type == USB_ENDPOINT_XFER_ISOC) +			return true; +	} +	return false; +} + +static void cppi41_dma_callback(void *private_data); + +static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) +{ +	struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; +	struct musb *musb = hw_ep->musb; + +	if (!cppi41_channel->prog_len || +	    (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)) { + +		/* done, complete */ +		cppi41_channel->channel.actual_len = +			cppi41_channel->transferred; +		cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE; +		musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx); +	} else { +		/* next iteration, reload */ +		struct dma_chan *dc = cppi41_channel->dc; +		struct dma_async_tx_descriptor *dma_desc; +		enum dma_transfer_direction direction; +		u16 csr; +		u32 remain_bytes; +		void __iomem *epio = cppi41_channel->hw_ep->regs; + +		cppi41_channel->buf_addr += cppi41_channel->packet_sz; + +		remain_bytes = cppi41_channel->total_len; +		remain_bytes -= cppi41_channel->transferred; +		remain_bytes = min(remain_bytes, cppi41_channel->packet_sz); +		cppi41_channel->prog_len = remain_bytes; + +		direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV +			: DMA_DEV_TO_MEM; +		dma_desc = dmaengine_prep_slave_single(dc, +				cppi41_channel->buf_addr, +				remain_bytes, +				direction, +				DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +		if (WARN_ON(!dma_desc)) +			return; + +		dma_desc->callback = cppi41_dma_callback; +		dma_desc->callback_param = &cppi41_channel->channel; +		cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); +		dma_async_issue_pending(dc); + +		if (!cppi41_channel->is_tx) { +			csr = musb_readw(epio, MUSB_RXCSR); +			csr |= MUSB_RXCSR_H_REQPKT; +			musb_writew(epio, MUSB_RXCSR, csr); +		} +	} +} + +static void cppi_trans_done_work(struct work_struct *work) +{ +	unsigned long flags; +	struct cppi41_dma_channel *cppi41_channel = +		container_of(work, struct cppi41_dma_channel, dma_completion); +	struct cppi41_dma_controller *controller = cppi41_channel->controller; +	struct musb *musb = controller->musb; +	struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; +	bool empty; + +	if (!cppi41_channel->is_tx && is_isoc(hw_ep, 1)) { +		spin_lock_irqsave(&musb->lock, flags); +		cppi41_trans_done(cppi41_channel); +		spin_unlock_irqrestore(&musb->lock, flags); +	} else { +		empty = musb_is_tx_fifo_empty(hw_ep); +		if (empty) { +			spin_lock_irqsave(&musb->lock, flags); +			cppi41_trans_done(cppi41_channel); +			spin_unlock_irqrestore(&musb->lock, flags); +		} else { +			schedule_work(&cppi41_channel->dma_completion); +		} +	} +} + +static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer) +{ +	struct cppi41_dma_controller *controller; +	struct cppi41_dma_channel *cppi41_channel, *n; +	struct musb *musb; +	unsigned long flags; +	enum hrtimer_restart ret = HRTIMER_NORESTART; + +	controller = container_of(timer, struct cppi41_dma_controller, +			early_tx); +	musb = controller->musb; + +	spin_lock_irqsave(&musb->lock, flags); +	list_for_each_entry_safe(cppi41_channel, n, &controller->early_tx_list, +			tx_check) { +		bool empty; +		struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; + +		empty = musb_is_tx_fifo_empty(hw_ep); +		if (empty) { +			list_del_init(&cppi41_channel->tx_check); +			cppi41_trans_done(cppi41_channel); +		} +	} + +	if (!list_empty(&controller->early_tx_list)) { +		ret = HRTIMER_RESTART; +		hrtimer_forward_now(&controller->early_tx, +				ktime_set(0, 150 * NSEC_PER_USEC)); +	} + +	spin_unlock_irqrestore(&musb->lock, flags); +	return ret; +} + +static void cppi41_dma_callback(void *private_data) +{ +	struct dma_channel *channel = private_data; +	struct cppi41_dma_channel *cppi41_channel = channel->private_data; +	struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; +	struct musb *musb = hw_ep->musb; +	unsigned long flags; +	struct dma_tx_state txstate; +	u32 transferred; +	bool empty; + +	spin_lock_irqsave(&musb->lock, flags); + +	dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie, +			&txstate); +	transferred = cppi41_channel->prog_len - txstate.residue; +	cppi41_channel->transferred += transferred; + +	dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n", +		hw_ep->epnum, cppi41_channel->transferred, +		cppi41_channel->total_len); + +	update_rx_toggle(cppi41_channel); + +	if (cppi41_channel->transferred == cppi41_channel->total_len || +			transferred < cppi41_channel->packet_sz) +		cppi41_channel->prog_len = 0; + +	if (!cppi41_channel->is_tx) { +		if (is_isoc(hw_ep, 1)) +			schedule_work(&cppi41_channel->dma_completion); +		else +			cppi41_trans_done(cppi41_channel); +		goto out; +	} + +	empty = musb_is_tx_fifo_empty(hw_ep); +	if (empty) { +		cppi41_trans_done(cppi41_channel); +	} else { +		struct cppi41_dma_controller *controller; +		/* +		 * On AM335x it has been observed that the TX interrupt fires +		 * too early that means the TXFIFO is not yet empty but the DMA +		 * engine says that it is done with the transfer. We don't +		 * receive a FIFO empty interrupt so the only thing we can do is +		 * to poll for the bit. On HS it usually takes 2us, on FS around +		 * 110us - 150us depending on the transfer size. +		 * We spin on HS (no longer than than 25us and setup a timer on +		 * FS to check for the bit and complete the transfer. +		 */ +		controller = cppi41_channel->controller; + +		if (musb->g.speed == USB_SPEED_HIGH) { +			unsigned wait = 25; + +			do { +				empty = musb_is_tx_fifo_empty(hw_ep); +				if (empty) +					break; +				wait--; +				if (!wait) +					break; +				udelay(1); +			} while (1); + +			empty = musb_is_tx_fifo_empty(hw_ep); +			if (empty) { +				cppi41_trans_done(cppi41_channel); +				goto out; +			} +		} +		if (is_isoc(hw_ep, 0)) { +			schedule_work(&cppi41_channel->dma_completion); +			goto out; +		} +		list_add_tail(&cppi41_channel->tx_check, +				&controller->early_tx_list); +		if (!hrtimer_is_queued(&controller->early_tx)) { +			hrtimer_start_range_ns(&controller->early_tx, +				ktime_set(0, 140 * NSEC_PER_USEC), +				40 * NSEC_PER_USEC, +				HRTIMER_MODE_REL); +		} +	} +out: +	spin_unlock_irqrestore(&musb->lock, flags); +} + +static u32 update_ep_mode(unsigned ep, unsigned mode, u32 old) +{ +	unsigned shift; + +	shift = (ep - 1) * 2; +	old &= ~(3 << shift); +	old |= mode << shift; +	return old; +} + +static void cppi41_set_dma_mode(struct cppi41_dma_channel *cppi41_channel, +		unsigned mode) +{ +	struct cppi41_dma_controller *controller = cppi41_channel->controller; +	u32 port; +	u32 new_mode; +	u32 old_mode; + +	if (cppi41_channel->is_tx) +		old_mode = controller->tx_mode; +	else +		old_mode = controller->rx_mode; +	port = cppi41_channel->port_num; +	new_mode = update_ep_mode(port, mode, old_mode); + +	if (new_mode == old_mode) +		return; +	if (cppi41_channel->is_tx) { +		controller->tx_mode = new_mode; +		musb_writel(controller->musb->ctrl_base, USB_CTRL_TX_MODE, +				new_mode); +	} else { +		controller->rx_mode = new_mode; +		musb_writel(controller->musb->ctrl_base, USB_CTRL_RX_MODE, +				new_mode); +	} +} + +static void cppi41_set_autoreq_mode(struct cppi41_dma_channel *cppi41_channel, +		unsigned mode) +{ +	struct cppi41_dma_controller *controller = cppi41_channel->controller; +	u32 port; +	u32 new_mode; +	u32 old_mode; + +	old_mode = controller->auto_req; +	port = cppi41_channel->port_num; +	new_mode = update_ep_mode(port, mode, old_mode); + +	if (new_mode == old_mode) +		return; +	controller->auto_req = new_mode; +	musb_writel(controller->musb->ctrl_base, USB_CTRL_AUTOREQ, new_mode); +} + +static bool cppi41_configure_channel(struct dma_channel *channel, +				u16 packet_sz, u8 mode, +				dma_addr_t dma_addr, u32 len) +{ +	struct cppi41_dma_channel *cppi41_channel = channel->private_data; +	struct dma_chan *dc = cppi41_channel->dc; +	struct dma_async_tx_descriptor *dma_desc; +	enum dma_transfer_direction direction; +	struct musb *musb = cppi41_channel->controller->musb; +	unsigned use_gen_rndis = 0; + +	dev_dbg(musb->controller, +		"configure ep%d/%x packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n", +		cppi41_channel->port_num, RNDIS_REG(cppi41_channel->port_num), +		packet_sz, mode, (unsigned long long) dma_addr, +		len, cppi41_channel->is_tx); + +	cppi41_channel->buf_addr = dma_addr; +	cppi41_channel->total_len = len; +	cppi41_channel->transferred = 0; +	cppi41_channel->packet_sz = packet_sz; + +	/* +	 * Due to AM335x' Advisory 1.0.13 we are not allowed to transfer more +	 * than max packet size at a time. +	 */ +	if (cppi41_channel->is_tx) +		use_gen_rndis = 1; + +	if (use_gen_rndis) { +		/* RNDIS mode */ +		if (len > packet_sz) { +			musb_writel(musb->ctrl_base, +				RNDIS_REG(cppi41_channel->port_num), len); +			/* gen rndis */ +			cppi41_set_dma_mode(cppi41_channel, +					EP_MODE_DMA_GEN_RNDIS); + +			/* auto req */ +			cppi41_set_autoreq_mode(cppi41_channel, +					EP_MODE_AUTOREG_ALL_NEOP); +		} else { +			musb_writel(musb->ctrl_base, +					RNDIS_REG(cppi41_channel->port_num), 0); +			cppi41_set_dma_mode(cppi41_channel, +					EP_MODE_DMA_TRANSPARENT); +			cppi41_set_autoreq_mode(cppi41_channel, +					EP_MODE_AUTOREG_NONE); +		} +	} else { +		/* fallback mode */ +		cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT); +		cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE); +		len = min_t(u32, packet_sz, len); +	} +	cppi41_channel->prog_len = len; +	direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; +	dma_desc = dmaengine_prep_slave_single(dc, dma_addr, len, direction, +			DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +	if (!dma_desc) +		return false; + +	dma_desc->callback = cppi41_dma_callback; +	dma_desc->callback_param = channel; +	cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); + +	save_rx_toggle(cppi41_channel); +	dma_async_issue_pending(dc); +	return true; +} + +static struct dma_channel *cppi41_dma_channel_allocate(struct dma_controller *c, +				struct musb_hw_ep *hw_ep, u8 is_tx) +{ +	struct cppi41_dma_controller *controller = container_of(c, +			struct cppi41_dma_controller, controller); +	struct cppi41_dma_channel *cppi41_channel = NULL; +	u8 ch_num = hw_ep->epnum - 1; + +	if (ch_num >= MUSB_DMA_NUM_CHANNELS) +		return NULL; + +	if (is_tx) +		cppi41_channel = &controller->tx_channel[ch_num]; +	else +		cppi41_channel = &controller->rx_channel[ch_num]; + +	if (!cppi41_channel->dc) +		return NULL; + +	if (cppi41_channel->is_allocated) +		return NULL; + +	cppi41_channel->hw_ep = hw_ep; +	cppi41_channel->is_allocated = 1; + +	return &cppi41_channel->channel; +} + +static void cppi41_dma_channel_release(struct dma_channel *channel) +{ +	struct cppi41_dma_channel *cppi41_channel = channel->private_data; + +	if (cppi41_channel->is_allocated) { +		cppi41_channel->is_allocated = 0; +		channel->status = MUSB_DMA_STATUS_FREE; +		channel->actual_len = 0; +	} +} + +static int cppi41_dma_channel_program(struct dma_channel *channel, +				u16 packet_sz, u8 mode, +				dma_addr_t dma_addr, u32 len) +{ +	int ret; +	struct cppi41_dma_channel *cppi41_channel = channel->private_data; +	int hb_mult = 0; + +	BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || +		channel->status == MUSB_DMA_STATUS_BUSY); + +	if (is_host_active(cppi41_channel->controller->musb)) { +		if (cppi41_channel->is_tx) +			hb_mult = cppi41_channel->hw_ep->out_qh->hb_mult; +		else +			hb_mult = cppi41_channel->hw_ep->in_qh->hb_mult; +	} + +	channel->status = MUSB_DMA_STATUS_BUSY; +	channel->actual_len = 0; + +	if (hb_mult) +		packet_sz = hb_mult * (packet_sz & 0x7FF); + +	ret = cppi41_configure_channel(channel, packet_sz, mode, dma_addr, len); +	if (!ret) +		channel->status = MUSB_DMA_STATUS_FREE; + +	return ret; +} + +static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket, +		void *buf, u32 length) +{ +	struct cppi41_dma_channel *cppi41_channel = channel->private_data; +	struct cppi41_dma_controller *controller = cppi41_channel->controller; +	struct musb *musb = controller->musb; + +	if (is_host_active(musb)) { +		WARN_ON(1); +		return 1; +	} +	if (cppi41_channel->hw_ep->ep_in.type != USB_ENDPOINT_XFER_BULK) +		return 0; +	if (cppi41_channel->is_tx) +		return 1; +	/* AM335x Advisory 1.0.13. No workaround for device RX mode */ +	return 0; +} + +static int cppi41_dma_channel_abort(struct dma_channel *channel) +{ +	struct cppi41_dma_channel *cppi41_channel = channel->private_data; +	struct cppi41_dma_controller *controller = cppi41_channel->controller; +	struct musb *musb = controller->musb; +	void __iomem *epio = cppi41_channel->hw_ep->regs; +	int tdbit; +	int ret; +	unsigned is_tx; +	u16 csr; + +	is_tx = cppi41_channel->is_tx; +	dev_dbg(musb->controller, "abort channel=%d, is_tx=%d\n", +			cppi41_channel->port_num, is_tx); + +	if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE) +		return 0; + +	list_del_init(&cppi41_channel->tx_check); +	if (is_tx) { +		csr = musb_readw(epio, MUSB_TXCSR); +		csr &= ~MUSB_TXCSR_DMAENAB; +		musb_writew(epio, MUSB_TXCSR, csr); +	} else { +		csr = musb_readw(epio, MUSB_RXCSR); +		csr &= ~(MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_DMAENAB); +		musb_writew(epio, MUSB_RXCSR, csr); + +		csr = musb_readw(epio, MUSB_RXCSR); +		if (csr & MUSB_RXCSR_RXPKTRDY) { +			csr |= MUSB_RXCSR_FLUSHFIFO; +			musb_writew(epio, MUSB_RXCSR, csr); +			musb_writew(epio, MUSB_RXCSR, csr); +		} +	} + +	tdbit = 1 << cppi41_channel->port_num; +	if (is_tx) +		tdbit <<= 16; + +	do { +		musb_writel(musb->ctrl_base, USB_TDOWN, tdbit); +		ret = dmaengine_terminate_all(cppi41_channel->dc); +	} while (ret == -EAGAIN); + +	musb_writel(musb->ctrl_base, USB_TDOWN, tdbit); + +	if (is_tx) { +		csr = musb_readw(epio, MUSB_TXCSR); +		if (csr & MUSB_TXCSR_TXPKTRDY) { +			csr |= MUSB_TXCSR_FLUSHFIFO; +			musb_writew(epio, MUSB_TXCSR, csr); +		} +	} + +	cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE; +	return 0; +} + +static void cppi41_release_all_dma_chans(struct cppi41_dma_controller *ctrl) +{ +	struct dma_chan *dc; +	int i; + +	for (i = 0; i < MUSB_DMA_NUM_CHANNELS; i++) { +		dc = ctrl->tx_channel[i].dc; +		if (dc) +			dma_release_channel(dc); +		dc = ctrl->rx_channel[i].dc; +		if (dc) +			dma_release_channel(dc); +	} +} + +static void cppi41_dma_controller_stop(struct cppi41_dma_controller *controller) +{ +	cppi41_release_all_dma_chans(controller); +} + +static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) +{ +	struct musb *musb = controller->musb; +	struct device *dev = musb->controller; +	struct device_node *np = dev->of_node; +	struct cppi41_dma_channel *cppi41_channel; +	int count; +	int i; +	int ret; + +	count = of_property_count_strings(np, "dma-names"); +	if (count < 0) +		return count; + +	for (i = 0; i < count; i++) { +		struct dma_chan *dc; +		struct dma_channel *musb_dma; +		const char *str; +		unsigned is_tx; +		unsigned int port; + +		ret = of_property_read_string_index(np, "dma-names", i, &str); +		if (ret) +			goto err; +		if (!strncmp(str, "tx", 2)) +			is_tx = 1; +		else if (!strncmp(str, "rx", 2)) +			is_tx = 0; +		else { +			dev_err(dev, "Wrong dmatype %s\n", str); +			goto err; +		} +		ret = kstrtouint(str + 2, 0, &port); +		if (ret) +			goto err; + +		ret = -EINVAL; +		if (port > MUSB_DMA_NUM_CHANNELS || !port) +			goto err; +		if (is_tx) +			cppi41_channel = &controller->tx_channel[port - 1]; +		else +			cppi41_channel = &controller->rx_channel[port - 1]; + +		cppi41_channel->controller = controller; +		cppi41_channel->port_num = port; +		cppi41_channel->is_tx = is_tx; +		INIT_LIST_HEAD(&cppi41_channel->tx_check); +		INIT_WORK(&cppi41_channel->dma_completion, +			  cppi_trans_done_work); + +		musb_dma = &cppi41_channel->channel; +		musb_dma->private_data = cppi41_channel; +		musb_dma->status = MUSB_DMA_STATUS_FREE; +		musb_dma->max_len = SZ_4M; + +		dc = dma_request_slave_channel(dev, str); +		if (!dc) { +			dev_err(dev, "Failed to request %s.\n", str); +			ret = -EPROBE_DEFER; +			goto err; +		} +		cppi41_channel->dc = dc; +	} +	return 0; +err: +	cppi41_release_all_dma_chans(controller); +	return ret; +} + +void dma_controller_destroy(struct dma_controller *c) +{ +	struct cppi41_dma_controller *controller = container_of(c, +			struct cppi41_dma_controller, controller); + +	hrtimer_cancel(&controller->early_tx); +	cppi41_dma_controller_stop(controller); +	kfree(controller); +} + +struct dma_controller *dma_controller_create(struct musb *musb, +					void __iomem *base) +{ +	struct cppi41_dma_controller *controller; +	int ret = 0; + +	if (!musb->controller->of_node) { +		dev_err(musb->controller, "Need DT for the DMA engine.\n"); +		return NULL; +	} + +	controller = kzalloc(sizeof(*controller), GFP_KERNEL); +	if (!controller) +		goto kzalloc_fail; + +	hrtimer_init(&controller->early_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL); +	controller->early_tx.function = cppi41_recheck_tx_req; +	INIT_LIST_HEAD(&controller->early_tx_list); +	controller->musb = musb; + +	controller->controller.channel_alloc = cppi41_dma_channel_allocate; +	controller->controller.channel_release = cppi41_dma_channel_release; +	controller->controller.channel_program = cppi41_dma_channel_program; +	controller->controller.channel_abort = cppi41_dma_channel_abort; +	controller->controller.is_compatible = cppi41_is_compatible; + +	ret = cppi41_dma_controller_start(controller); +	if (ret) +		goto plat_get_fail; +	return &controller->controller; + +plat_get_fail: +	kfree(controller); +kzalloc_fail: +	if (ret == -EPROBE_DEFER) +		return ERR_PTR(ret); +	return NULL; +} diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h index 94f6973cf8f..27ba8f79946 100644 --- a/drivers/usb/musb/musb_debug.h +++ b/drivers/usb/musb/musb_debug.h @@ -42,23 +42,9 @@  #define INFO(fmt, args...) yprintk(KERN_INFO, fmt, ## args)  #define ERR(fmt, args...) yprintk(KERN_ERR, fmt, ## args) -#define DBG(level, format, args...) do { \ -	if (_dbg_level(level)) \ -		pr_debug("%s %d: " format, __func__, __LINE__, ## args); \ -	} while (0) - -extern unsigned musb_debug; - -static inline int _dbg_level(unsigned l) -{ -	return musb_debug >= l; -} - -extern const char *otg_state_string(struct musb *); -  #ifdef CONFIG_DEBUG_FS -extern int musb_init_debugfs(struct musb *musb); -extern void musb_exit_debugfs(struct musb *musb); +int musb_init_debugfs(struct musb *musb); +void musb_exit_debugfs(struct musb *musb);  #else  static inline int musb_init_debugfs(struct musb *musb)  { diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c index 9e8639d4e86..4c216790e86 100644 --- a/drivers/usb/musb/musb_debugfs.c +++ b/drivers/usb/musb/musb_debugfs.c @@ -33,30 +33,15 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/sched.h>  #include <linux/init.h> -#include <linux/list.h> -#include <linux/kobject.h> -#include <linux/platform_device.h> -#include <linux/io.h>  #include <linux/debugfs.h>  #include <linux/seq_file.h> -#ifdef	CONFIG_ARM -#include <mach/hardware.h> -#include <mach/memory.h> -#include <asm/mach-types.h> -#endif -  #include <asm/uaccess.h>  #include "musb_core.h"  #include "musb_debug.h" -#ifdef CONFIG_ARCH_DAVINCI -#include "davinci.h" -#endif -  struct musb_register_map {  	char			*name;  	unsigned		offset; @@ -118,8 +103,6 @@ static const struct musb_register_map musb_regmap[] = {  	{  }	/* Terminating Entry */  }; -static struct dentry *musb_debugfs_root; -  static int musb_regdump_show(struct seq_file *s, void *unused)  {  	struct musb		*musb = s->private; @@ -250,33 +233,33 @@ static const struct file_operations musb_test_mode_fops = {  	.release		= single_release,  }; -int __init musb_init_debugfs(struct musb *musb) +int musb_init_debugfs(struct musb *musb)  {  	struct dentry		*root;  	struct dentry		*file;  	int			ret; -	root = debugfs_create_dir("musb", NULL); -	if (IS_ERR(root)) { -		ret = PTR_ERR(root); +	root = debugfs_create_dir(dev_name(musb->controller), NULL); +	if (!root) { +		ret = -ENOMEM;  		goto err0;  	}  	file = debugfs_create_file("regdump", S_IRUGO, root, musb,  			&musb_regdump_fops); -	if (IS_ERR(file)) { -		ret = PTR_ERR(file); +	if (!file) { +		ret = -ENOMEM;  		goto err1;  	}  	file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR,  			root, musb, &musb_test_mode_fops); -	if (IS_ERR(file)) { -		ret = PTR_ERR(file); +	if (!file) { +		ret = -ENOMEM;  		goto err1;  	} -	musb_debugfs_root = root; +	musb->debugfs_root = root;  	return 0; @@ -289,5 +272,5 @@ err0:  void /* __init_or_exit */ musb_exit_debugfs(struct musb *musb)  { -	debugfs_remove_recursive(musb_debugfs_root); +	debugfs_remove_recursive(musb->debugfs_root);  } diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h index 916065ba9e7..1345a4ff041 100644 --- a/drivers/usb/musb/musb_dma.h +++ b/drivers/usb/musb/musb_dma.h @@ -62,13 +62,13 @@ struct musb_hw_ep;  #define	DMA_ADDR_INVALID	(~(dma_addr_t)0) -#ifndef CONFIG_MUSB_PIO_ONLY -#define	is_dma_capable()	(1) -#else +#ifdef CONFIG_MUSB_PIO_ONLY  #define	is_dma_capable()	(0) +#else +#define	is_dma_capable()	(1)  #endif -#ifdef CONFIG_USB_TI_CPPI_DMA +#if defined(CONFIG_USB_TI_CPPI_DMA) || defined(CONFIG_USB_TI_CPPI41_DMA)  #define	is_cppi_enabled()	1  #else  #define	is_cppi_enabled()	0 @@ -159,8 +159,6 @@ dma_channel_status(struct dma_channel *c)   * Controllers manage dma channels.   */  struct dma_controller { -	int			(*start)(struct dma_controller *); -	int			(*stop)(struct dma_controller *);  	struct dma_channel	*(*channel_alloc)(struct dma_controller *,  					struct musb_hw_ep *, u8 is_tx);  	void			(*channel_release)(struct dma_channel *); @@ -169,15 +167,28 @@ struct dma_controller {  							dma_addr_t dma_addr,  							u32 length);  	int			(*channel_abort)(struct dma_channel *); +	int			(*is_compatible)(struct dma_channel *channel, +							u16 maxpacket, +							void *buf, u32 length);  };  /* called after channel_program(), may indicate a fault */  extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit); +#ifdef CONFIG_MUSB_PIO_ONLY +static inline struct dma_controller *dma_controller_create(struct musb *m, +		void __iomem *io) +{ +	return NULL; +} + +static inline void dma_controller_destroy(struct dma_controller *d) { } -extern struct dma_controller *__init -dma_controller_create(struct musb *, void __iomem *); +#else + +extern struct dma_controller *dma_controller_create(struct musb *, void __iomem *);  extern void dma_controller_destroy(struct dma_controller *); +#endif  #endif	/* __MUSB_DMA_H__ */ diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c new file mode 100644 index 00000000000..09529f94e72 --- /dev/null +++ b/drivers/usb/musb/musb_dsps.c @@ -0,0 +1,830 @@ +/* + * Texas Instruments DSPS platforms "glue layer" + * + * Copyright (C) 2012, by Texas Instruments + * + * Based on the am35x "glue layer" code. + * + * 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 + * + * musb_dsps.c will be a common file for all the TI DSPS platforms + * such as dm64x, dm36x, dm35x, da8x, am35x and ti81x. + * For now only ti81x is using this and in future davinci.c, am35x.c + * da8xx.c would be merged to this file after testing. + */ + +#include <linux/io.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/pm_runtime.h> +#include <linux/module.h> +#include <linux/usb/usb_phy_generic.h> +#include <linux/platform_data/usb-omap.h> +#include <linux/sizes.h> + +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/usb/of.h> + +#include <linux/debugfs.h> + +#include "musb_core.h" + +static const struct of_device_id musb_dsps_of_match[]; + +/** + * avoid using musb_readx()/musb_writex() as glue layer should not be + * dependent on musb core layer symbols. + */ +static inline u8 dsps_readb(const void __iomem *addr, unsigned offset) +	{ return __raw_readb(addr + offset); } + +static inline u32 dsps_readl(const void __iomem *addr, unsigned offset) +	{ return __raw_readl(addr + offset); } + +static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data) +	{ __raw_writeb(data, addr + offset); } + +static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data) +	{ __raw_writel(data, addr + offset); } + +/** + * DSPS musb wrapper register offset. + * FIXME: This should be expanded to have all the wrapper registers from TI DSPS + * musb ips. + */ +struct dsps_musb_wrapper { +	u16	revision; +	u16	control; +	u16	status; +	u16	epintr_set; +	u16	epintr_clear; +	u16	epintr_status; +	u16	coreintr_set; +	u16	coreintr_clear; +	u16	coreintr_status; +	u16	phy_utmi; +	u16	mode; +	u16	tx_mode; +	u16	rx_mode; + +	/* bit positions for control */ +	unsigned	reset:5; + +	/* bit positions for interrupt */ +	unsigned	usb_shift:5; +	u32		usb_mask; +	u32		usb_bitmap; +	unsigned	drvvbus:5; + +	unsigned	txep_shift:5; +	u32		txep_mask; +	u32		txep_bitmap; + +	unsigned	rxep_shift:5; +	u32		rxep_mask; +	u32		rxep_bitmap; + +	/* bit positions for phy_utmi */ +	unsigned	otg_disable:5; + +	/* bit positions for mode */ +	unsigned	iddig:5; +	unsigned	iddig_mux:5; +	/* miscellaneous stuff */ +	u8		poll_seconds; +}; + +/* + * register shadow for suspend + */ +struct dsps_context { +	u32 control; +	u32 epintr; +	u32 coreintr; +	u32 phy_utmi; +	u32 mode; +	u32 tx_mode; +	u32 rx_mode; +}; + +/** + * DSPS glue structure. + */ +struct dsps_glue { +	struct device *dev; +	struct platform_device *musb;	/* child musb pdev */ +	const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ +	struct timer_list timer;	/* otg_workaround timer */ +	unsigned long last_timer;    /* last timer data for each instance */ + +	struct dsps_context context; +	struct debugfs_regset32 regset; +	struct dentry *dbgfs_root; +}; + +static const struct debugfs_reg32 dsps_musb_regs[] = { +	{ "revision",		0x00 }, +	{ "control",		0x14 }, +	{ "status",		0x18 }, +	{ "eoi",		0x24 }, +	{ "intr0_stat",		0x30 }, +	{ "intr1_stat",		0x34 }, +	{ "intr0_set",		0x38 }, +	{ "intr1_set",		0x3c }, +	{ "txmode",		0x70 }, +	{ "rxmode",		0x74 }, +	{ "autoreq",		0xd0 }, +	{ "srpfixtime",		0xd4 }, +	{ "tdown",		0xd8 }, +	{ "phy_utmi",		0xe0 }, +	{ "mode",		0xe8 }, +}; + +static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) +{ +	struct device *dev = musb->controller; +	struct dsps_glue *glue = dev_get_drvdata(dev->parent); + +	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)) { +		dev_dbg(musb->controller, "%s active, deleting timer\n", +				usb_otg_state_string(musb->xceiv->state)); +		del_timer(&glue->timer); +		glue->last_timer = jiffies; +		return; +	} +	if (musb->port_mode != MUSB_PORT_MODE_DUAL_ROLE) +		return; + +	if (!musb->g.dev.driver) +		return; + +	if (time_after(glue->last_timer, timeout) && +				timer_pending(&glue->timer)) { +		dev_dbg(musb->controller, +			"Longer idle timer already pending, ignoring...\n"); +		return; +	} +	glue->last_timer = timeout; + +	dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", +		usb_otg_state_string(musb->xceiv->state), +			jiffies_to_msecs(timeout - jiffies)); +	mod_timer(&glue->timer, timeout); +} + +/** + * dsps_musb_enable - enable interrupts + */ +static void dsps_musb_enable(struct musb *musb) +{ +	struct device *dev = musb->controller; +	struct platform_device *pdev = to_platform_device(dev->parent); +	struct dsps_glue *glue = platform_get_drvdata(pdev); +	const struct dsps_musb_wrapper *wrp = glue->wrp; +	void __iomem *reg_base = musb->ctrl_base; +	u32 epmask, coremask; + +	/* Workaround: setup IRQs through both register sets. */ +	epmask = ((musb->epmask & wrp->txep_mask) << wrp->txep_shift) | +	       ((musb->epmask & wrp->rxep_mask) << wrp->rxep_shift); +	coremask = (wrp->usb_bitmap & ~MUSB_INTR_SOF); + +	dsps_writel(reg_base, wrp->epintr_set, epmask); +	dsps_writel(reg_base, wrp->coreintr_set, coremask); +	/* Force the DRVVBUS IRQ so we can start polling for ID change. */ +	dsps_writel(reg_base, wrp->coreintr_set, +		    (1 << wrp->drvvbus) << wrp->usb_shift); +	dsps_musb_try_idle(musb, 0); +} + +/** + * dsps_musb_disable - disable HDRC and flush interrupts + */ +static void dsps_musb_disable(struct musb *musb) +{ +	struct device *dev = musb->controller; +	struct platform_device *pdev = to_platform_device(dev->parent); +	struct dsps_glue *glue = platform_get_drvdata(pdev); +	const struct dsps_musb_wrapper *wrp = glue->wrp; +	void __iomem *reg_base = musb->ctrl_base; + +	dsps_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap); +	dsps_writel(reg_base, wrp->epintr_clear, +			 wrp->txep_bitmap | wrp->rxep_bitmap); +	dsps_writeb(musb->mregs, MUSB_DEVCTL, 0); +} + +static void otg_timer(unsigned long _musb) +{ +	struct musb *musb = (void *)_musb; +	void __iomem *mregs = musb->mregs; +	struct device *dev = musb->controller; +	struct dsps_glue *glue = dev_get_drvdata(dev->parent); +	const struct dsps_musb_wrapper *wrp = glue->wrp; +	u8 devctl; +	unsigned long flags; +	int skip_session = 0; + +	/* +	 * We poll because DSPS IP's won't expose several OTG-critical +	 * status change events (from the transceiver) otherwise. +	 */ +	devctl = dsps_readb(mregs, MUSB_DEVCTL); +	dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, +				usb_otg_state_string(musb->xceiv->state)); + +	spin_lock_irqsave(&musb->lock, flags); +	switch (musb->xceiv->state) { +	case OTG_STATE_A_WAIT_BCON: +		dsps_writeb(musb->mregs, MUSB_DEVCTL, 0); +		skip_session = 1; +		/* fall */ + +	case OTG_STATE_A_IDLE: +	case OTG_STATE_B_IDLE: +		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); +		} +		if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) +			dsps_writeb(mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); +		mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); +		break; +	case OTG_STATE_A_WAIT_VFALL: +		musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; +		dsps_writel(musb->ctrl_base, wrp->coreintr_set, +			    MUSB_INTR_VBUSERROR << wrp->usb_shift); +		break; +	default: +		break; +	} +	spin_unlock_irqrestore(&musb->lock, flags); +} + +static irqreturn_t dsps_interrupt(int irq, void *hci) +{ +	struct musb  *musb = hci; +	void __iomem *reg_base = musb->ctrl_base; +	struct device *dev = musb->controller; +	struct dsps_glue *glue = dev_get_drvdata(dev->parent); +	const struct dsps_musb_wrapper *wrp = glue->wrp; +	unsigned long flags; +	irqreturn_t ret = IRQ_NONE; +	u32 epintr, usbintr; + +	spin_lock_irqsave(&musb->lock, flags); + +	/* Get endpoint interrupts */ +	epintr = dsps_readl(reg_base, wrp->epintr_status); +	musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift; +	musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift; + +	if (epintr) +		dsps_writel(reg_base, wrp->epintr_status, epintr); + +	/* Get usb core interrupts */ +	usbintr = dsps_readl(reg_base, wrp->coreintr_status); +	if (!usbintr && !epintr) +		goto out; + +	musb->int_usb =	(usbintr & wrp->usb_bitmap) >> wrp->usb_shift; +	if (usbintr) +		dsps_writel(reg_base, wrp->coreintr_status, usbintr); + +	dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n", +			usbintr, epintr); +	/* +	 * DRVVBUS IRQs are the only proxy we have (a very poor one!) for +	 * DSPS IP'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 (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) { +		pr_info("CAUTION: musb: Babble Interrupt Occurred\n"); + +		/* +		 * When a babble condition occurs, the musb controller removes +		 * the session and is no longer in host mode. Hence, all +		 * devices connected to its root hub get disconnected. +		 * +		 * Hand this error down to the musb core isr, so it can +		 * recover. +		 */ +		musb->int_usb = MUSB_INTR_BABBLE | MUSB_INTR_DISCONNECT; +		musb->int_tx = musb->int_rx = 0; +	} + +	if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { +		int drvvbus = dsps_readl(reg_base, wrp->status); +		void __iomem *mregs = musb->mregs; +		u8 devctl = dsps_readb(mregs, MUSB_DEVCTL); +		int err; + +		err = 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(&glue->timer, +					jiffies + wrp->poll_seconds * HZ); +			WARNING("VBUS error workaround (delay coming)\n"); +		} else if (drvvbus) { +			MUSB_HST_MODE(musb); +			musb->xceiv->otg->default_a = 1; +			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; +			del_timer(&glue->timer); +		} else { +			musb->is_active = 0; +			MUSB_DEV_MODE(musb); +			musb->xceiv->otg->default_a = 0; +			musb->xceiv->state = OTG_STATE_B_IDLE; +		} + +		/* NOTE: this must complete power-on within 100 ms. */ +		dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", +				drvvbus ? "on" : "off", +				usb_otg_state_string(musb->xceiv->state), +				err ? " ERROR" : "", +				devctl); +		ret = IRQ_HANDLED; +	} + +	if (musb->int_tx || musb->int_rx || musb->int_usb) +		ret |= musb_interrupt(musb); + +	/* Poll for ID change in OTG port mode */ +	if (musb->xceiv->state == OTG_STATE_B_IDLE && +			musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) +		mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); +out: +	spin_unlock_irqrestore(&musb->lock, flags); + +	return ret; +} + +static int dsps_musb_dbg_init(struct musb *musb, struct dsps_glue *glue) +{ +	struct dentry *root; +	struct dentry *file; +	char buf[128]; + +	sprintf(buf, "%s.dsps", dev_name(musb->controller)); +	root = debugfs_create_dir(buf, NULL); +	if (!root) +		return -ENOMEM; +	glue->dbgfs_root = root; + +	glue->regset.regs = dsps_musb_regs; +	glue->regset.nregs = ARRAY_SIZE(dsps_musb_regs); +	glue->regset.base = musb->ctrl_base; + +	file = debugfs_create_regset32("regdump", S_IRUGO, root, &glue->regset); +	if (!file) { +		debugfs_remove_recursive(root); +		return -ENOMEM; +	} +	return 0; +} + +static int dsps_musb_init(struct musb *musb) +{ +	struct device *dev = musb->controller; +	struct dsps_glue *glue = dev_get_drvdata(dev->parent); +	struct platform_device *parent = to_platform_device(dev->parent); +	const struct dsps_musb_wrapper *wrp = glue->wrp; +	void __iomem *reg_base; +	struct resource *r; +	u32 rev, val; +	int ret; + +	r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control"); +	if (!r) +		return -EINVAL; + +	reg_base = devm_ioremap_resource(dev, r); +	if (IS_ERR(reg_base)) +		return PTR_ERR(reg_base); +	musb->ctrl_base = reg_base; + +	/* NOP driver needs change if supporting dual instance */ +	musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0); +	if (IS_ERR(musb->xceiv)) +		return PTR_ERR(musb->xceiv); + +	/* Returns zero if e.g. not clocked */ +	rev = dsps_readl(reg_base, wrp->revision); +	if (!rev) +		return -ENODEV; + +	usb_phy_init(musb->xceiv); +	setup_timer(&glue->timer, otg_timer, (unsigned long) musb); + +	/* Reset the musb */ +	dsps_writel(reg_base, wrp->control, (1 << wrp->reset)); + +	musb->isr = dsps_interrupt; + +	/* reset the otgdisable bit, needed for host mode to work */ +	val = dsps_readl(reg_base, wrp->phy_utmi); +	val &= ~(1 << wrp->otg_disable); +	dsps_writel(musb->ctrl_base, wrp->phy_utmi, val); + +	ret = dsps_musb_dbg_init(musb, glue); +	if (ret) +		return ret; + +	return 0; +} + +static int dsps_musb_exit(struct musb *musb) +{ +	struct device *dev = musb->controller; +	struct dsps_glue *glue = dev_get_drvdata(dev->parent); + +	del_timer_sync(&glue->timer); +	usb_phy_shutdown(musb->xceiv); +	debugfs_remove_recursive(glue->dbgfs_root); + +	return 0; +} + +static int dsps_musb_set_mode(struct musb *musb, u8 mode) +{ +	struct device *dev = musb->controller; +	struct dsps_glue *glue = dev_get_drvdata(dev->parent); +	const struct dsps_musb_wrapper *wrp = glue->wrp; +	void __iomem *ctrl_base = musb->ctrl_base; +	u32 reg; + +	reg = dsps_readl(ctrl_base, wrp->mode); + +	switch (mode) { +	case MUSB_HOST: +		reg &= ~(1 << wrp->iddig); + +		/* +		 * if we're setting mode to host-only or device-only, we're +		 * going to ignore whatever the PHY sends us and just force +		 * ID pin status by SW +		 */ +		reg |= (1 << wrp->iddig_mux); + +		dsps_writel(ctrl_base, wrp->mode, reg); +		dsps_writel(ctrl_base, wrp->phy_utmi, 0x02); +		break; +	case MUSB_PERIPHERAL: +		reg |= (1 << wrp->iddig); + +		/* +		 * if we're setting mode to host-only or device-only, we're +		 * going to ignore whatever the PHY sends us and just force +		 * ID pin status by SW +		 */ +		reg |= (1 << wrp->iddig_mux); + +		dsps_writel(ctrl_base, wrp->mode, reg); +		break; +	case MUSB_OTG: +		dsps_writel(ctrl_base, wrp->phy_utmi, 0x02); +		break; +	default: +		dev_err(glue->dev, "unsupported mode %d\n", mode); +		return -EINVAL; +	} + +	return 0; +} + +static void dsps_musb_reset(struct musb *musb) +{ +	struct device *dev = musb->controller; +	struct dsps_glue *glue = dev_get_drvdata(dev->parent); +	const struct dsps_musb_wrapper *wrp = glue->wrp; + +	dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset)); +	udelay(100); +} + +static struct musb_platform_ops dsps_ops = { +	.init		= dsps_musb_init, +	.exit		= dsps_musb_exit, + +	.enable		= dsps_musb_enable, +	.disable	= dsps_musb_disable, + +	.try_idle	= dsps_musb_try_idle, +	.set_mode	= dsps_musb_set_mode, +	.reset		= dsps_musb_reset, +}; + +static u64 musb_dmamask = DMA_BIT_MASK(32); + +static int get_int_prop(struct device_node *dn, const char *s) +{ +	int ret; +	u32 val; + +	ret = of_property_read_u32(dn, s, &val); +	if (ret) +		return 0; +	return val; +} + +static int get_musb_port_mode(struct device *dev) +{ +	enum usb_dr_mode mode; + +	mode = of_usb_get_dr_mode(dev->of_node); +	switch (mode) { +	case USB_DR_MODE_HOST: +		return MUSB_PORT_MODE_HOST; + +	case USB_DR_MODE_PERIPHERAL: +		return MUSB_PORT_MODE_GADGET; + +	case USB_DR_MODE_UNKNOWN: +	case USB_DR_MODE_OTG: +	default: +		return MUSB_PORT_MODE_DUAL_ROLE; +	} +} + +static int dsps_create_musb_pdev(struct dsps_glue *glue, +		struct platform_device *parent) +{ +	struct musb_hdrc_platform_data pdata; +	struct resource	resources[2]; +	struct resource	*res; +	struct device *dev = &parent->dev; +	struct musb_hdrc_config	*config; +	struct platform_device *musb; +	struct device_node *dn = parent->dev.of_node; +	int ret; + +	memset(resources, 0, sizeof(resources)); +	res = platform_get_resource_byname(parent, IORESOURCE_MEM, "mc"); +	if (!res) { +		dev_err(dev, "failed to get memory.\n"); +		return -EINVAL; +	} +	resources[0] = *res; + +	res = platform_get_resource_byname(parent, IORESOURCE_IRQ, "mc"); +	if (!res) { +		dev_err(dev, "failed to get irq.\n"); +		return -EINVAL; +	} +	resources[1] = *res; + +	/* allocate the child platform device */ +	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); +	if (!musb) { +		dev_err(dev, "failed to allocate musb device\n"); +		return -ENOMEM; +	} + +	musb->dev.parent		= dev; +	musb->dev.dma_mask		= &musb_dmamask; +	musb->dev.coherent_dma_mask	= musb_dmamask; +	musb->dev.of_node		= of_node_get(dn); + +	glue->musb = musb; + +	ret = platform_device_add_resources(musb, resources, +			ARRAY_SIZE(resources)); +	if (ret) { +		dev_err(dev, "failed to add resources\n"); +		goto err; +	} + +	config = devm_kzalloc(&parent->dev, sizeof(*config), GFP_KERNEL); +	if (!config) { +		dev_err(dev, "failed to allocate musb hdrc config\n"); +		ret = -ENOMEM; +		goto err; +	} +	pdata.config = config; +	pdata.platform_ops = &dsps_ops; + +	config->num_eps = get_int_prop(dn, "mentor,num-eps"); +	config->ram_bits = get_int_prop(dn, "mentor,ram-bits"); +	config->host_port_deassert_reset_at_resume = 1; +	pdata.mode = get_musb_port_mode(dev); +	/* DT keeps this entry in mA, musb expects it as per USB spec */ +	pdata.power = get_int_prop(dn, "mentor,power") / 2; +	config->multipoint = of_property_read_bool(dn, "mentor,multipoint"); + +	ret = platform_device_add_data(musb, &pdata, sizeof(pdata)); +	if (ret) { +		dev_err(dev, "failed to add platform_data\n"); +		goto err; +	} + +	ret = platform_device_add(musb); +	if (ret) { +		dev_err(dev, "failed to register musb device\n"); +		goto err; +	} +	return 0; + +err: +	platform_device_put(musb); +	return ret; +} + +static int dsps_probe(struct platform_device *pdev) +{ +	const struct of_device_id *match; +	const struct dsps_musb_wrapper *wrp; +	struct dsps_glue *glue; +	int ret; + +	if (!strcmp(pdev->name, "musb-hdrc")) +		return -ENODEV; + +	match = of_match_node(musb_dsps_of_match, pdev->dev.of_node); +	if (!match) { +		dev_err(&pdev->dev, "fail to get matching of_match struct\n"); +		return -EINVAL; +	} +	wrp = match->data; + +	/* allocate glue */ +	glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); +	if (!glue) { +		dev_err(&pdev->dev, "unable to allocate glue memory\n"); +		return -ENOMEM; +	} + +	glue->dev = &pdev->dev; +	glue->wrp = wrp; + +	platform_set_drvdata(pdev, glue); +	pm_runtime_enable(&pdev->dev); + +	ret = pm_runtime_get_sync(&pdev->dev); +	if (ret < 0) { +		dev_err(&pdev->dev, "pm_runtime_get_sync FAILED"); +		goto err2; +	} + +	ret = dsps_create_musb_pdev(glue, pdev); +	if (ret) +		goto err3; + +	return 0; + +err3: +	pm_runtime_put(&pdev->dev); +err2: +	pm_runtime_disable(&pdev->dev); +	return ret; +} + +static int dsps_remove(struct platform_device *pdev) +{ +	struct dsps_glue *glue = platform_get_drvdata(pdev); + +	platform_device_unregister(glue->musb); + +	/* disable usbss clocks */ +	pm_runtime_put(&pdev->dev); +	pm_runtime_disable(&pdev->dev); + +	return 0; +} + +static const struct dsps_musb_wrapper am33xx_driver_data = { +	.revision		= 0x00, +	.control		= 0x14, +	.status			= 0x18, +	.epintr_set		= 0x38, +	.epintr_clear		= 0x40, +	.epintr_status		= 0x30, +	.coreintr_set		= 0x3c, +	.coreintr_clear		= 0x44, +	.coreintr_status	= 0x34, +	.phy_utmi		= 0xe0, +	.mode			= 0xe8, +	.tx_mode		= 0x70, +	.rx_mode		= 0x74, +	.reset			= 0, +	.otg_disable		= 21, +	.iddig			= 8, +	.iddig_mux		= 7, +	.usb_shift		= 0, +	.usb_mask		= 0x1ff, +	.usb_bitmap		= (0x1ff << 0), +	.drvvbus		= 8, +	.txep_shift		= 0, +	.txep_mask		= 0xffff, +	.txep_bitmap		= (0xffff << 0), +	.rxep_shift		= 16, +	.rxep_mask		= 0xfffe, +	.rxep_bitmap		= (0xfffe << 16), +	.poll_seconds		= 2, +}; + +static const struct of_device_id musb_dsps_of_match[] = { +	{ .compatible = "ti,musb-am33xx", +		.data = (void *) &am33xx_driver_data, }, +	{  }, +}; +MODULE_DEVICE_TABLE(of, musb_dsps_of_match); + +#ifdef CONFIG_PM_SLEEP +static int dsps_suspend(struct device *dev) +{ +	struct dsps_glue *glue = dev_get_drvdata(dev); +	const struct dsps_musb_wrapper *wrp = glue->wrp; +	struct musb *musb = platform_get_drvdata(glue->musb); +	void __iomem *mbase = musb->ctrl_base; + +	glue->context.control = dsps_readl(mbase, wrp->control); +	glue->context.epintr = dsps_readl(mbase, wrp->epintr_set); +	glue->context.coreintr = dsps_readl(mbase, wrp->coreintr_set); +	glue->context.phy_utmi = dsps_readl(mbase, wrp->phy_utmi); +	glue->context.mode = dsps_readl(mbase, wrp->mode); +	glue->context.tx_mode = dsps_readl(mbase, wrp->tx_mode); +	glue->context.rx_mode = dsps_readl(mbase, wrp->rx_mode); + +	return 0; +} + +static int dsps_resume(struct device *dev) +{ +	struct dsps_glue *glue = dev_get_drvdata(dev); +	const struct dsps_musb_wrapper *wrp = glue->wrp; +	struct musb *musb = platform_get_drvdata(glue->musb); +	void __iomem *mbase = musb->ctrl_base; + +	dsps_writel(mbase, wrp->control, glue->context.control); +	dsps_writel(mbase, wrp->epintr_set, glue->context.epintr); +	dsps_writel(mbase, wrp->coreintr_set, glue->context.coreintr); +	dsps_writel(mbase, wrp->phy_utmi, glue->context.phy_utmi); +	dsps_writel(mbase, wrp->mode, glue->context.mode); +	dsps_writel(mbase, wrp->tx_mode, glue->context.tx_mode); +	dsps_writel(mbase, wrp->rx_mode, glue->context.rx_mode); + +	return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); + +static struct platform_driver dsps_usbss_driver = { +	.probe		= dsps_probe, +	.remove         = dsps_remove, +	.driver         = { +		.name   = "musb-dsps", +		.pm	= &dsps_pm_ops, +		.of_match_table	= musb_dsps_of_match, +	}, +}; + +MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer"); +MODULE_AUTHOR("Ravi B <ravibabu@ti.com>"); +MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>"); +MODULE_LICENSE("GPL v2"); + +module_platform_driver(dsps_usbss_driver); diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 36cfd060dbe..d4aa779339f 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -40,58 +40,102 @@  #include <linux/smp.h>  #include <linux/spinlock.h>  #include <linux/delay.h> -#include <linux/moduleparam.h> -#include <linux/stat.h>  #include <linux/dma-mapping.h>  #include <linux/slab.h>  #include "musb_core.h" -/* MUSB PERIPHERAL status 3-mar-2006: - * - * - EP0 seems solid.  It passes both USBCV and usbtest control cases. - *   Minor glitches: - * - *     + remote wakeup to Linux hosts work, but saw USBCV failures; - *       in one test run (operator error?) - *     + endpoint halt tests -- in both usbtest and usbcv -- seem - *       to break when dma is enabled ... is something wrongly - *       clearing SENDSTALL? - * - * - Mass storage behaved ok when last tested.  Network traffic patterns - *   (with lots of short transfers etc) need retesting; they turn up the - *   worst cases of the DMA, since short packets are typical but are not - *   required. - * - * - TX/IN - *     + both pio and dma behave in with network and g_zero tests - *     + no cppi throughput issues other than no-hw-queueing - *     + failed with FLAT_REG (DaVinci) - *     + seems to behave with double buffering, PIO -and- CPPI - *     + with gadgetfs + AIO, requests got lost? - * - * - RX/OUT - *     + both pio and dma behave in with network and g_zero tests - *     + dma is slow in typical case (short_not_ok is clear) - *     + double buffering ok with PIO - *     + double buffering *FAILS* with CPPI, wrong data bytes sometimes - *     + request lossage observed with gadgetfs - * - * - ISO not tested ... might work, but only weakly isochronous - * - * - Gadget driver disabling of softconnect during bind() is ignored; so - *   drivers can't hold off host requests until userspace is ready. - *   (Workaround:  they can turn it off later.) - * - * - PORTABILITY (assumes PIO works): - *     + DaVinci, basically works with cppi dma - *     + OMAP 2430, ditto with mentor dma - *     + TUSB 6010, platform-specific dma in the works - */ -  /* ----------------------------------------------------------------------- */ +#define is_buffer_mapped(req) (is_dma_capable() && \ +					(req->map_state != UN_MAPPED)) + +/* Maps the buffer to dma  */ + +static inline void map_dma_buffer(struct musb_request *request, +			struct musb *musb, struct musb_ep *musb_ep) +{ +	int compatible = true; +	struct dma_controller *dma = musb->dma_controller; + +	request->map_state = UN_MAPPED; + +	if (!is_dma_capable() || !musb_ep->dma) +		return; + +	/* Check if DMA engine can handle this request. +	 * DMA code must reject the USB request explicitly. +	 * Default behaviour is to map the request. +	 */ +	if (dma->is_compatible) +		compatible = dma->is_compatible(musb_ep->dma, +				musb_ep->packet_sz, request->request.buf, +				request->request.length); +	if (!compatible) +		return; + +	if (request->request.dma == DMA_ADDR_INVALID) { +		dma_addr_t dma_addr; +		int ret; + +		dma_addr = dma_map_single( +				musb->controller, +				request->request.buf, +				request->request.length, +				request->tx +					? DMA_TO_DEVICE +					: DMA_FROM_DEVICE); +		ret = dma_mapping_error(musb->controller, dma_addr); +		if (ret) +			return; + +		request->request.dma = dma_addr; +		request->map_state = MUSB_MAPPED; +	} else { +		dma_sync_single_for_device(musb->controller, +			request->request.dma, +			request->request.length, +			request->tx +				? DMA_TO_DEVICE +				: DMA_FROM_DEVICE); +		request->map_state = PRE_MAPPED; +	} +} + +/* Unmap the buffer from dma and maps it back to cpu */ +static inline void unmap_dma_buffer(struct musb_request *request, +				struct musb *musb) +{ +	struct musb_ep *musb_ep = request->ep; + +	if (!is_buffer_mapped(request) || !musb_ep->dma) +		return; + +	if (request->request.dma == DMA_ADDR_INVALID) { +		dev_vdbg(musb->controller, +				"not unmapping a never mapped buffer\n"); +		return; +	} +	if (request->map_state == MUSB_MAPPED) { +		dma_unmap_single(musb->controller, +			request->request.dma, +			request->request.length, +			request->tx +				? DMA_TO_DEVICE +				: DMA_FROM_DEVICE); +		request->request.dma = DMA_ADDR_INVALID; +	} else { /* PRE_MAPPED */ +		dma_sync_single_for_cpu(musb->controller, +			request->request.dma, +			request->request.length, +			request->tx +				? DMA_TO_DEVICE +				: DMA_FROM_DEVICE); +	} +	request->map_state = UN_MAPPED; +} +  /*   * Immediately complete a request.   * @@ -112,37 +156,23 @@ __acquires(ep->musb->lock)  	req = to_musb_request(request); -	list_del(&request->list); +	list_del(&req->list);  	if (req->request.status == -EINPROGRESS)  		req->request.status = status;  	musb = req->musb;  	ep->busy = 1;  	spin_unlock(&musb->lock); -	if (is_dma_capable()) { -		if (req->mapped) { -			dma_unmap_single(musb->controller, -					req->request.dma, -					req->request.length, -					req->tx -						? DMA_TO_DEVICE -						: DMA_FROM_DEVICE); -			req->request.dma = DMA_ADDR_INVALID; -			req->mapped = 0; -		} else if (req->request.dma != DMA_ADDR_INVALID) -			dma_sync_single_for_cpu(musb->controller, -					req->request.dma, -					req->request.length, -					req->tx -						? DMA_TO_DEVICE -						: DMA_FROM_DEVICE); -	} + +	if (!dma_mapping_error(&musb->g.dev, request->dma)) +		unmap_dma_buffer(req, musb); +  	if (request->status == 0) -		DBG(5, "%s done request %p,  %d/%d\n", +		dev_dbg(musb->controller, "%s done request %p,  %d/%d\n",  				ep->end_point.name, request,  				req->request.actual, req->request.length);  	else -		DBG(2, "%s request %p, %d/%d fault %d\n", +		dev_dbg(musb->controller, "%s request %p, %d/%d fault %d\n",  				ep->end_point.name, request,  				req->request.actual, req->request.length,  				request->status); @@ -159,6 +189,7 @@ __acquires(ep->musb->lock)   */  static void nuke(struct musb_ep *ep, const int status)  { +	struct musb		*musb = ep->musb;  	struct musb_request	*req = NULL;  	void __iomem *epio = ep->musb->endpoints[ep->current_epnum].regs; @@ -186,14 +217,14 @@ static void nuke(struct musb_ep *ep, const int status)  		}  		value = c->channel_abort(ep->dma); -		DBG(value ? 1 : 6, "%s: abort DMA --> %d\n", ep->name, value); +		dev_dbg(musb->controller, "%s: abort DMA --> %d\n", +				ep->name, value);  		c->channel_release(ep->dma);  		ep->dma = NULL;  	} -	while (!list_empty(&(ep->req_list))) { -		req = container_of(ep->req_list.next, struct musb_request, -				request.list); +	while (!list_empty(&ep->req_list)) { +		req = list_first_entry(&ep->req_list, struct musb_request, list);  		musb_g_giveback(ep, &req->request, status);  	}  } @@ -215,41 +246,6 @@ static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep)  		return ep->packet_sz;  } - -#ifdef CONFIG_USB_INVENTRA_DMA - -/* Peripheral tx (IN) using Mentor DMA works as follows: -	Only mode 0 is used for transfers <= wPktSize, -	mode 1 is used for larger transfers, - -	One of the following happens: -	- Host sends IN token which causes an endpoint interrupt -		-> TxAvail -			-> if DMA is currently busy, exit. -			-> if queue is non-empty, txstate(). - -	- Request is queued by the gadget driver. -		-> if queue was previously empty, txstate() - -	txstate() -		-> start -		  /\	-> setup DMA -		  |     (data is transferred to the FIFO, then sent out when -		  |	IN token(s) are recd from Host. -		  |		-> DMA interrupt on completion -		  |		   calls TxAvail. -		  |		      -> stop DMA, ~DMAENAB, -		  |		      -> set TxPktRdy for last short pkt or zlp -		  |		      -> Complete Request -		  |		      -> Continue next request (call txstate) -		  |___________________________________| - - * Non-Mentor DMA engines can of course work differently, such as by - * upleveling from irq-per-packet to irq-per-buffer. - */ - -#endif -  /*   * An endpoint is transmitting data. This can be called either from   * the IRQ routine or from ep.queue() to kickstart a request on an @@ -268,9 +264,16 @@ static void txstate(struct musb *musb, struct musb_request *req)  	musb_ep = req->ep; +	/* Check if EP is disabled */ +	if (!musb_ep->desc) { +		dev_dbg(musb->controller, "ep:%s disabled - ignore request\n", +						musb_ep->end_point.name); +		return; +	} +  	/* we shouldn't get here while DMA is active ... but we do ... */  	if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) { -		DBG(4, "dma pending...\n"); +		dev_dbg(musb->controller, "dma pending...\n");  		return;  	} @@ -282,23 +285,23 @@ static void txstate(struct musb *musb, struct musb_request *req)  			(int)(request->length - request->actual));  	if (csr & MUSB_TXCSR_TXPKTRDY) { -		DBG(5, "%s old packet still ready , txcsr %03x\n", +		dev_dbg(musb->controller, "%s old packet still ready , txcsr %03x\n",  				musb_ep->end_point.name, csr);  		return;  	}  	if (csr & MUSB_TXCSR_P_SENDSTALL) { -		DBG(5, "%s stalling, txcsr %03x\n", +		dev_dbg(musb->controller, "%s stalling, txcsr %03x\n",  				musb_ep->end_point.name, csr);  		return;  	} -	DBG(4, "hw_ep%d, maxpacket %d, fifo count %d, txcsr %03x\n", +	dev_dbg(musb->controller, "hw_ep%d, maxpacket %d, fifo count %d, txcsr %03x\n",  			epnum, musb_ep->packet_sz, fifo_count,  			csr);  #ifndef	CONFIG_MUSB_PIO_ONLY -	if (is_dma_capable() && musb_ep->dma) { +	if (is_buffer_mapped(req)) {  		struct dma_controller	*c = musb->dma_controller;  		size_t request_size; @@ -306,11 +309,11 @@ static void txstate(struct musb *musb, struct musb_request *req)  		request_size = min_t(size_t, request->length - request->actual,  					musb_ep->dma->max_len); -		use_dma = (request->dma != DMA_ADDR_INVALID); +		use_dma = (request->dma != DMA_ADDR_INVALID && request_size);  		/* MUSB_TXCSR_P_ISO is still set correctly */ -#ifdef CONFIG_USB_INVENTRA_DMA +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA)  		{  			if (request_size < musb_ep->packet_sz)  				musb_ep->dma->desired_mode = 0; @@ -341,7 +344,19 @@ static void txstate(struct musb *musb, struct musb_request *req)  					csr |= (MUSB_TXCSR_DMAENAB  							| MUSB_TXCSR_DMAMODE  							| MUSB_TXCSR_MODE); -					if (!musb_ep->hb_mult) +					/* +					 * Enable Autoset according to table +					 * below +					 * bulk_split hb_mult	Autoset_Enable +					 *	0	0	Yes(Normal) +					 *	0	>0	No(High BW ISO) +					 *	1	0	Yes(HS bulk) +					 *	1	>0	Yes(FS bulk) +					 */ +					if (!musb_ep->hb_mult || +						(musb_ep->hb_mult && +						 can_bulk_split(musb, +						    musb_ep->type)))  						csr |= MUSB_TXCSR_AUTOSET;  				}  				csr &= ~MUSB_TXCSR_P_UNDERRUN; @@ -350,51 +365,59 @@ static void txstate(struct musb *musb, struct musb_request *req)  			}  		} -#elif defined(CONFIG_USB_TI_CPPI_DMA) -		/* program endpoint CSR first, then setup DMA */ -		csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); -		csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE | -		       MUSB_TXCSR_MODE; -		musb_writew(epio, MUSB_TXCSR, -			(MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN) -				| csr); - -		/* ensure writebuffer is empty */ -		csr = musb_readw(epio, MUSB_TXCSR); - -		/* NOTE host side sets DMAENAB later than this; both are -		 * OK since the transfer dma glue (between CPPI and Mentor -		 * fifos) just tells CPPI it could start.  Data only moves -		 * to the USB TX fifo when both fifos are ready. -		 */ - -		/* "mode" is irrelevant here; handle terminating ZLPs like -		 * PIO does, since the hardware RNDIS mode seems unreliable -		 * except for the last-packet-is-already-short case. -		 */ -		use_dma = use_dma && c->channel_program( -				musb_ep->dma, musb_ep->packet_sz, -				0, -				request->dma + request->actual, -				request_size); -		if (!use_dma) { -			c->channel_release(musb_ep->dma); -			musb_ep->dma = NULL; -			csr &= ~MUSB_TXCSR_DMAENAB; -			musb_writew(epio, MUSB_TXCSR, csr); -			/* invariant: prequest->buf is non-null */ -		} -#elif defined(CONFIG_USB_TUSB_OMAP_DMA) -		use_dma = use_dma && c->channel_program( -				musb_ep->dma, musb_ep->packet_sz, -				request->zero, -				request->dma + request->actual, -				request_size);  #endif +		if (is_cppi_enabled()) { +			/* program endpoint CSR first, then setup DMA */ +			csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); +			csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE | +				MUSB_TXCSR_MODE; +			musb_writew(epio, MUSB_TXCSR, (MUSB_TXCSR_P_WZC_BITS & +						~MUSB_TXCSR_P_UNDERRUN) | csr); + +			/* ensure writebuffer is empty */ +			csr = musb_readw(epio, MUSB_TXCSR); + +			/* +			 * NOTE host side sets DMAENAB later than this; both are +			 * OK since the transfer dma glue (between CPPI and +			 * Mentor fifos) just tells CPPI it could start. Data +			 * only moves to the USB TX fifo when both fifos are +			 * ready. +			 */ +			/* +			 * "mode" is irrelevant here; handle terminating ZLPs +			 * like PIO does, since the hardware RNDIS mode seems +			 * unreliable except for the +			 * last-packet-is-already-short case. +			 */ +			use_dma = use_dma && c->channel_program( +					musb_ep->dma, musb_ep->packet_sz, +					0, +					request->dma + request->actual, +					request_size); +			if (!use_dma) { +				c->channel_release(musb_ep->dma); +				musb_ep->dma = NULL; +				csr &= ~MUSB_TXCSR_DMAENAB; +				musb_writew(epio, MUSB_TXCSR, csr); +				/* invariant: prequest->buf is non-null */ +			} +		} else if (tusb_dma_omap()) +			use_dma = use_dma && c->channel_program( +					musb_ep->dma, musb_ep->packet_sz, +					request->zero, +					request->dma + request->actual, +					request_size);  	}  #endif  	if (!use_dma) { +		/* +		 * Unmap the dma buffer back to cpu if dma channel +		 * programming fails +		 */ +		unmap_dma_buffer(req, musb); +  		musb_write_fifo(musb_ep->hw_ep, fifo_count,  				(u8 *) (request->buf + request->actual));  		request->actual += fifo_count; @@ -404,7 +427,7 @@ static void txstate(struct musb *musb, struct musb_request *req)  	}  	/* host may already have the data when this message shows... */ -	DBG(3, "%s TX/IN %s len %d/%d, txcsr %04x, fifo %d/%d\n", +	dev_dbg(musb->controller, "%s TX/IN %s len %d/%d, txcsr %04x, fifo %d/%d\n",  			musb_ep->end_point.name, use_dma ? "dma" : "pio",  			request->actual, request->length,  			musb_readw(epio, MUSB_TXCSR), @@ -419,6 +442,7 @@ static void txstate(struct musb *musb, struct musb_request *req)  void musb_g_tx(struct musb *musb, u8 epnum)  {  	u16			csr; +	struct musb_request	*req;  	struct usb_request	*request;  	u8 __iomem		*mbase = musb->mregs;  	struct musb_ep		*musb_ep = &musb->endpoints[epnum].ep_in; @@ -426,10 +450,11 @@ void musb_g_tx(struct musb *musb, u8 epnum)  	struct dma_channel	*dma;  	musb_ep_select(mbase, epnum); -	request = next_request(musb_ep); +	req = next_request(musb_ep); +	request = &req->request;  	csr = musb_readw(epio, MUSB_TXCSR); -	DBG(4, "<== %s, txcsr %04x\n", musb_ep->end_point.name, csr); +	dev_dbg(musb->controller, "<== %s, txcsr %04x\n", musb_ep->end_point.name, csr);  	dma = is_dma_capable() ? musb_ep->dma : NULL; @@ -449,7 +474,8 @@ void musb_g_tx(struct musb *musb, u8 epnum)  		csr |=	 MUSB_TXCSR_P_WZC_BITS;  		csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);  		musb_writew(epio, MUSB_TXCSR, csr); -		DBG(20, "underrun on ep%d, req %p\n", epnum, request); +		dev_vdbg(musb->controller, "underrun on ep%d, req %p\n", +				epnum, request);  	}  	if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { @@ -457,7 +483,7 @@ void musb_g_tx(struct musb *musb, u8 epnum)  		 * SHOULD NOT HAPPEN... has with CPPI though, after  		 * changing SENDSTALL (and other cases); harmless?  		 */ -		DBG(5, "%s dma still busy?\n", musb_ep->end_point.name); +		dev_dbg(musb->controller, "%s dma still busy?\n", musb_ep->end_point.name);  		return;  	} @@ -468,12 +494,12 @@ void musb_g_tx(struct musb *musb, u8 epnum)  			is_dma = 1;  			csr |= MUSB_TXCSR_P_WZC_BITS;  			csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN | -				 MUSB_TXCSR_TXPKTRDY); +				 MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_AUTOSET);  			musb_writew(epio, MUSB_TXCSR, csr);  			/* Ensure writebuffer is empty. */  			csr = musb_readw(epio, MUSB_TXCSR);  			request->actual += musb_ep->dma->actual_len; -			DBG(4, "TXCSR%d %04x, DMA off, len %zu, req %p\n", +			dev_dbg(musb->controller, "TXCSR%d %04x, DMA off, len %zu, req %p\n",  				epnum, csr, musb_ep->dma->actual_len, request);  		} @@ -484,7 +510,7 @@ void musb_g_tx(struct musb *musb, u8 epnum)  		if ((request->zero && request->length  			&& (request->length % musb_ep->packet_sz == 0)  			&& (request->actual == request->length)) -#ifdef CONFIG_USB_INVENTRA_DMA +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA)  			|| (is_dma && (!dma->desired_mode ||  				(request->actual &  					(musb_ep->packet_sz - 1)))) @@ -497,7 +523,7 @@ void musb_g_tx(struct musb *musb, u8 epnum)  			if (csr & MUSB_TXCSR_TXPKTRDY)  				return; -			DBG(4, "sending zero pkt\n"); +			dev_dbg(musb->controller, "sending zero pkt\n");  			musb_writew(epio, MUSB_TXCSR, MUSB_TXCSR_MODE  					| MUSB_TXCSR_TXPKTRDY);  			request->zero = 0; @@ -505,51 +531,29 @@ void musb_g_tx(struct musb *musb, u8 epnum)  		if (request->actual == request->length) {  			musb_g_giveback(musb_ep, request, 0); -			request = musb_ep->desc ? next_request(musb_ep) : NULL; -			if (!request) { -				DBG(4, "%s idle now\n", +			/* +			 * In the giveback function the MUSB lock is +			 * released and acquired after sometime. During +			 * this time period the INDEX register could get +			 * changed by the gadget_queue function especially +			 * on SMP systems. Reselect the INDEX to be sure +			 * we are reading/modifying the right registers +			 */ +			musb_ep_select(mbase, epnum); +			req = musb_ep->desc ? next_request(musb_ep) : NULL; +			if (!req) { +				dev_dbg(musb->controller, "%s idle now\n",  					musb_ep->end_point.name);  				return;  			}  		} -		txstate(musb, to_musb_request(request)); +		txstate(musb, req);  	}  }  /* ------------------------------------------------------------ */ -#ifdef CONFIG_USB_INVENTRA_DMA - -/* Peripheral rx (OUT) using Mentor DMA works as follows: -	- Only mode 0 is used. - -	- Request is queued by the gadget class driver. -		-> if queue was previously empty, rxstate() - -	- Host sends OUT token which causes an endpoint interrupt -	  /\      -> RxReady -	  |	      -> if request queued, call rxstate -	  |		/\	-> setup DMA -	  |		|	     -> DMA interrupt on completion -	  |		|		-> RxReady -	  |		|		      -> stop DMA -	  |		|		      -> ack the read -	  |		|		      -> if data recd = max expected -	  |		|				by the request, or host -	  |		|				sent a short packet, -	  |		|				complete the request, -	  |		|				and start the next one. -	  |		|_____________________________________| -	  |					 else just wait for the host -	  |					    to send the next OUT token. -	  |__________________________________________________| - - * Non-Mentor DMA engines can of course work differently. - */ - -#endif -  /*   * Context: controller locked, IRQs blocked, endpoint selected   */ @@ -559,31 +563,39 @@ static void rxstate(struct musb *musb, struct musb_request *req)  	struct usb_request	*request = &req->request;  	struct musb_ep		*musb_ep;  	void __iomem		*epio = musb->endpoints[epnum].regs; -	unsigned		fifo_count = 0; -	u16			len; +	unsigned		len = 0; +	u16			fifo_count;  	u16			csr = musb_readw(epio, MUSB_RXCSR);  	struct musb_hw_ep	*hw_ep = &musb->endpoints[epnum]; +	u8			use_mode_1;  	if (hw_ep->is_shared_fifo)  		musb_ep = &hw_ep->ep_in;  	else  		musb_ep = &hw_ep->ep_out; -	len = musb_ep->packet_sz; +	fifo_count = musb_ep->packet_sz; + +	/* Check if EP is disabled */ +	if (!musb_ep->desc) { +		dev_dbg(musb->controller, "ep:%s disabled - ignore request\n", +						musb_ep->end_point.name); +		return; +	}  	/* We shouldn't get here while DMA is active, but we do... */  	if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) { -		DBG(4, "DMA pending...\n"); +		dev_dbg(musb->controller, "DMA pending...\n");  		return;  	}  	if (csr & MUSB_RXCSR_P_SENDSTALL) { -		DBG(5, "%s stalling, RXCSR %04x\n", +		dev_dbg(musb->controller, "%s stalling, RXCSR %04x\n",  		    musb_ep->end_point.name, csr);  		return;  	} -	if (is_cppi_enabled() && musb_ep->dma) { +	if (is_cppi_enabled() && is_buffer_mapped(req)) {  		struct dma_controller	*c = musb->dma_controller;  		struct dma_channel	*channel = musb_ep->dma; @@ -611,13 +623,26 @@ static void rxstate(struct musb *musb, struct musb_request *req)  	}  	if (csr & MUSB_RXCSR_RXPKTRDY) { -		len = musb_readw(epio, MUSB_RXCOUNT); +		fifo_count = musb_readw(epio, MUSB_RXCOUNT); + +		/* +		 * Enable Mode 1 on RX transfers only when short_not_ok flag +		 * is set. Currently short_not_ok flag is set only from +		 * file_storage and f_mass_storage drivers +		 */ + +		if (request->short_not_ok && fifo_count == musb_ep->packet_sz) +			use_mode_1 = 1; +		else +			use_mode_1 = 0; +  		if (request->actual < request->length) {  #ifdef CONFIG_USB_INVENTRA_DMA -			if (is_dma_capable() && musb_ep->dma) { +			if (is_buffer_mapped(req)) {  				struct dma_controller	*c;  				struct dma_channel	*channel;  				int			use_dma = 0; +				unsigned int transfer_size;  				c = musb->dma_controller;  				channel = musb_ep->dma; @@ -633,7 +658,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)  	 * most these gadgets, end of is signified either by a short packet,  	 * or filling the last byte of the buffer.  (Sending extra data in  	 * that last pckate should trigger an overflow fault.)  But in mode 1, -	 * we don't get DMA completion interrrupt for short packets. +	 * we don't get DMA completion interrupt for short packets.  	 *  	 * Theoretically, we could enable DMAReq irq (MUSB_RXCSR_DMAMODE = 1),  	 * to get endpoint interrupt on every DMA req, but that didn't seem @@ -643,62 +668,111 @@ static void rxstate(struct musb *musb, struct musb_request *req)  	 * then becomes usable as a runtime "use mode 1" hint...  	 */ -				csr |= MUSB_RXCSR_DMAENAB; -#ifdef USE_MODE1 -				csr |= MUSB_RXCSR_AUTOCLEAR; -				/* csr |= MUSB_RXCSR_DMAMODE; */ - -				/* this special sequence (enabling and then -				 * disabling MUSB_RXCSR_DMAMODE) is required -				 * to get DMAReq to activate -				 */ -				musb_writew(epio, MUSB_RXCSR, -					csr | MUSB_RXCSR_DMAMODE); -#else -				if (!musb_ep->hb_mult && -					musb_ep->hw_ep->rx_double_buffered) +				/* Experimental: Mode1 works with mass storage use cases */ +				if (use_mode_1) {  					csr |= MUSB_RXCSR_AUTOCLEAR; -#endif -				musb_writew(epio, MUSB_RXCSR, csr); +					musb_writew(epio, MUSB_RXCSR, csr); +					csr |= MUSB_RXCSR_DMAENAB; +					musb_writew(epio, MUSB_RXCSR, csr); -				if (request->actual < request->length) { -					int transfer_size = 0; -#ifdef USE_MODE1 -					transfer_size = min(request->length - request->actual, +					/* +					 * this special sequence (enabling and then +					 * disabling MUSB_RXCSR_DMAMODE) is required +					 * to get DMAReq to activate +					 */ +					musb_writew(epio, MUSB_RXCSR, +						csr | MUSB_RXCSR_DMAMODE); +					musb_writew(epio, MUSB_RXCSR, csr); + +					transfer_size = min_t(unsigned int, +							request->length - +							request->actual,  							channel->max_len); -#else +					musb_ep->dma->desired_mode = 1; +				} else { +					if (!musb_ep->hb_mult && +						musb_ep->hw_ep->rx_double_buffered) +						csr |= MUSB_RXCSR_AUTOCLEAR; +					csr |= MUSB_RXCSR_DMAENAB; +					musb_writew(epio, MUSB_RXCSR, csr); +  					transfer_size = min(request->length - request->actual, -							(unsigned)len); -#endif -					if (transfer_size <= musb_ep->packet_sz) -						musb_ep->dma->desired_mode = 0; -					else -						musb_ep->dma->desired_mode = 1; +							(unsigned)fifo_count); +					musb_ep->dma->desired_mode = 0; +				} + +				use_dma = c->channel_program( +						channel, +						musb_ep->packet_sz, +						channel->desired_mode, +						request->dma +						+ request->actual, +						transfer_size); + +				if (use_dma) +					return; +			} +#elif defined(CONFIG_USB_UX500_DMA) +			if ((is_buffer_mapped(req)) && +				(request->actual < request->length)) { -					use_dma = c->channel_program( -							channel, +				struct dma_controller *c; +				struct dma_channel *channel; +				unsigned int transfer_size = 0; + +				c = musb->dma_controller; +				channel = musb_ep->dma; + +				/* In case first packet is short */ +				if (fifo_count < musb_ep->packet_sz) +					transfer_size = fifo_count; +				else if (request->short_not_ok) +					transfer_size =	min_t(unsigned int, +							request->length - +							request->actual, +							channel->max_len); +				else +					transfer_size = min_t(unsigned int, +							request->length - +							request->actual, +							(unsigned)fifo_count); + +				csr &= ~MUSB_RXCSR_DMAMODE; +				csr |= (MUSB_RXCSR_DMAENAB | +					MUSB_RXCSR_AUTOCLEAR); + +				musb_writew(epio, MUSB_RXCSR, csr); + +				if (transfer_size <= musb_ep->packet_sz) { +					musb_ep->dma->desired_mode = 0; +				} else { +					musb_ep->dma->desired_mode = 1; +					/* Mode must be set after DMAENAB */ +					csr |= MUSB_RXCSR_DMAMODE; +					musb_writew(epio, MUSB_RXCSR, csr); +				} + +				if (c->channel_program(channel,  							musb_ep->packet_sz,  							channel->desired_mode,  							request->dma  							+ request->actual, -							transfer_size); -				} +							transfer_size)) -				if (use_dma)  					return;  			}  #endif	/* Mentor's DMA */ -			fifo_count = request->length - request->actual; -			DBG(3, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n", +			len = request->length - request->actual; +			dev_dbg(musb->controller, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n",  					musb_ep->end_point.name, -					len, fifo_count, +					fifo_count, len,  					musb_ep->packet_sz);  			fifo_count = min_t(unsigned, len, fifo_count);  #ifdef	CONFIG_USB_TUSB_OMAP_DMA -			if (tusb_dma_omap() && musb_ep->dma) { +			if (tusb_dma_omap() && is_buffer_mapped(req)) {  				struct dma_controller *c = musb->dma_controller;  				struct dma_channel *channel = musb_ep->dma;  				u32 dma_addr = request->dma + request->actual; @@ -713,6 +787,21 @@ static void rxstate(struct musb *musb, struct musb_request *req)  					return;  			}  #endif +			/* +			 * Unmap the dma buffer back to cpu if dma channel +			 * programming fails. This buffer is mapped if the +			 * channel allocation is successful +			 */ +			 if (is_buffer_mapped(req)) { +				unmap_dma_buffer(req, musb); + +				/* +				 * Clear DMAENAB and AUTOCLEAR for the +				 * PIO mode transfer +				 */ +				csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR); +				musb_writew(epio, MUSB_RXCSR, csr); +			}  			musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *)  					(request->buf + request->actual)); @@ -730,7 +819,8 @@ static void rxstate(struct musb *musb, struct musb_request *req)  	}  	/* reach the end or short packet detected */ -	if (request->actual == request->length || len < musb_ep->packet_sz) +	if (request->actual == request->length || +	    fifo_count < musb_ep->packet_sz)  		musb_g_giveback(musb_ep, request, 0);  } @@ -740,6 +830,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)  void musb_g_rx(struct musb *musb, u8 epnum)  {  	u16			csr; +	struct musb_request	*req;  	struct usb_request	*request;  	void __iomem		*mbase = musb->mregs;  	struct musb_ep		*musb_ep; @@ -754,14 +845,16 @@ void musb_g_rx(struct musb *musb, u8 epnum)  	musb_ep_select(mbase, epnum); -	request = next_request(musb_ep); -	if (!request) +	req = next_request(musb_ep); +	if (!req)  		return; +	request = &req->request; +  	csr = musb_readw(epio, MUSB_RXCSR);  	dma = is_dma_capable() ? musb_ep->dma : NULL; -	DBG(4, "<== %s, rxcsr %04x%s %p\n", musb_ep->end_point.name, +	dev_dbg(musb->controller, "<== %s, rxcsr %04x%s %p\n", musb_ep->end_point.name,  			csr, dma ? " (dma)" : "", request);  	if (csr & MUSB_RXCSR_P_SENTSTALL) { @@ -776,19 +869,18 @@ void musb_g_rx(struct musb *musb, u8 epnum)  		csr &= ~MUSB_RXCSR_P_OVERRUN;  		musb_writew(epio, MUSB_RXCSR, csr); -		DBG(3, "%s iso overrun on %p\n", musb_ep->name, request); +		dev_dbg(musb->controller, "%s iso overrun on %p\n", musb_ep->name, request);  		if (request->status == -EINPROGRESS)  			request->status = -EOVERFLOW;  	}  	if (csr & MUSB_RXCSR_INCOMPRX) {  		/* REVISIT not necessarily an error */ -		DBG(4, "%s, incomprx\n", musb_ep->end_point.name); +		dev_dbg(musb->controller, "%s, incomprx\n", musb_ep->end_point.name);  	}  	if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {  		/* "should not happen"; likely RXPKTRDY pending for DMA */ -		DBG((csr & MUSB_RXCSR_DMAENAB) ? 4 : 1, -			"%s busy, csr %04x\n", +		dev_dbg(musb->controller, "%s busy, csr %04x\n",  			musb_ep->end_point.name, csr);  		return;  	} @@ -802,12 +894,13 @@ void musb_g_rx(struct musb *musb, u8 epnum)  		request->actual += musb_ep->dma->actual_len; -		DBG(4, "RXCSR%d %04x, dma off, %04x, len %zu, req %p\n", +		dev_dbg(musb->controller, "RXCSR%d %04x, dma off, %04x, len %zu, req %p\n",  			epnum, csr,  			musb_readw(epio, MUSB_RXCSR),  			musb_ep->dma->actual_len, request); -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) || \ +	defined(CONFIG_USB_UX500_DMA)  		/* Autoclear doesn't clear RxPktRdy for short packets */  		if ((dma->desired_mode == 0 && !hw_ep->rx_double_buffered)  				|| (dma->actual_len @@ -832,14 +925,26 @@ void musb_g_rx(struct musb *musb, u8 epnum)  		}  #endif  		musb_g_giveback(musb_ep, request, 0); +		/* +		 * In the giveback function the MUSB lock is +		 * released and acquired after sometime. During +		 * this time period the INDEX register could get +		 * changed by the gadget_queue function especially +		 * on SMP systems. Reselect the INDEX to be sure +		 * we are reading/modifying the right registers +		 */ +		musb_ep_select(mbase, epnum); -		request = next_request(musb_ep); -		if (!request) +		req = next_request(musb_ep); +		if (!req)  			return;  	} +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) || \ +	defined(CONFIG_USB_UX500_DMA)  exit: +#endif  	/* Analyze request */ -	rxstate(musb, to_musb_request(request)); +	rxstate(musb, req);  }  /* ------------------------------------------------------------ */ @@ -881,7 +986,7 @@ static int musb_gadget_enable(struct usb_ep *ep,  		goto fail;  	/* REVISIT this rules out high bandwidth periodic transfers */ -	tmp = le16_to_cpu(desc->wMaxPacketSize); +	tmp = usb_endpoint_maxp(desc);  	if (tmp & ~0x07ff) {  		int ok; @@ -891,7 +996,7 @@ static int musb_gadget_enable(struct usb_ep *ep,  			ok = musb->hb_iso_rx;  		if (!ok) { -			DBG(4, "%s: not support ISO high bandwidth\n", __func__); +			dev_dbg(musb->controller, "no support for high bandwidth ISO\n");  			goto fail;  		}  		musb_ep->hb_mult = (tmp >> 11) & 3; @@ -907,7 +1012,6 @@ static int musb_gadget_enable(struct usb_ep *ep,  	 */  	musb_ep_select(mbase, epnum);  	if (usb_endpoint_dir_in(desc)) { -		u16 int_txe = musb_readw(mbase, MUSB_INTRTXE);  		if (hw_ep->is_shared_fifo)  			musb_ep->is_in = 1; @@ -915,12 +1019,12 @@ static int musb_gadget_enable(struct usb_ep *ep,  			goto fail;  		if (tmp > hw_ep->max_packet_sz_tx) { -			DBG(4, "%s: packet size beyond hw fifo size\n", __func__); +			dev_dbg(musb->controller, "packet size beyond hardware FIFO size\n");  			goto fail;  		} -		int_txe |= (1 << epnum); -		musb_writew(mbase, MUSB_INTRTXE, int_txe); +		musb->intrtxe |= (1 << epnum); +		musb_writew(mbase, MUSB_INTRTXE, musb->intrtxe);  		/* REVISIT if can_bulk_split(), use by updating "tmp";  		 * likewise high bandwidth periodic tx @@ -928,7 +1032,15 @@ static int musb_gadget_enable(struct usb_ep *ep,  		/* Set TXMAXP with the FIFO size of the endpoint  		 * to disable double buffering mode.  		 */ -		musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11)); +		if (musb->double_buffer_not_ok) { +			musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx); +		} else { +			if (can_bulk_split(musb, musb_ep->type)) +				musb_ep->hb_mult = (hw_ep->max_packet_sz_tx / +							musb_ep->packet_sz) - 1; +			musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz +					| (musb_ep->hb_mult << 11)); +		}  		csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG;  		if (musb_readw(regs, MUSB_TXCSR) @@ -943,7 +1055,6 @@ static int musb_gadget_enable(struct usb_ep *ep,  		musb_writew(regs, MUSB_TXCSR, csr);  	} else { -		u16 int_rxe = musb_readw(mbase, MUSB_INTRRXE);  		if (hw_ep->is_shared_fifo)  			musb_ep->is_in = 0; @@ -951,12 +1062,12 @@ static int musb_gadget_enable(struct usb_ep *ep,  			goto fail;  		if (tmp > hw_ep->max_packet_sz_rx) { -			DBG(4, "%s: packet size beyond hw fifo size\n", __func__); +			dev_dbg(musb->controller, "packet size beyond hardware FIFO size\n");  			goto fail;  		} -		int_rxe |= (1 << epnum); -		musb_writew(mbase, MUSB_INTRRXE, int_rxe); +		musb->intrrxe |= (1 << epnum); +		musb_writew(mbase, MUSB_INTRRXE, musb->intrrxe);  		/* REVISIT if can_bulk_combine() use by updating "tmp"  		 * likewise high bandwidth periodic rx @@ -964,7 +1075,11 @@ static int musb_gadget_enable(struct usb_ep *ep,  		/* Set RXMAXP with the FIFO size of the endpoint  		 * to disable double buffering mode.  		 */ -		musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11)); +		if (musb->double_buffer_not_ok) +			musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_tx); +		else +			musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz +					| (musb_ep->hb_mult << 11));  		/* force shared fifo to OUT-only mode */  		if (hw_ep->is_shared_fifo) { @@ -1006,7 +1121,7 @@ static int musb_gadget_enable(struct usb_ep *ep,  			case USB_ENDPOINT_XFER_BULK:	s = "bulk"; break;  			case USB_ENDPOINT_XFER_INT:	s = "int"; break;  			default:			s = "iso"; break; -			}; s; }), +			} s; }),  			musb_ep->is_in ? "IN" : "OUT",  			musb_ep->dma ? "dma, " : "",  			musb_ep->packet_sz); @@ -1040,18 +1155,17 @@ static int musb_gadget_disable(struct usb_ep *ep)  	/* zero the endpoint sizes */  	if (musb_ep->is_in) { -		u16 int_txe = musb_readw(musb->mregs, MUSB_INTRTXE); -		int_txe &= ~(1 << epnum); -		musb_writew(musb->mregs, MUSB_INTRTXE, int_txe); +		musb->intrtxe &= ~(1 << epnum); +		musb_writew(musb->mregs, MUSB_INTRTXE, musb->intrtxe);  		musb_writew(epio, MUSB_TXMAXP, 0);  	} else { -		u16 int_rxe = musb_readw(musb->mregs, MUSB_INTRRXE); -		int_rxe &= ~(1 << epnum); -		musb_writew(musb->mregs, MUSB_INTRRXE, int_rxe); +		musb->intrrxe &= ~(1 << epnum); +		musb_writew(musb->mregs, MUSB_INTRRXE, musb->intrrxe);  		musb_writew(epio, MUSB_RXMAXP, 0);  	}  	musb_ep->desc = NULL; +	musb_ep->end_point.desc = NULL;  	/* abort all pending DMA and requests */  	nuke(musb_ep, -ESHUTDOWN); @@ -1060,7 +1174,7 @@ static int musb_gadget_disable(struct usb_ep *ep)  	spin_unlock_irqrestore(&(musb->lock), flags); -	DBG(2, "%s\n", musb_ep->end_point.name); +	dev_dbg(musb->controller, "%s\n", musb_ep->end_point.name);  	return status;  } @@ -1072,16 +1186,19 @@ static int musb_gadget_disable(struct usb_ep *ep)  struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)  {  	struct musb_ep		*musb_ep = to_musb_ep(ep); +	struct musb		*musb = musb_ep->musb;  	struct musb_request	*request = NULL;  	request = kzalloc(sizeof *request, gfp_flags); -	if (request) { -		INIT_LIST_HEAD(&request->request.list); -		request->request.dma = DMA_ADDR_INVALID; -		request->epnum = musb_ep->current_epnum; -		request->ep = musb_ep; +	if (!request) { +		dev_dbg(musb->controller, "not enough memory\n"); +		return NULL;  	} +	request->request.dma = DMA_ADDR_INVALID; +	request->epnum = musb_ep->current_epnum; +	request->ep = musb_ep; +  	return &request->request;  } @@ -1108,7 +1225,7 @@ struct free_record {   */  void musb_ep_restart(struct musb *musb, struct musb_request *req)  { -	DBG(3, "<== %s request %p len %u on hw_ep%d\n", +	dev_dbg(musb->controller, "<== %s request %p len %u on hw_ep%d\n",  		req->tx ? "TX/IN" : "RX/OUT",  		&req->request, req->request.length, req->epnum); @@ -1142,7 +1259,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,  	if (request->ep != musb_ep)  		return -EINVAL; -	DBG(4, "<== to %s request=%p\n", ep->name, req); +	dev_dbg(musb->controller, "<== to %s request=%p\n", ep->name, req);  	/* request is mine now... */  	request->request.actual = 0; @@ -1150,46 +1267,27 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,  	request->epnum = musb_ep->current_epnum;  	request->tx = musb_ep->is_in; -	if (is_dma_capable() && musb_ep->dma) { -		if (request->request.dma == DMA_ADDR_INVALID) { -			request->request.dma = dma_map_single( -					musb->controller, -					request->request.buf, -					request->request.length, -					request->tx -						? DMA_TO_DEVICE -						: DMA_FROM_DEVICE); -			request->mapped = 1; -		} else { -			dma_sync_single_for_device(musb->controller, -					request->request.dma, -					request->request.length, -					request->tx -						? DMA_TO_DEVICE -						: DMA_FROM_DEVICE); -			request->mapped = 0; -		} -	} else -		request->mapped = 0; +	map_dma_buffer(request, musb, musb_ep);  	spin_lock_irqsave(&musb->lock, lockflags);  	/* don't queue if the ep is down */  	if (!musb_ep->desc) { -		DBG(4, "req %p queued to %s while ep %s\n", +		dev_dbg(musb->controller, "req %p queued to %s while ep %s\n",  				req, ep->name, "disabled");  		status = -ESHUTDOWN; -		goto cleanup; +		unmap_dma_buffer(request, musb); +		goto unlock;  	}  	/* add request to the list */ -	list_add_tail(&(request->request.list), &(musb_ep->req_list)); +	list_add_tail(&request->list, &musb_ep->req_list);  	/* it this is the head of the queue, start i/o ... */ -	if (!musb_ep->busy && &request->request.list == musb_ep->req_list.next) +	if (!musb_ep->busy && &request->list == musb_ep->req_list.next)  		musb_ep_restart(musb, request); -cleanup: +unlock:  	spin_unlock_irqrestore(&musb->lock, lockflags);  	return status;  } @@ -1197,7 +1295,8 @@ cleanup:  static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *request)  {  	struct musb_ep		*musb_ep = to_musb_ep(ep); -	struct usb_request	*r; +	struct musb_request	*req = to_musb_request(request); +	struct musb_request	*r;  	unsigned long		flags;  	int			status = 0;  	struct musb		*musb = musb_ep->musb; @@ -1208,17 +1307,17 @@ static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *request)  	spin_lock_irqsave(&musb->lock, flags);  	list_for_each_entry(r, &musb_ep->req_list, list) { -		if (r == request) +		if (r == req)  			break;  	} -	if (r != request) { -		DBG(3, "request %p not queued to %s\n", request, ep->name); +	if (r != req) { +		dev_dbg(musb->controller, "request %p not queued to %s\n", request, ep->name);  		status = -EINVAL;  		goto done;  	}  	/* if the hardware doesn't have the request, easy ... */ -	if (musb_ep->req_list.next != &request->list || musb_ep->busy) +	if (musb_ep->req_list.next != &req->list || musb_ep->busy)  		musb_g_giveback(musb_ep, request, -ECONNRESET);  	/* ... else abort the dma transfer ... */ @@ -1275,10 +1374,10 @@ static int musb_gadget_set_halt(struct usb_ep *ep, int value)  	musb_ep_select(mbase, epnum); -	request = to_musb_request(next_request(musb_ep)); +	request = next_request(musb_ep);  	if (value) {  		if (request) { -			DBG(3, "request in progress, cannot halt %s\n", +			dev_dbg(musb->controller, "request in progress, cannot halt %s\n",  			    ep->name);  			status = -EAGAIN;  			goto done; @@ -1287,7 +1386,7 @@ static int musb_gadget_set_halt(struct usb_ep *ep, int value)  		if (musb_ep->is_in) {  			csr = musb_readw(epio, MUSB_TXCSR);  			if (csr & MUSB_TXCSR_FIFONOTEMPTY) { -				DBG(3, "FIFO busy, cannot halt %s\n", ep->name); +				dev_dbg(musb->controller, "FIFO busy, cannot halt %s\n", ep->name);  				status = -EAGAIN;  				goto done;  			} @@ -1296,7 +1395,7 @@ static int musb_gadget_set_halt(struct usb_ep *ep, int value)  		musb_ep->wedged = 0;  	/* set/clear the stall and toggle bits */ -	DBG(2, "%s: %s stall\n", ep->name, value ? "set" : "clear"); +	dev_dbg(musb->controller, "%s: %s stall\n", ep->name, value ? "set" : "clear");  	if (musb_ep->is_in) {  		csr = musb_readw(epio, MUSB_TXCSR);  		csr |= MUSB_TXCSR_P_WZC_BITS @@ -1323,7 +1422,7 @@ static int musb_gadget_set_halt(struct usb_ep *ep, int value)  	/* maybe start the first request in the queue */  	if (!musb_ep->busy && !value && request) { -		DBG(3, "restarting the request\n"); +		dev_dbg(musb->controller, "restarting the request\n");  		musb_ep_restart(musb, request);  	} @@ -1378,7 +1477,7 @@ static void musb_gadget_fifo_flush(struct usb_ep *ep)  	void __iomem	*epio = musb->endpoints[epnum].regs;  	void __iomem	*mbase;  	unsigned long	flags; -	u16		csr, int_txe; +	u16		csr;  	mbase = musb->mregs; @@ -1386,13 +1485,18 @@ static void musb_gadget_fifo_flush(struct usb_ep *ep)  	musb_ep_select(mbase, (u8) epnum);  	/* disable interrupts */ -	int_txe = musb_readw(mbase, MUSB_INTRTXE); -	musb_writew(mbase, MUSB_INTRTXE, int_txe & ~(1 << epnum)); +	musb_writew(mbase, MUSB_INTRTXE, musb->intrtxe & ~(1 << epnum));  	if (musb_ep->is_in) {  		csr = musb_readw(epio, MUSB_TXCSR);  		if (csr & MUSB_TXCSR_FIFONOTEMPTY) {  			csr |= MUSB_TXCSR_FLUSHFIFO | MUSB_TXCSR_P_WZC_BITS; +			/* +			 * Setting both TXPKTRDY and FLUSHFIFO makes controller +			 * to interrupt current FIFO loading, but not flushing +			 * the already loaded ones. +			 */ +			csr &= ~MUSB_TXCSR_TXPKTRDY;  			musb_writew(epio, MUSB_TXCSR, csr);  			/* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */  			musb_writew(epio, MUSB_TXCSR, csr); @@ -1405,7 +1509,7 @@ static void musb_gadget_fifo_flush(struct usb_ep *ep)  	}  	/* re-enable interrupt */ -	musb_writew(mbase, MUSB_INTRTXE, int_txe); +	musb_writew(mbase, MUSB_INTRTXE, musb->intrtxe);  	spin_unlock_irqrestore(&musb->lock, flags);  } @@ -1454,7 +1558,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)  	case OTG_STATE_B_IDLE:  		/* Start SRP ... OTG not required. */  		devctl = musb_readb(mregs, MUSB_DEVCTL); -		DBG(2, "Sending SRP: devctl: %02x\n", devctl); +		dev_dbg(musb->controller, "Sending SRP: devctl: %02x\n", devctl);  		devctl |= MUSB_DEVCTL_SESSION;  		musb_writeb(mregs, MUSB_DEVCTL, devctl);  		devctl = musb_readb(mregs, MUSB_DEVCTL); @@ -1471,6 +1575,10 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)  				break;  		} +		spin_unlock_irqrestore(&musb->lock, flags); +		otg_start_srp(musb->xceiv->otg); +		spin_lock_irqsave(&musb->lock, flags); +  		/* Block idling for at least 1s */  		musb_platform_try_idle(musb,  			jiffies + msecs_to_jiffies(1 * HZ)); @@ -1478,7 +1586,8 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)  		status = 0;  		goto done;  	default: -		DBG(2, "Unhandled wake: %s\n", otg_state_string(musb)); +		dev_dbg(musb->controller, "Unhandled wake: %s\n", +			usb_otg_state_string(musb->xceiv->state));  		goto done;  	} @@ -1487,7 +1596,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)  	power = musb_readb(mregs, MUSB_POWER);  	power |= MUSB_POWER_RESUME;  	musb_writeb(mregs, MUSB_POWER, power); -	DBG(2, "issue wakeup\n"); +	dev_dbg(musb->controller, "issue wakeup\n");  	/* FIXME do this next chunk in a timer callback, no udelay */  	mdelay(2); @@ -1521,15 +1630,15 @@ static void musb_pullup(struct musb *musb, int is_on)  	/* FIXME if on, HdrcStart; if off, HdrcStop */ -	DBG(3, "gadget %s D+ pullup %s\n", -		musb->gadget_driver->function, is_on ? "on" : "off"); +	dev_dbg(musb->controller, "gadget D+ pullup %s\n", +		is_on ? "on" : "off");  	musb_writeb(musb->mregs, MUSB_POWER, power);  }  #if 0  static int musb_gadget_vbus_session(struct usb_gadget *gadget, int is_active)  { -	DBG(2, "<= %s =>\n", __func__); +	dev_dbg(musb->controller, "<= %s =>\n", __func__);  	/*  	 * FIXME iff driver's softconnect flag is set (as it is during probe, @@ -1546,7 +1655,7 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)  	if (!musb->xceiv->set_power)  		return -EOPNOTSUPP; -	return otg_set_power(musb->xceiv, mA); +	return usb_phy_set_power(musb->xceiv, mA);  }  static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on) @@ -1556,6 +1665,8 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)  	is_on = !!is_on; +	pm_runtime_get_sync(musb->controller); +  	/* NOTE: this assumes we are sensing vbus; we'd rather  	 * not pullup unless the B-session is active.  	 */ @@ -1565,9 +1676,17 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)  		musb_pullup(musb, is_on);  	}  	spin_unlock_irqrestore(&musb->lock, flags); + +	pm_runtime_put(musb->controller); +  	return 0;  } +static int musb_gadget_start(struct usb_gadget *g, +		struct usb_gadget_driver *driver); +static int musb_gadget_stop(struct usb_gadget *g, +		struct usb_gadget_driver *driver); +  static const struct usb_gadget_ops musb_gadget_operations = {  	.get_frame		= musb_gadget_get_frame,  	.wakeup			= musb_gadget_wakeup, @@ -1575,6 +1694,8 @@ static const struct usb_gadget_ops musb_gadget_operations = {  	/* .vbus_session		= musb_gadget_vbus_session, */  	.vbus_draw		= musb_gadget_vbus_draw,  	.pullup			= musb_gadget_pullup, +	.udc_start		= musb_gadget_start, +	.udc_stop		= musb_gadget_stop,  };  /* ----------------------------------------------------------------------- */ @@ -1585,16 +1706,8 @@ static const struct usb_gadget_ops musb_gadget_operations = {   * about there being only one external upstream port.  It assumes   * all peripheral ports are external...   */ -static struct musb *the_gadget; - -static void musb_gadget_release(struct device *dev) -{ -	/* kref_put(WHAT) */ -	dev_dbg(dev, "%s\n", __func__); -} - -static void __init +static void  init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)  {  	struct musb_hw_ep	*hw_ep = musb->endpoints + epnum; @@ -1614,14 +1727,14 @@ init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)  	ep->end_point.name = ep->name;  	INIT_LIST_HEAD(&ep->end_point.ep_list);  	if (!epnum) { -		ep->end_point.maxpacket = 64; +		usb_ep_set_maxpacket_limit(&ep->end_point, 64);  		ep->end_point.ops = &musb_g_ep0_ops;  		musb->g.ep0 = &ep->end_point;  	} else {  		if (is_in) -			ep->end_point.maxpacket = hw_ep->max_packet_sz_tx; +			usb_ep_set_maxpacket_limit(&ep->end_point, hw_ep->max_packet_sz_tx);  		else -			ep->end_point.maxpacket = hw_ep->max_packet_sz_rx; +			usb_ep_set_maxpacket_limit(&ep->end_point, hw_ep->max_packet_sz_rx);  		ep->end_point.ops = &musb_ep_ops;  		list_add_tail(&ep->end_point.ep_list, &musb->g.ep_list);  	} @@ -1631,13 +1744,13 @@ init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)   * Initialize the endpoints exposed to peripheral drivers, with backlinks   * to the rest of the driver state.   */ -static inline void __init musb_g_init_endpoints(struct musb *musb) +static inline void musb_g_init_endpoints(struct musb *musb)  {  	u8			epnum;  	struct musb_hw_ep	*hw_ep;  	unsigned		count = 0; -	/* intialize endpoint list just once */ +	/* initialize endpoint list just once */  	INIT_LIST_HEAD(&(musb->g.ep_list));  	for (epnum = 0, hw_ep = musb->endpoints; @@ -1664,7 +1777,7 @@ static inline void __init musb_g_init_endpoints(struct musb *musb)  /* called once during driver setup to initialize and link into   * the driver model; memory is zeroed.   */ -int __init musb_gadget_setup(struct musb *musb) +int musb_gadget_setup(struct musb *musb)  {  	int status; @@ -1672,44 +1785,44 @@ int __init musb_gadget_setup(struct musb *musb)  	 * musb peripherals at the same time, only the bus lock  	 * is probably held.  	 */ -	if (the_gadget) -		return -EBUSY; -	the_gadget = musb;  	musb->g.ops = &musb_gadget_operations; -	musb->g.is_dualspeed = 1; +	musb->g.max_speed = USB_SPEED_HIGH;  	musb->g.speed = USB_SPEED_UNKNOWN; +	MUSB_DEV_MODE(musb); +	musb->xceiv->otg->default_a = 0; +	musb->xceiv->state = OTG_STATE_B_IDLE; +  	/* this "gadget" abstracts/virtualizes the controller */ -	dev_set_name(&musb->g.dev, "gadget"); -	musb->g.dev.parent = musb->controller; -	musb->g.dev.dma_mask = musb->controller->dma_mask; -	musb->g.dev.release = musb_gadget_release;  	musb->g.name = musb_driver_name; - -	if (is_otg_enabled(musb)) -		musb->g.is_otg = 1; +#if IS_ENABLED(CONFIG_USB_MUSB_DUAL_ROLE) +	musb->g.is_otg = 1; +#elif IS_ENABLED(CONFIG_USB_MUSB_GADGET) +	musb->g.is_otg = 0; +#endif  	musb_g_init_endpoints(musb);  	musb->is_active = 0;  	musb_platform_try_idle(musb, 0); -	status = device_register(&musb->g.dev); -	if (status != 0) { -		put_device(&musb->g.dev); -		the_gadget = NULL; -	} +	status = usb_add_gadget_udc(musb->controller, &musb->g); +	if (status) +		goto err; + +	return 0; +err: +	musb->g.dev.parent = NULL; +	device_unregister(&musb->g.dev);  	return status;  }  void musb_gadget_cleanup(struct musb *musb)  { -	if (musb != the_gadget) +	if (musb->port_mode == MUSB_PORT_MODE_HOST)  		return; - -	device_unregister(&musb->g.dev); -	the_gadget = NULL; +	usb_del_gadget_udc(&musb->g);  }  /* @@ -1718,98 +1831,55 @@ void musb_gadget_cleanup(struct musb *musb)   *   * -EINVAL something went wrong (not driver)   * -EBUSY another gadget is already using the controller - * -ENOMEM no memeory to perform the operation + * -ENOMEM no memory to perform the operation   *   * @param driver the gadget driver - * @param bind the driver's bind function   * @return <0 if error, 0 if everything is fine   */ -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, -		int (*bind)(struct usb_gadget *)) +static int musb_gadget_start(struct usb_gadget *g, +		struct usb_gadget_driver *driver)  { -	int retval; -	unsigned long flags; -	struct musb *musb = the_gadget; - -	if (!driver -			|| driver->speed != USB_SPEED_HIGH -			|| !bind || !driver->setup) -		return -EINVAL; - -	/* driver must be initialized to support peripheral mode */ -	if (!musb) { -		DBG(1, "%s, no dev??\n", __func__); -		return -ENODEV; -	} - -	DBG(3, "registering driver %s\n", driver->function); -	spin_lock_irqsave(&musb->lock, flags); +	struct musb		*musb = gadget_to_musb(g); +	struct usb_otg		*otg = musb->xceiv->otg; +	unsigned long		flags; +	int			retval = 0; -	if (musb->gadget_driver) { -		DBG(1, "%s is already bound to %s\n", -				musb_driver_name, -				musb->gadget_driver->driver.name); -		retval = -EBUSY; -	} else { -		musb->gadget_driver = driver; -		musb->g.dev.driver = &driver->driver; -		driver->driver.bus = NULL; -		musb->softconnect = 1; -		retval = 0; +	if (driver->max_speed < USB_SPEED_HIGH) { +		retval = -EINVAL; +		goto err;  	} -	spin_unlock_irqrestore(&musb->lock, flags); - -	if (retval == 0) { -		retval = bind(&musb->g); -		if (retval != 0) { -			DBG(3, "bind to driver %s failed --> %d\n", -					driver->driver.name, retval); -			musb->gadget_driver = NULL; -			musb->g.dev.driver = NULL; -		} +	pm_runtime_get_sync(musb->controller); -		spin_lock_irqsave(&musb->lock, flags); +	dev_dbg(musb->controller, "registering driver %s\n", driver->function); -		otg_set_peripheral(musb->xceiv, &musb->g); -		musb->xceiv->state = OTG_STATE_B_IDLE; -		musb->is_active = 1; +	musb->softconnect = 0; +	musb->gadget_driver = driver; -		/* FIXME this ignores the softconnect flag.  Drivers are -		 * allowed hold the peripheral inactive until for example -		 * userspace hooks up printer hardware or DSP codecs, so -		 * hosts only see fully functional devices. -		 */ +	spin_lock_irqsave(&musb->lock, flags); +	musb->is_active = 1; -		if (!is_otg_enabled(musb)) -			musb_start(musb); +	otg_set_peripheral(otg, &musb->g); +	musb->xceiv->state = OTG_STATE_B_IDLE; +	spin_unlock_irqrestore(&musb->lock, flags); -		otg_set_peripheral(musb->xceiv, &musb->g); +	musb_start(musb); -		spin_unlock_irqrestore(&musb->lock, flags); +	/* REVISIT:  funcall to other code, which also +	 * handles power budgeting ... this way also +	 * ensures HdrcStart is indirectly called. +	 */ +	if (musb->xceiv->last_event == USB_EVENT_ID) +		musb_platform_set_vbus(musb, 1); -		if (is_otg_enabled(musb)) { -			DBG(3, "OTG startup...\n"); +	if (musb->xceiv->last_event == USB_EVENT_NONE) +		pm_runtime_put(musb->controller); -			/* REVISIT:  funcall to other code, which also -			 * handles power budgeting ... this way also -			 * ensures HdrcStart is indirectly called. -			 */ -			retval = usb_add_hcd(musb_to_hcd(musb), -1, 0); -			if (retval < 0) { -				DBG(1, "add_hcd failed, %d\n", retval); -				spin_lock_irqsave(&musb->lock, flags); -				otg_set_peripheral(musb->xceiv, NULL); -				musb->gadget_driver = NULL; -				musb->g.dev.driver = NULL; -				spin_unlock_irqrestore(&musb->lock, flags); -			} -		} -	} +	return 0; +err:  	return retval;  } -EXPORT_SYMBOL(usb_gadget_probe_driver);  static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver)  { @@ -1846,10 +1916,6 @@ static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver)  					nuke(&hw_ep->ep_out, -ESHUTDOWN);  			}  		} - -		spin_unlock(&musb->lock); -		driver->disconnect(&musb->g); -		spin_lock(&musb->lock);  	}  } @@ -1859,59 +1925,48 @@ static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver)   *   * @param driver the gadget driver to unregister   */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int musb_gadget_stop(struct usb_gadget *g, +		struct usb_gadget_driver *driver)  { +	struct musb	*musb = gadget_to_musb(g);  	unsigned long	flags; -	int		retval = 0; -	struct musb	*musb = the_gadget; -	if (!driver || !driver->unbind || !musb) -		return -EINVAL; +	if (musb->xceiv->last_event == USB_EVENT_NONE) +		pm_runtime_get_sync(musb->controller); -	/* REVISIT always use otg_set_peripheral() here too; +	/* +	 * REVISIT always use otg_set_peripheral() here too;  	 * this needs to shut down the OTG engine.  	 */  	spin_lock_irqsave(&musb->lock, flags); -#ifdef	CONFIG_USB_MUSB_OTG  	musb_hnp_stop(musb); -#endif - -	if (musb->gadget_driver == driver) { - -		(void) musb_gadget_vbus_draw(&musb->g, 0); -		musb->xceiv->state = OTG_STATE_UNDEFINED; -		stop_activity(musb, driver); -		otg_set_peripheral(musb->xceiv, NULL); +	(void) musb_gadget_vbus_draw(&musb->g, 0); -		DBG(3, "unregistering driver %s\n", driver->function); -		spin_unlock_irqrestore(&musb->lock, flags); -		driver->unbind(&musb->g); -		spin_lock_irqsave(&musb->lock, flags); +	musb->xceiv->state = OTG_STATE_UNDEFINED; +	stop_activity(musb, driver); +	otg_set_peripheral(musb->xceiv->otg, NULL); -		musb->gadget_driver = NULL; -		musb->g.dev.driver = NULL; +	dev_dbg(musb->controller, "unregistering driver %s\n", +				  driver ? driver->function : "(removed)"); -		musb->is_active = 0; -		musb_platform_try_idle(musb, 0); -	} else -		retval = -EINVAL; +	musb->is_active = 0; +	musb->gadget_driver = NULL; +	musb_platform_try_idle(musb, 0);  	spin_unlock_irqrestore(&musb->lock, flags); -	if (is_otg_enabled(musb) && retval == 0) { -		usb_remove_hcd(musb_to_hcd(musb)); -		/* FIXME we need to be able to register another -		 * gadget driver here and have everything work; -		 * that currently misbehaves. -		 */ -	} +	/* +	 * FIXME we need to be able to register another +	 * gadget driver here and have everything work; +	 * that currently misbehaves. +	 */ -	return retval; -} -EXPORT_SYMBOL(usb_gadget_unregister_driver); +	pm_runtime_put(musb->controller); +	return 0; +}  /* ----------------------------------------------------------------------- */ @@ -1934,7 +1989,7 @@ void musb_g_resume(struct musb *musb)  		break;  	default:  		WARNING("unhandled RESUME transition (%s)\n", -				otg_state_string(musb)); +				usb_otg_state_string(musb->xceiv->state));  	}  } @@ -1944,7 +1999,7 @@ void musb_g_suspend(struct musb *musb)  	u8	devctl;  	devctl = musb_readb(musb->mregs, MUSB_DEVCTL); -	DBG(3, "devctl %02x\n", devctl); +	dev_dbg(musb->controller, "devctl %02x\n", devctl);  	switch (musb->xceiv->state) {  	case OTG_STATE_B_IDLE: @@ -1964,7 +2019,7 @@ void musb_g_suspend(struct musb *musb)  		 * A_PERIPHERAL may need care too  		 */  		WARNING("unhandled SUSPEND transition (%s)\n", -				otg_state_string(musb)); +				usb_otg_state_string(musb->xceiv->state));  	}  } @@ -1980,7 +2035,7 @@ void musb_g_disconnect(struct musb *musb)  	void __iomem	*mregs = musb->mregs;  	u8	devctl = musb_readb(mregs, MUSB_DEVCTL); -	DBG(3, "devctl %02x\n", devctl); +	dev_dbg(musb->controller, "devctl %02x\n", devctl);  	/* clear HR */  	musb_writeb(mregs, MUSB_DEVCTL, devctl & MUSB_DEVCTL_SESSION); @@ -1997,9 +2052,8 @@ void musb_g_disconnect(struct musb *musb)  	switch (musb->xceiv->state) {  	default: -#ifdef	CONFIG_USB_MUSB_OTG -		DBG(2, "Unhandled disconnect %s, setting a_idle\n", -			otg_state_string(musb)); +		dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n", +			usb_otg_state_string(musb->xceiv->state));  		musb->xceiv->state = OTG_STATE_A_IDLE;  		MUSB_HST_MODE(musb);  		break; @@ -2009,7 +2063,6 @@ void musb_g_disconnect(struct musb *musb)  		break;  	case OTG_STATE_B_WAIT_ACON:  	case OTG_STATE_B_HOST: -#endif  	case OTG_STATE_B_PERIPHERAL:  	case OTG_STATE_B_IDLE:  		musb->xceiv->state = OTG_STATE_B_IDLE; @@ -2029,10 +2082,9 @@ __acquires(musb->lock)  	u8		devctl = musb_readb(mbase, MUSB_DEVCTL);  	u8		power; -	DBG(3, "<== %s addr=%x driver '%s'\n", +	dev_dbg(musb->controller, "<== %s driver '%s'\n",  			(devctl & MUSB_DEVCTL_BDEVICE)  				? "B-Device" : "A-Device", -			musb_readb(mbase, MUSB_FADDR),  			musb->gadget_driver  				? musb->gadget_driver->driver.name  				: NULL @@ -2067,16 +2119,22 @@ __acquires(musb->lock)  	/* Normal reset, as B-Device;  	 * or else after HNP, as A-Device  	 */ -	if (devctl & MUSB_DEVCTL_BDEVICE) { +	if (!musb->g.is_otg) { +		/* USB device controllers that are not OTG compatible +		 * may not have DEVCTL register in silicon. +		 * In that case, do not rely on devctl for setting +		 * peripheral mode. +		 */ +		musb->xceiv->state = OTG_STATE_B_PERIPHERAL; +		musb->g.is_a_peripheral = 0; +	} else if (devctl & MUSB_DEVCTL_BDEVICE) {  		musb->xceiv->state = OTG_STATE_B_PERIPHERAL;  		musb->g.is_a_peripheral = 0; -	} else if (is_otg_enabled(musb)) { +	} else {  		musb->xceiv->state = OTG_STATE_A_PERIPHERAL;  		musb->g.is_a_peripheral = 1; -	} else -		WARN_ON(1); +	}  	/* start with default limits on VBUS power draw */ -	(void) musb_gadget_vbus_draw(&musb->g, -			is_otg_enabled(musb) ? 8 : 100); +	(void) musb_gadget_vbus_draw(&musb->g, 8);  } diff --git a/drivers/usb/musb/musb_gadget.h b/drivers/usb/musb/musb_gadget.h index dec8dc00819..0314dfc770c 100644 --- a/drivers/usb/musb/musb_gadget.h +++ b/drivers/usb/musb/musb_gadget.h @@ -35,13 +35,54 @@  #ifndef __MUSB_GADGET_H  #define __MUSB_GADGET_H +#include <linux/list.h> + +#if IS_ENABLED(CONFIG_USB_MUSB_GADGET) || IS_ENABLED(CONFIG_USB_MUSB_DUAL_ROLE) +extern irqreturn_t musb_g_ep0_irq(struct musb *); +extern void musb_g_tx(struct musb *, u8); +extern void musb_g_rx(struct musb *, u8); +extern void musb_g_reset(struct musb *); +extern void musb_g_suspend(struct musb *); +extern void musb_g_resume(struct musb *); +extern void musb_g_wakeup(struct musb *); +extern void musb_g_disconnect(struct musb *); +extern void musb_gadget_cleanup(struct musb *); +extern int musb_gadget_setup(struct musb *); + +#else +static inline irqreturn_t musb_g_ep0_irq(struct musb *musb) +{ +	return 0; +} + +static inline void musb_g_tx(struct musb *musb, u8 epnum)	{} +static inline void musb_g_rx(struct musb *musb, u8 epnum)	{} +static inline void musb_g_reset(struct musb *musb)		{} +static inline void musb_g_suspend(struct musb *musb)		{} +static inline void musb_g_resume(struct musb *musb)		{} +static inline void musb_g_wakeup(struct musb *musb)		{} +static inline void musb_g_disconnect(struct musb *musb)		{} +static inline void musb_gadget_cleanup(struct musb *musb)	{} +static inline int musb_gadget_setup(struct musb *musb) +{ +	return 0; +} +#endif + +enum buffer_map_state { +	UN_MAPPED = 0, +	PRE_MAPPED, +	MUSB_MAPPED +}; +  struct musb_request {  	struct usb_request	request; +	struct list_head	list;  	struct musb_ep		*ep;  	struct musb		*musb;  	u8 tx;			/* endpoint direction */  	u8 epnum; -	u8 mapped; +	enum buffer_map_state map_state;  };  static inline struct musb_request *to_musb_request(struct usb_request *req) @@ -88,23 +129,17 @@ static inline struct musb_ep *to_musb_ep(struct usb_ep *ep)  	return ep ? container_of(ep, struct musb_ep, end_point) : NULL;  } -static inline struct usb_request *next_request(struct musb_ep *ep) +static inline struct musb_request *next_request(struct musb_ep *ep)  {  	struct list_head	*queue = &ep->req_list;  	if (list_empty(queue))  		return NULL; -	return container_of(queue->next, struct usb_request, list); +	return container_of(queue->next, struct musb_request, list);  } -extern void musb_g_tx(struct musb *musb, u8 epnum); -extern void musb_g_rx(struct musb *musb, u8 epnum); -  extern const struct usb_ep_ops musb_g_ep0_ops; -extern int musb_gadget_setup(struct musb *); -extern void musb_gadget_cleanup(struct musb *); -  extern void musb_g_giveback(struct musb_ep *, struct usb_request *, int);  extern void musb_ep_restart(struct musb *, struct musb_request *); diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index 6dd03f4c5f4..2af45a0c893 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -37,7 +37,6 @@  #include <linux/list.h>  #include <linux/timer.h>  #include <linux/spinlock.h> -#include <linux/init.h>  #include <linux/device.h>  #include <linux/interrupt.h> @@ -88,7 +87,6 @@ static int service_tx_status_request(  	case USB_RECIP_DEVICE:  		result[0] = musb->is_self_powered << USB_DEVICE_SELF_POWERED;  		result[0] |= musb->may_wakeup << USB_DEVICE_REMOTE_WAKEUP; -#ifdef CONFIG_USB_MUSB_OTG  		if (musb->g.is_otg) {  			result[0] |= musb->g.b_hnp_enable  				<< USB_DEVICE_B_HNP_ENABLE; @@ -97,7 +95,6 @@ static int service_tx_status_request(  			result[0] |= musb->g.a_hnp_support  				<< USB_DEVICE_A_HNP_SUPPORT;  		} -#endif  		break;  	case USB_RECIP_INTERFACE: @@ -209,7 +206,7 @@ static inline void musb_try_b_hnp_enable(struct musb *musb)  	void __iomem	*mbase = musb->mregs;  	u8		devctl; -	DBG(1, "HNP: Setting HR\n"); +	dev_dbg(musb->controller, "HNP: Setting HR\n");  	devctl = musb_readb(mbase, MUSB_DEVCTL);  	musb_writeb(mbase, MUSB_DEVCTL, devctl | MUSB_DEVCTL_HR);  } @@ -304,10 +301,9 @@ __acquires(musb->lock)  				}  				/* Maybe start the first request in the queue */ -				request = to_musb_request( -						next_request(musb_ep)); +				request = next_request(musb_ep);  				if (!musb_ep->busy && request) { -					DBG(3, "restarting the request\n"); +					dev_dbg(musb->controller, "restarting the request\n");  					musb_ep_restart(musb, request);  				} @@ -393,7 +389,6 @@ __acquires(musb->lock)  					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; @@ -410,7 +405,6 @@ __acquires(musb->lock)  						goto stall;  					musb->g.a_alt_hnp_support = 1;  					break; -#endif  				case USB_DEVICE_DEBUG_MODE:  					handled = 0;  					break; @@ -491,10 +485,12 @@ stall:  static void ep0_rxstate(struct musb *musb)  {  	void __iomem		*regs = musb->control_ep->regs; +	struct musb_request	*request;  	struct usb_request	*req;  	u16			count, csr; -	req = next_ep0_request(musb); +	request = next_ep0_request(musb); +	req = &request->request;  	/* read packet and ack; or stall because of gadget driver bug:  	 * should have provided the rx buffer before setup() returned. @@ -509,8 +505,10 @@ static void ep0_rxstate(struct musb *musb)  			req->status = -EOVERFLOW;  			count = len;  		} -		musb_read_fifo(&musb->endpoints[0], count, buf); -		req->actual += count; +		if (count > 0) { +			musb_read_fifo(&musb->endpoints[0], count, buf); +			req->actual += count; +		}  		csr = MUSB_CSR0_P_SVDRXPKTRDY;  		if (count < 64 || req->actual == req->length) {  			musb->ep0_state = MUSB_EP0_STAGE_STATUSIN; @@ -544,17 +542,20 @@ static void ep0_rxstate(struct musb *musb)  static void ep0_txstate(struct musb *musb)  {  	void __iomem		*regs = musb->control_ep->regs; -	struct usb_request	*request = next_ep0_request(musb); +	struct musb_request	*req = next_ep0_request(musb); +	struct usb_request	*request;  	u16			csr = MUSB_CSR0_TXPKTRDY;  	u8			*fifo_src;  	u8			fifo_count; -	if (!request) { +	if (!req) {  		/* WARN_ON(1); */ -		DBG(2, "odd; csr0 %04x\n", musb_readw(regs, MUSB_CSR0)); +		dev_dbg(musb->controller, "odd; csr0 %04x\n", musb_readw(regs, MUSB_CSR0));  		return;  	} +	request = &req->request; +  	/* load the data */  	fifo_src = (u8 *) request->buf + request->actual;  	fifo_count = min((unsigned) MUSB_EP0_FIFOSIZE, @@ -598,7 +599,7 @@ static void ep0_txstate(struct musb *musb)  static void  musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req)  { -	struct usb_request	*r; +	struct musb_request	*r;  	void __iomem		*regs = musb->control_ep->regs;  	musb_read_fifo(&musb->endpoints[0], sizeof *req, (u8 *)req); @@ -606,7 +607,7 @@ musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req)  	/* NOTE:  earlier 2.6 versions changed setup packets to host  	 * order, but now USB packets always stay in USB byte order.  	 */ -	DBG(3, "SETUP req%02x.%02x v%04x i%04x l%d\n", +	dev_dbg(musb->controller, "SETUP req%02x.%02x v%04x i%04x l%d\n",  		req->bRequestType,  		req->bRequest,  		le16_to_cpu(req->wValue), @@ -616,7 +617,7 @@ musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req)  	/* clean up any leftover transfers */  	r = next_ep0_request(musb);  	if (r) -		musb_g_ep0_giveback(musb, r); +		musb_g_ep0_giveback(musb, &r->request);  	/* For zero-data requests we want to delay the STATUS stage to  	 * avoid SETUPEND errors.  If we read data (OUT), delay accepting @@ -674,10 +675,16 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)  	csr = musb_readw(regs, MUSB_CSR0);  	len = musb_readb(regs, MUSB_COUNT0); -	DBG(4, "csr %04x, count %d, myaddr %d, ep0stage %s\n", -			csr, len, -			musb_readb(mbase, MUSB_FADDR), -			decode_ep0stage(musb->ep0_state)); +	dev_dbg(musb->controller, "csr %04x, count %d, ep0stage %s\n", +			csr, len, decode_ep0stage(musb->ep0_state)); + +	if (csr & MUSB_CSR0_P_DATAEND) { +		/* +		 * If DATAEND is set we should not call the callback, +		 * hence the status stage is not complete. +		 */ +		return IRQ_HANDLED; +	}  	/* I sent a stall.. need to acknowledge it now.. */  	if (csr & MUSB_CSR0_P_SENTSTALL) { @@ -745,7 +752,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)  		/* enter test mode if needed (exit by reset) */  		else if (musb->test_mode) { -			DBG(1, "entering TESTMODE\n"); +			dev_dbg(musb->controller, "entering TESTMODE\n");  			if (MUSB_TEST_PACKET == musb->test_mode_nr)  				musb_load_testpacket(musb); @@ -758,11 +765,11 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)  	case MUSB_EP0_STAGE_STATUSOUT:  		/* end of sequence #1: write to host (TX state) */  		{ -			struct usb_request	*req; +			struct musb_request	*req;  			req = next_ep0_request(musb);  			if (req) -				musb_g_ep0_giveback(musb, req); +				musb_g_ep0_giveback(musb, &req->request);  		}  		/* @@ -857,7 +864,7 @@ setup:  				break;  			} -			DBG(3, "handled %d, csr %04x, ep0stage %s\n", +			dev_dbg(musb->controller, "handled %d, csr %04x, ep0stage %s\n",  				handled, csr,  				decode_ep0stage(musb->ep0_state)); @@ -874,7 +881,7 @@ setup:  			if (handled < 0) {  				musb_ep_select(mbase, 0);  stall: -				DBG(3, "stall (%d)\n", handled); +				dev_dbg(musb->controller, "stall (%d)\n", handled);  				musb->ackpend |= MUSB_CSR0_P_SENDSTALL;  				musb->ep0_state = MUSB_EP0_STAGE_IDLE;  finish: @@ -954,16 +961,16 @@ musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags)  		status = 0;  		break;  	default: -		DBG(1, "ep0 request queued in state %d\n", +		dev_dbg(musb->controller, "ep0 request queued in state %d\n",  				musb->ep0_state);  		status = -EINVAL;  		goto cleanup;  	}  	/* add request to the list */ -	list_add_tail(&(req->request.list), &(ep->req_list)); +	list_add_tail(&req->list, &ep->req_list); -	DBG(3, "queue to %s (%s), length=%d\n", +	dev_dbg(musb->controller, "queue to %s (%s), length=%d\n",  			ep->name, ep->is_in ? "IN/TX" : "OUT/RX",  			req->request.length); @@ -1056,7 +1063,7 @@ static int musb_g_ep0_halt(struct usb_ep *e, int value)  		musb->ackpend = 0;  		break;  	default: -		DBG(1, "ep0 can't halt in state %d\n", musb->ep0_state); +		dev_dbg(musb->controller, "ep0 can't halt in state %d\n", musb->ep0_state);  		status = -EINVAL;  	} diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 4d5bcb4e14d..eb06291a40c 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -39,14 +39,12 @@  #include <linux/sched.h>  #include <linux/slab.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/dma-mapping.h>  #include "musb_core.h"  #include "musb_host.h" -  /* MUSB HOST status 22-mar-2006   *   * - There's still lots of partial code duplication for fault paths, so @@ -96,6 +94,11 @@   * of transfers between endpoints, or anything clever.   */ +struct musb *hcd_to_musb(struct usb_hcd *hcd) +{ +	return *(struct musb **) hcd->hcd_priv; +} +  static void musb_ep_program(struct musb *musb, u8 epnum,  			struct urb *urb, int is_out, @@ -106,6 +109,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum,   */  static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)  { +	struct musb	*musb = ep->musb;  	void __iomem	*epio = ep->regs;  	u16		csr;  	u16		lastcsr = 0; @@ -114,7 +118,7 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)  	csr = musb_readw(epio, MUSB_TXCSR);  	while (csr & MUSB_TXCSR_FIFONOTEMPTY) {  		if (csr != lastcsr) -			DBG(3, "Host TX FIFONOTEMPTY csr: %02x\n", csr); +			dev_dbg(musb->controller, "Host TX FIFONOTEMPTY csr: %02x\n", csr);  		lastcsr = csr;  		csr |= MUSB_TXCSR_FLUSHFIFO;  		musb_writew(epio, MUSB_TXCSR, csr); @@ -240,7 +244,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)  		len = urb->transfer_buffer_length - urb->actual_length;  	} -	DBG(4, "qh %p urb %p dev%d ep%d%s%s, hw_ep %d, %p/%d\n", +	dev_dbg(musb->controller, "qh %p urb %p dev%d ep%d%s%s, hw_ep %d, %p/%d\n",  			qh, urb, address, qh->epnum,  			is_in ? "in" : "out",  			({char *s; switch (qh->type) { @@ -248,7 +252,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)  			case USB_ENDPOINT_XFER_BULK:	s = "-bulk"; break;  			case USB_ENDPOINT_XFER_ISOC:	s = "-iso"; break;  			default:			s = "-intr"; break; -			}; s; }), +			} s; }),  			epnum, buf + offset, len);  	/* Configure endpoint */ @@ -263,13 +267,12 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)  	switch (qh->type) {  	case USB_ENDPOINT_XFER_ISOC:  	case USB_ENDPOINT_XFER_INT: -		DBG(3, "check whether there's still time for periodic Tx\n"); +		dev_dbg(musb->controller, "check whether there's still time for periodic Tx\n");  		frame = musb_readw(mbase, MUSB_FRAME);  		/* FIXME this doesn't implement that scheduling policy ...  		 * or handle framecounter wrapping  		 */ -		if ((urb->transfer_flags & URB_ISO_ASAP) -				|| (frame >= urb->start_frame)) { +		if (1) {	/* Always assume URB_ISO_ASAP */  			/* REVISIT the SOF irq handler shouldn't duplicate  			 * this code; and we don't init urb->start_frame...  			 */ @@ -278,7 +281,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)  		} else {  			qh->frame = urb->start_frame;  			/* enable SOF interrupt so we can count down */ -			DBG(1, "SOF for %d\n", epnum); +			dev_dbg(musb->controller, "SOF for %d\n", epnum);  #if 1 /* ifndef	CONFIG_ARCH_DAVINCI */  			musb_writeb(mbase, MUSB_INTRUSBE, 0xff);  #endif @@ -286,7 +289,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)  		break;  	default:  start: -		DBG(4, "Start TX%d %s\n", epnum, +		dev_dbg(musb->controller, "Start TX%d %s\n", epnum,  			hw_ep->tx_channel ? "dma" : "pio");  		if (!hw_ep->tx_channel) @@ -301,21 +304,7 @@ static void musb_giveback(struct musb *musb, struct urb *urb, int status)  __releases(musb->lock)  __acquires(musb->lock)  { -	DBG(({ int level; switch (status) { -				case 0: -					level = 4; -					break; -				/* common/boring faults */ -				case -EREMOTEIO: -				case -ESHUTDOWN: -				case -ECONNRESET: -				case -EPIPE: -					level = 3; -					break; -				default: -					level = 2; -					break; -				}; level; }), +	dev_dbg(musb->controller,  			"complete %p %pF (%d), dev%d ep%d%s, %d/%d\n",  			urb, urb->complete, status,  			usb_pipedevice(urb->pipe), @@ -324,9 +313,9 @@ __acquires(musb->lock)  			urb->actual_length, urb->transfer_buffer_length  			); -	usb_hcd_unlink_urb_from_ep(musb_to_hcd(musb), urb); +	usb_hcd_unlink_urb_from_ep(musb->hcd, urb);  	spin_unlock(&musb->lock); -	usb_hcd_giveback_urb(musb_to_hcd(musb), urb, status); +	usb_hcd_giveback_urb(musb->hcd, urb, status);  	spin_lock(&musb->lock);  } @@ -388,11 +377,21 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb,  	 */  	if (list_empty(&qh->hep->urb_list)) {  		struct list_head	*head; +		struct dma_controller	*dma = musb->dma_controller; -		if (is_in) +		if (is_in) {  			ep->rx_reinit = 1; -		else +			if (ep->rx_channel) { +				dma->channel_release(ep->rx_channel); +				ep->rx_channel = NULL; +			} +		} else {  			ep->tx_reinit = 1; +			if (ep->tx_channel) { +				dma->channel_release(ep->tx_channel); +				ep->tx_channel = NULL; +			} +		}  		/* Clobber old pointers to this qh */  		musb_ep_set_qh(ep, is_in, NULL); @@ -426,7 +425,7 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb,  	}  	if (qh != NULL && qh->is_ready) { -		DBG(4, "... next ep%d %cX urb %p\n", +		dev_dbg(musb->controller, "... next ep%d %cX urb %p\n",  		    hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh));  		musb_start_urb(musb, is_in, qh);  	} @@ -471,7 +470,7 @@ musb_host_packet_rx(struct musb *musb, struct urb *urb, u8 epnum, u8 iso_err)  	/* musb_ep_select(mbase, epnum); */  	rx_count = musb_readw(epio, MUSB_RXCOUNT); -	DBG(3, "RX%d count %d, buffer %p len %d/%d\n", epnum, rx_count, +	dev_dbg(musb->controller, "RX%d count %d, buffer %p len %d/%d\n", epnum, rx_count,  			urb->transfer_buffer, qh->offset,  			urb->transfer_buffer_length); @@ -493,7 +492,7 @@ musb_host_packet_rx(struct musb *musb, struct urb *urb, u8 epnum, u8 iso_err)  				status = -EOVERFLOW;  				urb->error_count++;  			} -			DBG(2, "** OVERFLOW %d into %d\n", rx_count, length); +			dev_dbg(musb->controller, "** OVERFLOW %d into %d\n", rx_count, length);  			do_flush = 1;  		} else  			length = rx_count; @@ -511,7 +510,7 @@ musb_host_packet_rx(struct musb *musb, struct urb *urb, u8 epnum, u8 iso_err)  		if (rx_count > length) {  			if (urb->status == -EINPROGRESS)  				urb->status = -EOVERFLOW; -			DBG(2, "** OVERFLOW %d into %d\n", rx_count, length); +			dev_dbg(musb->controller, "** OVERFLOW %d into %d\n", rx_count, length);  			do_flush = 1;  		} else  			length = rx_count; @@ -609,7 +608,7 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)  	/* Set RXMAXP with the FIFO size of the endpoint  	 * to disable double buffer mode.  	 */ -	if (musb->hwvers < MUSB_HWVERS_2000) +	if (musb->double_buffer_not_ok)  		musb_writew(ep->regs, MUSB_RXMAXP, ep->max_packet_sz_rx);  	else  		musb_writew(ep->regs, MUSB_RXMAXP, @@ -628,7 +627,7 @@ static bool musb_tx_dma_program(struct dma_controller *dma,  	u16			csr;  	u8			mode; -#ifdef	CONFIG_USB_INVENTRA_DMA +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA)  	if (length > channel->max_len)  		length = channel->max_len; @@ -637,7 +636,17 @@ static bool musb_tx_dma_program(struct dma_controller *dma,  		mode = 1;  		csr |= MUSB_TXCSR_DMAMODE | MUSB_TXCSR_DMAENAB;  		/* autoset shouldn't be set in high bandwidth */ -		if (qh->hb_mult == 1) +		/* +		 * Enable Autoset according to table +		 * below +		 * bulk_split hb_mult	Autoset_Enable +		 *	0	1	Yes(Normal) +		 *	0	>1	No(High BW ISO) +		 *	1	1	Yes(HS bulk) +		 *	1	>1	Yes(FS bulk) +		 */ +		if (qh->hb_mult == 1 || (qh->hb_mult > 1 && +					can_bulk_split(hw_ep->musb, qh->type)))  			csr |= MUSB_TXCSR_AUTOSET;  	} else {  		mode = 0; @@ -696,8 +705,10 @@ static void musb_ep_program(struct musb *musb, u8 epnum,  	void __iomem		*epio = hw_ep->regs;  	struct musb_qh		*qh = musb_ep_get_qh(hw_ep, !is_out);  	u16			packet_sz = qh->maxpacket; +	u8			use_dma = 1; +	u16			csr; -	DBG(3, "%s hw%d urb %p spd%d dev%d ep%d%s " +	dev_dbg(musb->controller, "%s hw%d urb %p spd%d dev%d ep%d%s "  				"h_addr%02x h_port%02x bytes %d\n",  			is_out ? "-->" : "<--",  			epnum, urb, urb->dev->speed, @@ -707,9 +718,17 @@ static void musb_ep_program(struct musb *musb, u8 epnum,  	musb_ep_select(mbase, epnum); +	if (is_out && !len) { +		use_dma = 0; +		csr = musb_readw(epio, MUSB_TXCSR); +		csr &= ~MUSB_TXCSR_DMAENAB; +		musb_writew(epio, MUSB_TXCSR, csr); +		hw_ep->tx_channel = NULL; +	} +  	/* candidate for DMA? */  	dma_controller = musb->dma_controller; -	if (is_dma_capable() && epnum && dma_controller) { +	if (use_dma && is_dma_capable() && epnum && dma_controller) {  		dma_channel = is_out ? hw_ep->tx_channel : hw_ep->rx_channel;  		if (!dma_channel) {  			dma_channel = dma_controller->channel_alloc( @@ -733,13 +752,19 @@ static void musb_ep_program(struct musb *musb, u8 epnum,  		csr = musb_readw(epio, MUSB_TXCSR);  		/* disable interrupt in case we flush */ -		int_txe = musb_readw(mbase, MUSB_INTRTXE); +		int_txe = musb->intrtxe;  		musb_writew(mbase, MUSB_INTRTXE, int_txe & ~(1 << epnum));  		/* general endpoint setup */  		if (epnum) {  			/* flush all old state, set default */ -			musb_h_tx_flush_fifo(hw_ep); +			/* +			 * We could be flushing valid +			 * packets in double buffering +			 * case +			 */ +			if (!hw_ep->tx_double_buffered) +				musb_h_tx_flush_fifo(hw_ep);  			/*  			 * We must not clear the DMAMODE bit before or in @@ -756,11 +781,13 @@ static void musb_ep_program(struct musb *musb, u8 epnum,  					);  			csr |= MUSB_TXCSR_MODE; -			if (usb_gettoggle(urb->dev, qh->epnum, 1)) -				csr |= MUSB_TXCSR_H_WR_DATATOGGLE -					| MUSB_TXCSR_H_DATATOGGLE; -			else -				csr |= MUSB_TXCSR_CLRDATATOG; +			if (!hw_ep->tx_double_buffered) { +				if (usb_gettoggle(urb->dev, qh->epnum, 1)) +					csr |= MUSB_TXCSR_H_WR_DATATOGGLE +						| MUSB_TXCSR_H_DATATOGGLE; +				else +					csr |= MUSB_TXCSR_CLRDATATOG; +			}  			musb_writew(epio, MUSB_TXCSR, csr);  			/* REVISIT may need to clear FLUSHFIFO ... */ @@ -784,14 +811,19 @@ static void musb_ep_program(struct musb *musb, u8 epnum,  		/* protocol/endpoint/interval/NAKlimit */  		if (epnum) {  			musb_writeb(epio, MUSB_TXTYPE, qh->type_reg); -			if (can_bulk_split(musb, qh->type)) +			if (musb->double_buffer_not_ok) {  				musb_writew(epio, MUSB_TXMAXP, -					packet_sz -					| ((hw_ep->max_packet_sz_tx / -						packet_sz) - 1) << 11); -			else +						hw_ep->max_packet_sz_tx); +			} else if (can_bulk_split(musb, qh->type)) { +				qh->hb_mult = hw_ep->max_packet_sz_tx +						/ packet_sz; +				musb_writew(epio, MUSB_TXMAXP, packet_sz +					| ((qh->hb_mult) - 1) << 11); +			} else {  				musb_writew(epio, MUSB_TXMAXP, -					packet_sz); +						qh->maxpacket | +						((qh->hb_mult - 1) << 11)); +			}  			musb_writeb(epio, MUSB_TXINTERVAL, qh->intv_reg);  		} else {  			musb_writeb(epio, MUSB_NAKLIMIT0, qh->intv_reg); @@ -813,9 +845,28 @@ static void musb_ep_program(struct musb *musb, u8 epnum,  		if (load_count) {  			/* PIO to load FIFO */  			qh->segsize = load_count; -			musb_write_fifo(hw_ep, load_count, buf); +			if (!buf) { +				sg_miter_start(&qh->sg_miter, urb->sg, 1, +						SG_MITER_ATOMIC +						| SG_MITER_FROM_SG); +				if (!sg_miter_next(&qh->sg_miter)) { +					dev_err(musb->controller, +							"error: sg" +							"list empty\n"); +					sg_miter_stop(&qh->sg_miter); +					goto finish; +				} +				buf = qh->sg_miter.addr + urb->sg->offset + +					urb->actual_length; +				load_count = min_t(u32, load_count, +						qh->sg_miter.length); +				musb_write_fifo(hw_ep, load_count, buf); +				qh->sg_miter.consumed = load_count; +				sg_miter_stop(&qh->sg_miter); +			} else +				musb_write_fifo(hw_ep, load_count, buf);  		} - +finish:  		/* re-enable interrupt */  		musb_writew(mbase, MUSB_INTRTXE, int_txe); @@ -851,42 +902,104 @@ static void musb_ep_program(struct musb *musb, u8 epnum,  		/* kick things off */  		if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) { -			/* candidate for DMA */ -			if (dma_channel) { -				dma_channel->actual_len = 0L; -				qh->segsize = len; - -				/* AUTOREQ is in a DMA register */ -				musb_writew(hw_ep->regs, MUSB_RXCSR, csr); -				csr = musb_readw(hw_ep->regs, -						MUSB_RXCSR); - -				/* unless caller treats short rx transfers as -				 * errors, we dare not queue multiple transfers. -				 */ -				dma_ok = dma_controller->channel_program( -						dma_channel, packet_sz, -						!(urb->transfer_flags -							& URB_SHORT_NOT_OK), -						urb->transfer_dma + offset, -						qh->segsize); -				if (!dma_ok) { -					dma_controller->channel_release( -							dma_channel); -					hw_ep->rx_channel = NULL; -					dma_channel = NULL; -				} else -					csr |= MUSB_RXCSR_DMAENAB; -			} +			/* Candidate for DMA */ +			dma_channel->actual_len = 0L; +			qh->segsize = len; + +			/* AUTOREQ is in a DMA register */ +			musb_writew(hw_ep->regs, MUSB_RXCSR, csr); +			csr = musb_readw(hw_ep->regs, MUSB_RXCSR); + +			/* +			 * Unless caller treats short RX transfers as +			 * errors, we dare not queue multiple transfers. +			 */ +			dma_ok = dma_controller->channel_program(dma_channel, +					packet_sz, !(urb->transfer_flags & +						     URB_SHORT_NOT_OK), +					urb->transfer_dma + offset, +					qh->segsize); +			if (!dma_ok) { +				dma_controller->channel_release(dma_channel); +				hw_ep->rx_channel = dma_channel = NULL; +			} else +				csr |= MUSB_RXCSR_DMAENAB;  		}  		csr |= MUSB_RXCSR_H_REQPKT; -		DBG(7, "RXCSR%d := %04x\n", epnum, csr); +		dev_dbg(musb->controller, "RXCSR%d := %04x\n", epnum, csr);  		musb_writew(hw_ep->regs, MUSB_RXCSR, csr);  		csr = musb_readw(hw_ep->regs, MUSB_RXCSR);  	}  } +/* Schedule next QH from musb->in_bulk/out_bulk and move the current qh to + * the end; avoids starvation for other endpoints. + */ +static void musb_bulk_nak_timeout(struct musb *musb, struct musb_hw_ep *ep, +	int is_in) +{ +	struct dma_channel	*dma; +	struct urb		*urb; +	void __iomem		*mbase = musb->mregs; +	void __iomem		*epio = ep->regs; +	struct musb_qh		*cur_qh, *next_qh; +	u16			rx_csr, tx_csr; + +	musb_ep_select(mbase, ep->epnum); +	if (is_in) { +		dma = is_dma_capable() ? ep->rx_channel : NULL; + +		/* clear nak timeout bit */ +		rx_csr = musb_readw(epio, MUSB_RXCSR); +		rx_csr |= MUSB_RXCSR_H_WZC_BITS; +		rx_csr &= ~MUSB_RXCSR_DATAERROR; +		musb_writew(epio, MUSB_RXCSR, rx_csr); + +		cur_qh = first_qh(&musb->in_bulk); +	} else { +		dma = is_dma_capable() ? ep->tx_channel : NULL; + +		/* clear nak timeout bit */ +		tx_csr = musb_readw(epio, MUSB_TXCSR); +		tx_csr |= MUSB_TXCSR_H_WZC_BITS; +		tx_csr &= ~MUSB_TXCSR_H_NAKTIMEOUT; +		musb_writew(epio, MUSB_TXCSR, tx_csr); + +		cur_qh = first_qh(&musb->out_bulk); +	} +	if (cur_qh) { +		urb = next_urb(cur_qh); +		if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { +			dma->status = MUSB_DMA_STATUS_CORE_ABORT; +			musb->dma_controller->channel_abort(dma); +			urb->actual_length += dma->actual_len; +			dma->actual_len = 0L; +		} +		musb_save_toggle(cur_qh, is_in, urb); + +		if (is_in) { +			/* move cur_qh to end of queue */ +			list_move_tail(&cur_qh->ring, &musb->in_bulk); + +			/* get the next qh from musb->in_bulk */ +			next_qh = first_qh(&musb->in_bulk); + +			/* set rx_reinit and schedule the next qh */ +			ep->rx_reinit = 1; +		} else { +			/* move cur_qh to end of queue */ +			list_move_tail(&cur_qh->ring, &musb->out_bulk); + +			/* get the next qh from musb->out_bulk */ +			next_qh = first_qh(&musb->out_bulk); + +			/* set tx_reinit and schedule the next qh */ +			ep->tx_reinit = 1; +		} +		musb_start_urb(musb, is_in, next_qh); +	} +}  /*   * Service the default endpoint (ep0) as host. @@ -924,15 +1037,15 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb)  		request = (struct usb_ctrlrequest *) urb->setup_packet;  		if (!request->wLength) { -			DBG(4, "start no-DATA\n"); +			dev_dbg(musb->controller, "start no-DATA\n");  			break;  		} else if (request->bRequestType & USB_DIR_IN) { -			DBG(4, "start IN-DATA\n"); +			dev_dbg(musb->controller, "start IN-DATA\n");  			musb->ep0_stage = MUSB_EP0_IN;  			more = true;  			break;  		} else { -			DBG(4, "start OUT-DATA\n"); +			dev_dbg(musb->controller, "start OUT-DATA\n");  			musb->ep0_stage = MUSB_EP0_OUT;  			more = true;  		} @@ -944,7 +1057,7 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb)  		if (fifo_count) {  			fifo_dest = (u8 *) (urb->transfer_buffer  					+ urb->actual_length); -			DBG(3, "Sending %d byte%s to ep0 fifo %p\n", +			dev_dbg(musb->controller, "Sending %d byte%s to ep0 fifo %p\n",  					fifo_count,  					(fifo_count == 1) ? "" : "s",  					fifo_dest); @@ -989,7 +1102,7 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)  			? musb_readb(epio, MUSB_COUNT0)  			: 0; -	DBG(4, "<== csr0 %04x, qh %p, count %d, urb %p, stage %d\n", +	dev_dbg(musb->controller, "<== csr0 %04x, qh %p, count %d, urb %p, stage %d\n",  		csr, qh, len, urb, musb->ep0_stage);  	/* if we just did status stage, we are done */ @@ -1000,15 +1113,15 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)  	/* prepare status */  	if (csr & MUSB_CSR0_H_RXSTALL) { -		DBG(6, "STALLING ENDPOINT\n"); +		dev_dbg(musb->controller, "STALLING ENDPOINT\n");  		status = -EPIPE;  	} else if (csr & MUSB_CSR0_H_ERROR) { -		DBG(2, "no response, csr0 %04x\n", csr); +		dev_dbg(musb->controller, "no response, csr0 %04x\n", csr);  		status = -EPROTO;  	} else if (csr & MUSB_CSR0_H_NAKTIMEOUT) { -		DBG(2, "control NAK timeout\n"); +		dev_dbg(musb->controller, "control NAK timeout\n");  		/* NOTE:  this code path would be a good place to PAUSE a  		 * control transfer, if another one is queued, so that @@ -1023,7 +1136,7 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)  	}  	if (status) { -		DBG(6, "aborting\n"); +		dev_dbg(musb->controller, "aborting\n");  		retval = IRQ_HANDLED;  		if (urb)  			urb->status = status; @@ -1070,10 +1183,13 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)  				csr = MUSB_CSR0_H_STATUSPKT  					| MUSB_CSR0_TXPKTRDY; +			/* disable ping token in status phase */ +			csr |= MUSB_CSR0_H_DIS_PING; +  			/* flag status stage */  			musb->ep0_stage = MUSB_EP0_STATUS; -			DBG(5, "ep0 STATUS, csr %04x\n", csr); +			dev_dbg(musb->controller, "ep0 STATUS, csr %04x\n", csr);  		}  		musb_writew(epio, MUSB_CSR0, csr); @@ -1127,47 +1243,55 @@ void musb_host_tx(struct musb *musb, u8 epnum)  	/* with CPPI, DMA sometimes triggers "extra" irqs */  	if (!urb) { -		DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr); +		dev_dbg(musb->controller, "extra TX%d ready, csr %04x\n", epnum, tx_csr);  		return;  	}  	pipe = urb->pipe;  	dma = is_dma_capable() ? hw_ep->tx_channel : NULL; -	DBG(4, "OUT/TX%d end, csr %04x%s\n", epnum, tx_csr, +	dev_dbg(musb->controller, "OUT/TX%d end, csr %04x%s\n", epnum, tx_csr,  			dma ? ", dma" : "");  	/* check for errors */  	if (tx_csr & MUSB_TXCSR_H_RXSTALL) {  		/* dma was disabled, fifo flushed */ -		DBG(3, "TX end %d stall\n", epnum); +		dev_dbg(musb->controller, "TX end %d stall\n", epnum);  		/* stall; record URB status */  		status = -EPIPE;  	} else if (tx_csr & MUSB_TXCSR_H_ERROR) {  		/* (NON-ISO) dma was disabled, fifo flushed */ -		DBG(3, "TX 3strikes on ep=%d\n", epnum); +		dev_dbg(musb->controller, "TX 3strikes on ep=%d\n", epnum);  		status = -ETIMEDOUT;  	} else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) { -		DBG(6, "TX end=%d device not responding\n", epnum); - -		/* NOTE:  this code path would be a good place to PAUSE a -		 * transfer, if there's some other (nonperiodic) tx urb -		 * that could use this fifo.  (dma complicates it...) -		 * That's already done for bulk RX transfers. -		 * -		 * if (bulk && qh->ring.next != &musb->out_bulk), then -		 * we have a candidate... NAKing is *NOT* an error -		 */ -		musb_ep_select(mbase, epnum); -		musb_writew(epio, MUSB_TXCSR, -				MUSB_TXCSR_H_WZC_BITS -				| MUSB_TXCSR_TXPKTRDY); -		return; +		if (USB_ENDPOINT_XFER_BULK == qh->type && qh->mux == 1 +				&& !list_is_singular(&musb->out_bulk)) { +			dev_dbg(musb->controller, +				"NAK timeout on TX%d ep\n", epnum); +			musb_bulk_nak_timeout(musb, hw_ep, 0); +		} else { +			dev_dbg(musb->controller, +				"TX end=%d device not responding\n", epnum); +			/* NOTE:  this code path would be a good place to PAUSE a +			 * transfer, if there's some other (nonperiodic) tx urb +			 * that could use this fifo.  (dma complicates it...) +			 * That's already done for bulk RX transfers. +			 * +			 * if (bulk && qh->ring.next != &musb->out_bulk), then +			 * we have a candidate... NAKing is *NOT* an error +			 */ +			musb_ep_select(mbase, epnum); +			musb_writew(epio, MUSB_TXCSR, +					MUSB_TXCSR_H_WZC_BITS +					| MUSB_TXCSR_TXPKTRDY); +		} +			return;  	} +done:  	if (status) {  		if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {  			dma->status = MUSB_DMA_STATUS_CORE_ABORT; @@ -1196,7 +1320,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)  	/* second cppi case */  	if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { -		DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr); +		dev_dbg(musb->controller, "extra TX%d ready, csr %04x\n", epnum, tx_csr);  		return;  	} @@ -1255,7 +1379,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)  		 * FIFO mode too...  		 */  		if (tx_csr & (MUSB_TXCSR_FIFONOTEMPTY | MUSB_TXCSR_TXPKTRDY)) { -			DBG(2, "DMA complete but packet still in FIFO, " +			dev_dbg(musb->controller, "DMA complete but packet still in FIFO, "  			    "CSR %04x\n", tx_csr);  			return;  		} @@ -1322,7 +1446,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)  			return;  		}  	} else	if (tx_csr & MUSB_TXCSR_DMAENAB) { -		DBG(1, "not complete, but DMA enabled?\n"); +		dev_dbg(musb->controller, "not complete, but DMA enabled?\n");  		return;  	} @@ -1336,10 +1460,39 @@ void musb_host_tx(struct musb *musb, u8 epnum)  	if (length > qh->maxpacket)  		length = qh->maxpacket;  	/* Unmap the buffer so that CPU can use it */ -	unmap_urb_for_dma(musb_to_hcd(musb), urb); -	musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset); +	usb_hcd_unmap_urb_for_dma(musb->hcd, urb); + +	/* +	 * We need to map sg if the transfer_buffer is +	 * NULL. +	 */ +	if (!urb->transfer_buffer) +		qh->use_sg = true; + +	if (qh->use_sg) { +		/* sg_miter_start is already done in musb_ep_program */ +		if (!sg_miter_next(&qh->sg_miter)) { +			dev_err(musb->controller, "error: sg list empty\n"); +			sg_miter_stop(&qh->sg_miter); +			status = -EINVAL; +			goto done; +		} +		urb->transfer_buffer = qh->sg_miter.addr; +		length = min_t(u32, length, qh->sg_miter.length); +		musb_write_fifo(hw_ep, length, urb->transfer_buffer); +		qh->sg_miter.consumed = length; +		sg_miter_stop(&qh->sg_miter); +	} else { +		musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset); +	} +  	qh->segsize = length; +	if (qh->use_sg) { +		if (offset + length >= urb->transfer_buffer_length) +			qh->use_sg = false; +	} +  	musb_ep_select(mbase, epnum);  	musb_writew(epio, MUSB_TXCSR,  			MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); @@ -1385,50 +1538,6 @@ void musb_host_tx(struct musb *musb, u8 epnum)  #endif -/* Schedule next QH from musb->in_bulk and move the current qh to - * the end; avoids starvation for other endpoints. - */ -static void musb_bulk_rx_nak_timeout(struct musb *musb, struct musb_hw_ep *ep) -{ -	struct dma_channel	*dma; -	struct urb		*urb; -	void __iomem		*mbase = musb->mregs; -	void __iomem		*epio = ep->regs; -	struct musb_qh		*cur_qh, *next_qh; -	u16			rx_csr; - -	musb_ep_select(mbase, ep->epnum); -	dma = is_dma_capable() ? ep->rx_channel : NULL; - -	/* clear nak timeout bit */ -	rx_csr = musb_readw(epio, MUSB_RXCSR); -	rx_csr |= MUSB_RXCSR_H_WZC_BITS; -	rx_csr &= ~MUSB_RXCSR_DATAERROR; -	musb_writew(epio, MUSB_RXCSR, rx_csr); - -	cur_qh = first_qh(&musb->in_bulk); -	if (cur_qh) { -		urb = next_urb(cur_qh); -		if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { -			dma->status = MUSB_DMA_STATUS_CORE_ABORT; -			musb->dma_controller->channel_abort(dma); -			urb->actual_length += dma->actual_len; -			dma->actual_len = 0L; -		} -		musb_save_toggle(cur_qh, 1, urb); - -		/* move cur_qh to end of queue */ -		list_move_tail(&cur_qh->ring, &musb->in_bulk); - -		/* get the next qh from musb->in_bulk */ -		next_qh = first_qh(&musb->in_bulk); - -		/* set rx_reinit and schedule the next qh */ -		ep->rx_reinit = 1; -		musb_start_urb(musb, 1, next_qh); -	} -} -  /*   * Service an RX interrupt for the given IN endpoint; docs cover bulk, iso,   * and high-bandwidth IN transfer cases. @@ -1447,6 +1556,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)  	bool			done = false;  	u32			status;  	struct dma_channel	*dma; +	unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG;  	musb_ep_select(mbase, epnum); @@ -1463,7 +1573,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)  		 * usbtest #11 (unlinks) triggers it regularly, sometimes  		 * with fifo full.  (Only with DMA??)  		 */ -		DBG(3, "BOGUS RX%d ready, csr %04x, count %d\n", epnum, val, +		dev_dbg(musb->controller, "BOGUS RX%d ready, csr %04x, count %d\n", epnum, val,  			musb_readw(epio, MUSB_RXCOUNT));  		musb_h_flush_rxfifo(hw_ep, MUSB_RXCSR_CLRDATATOG);  		return; @@ -1471,20 +1581,20 @@ void musb_host_rx(struct musb *musb, u8 epnum)  	pipe = urb->pipe; -	DBG(5, "<== hw %d rxcsr %04x, urb actual %d (+dma %zu)\n", +	dev_dbg(musb->controller, "<== hw %d rxcsr %04x, urb actual %d (+dma %zu)\n",  		epnum, rx_csr, urb->actual_length,  		dma ? dma->actual_len : 0);  	/* check for errors, concurrent stall & unlink is not really  	 * handled yet! */  	if (rx_csr & MUSB_RXCSR_H_RXSTALL) { -		DBG(3, "RX end %d STALL\n", epnum); +		dev_dbg(musb->controller, "RX end %d STALL\n", epnum);  		/* stall; record URB status */  		status = -EPIPE;  	} else if (rx_csr & MUSB_RXCSR_H_ERROR) { -		DBG(3, "end %d RX proto error\n", epnum); +		dev_dbg(musb->controller, "end %d RX proto error\n", epnum);  		status = -EPROTO;  		musb_writeb(epio, MUSB_RXINTERVAL, 0); @@ -1492,7 +1602,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)  	} else if (rx_csr & MUSB_RXCSR_DATAERROR) {  		if (USB_ENDPOINT_XFER_ISOC != qh->type) { -			DBG(6, "RX end %d NAK timeout\n", epnum); +			dev_dbg(musb->controller, "RX end %d NAK timeout\n", epnum);  			/* NOTE: NAKing is *NOT* an error, so we want to  			 * continue.  Except ... if there's a request for @@ -1505,7 +1615,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)  			if (usb_pipebulk(urb->pipe)  					&& qh->mux == 1  					&& !list_is_singular(&musb->in_bulk)) { -				musb_bulk_rx_nak_timeout(musb, hw_ep); +				musb_bulk_nak_timeout(musb, hw_ep, 1);  				return;  			}  			musb_ep_select(mbase, epnum); @@ -1515,12 +1625,12 @@ void musb_host_rx(struct musb *musb, u8 epnum)  			goto finish;  		} else { -			DBG(4, "RX end %d ISO data error\n", epnum); +			dev_dbg(musb->controller, "RX end %d ISO data error\n", epnum);  			/* packet error reported later */  			iso_err = true;  		}  	} else if (rx_csr & MUSB_RXCSR_INCOMPRX) { -		DBG(3, "end %d high bandwidth incomplete ISO packet RX\n", +		dev_dbg(musb->controller, "end %d high bandwidth incomplete ISO packet RX\n",  				epnum);  		status = -EPROTO;  	} @@ -1552,7 +1662,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)  	/* FIXME this is _way_ too much in-line logic for Mentor DMA */ -#ifndef CONFIG_USB_INVENTRA_DMA +#if !defined(CONFIG_USB_INVENTRA_DMA) && !defined(CONFIG_USB_UX500_DMA)  	if (rx_csr & MUSB_RXCSR_H_REQPKT)  {  		/* REVISIT this happened for a while on some short reads...  		 * the cleanup still needs investigation... looks bad... @@ -1566,7 +1676,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)  			done = true;  		} -		DBG(2, "RXCSR%d %04x, reqpkt, len %zu%s\n", epnum, rx_csr, +		dev_dbg(musb->controller, "RXCSR%d %04x, reqpkt, len %zu%s\n", epnum, rx_csr,  				xfer_len, dma ? ", dma" : "");  		rx_csr &= ~MUSB_RXCSR_H_REQPKT; @@ -1584,7 +1694,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)  			| MUSB_RXCSR_RXPKTRDY);  		musb_writew(hw_ep->regs, MUSB_RXCSR, val); -#ifdef CONFIG_USB_INVENTRA_DMA +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) || \ +	defined(CONFIG_USB_TI_CPPI41_DMA)  		if (usb_pipeisoc(pipe)) {  			struct usb_iso_packet_descriptor *d; @@ -1594,13 +1705,33 @@ void musb_host_rx(struct musb *musb, u8 epnum)  			/* even if there was an error, we did the dma  			 * for iso_frame_desc->length  			 */ -			if (d->status != EILSEQ && d->status != -EOVERFLOW) +			if (d->status != -EILSEQ && d->status != -EOVERFLOW)  				d->status = 0; -			if (++qh->iso_idx >= urb->number_of_packets) +			if (++qh->iso_idx >= urb->number_of_packets) {  				done = true; -			else +			} else { +#if defined(CONFIG_USB_TI_CPPI41_DMA) +				struct dma_controller   *c; +				dma_addr_t *buf; +				u32 length, ret; + +				c = musb->dma_controller; +				buf = (void *) +					urb->iso_frame_desc[qh->iso_idx].offset +					+ (u32)urb->transfer_dma; + +				length = +					urb->iso_frame_desc[qh->iso_idx].length; + +				val |= MUSB_RXCSR_DMAENAB; +				musb_writew(hw_ep->regs, MUSB_RXCSR, val); + +				ret = c->channel_program(dma, qh->maxpacket, +						0, (u32) buf, length); +#endif  				done = false; +			}  		} else  {  		/* done if urb buffer is full or short packet is recd */ @@ -1616,7 +1747,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)  				MUSB_RXCSR_H_WZC_BITS | val);  		} -		DBG(4, "ep %d dma %s, rxcsr %04x, rxcount %d\n", epnum, +		dev_dbg(musb->controller, "ep %d dma %s, rxcsr %04x, rxcount %d\n", epnum,  			done ? "off" : "reset",  			musb_readw(epio, MUSB_RXCSR),  			musb_readw(epio, MUSB_RXCOUNT)); @@ -1640,7 +1771,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)  		}  		/* we are expecting IN packets */ -#ifdef CONFIG_USB_INVENTRA_DMA +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) || \ +	defined(CONFIG_USB_TI_CPPI41_DMA)  		if (dma) {  			struct dma_controller	*c;  			u16			rx_count; @@ -1649,10 +1781,10 @@ void musb_host_rx(struct musb *musb, u8 epnum)  			rx_count = musb_readw(epio, MUSB_RXCOUNT); -			DBG(2, "RX%d count %d, buffer 0x%x len %d/%d\n", +			dev_dbg(musb->controller, "RX%d count %d, buffer 0x%llx len %d/%d\n",  					epnum, rx_count, -					urb->transfer_dma -						+ urb->actual_length, +					(unsigned long long) urb->transfer_dma +					+ urb->actual_length,  					qh->offset,  					urb->transfer_buffer_length); @@ -1673,7 +1805,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)  						d_status = -EOVERFLOW;  						urb->error_count++;  					} -					DBG(2, "** OVERFLOW %d into %d\n",\ +					dev_dbg(musb->controller, "** OVERFLOW %d into %d\n",\  					    rx_count, d->length);  					length = d->length; @@ -1751,17 +1883,54 @@ void musb_host_rx(struct musb *musb, u8 epnum)  				c->channel_release(dma);  				hw_ep->rx_channel = NULL;  				dma = NULL; -				/* REVISIT reset CSR */ +				val = musb_readw(epio, MUSB_RXCSR); +				val &= ~(MUSB_RXCSR_DMAENAB +					| MUSB_RXCSR_H_AUTOREQ +					| MUSB_RXCSR_AUTOCLEAR); +				musb_writew(epio, MUSB_RXCSR, val);  			}  		}  #endif	/* Mentor DMA */  		if (!dma) { +			unsigned int received_len; +  			/* Unmap the buffer so that CPU can use it */ -			unmap_urb_for_dma(musb_to_hcd(musb), urb); -			done = musb_host_packet_rx(musb, urb, -					epnum, iso_err); -			DBG(6, "read %spacket\n", done ? "last " : ""); +			usb_hcd_unmap_urb_for_dma(musb->hcd, urb); + +			/* +			 * We need to map sg if the transfer_buffer is +			 * NULL. +			 */ +			if (!urb->transfer_buffer) { +				qh->use_sg = true; +				sg_miter_start(&qh->sg_miter, urb->sg, 1, +						sg_flags); +			} + +			if (qh->use_sg) { +				if (!sg_miter_next(&qh->sg_miter)) { +					dev_err(musb->controller, "error: sg list empty\n"); +					sg_miter_stop(&qh->sg_miter); +					status = -EINVAL; +					done = true; +					goto finish; +				} +				urb->transfer_buffer = qh->sg_miter.addr; +				received_len = urb->actual_length; +				qh->offset = 0x0; +				done = musb_host_packet_rx(musb, urb, epnum, +						iso_err); +				/* Calculate the number of bytes received */ +				received_len = urb->actual_length - +					received_len; +				qh->sg_miter.consumed = received_len; +				sg_miter_stop(&qh->sg_miter); +			} else { +				done = musb_host_packet_rx(musb, urb, +						epnum, iso_err); +			} +			dev_dbg(musb->controller, "read %spacket\n", done ? "last " : "");  		}  	} @@ -1769,6 +1938,9 @@ finish:  	urb->actual_length += xfer_len;  	qh->offset += xfer_len;  	if (done) { +		if (qh->use_sg) +			qh->use_sg = false; +  		if (urb->status == -EINPROGRESS)  			urb->status = status;  		musb_advance_schedule(musb, urb, hw_ep, USB_DIR_IN); @@ -1864,14 +2036,14 @@ static int musb_schedule(  		else  			head = &musb->out_bulk; -		/* Enable bulk RX NAK timeout scheme when bulk requests are -		 * multiplexed.  This scheme doen't work in high speed to full +		/* Enable bulk RX/TX NAK timeout scheme when bulk requests are +		 * multiplexed. This scheme does not work in high speed to full  		 * speed scenario as NAK interrupts are not coming from a  		 * full speed device connected to a high speed device.  		 * NAK timeout interval is 8 (128 uframe or 16ms) for HS and  		 * 4 (8 frame or 8ms) for FS device.  		 */ -		if (is_in && qh->dev) +		if (qh->dev)  			qh->intv_reg =  				(USB_SPEED_HIGH == qh->dev->speed) ? 8 : 4;  		goto success; @@ -1882,7 +2054,7 @@ static int musb_schedule(  	idle = 1;  	qh->mux = 0;  	hw_ep = musb->endpoints + best_end; -	DBG(4, "qh %p periodic slot %d\n", qh, best_end); +	dev_dbg(musb->controller, "qh %p periodic slot %d\n", qh, best_end);  success:  	if (head) {  		idle = list_empty(head); @@ -1951,7 +2123,7 @@ static int musb_urb_enqueue(  	INIT_LIST_HEAD(&qh->ring);  	qh->is_ready = 1; -	qh->maxpacket = le16_to_cpu(epd->wMaxPacketSize); +	qh->maxpacket = usb_endpoint_maxp(epd);  	qh->type = usb_endpoint_type(epd);  	/* Bits 11 & 12 of wMaxPacketSize encode high bandwidth multiplier. @@ -2050,7 +2222,7 @@ static int musb_urb_enqueue(  	 * we only have work to do in the former case.  	 */  	spin_lock_irqsave(&musb->lock, flags); -	if (hep->hcpriv) { +	if (hep->hcpriv || !next_urb(qh)) {  		/* some concurrent activity submitted another urb to hep...  		 * odd, rare, error prone, but legal.  		 */ @@ -2088,6 +2260,7 @@ done:  static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)  {  	struct musb_hw_ep	*ep = qh->hw_ep; +	struct musb		*musb = ep->musb;  	void __iomem		*epio = ep->regs;  	unsigned		hw_end = ep->epnum;  	void __iomem		*regs = ep->musb->mregs; @@ -2103,7 +2276,7 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)  		dma = is_in ? ep->rx_channel : ep->tx_channel;  		if (dma) {  			status = ep->musb->dma_controller->channel_abort(dma); -			DBG(status ? 1 : 3, +			dev_dbg(musb->controller,  				"abort %cX%d DMA for urb %p --> %d\n",  				is_in ? 'R' : 'T', ep->epnum,  				urb, status); @@ -2112,7 +2285,7 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)  	}  	/* turn off DMA requests, discard state, stop polling ... */ -	if (is_in) { +	if (ep->epnum && is_in) {  		/* giveback saves bulk toggle */  		csr = musb_h_flush_rxfifo(ep, 0); @@ -2150,7 +2323,7 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)  	int			is_in  = usb_pipein(urb->pipe);  	int			ret; -	DBG(4, "urb=%p, dev%d ep%d%s\n", urb, +	dev_dbg(musb->controller, "urb=%p, dev%d ep%d%s\n", urb,  			usb_pipedevice(urb->pipe),  			usb_pipeendpoint(urb->pipe),  			is_in ? "in" : "out"); @@ -2284,6 +2457,8 @@ static int musb_bus_suspend(struct usb_hcd *hcd)  	struct musb	*musb = hcd_to_musb(hcd);  	u8		devctl; +	musb_port_suspend(musb, true); +  	if (!is_host_active(musb))  		return 0; @@ -2305,7 +2480,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd)  	if (musb->is_active) {  		WARNING("trying to suspend as %s while active\n", -				otg_state_string(musb)); +				usb_otg_state_string(musb->xceiv->state));  		return -EBUSY;  	} else  		return 0; @@ -2313,14 +2488,130 @@ static int musb_bus_suspend(struct usb_hcd *hcd)  static int musb_bus_resume(struct usb_hcd *hcd)  { -	/* resuming child port does the work */ +	struct musb *musb = hcd_to_musb(hcd); + +	if (musb->config && +	    musb->config->host_port_deassert_reset_at_resume) +		musb_port_reset(musb, false); + +	return 0; +} + +#ifndef CONFIG_MUSB_PIO_ONLY + +#define MUSB_USB_DMA_ALIGN 4 + +struct musb_temp_buffer { +	void *kmalloc_ptr; +	void *old_xfer_buffer; +	u8 data[0]; +}; + +static void musb_free_temp_buffer(struct urb *urb) +{ +	enum dma_data_direction dir; +	struct musb_temp_buffer *temp; + +	if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) +		return; + +	dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + +	temp = container_of(urb->transfer_buffer, struct musb_temp_buffer, +			    data); + +	if (dir == DMA_FROM_DEVICE) { +		memcpy(temp->old_xfer_buffer, temp->data, +		       urb->transfer_buffer_length); +	} +	urb->transfer_buffer = temp->old_xfer_buffer; +	kfree(temp->kmalloc_ptr); + +	urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; +} + +static int musb_alloc_temp_buffer(struct urb *urb, gfp_t mem_flags) +{ +	enum dma_data_direction dir; +	struct musb_temp_buffer *temp; +	void *kmalloc_ptr; +	size_t kmalloc_size; + +	if (urb->num_sgs || urb->sg || +	    urb->transfer_buffer_length == 0 || +	    !((uintptr_t)urb->transfer_buffer & (MUSB_USB_DMA_ALIGN - 1))) +		return 0; + +	dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + +	/* Allocate a buffer with enough padding for alignment */ +	kmalloc_size = urb->transfer_buffer_length + +		sizeof(struct musb_temp_buffer) + MUSB_USB_DMA_ALIGN - 1; + +	kmalloc_ptr = kmalloc(kmalloc_size, mem_flags); +	if (!kmalloc_ptr) +		return -ENOMEM; + +	/* Position our struct temp_buffer such that data is aligned */ +	temp = PTR_ALIGN(kmalloc_ptr, MUSB_USB_DMA_ALIGN); + + +	temp->kmalloc_ptr = kmalloc_ptr; +	temp->old_xfer_buffer = urb->transfer_buffer; +	if (dir == DMA_TO_DEVICE) +		memcpy(temp->data, urb->transfer_buffer, +		       urb->transfer_buffer_length); +	urb->transfer_buffer = temp->data; + +	urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER; +  	return 0;  } -const struct hc_driver musb_hc_driver = { +static int musb_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, +				      gfp_t mem_flags) +{ +	struct musb	*musb = hcd_to_musb(hcd); +	int ret; + +	/* +	 * The DMA engine in RTL1.8 and above cannot handle +	 * DMA addresses that are not aligned to a 4 byte boundary. +	 * For such engine implemented (un)map_urb_for_dma hooks. +	 * Do not use these hooks for RTL<1.8 +	 */ +	if (musb->hwvers < MUSB_HWVERS_1800) +		return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); + +	ret = musb_alloc_temp_buffer(urb, mem_flags); +	if (ret) +		return ret; + +	ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); +	if (ret) +		musb_free_temp_buffer(urb); + +	return ret; +} + +static void musb_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ +	struct musb	*musb = hcd_to_musb(hcd); + +	usb_hcd_unmap_urb_for_dma(hcd, urb); + +	/* Do not use this hook for RTL<1.8 (see description above) */ +	if (musb->hwvers < MUSB_HWVERS_1800) +		return; + +	musb_free_temp_buffer(urb); +} +#endif /* !CONFIG_MUSB_PIO_ONLY */ + +static const struct hc_driver musb_hc_driver = {  	.description		= "musb-hcd",  	.product_desc		= "MUSB HDRC host driver", -	.hcd_priv_size		= sizeof(struct musb), +	.hcd_priv_size		= sizeof(struct musb *),  	.flags			= HCD_USB2 | HCD_MEMORY,  	/* not using irq handler or reset hooks from usbcore, since @@ -2336,6 +2627,11 @@ const struct hc_driver musb_hc_driver = {  	.urb_dequeue		= musb_urb_dequeue,  	.endpoint_disable	= musb_h_disable, +#ifndef CONFIG_MUSB_PIO_ONLY +	.map_urb_for_dma	= musb_map_urb_for_dma, +	.unmap_urb_for_dma	= musb_unmap_urb_for_dma, +#endif +  	.hub_status_data	= musb_hub_status_data,  	.hub_control		= musb_hub_control,  	.bus_suspend		= musb_bus_suspend, @@ -2343,3 +2639,69 @@ const struct hc_driver musb_hc_driver = {  	/* .start_port_reset	= NULL, */  	/* .hub_irq_enable	= NULL, */  }; + +int musb_host_alloc(struct musb *musb) +{ +	struct device	*dev = musb->controller; + +	/* usbcore sets dev->driver_data to hcd, and sometimes uses that... */ +	musb->hcd = usb_create_hcd(&musb_hc_driver, dev, dev_name(dev)); +	if (!musb->hcd) +		return -EINVAL; + +	*musb->hcd->hcd_priv = (unsigned long) musb; +	musb->hcd->self.uses_pio_for_control = 1; +	musb->hcd->uses_new_polling = 1; +	musb->hcd->has_tt = 1; + +	return 0; +} + +void musb_host_cleanup(struct musb *musb) +{ +	if (musb->port_mode == MUSB_PORT_MODE_GADGET) +		return; +	usb_remove_hcd(musb->hcd); +	musb->hcd = NULL; +} + +void musb_host_free(struct musb *musb) +{ +	usb_put_hcd(musb->hcd); +} + +int musb_host_setup(struct musb *musb, int power_budget) +{ +	int ret; +	struct usb_hcd *hcd = musb->hcd; + +	MUSB_HST_MODE(musb); +	musb->xceiv->otg->default_a = 1; +	musb->xceiv->state = OTG_STATE_A_IDLE; + +	otg_set_host(musb->xceiv->otg, &hcd->self); +	hcd->self.otg_port = 1; +	musb->xceiv->otg->host = &hcd->self; +	hcd->power_budget = 2 * (power_budget ? : 250); + +	ret = usb_add_hcd(hcd, 0, 0); +	if (ret < 0) +		return ret; + +	device_wakeup_enable(hcd->self.controller); +	return 0; +} + +void musb_host_resume_root_hub(struct musb *musb) +{ +	usb_hcd_resume_root_hub(musb->hcd); +} + +void musb_host_poke_root_hub(struct musb *musb) +{ +	MUSB_HST_MODE(musb); +	if (musb->hcd->status_urb) +		usb_hcd_poll_rh_status(musb->hcd); +	else +		usb_hcd_resume_root_hub(musb->hcd); +} diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 14b00776638..7bbf01bf4bb 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h @@ -35,15 +35,7 @@  #ifndef _MUSB_HOST_H  #define _MUSB_HOST_H -static inline struct usb_hcd *musb_to_hcd(struct musb *musb) -{ -	return container_of((void *) musb, struct usb_hcd, hcd_priv); -} - -static inline struct musb *hcd_to_musb(struct usb_hcd *hcd) -{ -	return (struct musb *) (hcd->hcd_priv); -} +#include <linux/scatterlist.h>  /* stored in "usb_host_endpoint.hcpriv" for scheduled endpoints */  struct musb_qh { @@ -71,6 +63,8 @@ struct musb_qh {  	u16			maxpacket;  	u16			frame;		/* for periodic schedule */  	unsigned		iso_idx;	/* in urb->iso_frame_desc[] */ +	struct sg_mapping_iter sg_miter;	/* for highmem in PIO mode */ +	bool			use_sg;		/* to track urb using sglist */  };  /* map from control or bulk queue head to the first qh on that ring */ @@ -82,7 +76,58 @@ static inline struct musb_qh *first_qh(struct list_head *q)  } +#if IS_ENABLED(CONFIG_USB_MUSB_HOST) || IS_ENABLED(CONFIG_USB_MUSB_DUAL_ROLE) +extern struct musb *hcd_to_musb(struct usb_hcd *); +extern irqreturn_t musb_h_ep0_irq(struct musb *); +extern int musb_host_alloc(struct musb *); +extern int musb_host_setup(struct musb *, int); +extern void musb_host_cleanup(struct musb *); +extern void musb_host_tx(struct musb *, u8); +extern void musb_host_rx(struct musb *, u8); +extern void musb_root_disconnect(struct musb *musb); +extern void musb_host_free(struct musb *); +extern void musb_host_cleanup(struct musb *); +extern void musb_host_tx(struct musb *, u8); +extern void musb_host_rx(struct musb *, u8);  extern void musb_root_disconnect(struct musb *musb); +extern void musb_host_resume_root_hub(struct musb *musb); +extern void musb_host_poke_root_hub(struct musb *musb); +extern void musb_port_suspend(struct musb *musb, bool do_suspend); +extern void musb_port_reset(struct musb *musb, bool do_reset); +extern void musb_host_finish_resume(struct work_struct *work); +#else +static inline struct musb *hcd_to_musb(struct usb_hcd *hcd) +{ +	return NULL; +} + +static inline irqreturn_t musb_h_ep0_irq(struct musb *musb) +{ +	return 0; +} + +static inline int musb_host_alloc(struct musb *musb) +{ +	return 0; +} + +static inline int musb_host_setup(struct musb *musb, int power_budget) +{ +	return 0; +} + +static inline void musb_host_cleanup(struct musb *musb)		{} +static inline void musb_host_free(struct musb *musb)		{} +static inline void musb_host_tx(struct musb *musb, u8 epnum)	{} +static inline void musb_host_rx(struct musb *musb, u8 epnum)	{} +static inline void musb_root_disconnect(struct musb *musb)	{} +static inline void musb_host_resume_root_hub(struct musb *musb)	{} +static inline void musb_host_poll_rh_status(struct musb *musb)	{} +static inline void musb_host_poke_root_hub(struct musb *musb)	{} +static inline void musb_port_suspend(struct musb *musb, bool do_suspend) {} +static inline void musb_port_reset(struct musb *musb, bool do_reset) {} +static inline void musb_host_finish_resume(struct work_struct *work) {} +#endif  struct usb_hcd; @@ -91,11 +136,8 @@ extern int musb_hub_control(struct usb_hcd *hcd,  			u16 typeReq, u16 wValue, u16 wIndex,  			char *buf, u16 wLength); -extern const struct hc_driver musb_hc_driver; -  static inline struct urb *next_urb(struct musb_qh *qh)  { -#ifdef CONFIG_USB_MUSB_HDRC_HCD  	struct list_head	*queue;  	if (!qh) @@ -104,9 +146,6 @@ static inline struct urb *next_urb(struct musb_qh *qh)  	if (list_empty(queue))  		return NULL;  	return list_entry(queue->next, struct urb, urb_list); -#else -	return NULL; -#endif  }  #endif				/* _MUSB_HOST_H */ diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h index b06e9ef00cf..eebeed78edd 100644 --- a/drivers/usb/musb/musb_io.h +++ b/drivers/usb/musb/musb_io.h @@ -37,25 +37,6 @@  #include <linux/io.h> -#if !defined(CONFIG_ARM) && !defined(CONFIG_SUPERH) \ -	&& !defined(CONFIG_AVR32) && !defined(CONFIG_PPC32) \ -	&& !defined(CONFIG_PPC64) && !defined(CONFIG_BLACKFIN) -static inline void readsl(const void __iomem *addr, void *buf, int len) -	{ insl((unsigned long)addr, buf, len); } -static inline void readsw(const void __iomem *addr, void *buf, int len) -	{ insw((unsigned long)addr, buf, len); } -static inline void readsb(const void __iomem *addr, void *buf, int len) -	{ insb((unsigned long)addr, buf, len); } - -static inline void writesl(const void __iomem *addr, const void *buf, int len) -	{ outsl((unsigned long)addr, buf, len); } -static inline void writesw(const void __iomem *addr, const void *buf, int len) -	{ outsw((unsigned long)addr, buf, len); } -static inline void writesb(const void __iomem *addr, const void *buf, int len) -	{ outsb((unsigned long)addr, buf, len); } - -#endif -  #ifndef CONFIG_BLACKFIN  /* NOTE:  these offsets are all in bytes */ @@ -74,7 +55,7 @@ static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)  	{ __raw_writel(data, addr + offset); } -#ifdef CONFIG_USB_TUSB6010 +#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE)  /*   * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum. @@ -114,7 +95,7 @@ static inline u8 musb_readb(const void __iomem *addr, unsigned offset)  static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)  	{ __raw_writeb(data, addr + offset); } -#endif	/* CONFIG_USB_TUSB6010 */ +#endif	/* CONFIG_USB_MUSB_TUSB6010 */  #else diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h index 5a727c5b867..03f2655af29 100644 --- a/drivers/usb/musb/musb_regs.h +++ b/drivers/usb/musb/musb_regs.h @@ -234,7 +234,8 @@  #define MUSB_TESTMODE		0x0F	/* 8 bit */  /* Get offset for a given FIFO from musb->mregs */ -#ifdef	CONFIG_USB_TUSB6010 +#if defined(CONFIG_USB_MUSB_TUSB6010) ||	\ +	defined(CONFIG_USB_MUSB_TUSB6010_MODULE)  #define MUSB_FIFO_OFFSET(epnum)	(0x200 + ((epnum) * 0x20))  #else  #define MUSB_FIFO_OFFSET(epnum)	(0x20 + ((epnum) * 4)) @@ -295,7 +296,8 @@  #define MUSB_FLAT_OFFSET(_epnum, _offset)	\  	(0x100 + (0x10*(_epnum)) + (_offset)) -#ifdef CONFIG_USB_TUSB6010 +#if defined(CONFIG_USB_MUSB_TUSB6010) ||	\ +	defined(CONFIG_USB_MUSB_TUSB6010_MODULE)  /* TUSB6010 EP0 configuration register is special */  #define MUSB_TUSB_OFFSET(_epnum, _offset)	\  	(0x10 + _offset) diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index 43233c397b6..e2d2d8c9891 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -36,7 +36,6 @@  #include <linux/kernel.h>  #include <linux/sched.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/time.h>  #include <linux/timer.h> @@ -44,9 +43,40 @@  #include "musb_core.h" +void musb_host_finish_resume(struct work_struct *work) +{ +	struct musb *musb; +	unsigned long flags; +	u8 power; + +	musb = container_of(work, struct musb, finish_resume_work.work); + +	spin_lock_irqsave(&musb->lock, flags); -static void musb_port_suspend(struct musb *musb, bool do_suspend) +	power = musb_readb(musb->mregs, MUSB_POWER); +	power &= ~MUSB_POWER_RESUME; +	dev_dbg(musb->controller, "root port resume stopped, power %02x\n", +		power); +	musb_writeb(musb->mregs, MUSB_POWER, power); + +	/* +	 * ISSUE:  DaVinci (RTL 1.300) disconnects after +	 * resume of high speed peripherals (but not full +	 * speed ones). +	 */ +	musb->is_active = 1; +	musb->port1_status &= ~(USB_PORT_STAT_SUSPEND | MUSB_PORT_STAT_RESUME); +	musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; +	usb_hcd_poll_rh_status(musb->hcd); +	/* NOTE: it might really be A_WAIT_BCON ... */ +	musb->xceiv->state = OTG_STATE_A_HOST; + +	spin_unlock_irqrestore(&musb->lock, flags); +} + +void musb_port_suspend(struct musb *musb, bool do_suspend)  { +	struct usb_otg	*otg = musb->xceiv->otg;  	u8		power;  	void __iomem	*mbase = musb->mregs; @@ -74,57 +104,52 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)  				break;  		} -		DBG(3, "Root port suspended, power %02x\n", power); +		dev_dbg(musb->controller, "Root port suspended, power %02x\n", power);  		musb->port1_status |= USB_PORT_STAT_SUSPEND;  		switch (musb->xceiv->state) {  		case OTG_STATE_A_HOST:  			musb->xceiv->state = OTG_STATE_A_SUSPEND; -			musb->is_active = is_otg_enabled(musb) -					&& musb->xceiv->host->b_hnp_enable; +			musb->is_active = otg->host->b_hnp_enable;  			if (musb->is_active)  				mod_timer(&musb->otg_timer, jiffies  					+ msecs_to_jiffies(  						OTG_TIME_A_AIDL_BDIS));  			musb_platform_try_idle(musb, 0);  			break; -#ifdef	CONFIG_USB_MUSB_OTG  		case OTG_STATE_B_HOST:  			musb->xceiv->state = OTG_STATE_B_WAIT_ACON; -			musb->is_active = is_otg_enabled(musb) -					&& musb->xceiv->host->b_hnp_enable; +			musb->is_active = otg->host->b_hnp_enable;  			musb_platform_try_idle(musb, 0);  			break; -#endif  		default: -			DBG(1, "bogus rh suspend? %s\n", -				otg_state_string(musb)); +			dev_dbg(musb->controller, "bogus rh suspend? %s\n", +				usb_otg_state_string(musb->xceiv->state));  		}  	} else if (power & MUSB_POWER_SUSPENDM) {  		power &= ~MUSB_POWER_SUSPENDM;  		power |= MUSB_POWER_RESUME;  		musb_writeb(mbase, MUSB_POWER, power); -		DBG(3, "Root port resuming, power %02x\n", power); +		dev_dbg(musb->controller, "Root port resuming, power %02x\n", power);  		/* later, GetPortStatus will stop RESUME signaling */  		musb->port1_status |= MUSB_PORT_STAT_RESUME; -		musb->rh_timer = jiffies + msecs_to_jiffies(20); +		schedule_delayed_work(&musb->finish_resume_work, +				      msecs_to_jiffies(20));  	}  } -static void musb_port_reset(struct musb *musb, bool do_reset) +void musb_port_reset(struct musb *musb, bool do_reset)  {  	u8		power;  	void __iomem	*mbase = musb->mregs; -#ifdef CONFIG_USB_MUSB_OTG  	if (musb->xceiv->state == OTG_STATE_B_IDLE) { -		DBG(2, "HNP: Returning from HNP; no hub reset from b_idle\n"); +		dev_dbg(musb->controller, "HNP: Returning from HNP; no hub reset from b_idle\n");  		musb->port1_status &= ~USB_PORT_STAT_RESET;  		return;  	} -#endif  	if (!is_host_active(musb))  		return; @@ -134,7 +159,6 @@ static void musb_port_reset(struct musb *musb, bool do_reset)  	 */  	power = musb_readb(mbase, MUSB_POWER);  	if (do_reset) { -  		/*  		 * If RESUME is set, we must make sure it stays minimum 20 ms.  		 * Then we must clear RESUME and wait a bit to let musb start @@ -143,31 +167,40 @@ static void musb_port_reset(struct musb *musb, bool do_reset)  		 * detected".  		 */  		if (power &  MUSB_POWER_RESUME) { -			while (time_before(jiffies, musb->rh_timer)) -				msleep(1); +			long remain = (unsigned long) musb->rh_timer - jiffies; + +			if (musb->rh_timer > 0 && remain > 0) { +				/* take into account the minimum delay after resume */ +				schedule_delayed_work( +					&musb->deassert_reset_work, remain); +				return; +			} +  			musb_writeb(mbase, MUSB_POWER, -				power & ~MUSB_POWER_RESUME); -			msleep(1); +				    power & ~MUSB_POWER_RESUME); + +			/* Give the core 1 ms to clear MUSB_POWER_RESUME */ +			schedule_delayed_work(&musb->deassert_reset_work, +					      msecs_to_jiffies(1)); +			return;  		} -		musb->ignore_disconnect = true;  		power &= 0xf0;  		musb_writeb(mbase, MUSB_POWER,  				power | MUSB_POWER_RESET);  		musb->port1_status |= USB_PORT_STAT_RESET;  		musb->port1_status &= ~USB_PORT_STAT_ENABLE; -		musb->rh_timer = jiffies + msecs_to_jiffies(50); +		schedule_delayed_work(&musb->deassert_reset_work, +				      msecs_to_jiffies(50));  	} else { -		DBG(4, "root port reset stopped\n"); +		dev_dbg(musb->controller, "root port reset stopped\n");  		musb_writeb(mbase, MUSB_POWER,  				power & ~MUSB_POWER_RESET); -		musb->ignore_disconnect = false; -  		power = musb_readb(mbase, MUSB_POWER);  		if (power & MUSB_POWER_HSMODE) { -			DBG(4, "high-speed device connected\n"); +			dev_dbg(musb->controller, "high-speed device connected\n");  			musb->port1_status |= USB_PORT_STAT_HIGH_SPEED;  		} @@ -175,7 +208,7 @@ static void musb_port_reset(struct musb *musb, bool do_reset)  		musb->port1_status |= USB_PORT_STAT_ENABLE  					| (USB_PORT_STAT_C_RESET << 16)  					| (USB_PORT_STAT_C_ENABLE << 16); -		usb_hcd_poll_rh_status(musb_to_hcd(musb)); +		usb_hcd_poll_rh_status(musb->hcd);  		musb->vbuserr_retry = VBUSERR_RETRY_COUNT;  	} @@ -183,22 +216,21 @@ static void musb_port_reset(struct musb *musb, bool do_reset)  void musb_root_disconnect(struct musb *musb)  { +	struct usb_otg	*otg = musb->xceiv->otg; +  	musb->port1_status = USB_PORT_STAT_POWER  			| (USB_PORT_STAT_C_CONNECTION << 16); -	usb_hcd_poll_rh_status(musb_to_hcd(musb)); +	usb_hcd_poll_rh_status(musb->hcd);  	musb->is_active = 0;  	switch (musb->xceiv->state) {  	case OTG_STATE_A_SUSPEND: -#ifdef	CONFIG_USB_MUSB_OTG -		if (is_otg_enabled(musb) -				&& musb->xceiv->host->b_hnp_enable) { +		if (otg->host->b_hnp_enable) {  			musb->xceiv->state = OTG_STATE_A_PERIPHERAL;  			musb->g.is_a_peripheral = 1;  			break;  		} -#endif  		/* FALLTHROUGH */  	case OTG_STATE_A_HOST:  		musb->xceiv->state = OTG_STATE_A_WAIT_BCON; @@ -208,7 +240,8 @@ void musb_root_disconnect(struct musb *musb)  		musb->xceiv->state = OTG_STATE_B_IDLE;  		break;  	default: -		DBG(1, "host disconnect (%s)\n", otg_state_string(musb)); +		dev_dbg(musb->controller, "host disconnect (%s)\n", +			usb_otg_state_string(musb->xceiv->state));  	}  } @@ -229,6 +262,23 @@ int musb_hub_status_data(struct usb_hcd *hcd, char *buf)  	return retval;  } +static int musb_has_gadget(struct musb *musb) +{ +	/* +	 * In host-only mode we start a connection right away. In OTG mode +	 * we have to wait until we loaded a gadget. We don't really need a +	 * gadget if we operate as a host but we should not start a session +	 * as a device without a gadget or else we explode. +	 */ +#ifdef CONFIG_USB_MUSB_HOST +	return 1; +#else +	if (musb->port_mode == MUSB_PORT_MODE_HOST) +		return 1; +	return musb->g.dev.driver != NULL; +#endif +} +  int musb_hub_control(  	struct usb_hcd	*hcd,  	u16		typeReq, @@ -275,8 +325,8 @@ int musb_hub_control(  			musb_port_suspend(musb, false);  			break;  		case USB_PORT_FEAT_POWER: -			if (!(is_otg_enabled(musb) && hcd->self.is_b_host)) -				musb_set_vbus(musb, 0); +			if (!hcd->self.is_b_host) +				musb_platform_set_vbus(musb, 0);  			break;  		case USB_PORT_FEAT_C_CONNECTION:  		case USB_PORT_FEAT_C_ENABLE: @@ -287,7 +337,7 @@ int musb_hub_control(  		default:  			goto error;  		} -		DBG(5, "clear feature %d\n", wValue); +		dev_dbg(musb->controller, "clear feature %d\n", wValue);  		musb->port1_status &= ~(1 << wValue);  		break;  	case GetHubDescriptor: @@ -305,8 +355,8 @@ int musb_hub_control(  		desc->bHubContrCurrent = 0;  		/* workaround bogus struct definition */ -		desc->DeviceRemovable[0] = 0x02;	/* port 1 */ -		desc->DeviceRemovable[1] = 0xff; +		desc->u.hs.DeviceRemovable[0] = 0x02;	/* port 1 */ +		desc->u.hs.DeviceRemovable[1] = 0xff;  		}  		break;  	case GetHubStatus: @@ -317,42 +367,12 @@ int musb_hub_control(  		if (wIndex != 1)  			goto error; -		/* finish RESET signaling? */ -		if ((musb->port1_status & USB_PORT_STAT_RESET) -				&& time_after_eq(jiffies, musb->rh_timer)) -			musb_port_reset(musb, false); - -		/* finish RESUME signaling? */ -		if ((musb->port1_status & MUSB_PORT_STAT_RESUME) -				&& time_after_eq(jiffies, musb->rh_timer)) { -			u8		power; - -			power = musb_readb(musb->mregs, MUSB_POWER); -			power &= ~MUSB_POWER_RESUME; -			DBG(4, "root port resume stopped, power %02x\n", -					power); -			musb_writeb(musb->mregs, MUSB_POWER, power); - -			/* ISSUE:  DaVinci (RTL 1.300) disconnects after -			 * resume of high speed peripherals (but not full -			 * speed ones). -			 */ - -			musb->is_active = 1; -			musb->port1_status &= ~(USB_PORT_STAT_SUSPEND -					| MUSB_PORT_STAT_RESUME); -			musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; -			usb_hcd_poll_rh_status(musb_to_hcd(musb)); -			/* NOTE: it might really be A_WAIT_BCON ... */ -			musb->xceiv->state = OTG_STATE_A_HOST; -		} -  		put_unaligned(cpu_to_le32(musb->port1_status  					& ~MUSB_PORT_STAT_RESUME),  				(__le32 *) buf);  		/* port change status is more interesting */ -		DBG(get_unaligned((u16 *)(buf+2)) ? 2 : 5, "port status %08x\n", +		dev_dbg(musb->controller, "port status %08x\n",  				musb->port1_status);  		break;  	case SetPortFeature: @@ -371,7 +391,7 @@ int musb_hub_control(  			 * initialization logic, e.g. for OTG, or change any  			 * logic relating to VBUS power-up.  			 */ -			if (!(is_otg_enabled(musb) && hcd->self.is_b_host)) +			if (!hcd->self.is_b_host && musb_has_gadget(musb))  				musb_start(musb);  			break;  		case USB_PORT_FEAT_RESET: @@ -423,7 +443,7 @@ int musb_hub_control(  		default:  			goto error;  		} -		DBG(5, "set feature %d\n", wValue); +		dev_dbg(musb->controller, "set feature %d\n", wValue);  		musb->port1_status |= 1 << wValue;  		break; diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index 563114d613d..e8e9f9aab20 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -37,18 +37,10 @@  #include "musb_core.h"  #include "musbhsdma.h" -static int dma_controller_start(struct dma_controller *c) -{ -	/* nothing to do */ -	return 0; -} -  static void dma_channel_release(struct dma_channel *channel); -static int dma_controller_stop(struct dma_controller *c) +static void dma_controller_stop(struct musb_dma_controller *controller)  { -	struct musb_dma_controller *controller = container_of(c, -			struct musb_dma_controller, controller);  	struct musb *musb = controller->private_data;  	struct dma_channel *channel;  	u8 bit; @@ -67,8 +59,6 @@ static int dma_controller_stop(struct dma_controller *c)  			}  		}  	} - -	return 0;  }  static struct dma_channel *dma_channel_allocate(struct dma_controller *c, @@ -122,11 +112,12 @@ static void configure_channel(struct dma_channel *channel,  {  	struct musb_dma_channel *musb_channel = channel->private_data;  	struct musb_dma_controller *controller = musb_channel->controller; +	struct musb *musb = controller->private_data;  	void __iomem *mbase = controller->base;  	u8 bchannel = musb_channel->idx;  	u16 csr = 0; -	DBG(4, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n", +	dev_dbg(musb->controller, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n",  			channel, packet_sz, dma_addr, len, mode);  	if (mode) { @@ -161,7 +152,7 @@ static int dma_channel_program(struct dma_channel *channel,  	struct musb_dma_controller *controller = musb_channel->controller;  	struct musb *musb = controller->private_data; -	DBG(2, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n", +	dev_dbg(musb->controller, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n",  		musb_channel->epnum,  		musb_channel->transmit ? "Tx" : "Rx",  		packet_sz, dma_addr, len, mode); @@ -169,6 +160,14 @@ static int dma_channel_program(struct dma_channel *channel,  	BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||  		channel->status == MUSB_DMA_STATUS_BUSY); +	/* Let targets check/tweak the arguments */ +	if (musb->ops->adjust_channel_params) { +		int ret = musb->ops->adjust_channel_params(channel, +			packet_sz, &mode, &dma_addr, &len); +		if (ret) +			return ret; +	} +  	/*  	 * The DMA engine in RTL1.8 and above cannot handle  	 * DMA addresses that are not aligned to a 4 byte boundary. @@ -266,7 +265,7 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)  #endif  	if (!int_hsdma) { -		DBG(2, "spurious DMA irq\n"); +		dev_dbg(musb->controller, "spurious DMA irq\n");  		for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {  			musb_channel = (struct musb_dma_channel *) @@ -280,7 +279,7 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)  			}  		} -		DBG(2, "int_hsdma = 0x%x\n", int_hsdma); +		dev_dbg(musb->controller, "int_hsdma = 0x%x\n", int_hsdma);  		if (!int_hsdma)  			goto done; @@ -307,7 +306,7 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)  				channel->actual_len = addr  					- musb_channel->start_addr; -				DBG(2, "ch %p, 0x%x -> 0x%x (%zu / %d) %s\n", +				dev_dbg(musb->controller, "ch %p, 0x%x -> 0x%x (%zu / %d) %s\n",  					channel, musb_channel->start_addr,  					addr, channel->actual_len,  					musb_channel->len, @@ -362,8 +361,7 @@ void dma_controller_destroy(struct dma_controller *c)  	struct musb_dma_controller *controller = container_of(c,  			struct musb_dma_controller, controller); -	if (!controller) -		return; +	dma_controller_stop(controller);  	if (controller->irq)  		free_irq(controller->irq, c); @@ -371,15 +369,14 @@ void dma_controller_destroy(struct dma_controller *c)  	kfree(controller);  } -struct dma_controller *__init -dma_controller_create(struct musb *musb, void __iomem *base) +struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *base)  {  	struct musb_dma_controller *controller;  	struct device *dev = musb->controller;  	struct platform_device *pdev = to_platform_device(dev); -	int irq = platform_get_irq(pdev, 1); +	int irq = platform_get_irq_byname(pdev, "dma"); -	if (irq == 0) { +	if (irq <= 0) {  		dev_err(dev, "No DMA interrupt line!\n");  		return NULL;  	} @@ -392,14 +389,12 @@ dma_controller_create(struct musb *musb, void __iomem *base)  	controller->private_data = musb;  	controller->base = base; -	controller->controller.start = dma_controller_start; -	controller->controller.stop = dma_controller_stop;  	controller->controller.channel_alloc = dma_channel_allocate;  	controller->controller.channel_release = dma_channel_release;  	controller->controller.channel_program = dma_channel_program;  	controller->controller.channel_abort = dma_channel_abort; -	if (request_irq(irq, dma_controller_irq, IRQF_DISABLED, +	if (request_irq(irq, dma_controller_irq, 0,  			dev_name(musb->controller), &controller->controller)) {  		dev_err(dev, "request_irq %d failed!\n", irq);  		dma_controller_destroy(&controller->controller); diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h index f763d62f151..f7b13fd2525 100644 --- a/drivers/usb/musb/musbhsdma.h +++ b/drivers/usb/musb/musbhsdma.h @@ -31,10 +31,6 @@   *   */ -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) -#include "omap2430.h" -#endif -  #ifndef CONFIG_BLACKFIN  #define MUSB_HSDMA_BASE		0x200 @@ -94,24 +90,33 @@ static inline void musb_write_hsdma_addr(void __iomem *mbase,  {  	musb_writew(mbase,  		MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_LOW), -		((u16)((u32) dma_addr & 0xFFFF))); +		dma_addr);  	musb_writew(mbase,  		MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_HIGH), -		((u16)(((u32) dma_addr >> 16) & 0xFFFF))); +		(dma_addr >> 16));  }  static inline u32 musb_read_hsdma_count(void __iomem *mbase, u8 bchannel)  { -	return musb_readl(mbase, +	u32 count = musb_readw(mbase,  		MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH)); + +	count = count << 16; + +	count |= musb_readw(mbase, +		MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW)); + +	return count;  }  static inline void musb_write_hsdma_count(void __iomem *mbase,  				u8 bchannel, u32 len)  { -	musb_writel(mbase, +	musb_writew(mbase, +		MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW),len); +	musb_writew(mbase,  		MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH), -		len); +		(len >> 16));  }  #endif /* CONFIG_BLACKFIN */ diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index ed618bde1ee..d369bf1f393 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -29,12 +29,30 @@  #include <linux/sched.h>  #include <linux/init.h>  #include <linux/list.h> -#include <linux/clk.h>  #include <linux/io.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/pm_runtime.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/usb/musb-omap.h> +#include <linux/phy/omap_control_phy.h> +#include <linux/of_platform.h>  #include "musb_core.h"  #include "omap2430.h" +struct omap2430_glue { +	struct device		*dev; +	struct platform_device	*musb; +	enum omap_musb_vbus_id_status status; +	struct work_struct	omap_musb_mailbox_work; +	struct device		*control_otghs; +}; +#define glue_to_musb(g)		platform_get_drvdata(g->musb) + +static struct omap2430_glue	*_glue;  static struct timer_list musb_idle_timer; @@ -42,19 +60,13 @@ static void musb_do_idle(unsigned long _musb)  {  	struct musb	*musb = (void *)_musb;  	unsigned long	flags; -#ifdef CONFIG_USB_MUSB_HDRC_HCD  	u8	power; -#endif  	u8	devctl;  	spin_lock_irqsave(&musb->lock, flags); -	devctl = musb_readb(musb->mregs, MUSB_DEVCTL); -  	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) { @@ -65,32 +77,28 @@ static void musb_do_idle(unsigned long _musb)  			MUSB_HST_MODE(musb);  		}  		break; -#ifdef CONFIG_USB_MUSB_HDRC_HCD  	case OTG_STATE_A_SUSPEND:  		/* finish RESUME signaling? */  		if (musb->port1_status & MUSB_PORT_STAT_RESUME) {  			power = musb_readb(musb->mregs, MUSB_POWER);  			power &= ~MUSB_POWER_RESUME; -			DBG(1, "root port resume stopped, power %02x\n", power); +			dev_dbg(musb->controller, "root port resume stopped, power %02x\n", power);  			musb_writeb(musb->mregs, MUSB_POWER, power);  			musb->is_active = 1;  			musb->port1_status &= ~(USB_PORT_STAT_SUSPEND  						| MUSB_PORT_STAT_RESUME);  			musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; -			usb_hcd_poll_rh_status(musb_to_hcd(musb)); +			usb_hcd_poll_rh_status(musb->hcd);  			/* NOTE: it might really be A_WAIT_BCON ... */  			musb->xceiv->state = OTG_STATE_A_HOST;  		}  		break; -#endif -#ifdef CONFIG_USB_MUSB_HDRC_HCD  	case OTG_STATE_A_HOST:  		devctl = musb_readb(musb->mregs, MUSB_DEVCTL);  		if (devctl &  MUSB_DEVCTL_BDEVICE)  			musb->xceiv->state = OTG_STATE_B_IDLE;  		else  			musb->xceiv->state = OTG_STATE_A_WAIT_BCON; -#endif  	default:  		break;  	} @@ -98,7 +106,7 @@ static void musb_do_idle(unsigned long _musb)  } -void musb_platform_try_idle(struct musb *musb, unsigned long timeout) +static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)  {  	unsigned long		default_timeout = jiffies + msecs_to_jiffies(3);  	static unsigned long	last_timer; @@ -109,7 +117,8 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)  	/* 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)); +		dev_dbg(musb->controller, "%s active, deleting timer\n", +			usb_otg_state_string(musb->xceiv->state));  		del_timer(&musb_idle_timer);  		last_timer = jiffies;  		return; @@ -119,27 +128,23 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)  		if (!timer_pending(&musb_idle_timer))  			last_timer = timeout;  		else { -			DBG(4, "Longer idle timer already pending, ignoring\n"); +			dev_dbg(musb->controller, "Longer idle timer already pending, ignoring\n");  			return;  		}  	}  	last_timer = timeout; -	DBG(4, "%s inactive, for idle timer for %lu ms\n", -		otg_state_string(musb), +	dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n", +		usb_otg_state_string(musb->xceiv->state),  		(unsigned long)jiffies_to_msecs(timeout - jiffies));  	mod_timer(&musb_idle_timer, timeout);  } -void musb_platform_enable(struct musb *musb) -{ -} -void musb_platform_disable(struct musb *musb) -{ -} -static void omap_set_vbus(struct musb *musb, int is_on) +static void omap2430_musb_set_vbus(struct musb *musb, int is_on)  { +	struct usb_otg	*otg = musb->xceiv->otg;  	u8		devctl; +	unsigned long timeout = jiffies + msecs_to_jiffies(1000);  	/* HDRC controls CPEN, but beware current surges during device  	 * connect.  They can trigger transient overcurrent conditions  	 * that must be ignored. @@ -148,12 +153,36 @@ static void omap_set_vbus(struct musb *musb, int is_on)  	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);  	if (is_on) { -		musb->is_active = 1; -		musb->xceiv->default_a = 1; -		musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; -		devctl |= MUSB_DEVCTL_SESSION; - -		MUSB_HST_MODE(musb); +		if (musb->xceiv->state == OTG_STATE_A_IDLE) { +			int loops = 100; +			/* start the session */ +			devctl |= MUSB_DEVCTL_SESSION; +			musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); +			/* +			 * Wait for the musb to set as A device to enable the +			 * VBUS +			 */ +			while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) { + +				mdelay(5); +				cpu_relax(); + +				if (time_after(jiffies, timeout) +				    || loops-- <= 0) { +					dev_err(musb->controller, +					"configured as A device timeout"); +					break; +				} +			} + +			otg_set_vbus(otg, 1); +		} else { +			musb->is_active = 1; +			otg->default_a = 1; +			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; +			devctl |= MUSB_DEVCTL_SESSION; +			MUSB_HST_MODE(musb); +		}  	} else {  		musb->is_active = 0; @@ -161,7 +190,7 @@ static void omap_set_vbus(struct musb *musb, int is_on)  		 * jumping right to B_IDLE...  		 */ -		musb->xceiv->default_a = 0; +		otg->default_a = 0;  		musb->xceiv->state = OTG_STATE_B_IDLE;  		devctl &= ~MUSB_DEVCTL_SESSION; @@ -169,15 +198,13 @@ static void omap_set_vbus(struct musb *musb, int is_on)  	}  	musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); -	DBG(1, "VBUS %s, devctl %02x " +	dev_dbg(musb->controller, "VBUS %s, devctl %02x "  		/* otg %3x conf %08x prcm %08x */ "\n", -		otg_state_string(musb), +		usb_otg_state_string(musb->xceiv->state),  		musb_readb(musb->mregs, MUSB_DEVCTL));  } -static int musb_platform_resume(struct musb *musb); - -int musb_platform_set_mode(struct musb *musb, u8 musb_mode) +static int omap2430_musb_set_mode(struct musb *musb, u8 musb_mode)  {  	u8	devctl = musb_readb(musb->mregs, MUSB_DEVCTL); @@ -187,37 +214,187 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)  	return 0;  } -int __init musb_platform_init(struct musb *musb, void *board_data) +static inline void omap2430_low_level_exit(struct musb *musb) +{ +	u32 l; + +	/* in any role */ +	l = musb_readl(musb->mregs, OTG_FORCESTDBY); +	l |= ENABLEFORCE;	/* enable MSTANDBY */ +	musb_writel(musb->mregs, OTG_FORCESTDBY, l); +} + +static inline void omap2430_low_level_init(struct musb *musb)  {  	u32 l; -	struct omap_musb_board_data *data = board_data; + +	l = musb_readl(musb->mregs, OTG_FORCESTDBY); +	l &= ~ENABLEFORCE;	/* disable MSTANDBY */ +	musb_writel(musb->mregs, OTG_FORCESTDBY, l); +} + +void omap_musb_mailbox(enum omap_musb_vbus_id_status status) +{ +	struct omap2430_glue	*glue = _glue; + +	if (!glue) { +		pr_err("%s: musb core is not yet initialized\n", __func__); +		return; +	} +	glue->status = status; + +	if (!glue_to_musb(glue)) { +		pr_err("%s: musb core is not yet ready\n", __func__); +		return; +	} + +	schedule_work(&glue->omap_musb_mailbox_work); +} +EXPORT_SYMBOL_GPL(omap_musb_mailbox); + +static void omap_musb_set_mailbox(struct omap2430_glue *glue) +{ +	struct musb *musb = glue_to_musb(glue); +	struct device *dev = musb->controller; +	struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); +	struct omap_musb_board_data *data = pdata->board_data; +	struct usb_otg *otg = musb->xceiv->otg; + +	switch (glue->status) { +	case OMAP_MUSB_ID_GROUND: +		dev_dbg(dev, "ID GND\n"); + +		otg->default_a = true; +		musb->xceiv->state = OTG_STATE_A_IDLE; +		musb->xceiv->last_event = USB_EVENT_ID; +		if (musb->gadget_driver) { +			pm_runtime_get_sync(dev); +			omap_control_usb_set_mode(glue->control_otghs, +				USB_MODE_HOST); +			omap2430_musb_set_vbus(musb, 1); +		} +		break; + +	case OMAP_MUSB_VBUS_VALID: +		dev_dbg(dev, "VBUS Connect\n"); + +		otg->default_a = false; +		musb->xceiv->state = OTG_STATE_B_IDLE; +		musb->xceiv->last_event = USB_EVENT_VBUS; +		if (musb->gadget_driver) +			pm_runtime_get_sync(dev); +		omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE); +		break; + +	case OMAP_MUSB_ID_FLOAT: +	case OMAP_MUSB_VBUS_OFF: +		dev_dbg(dev, "VBUS Disconnect\n"); + +		musb->xceiv->last_event = USB_EVENT_NONE; +		if (musb->gadget_driver) { +			omap2430_musb_set_vbus(musb, 0); +			pm_runtime_mark_last_busy(dev); +			pm_runtime_put_autosuspend(dev); +		} + +		if (data->interface_type == MUSB_INTERFACE_UTMI) +			otg_set_vbus(musb->xceiv->otg, 0); + +		omap_control_usb_set_mode(glue->control_otghs, +			USB_MODE_DISCONNECT); +		break; +	default: +		dev_dbg(dev, "ID float\n"); +	} + +	atomic_notifier_call_chain(&musb->xceiv->notifier, +			musb->xceiv->last_event, NULL); +} + + +static void omap_musb_mailbox_work(struct work_struct *mailbox_work) +{ +	struct omap2430_glue *glue = container_of(mailbox_work, +				struct omap2430_glue, omap_musb_mailbox_work); +	struct musb *musb = glue_to_musb(glue); +	struct device *dev = musb->controller; + +	pm_runtime_get_sync(dev); +	omap_musb_set_mailbox(glue); +	pm_runtime_mark_last_busy(dev); +	pm_runtime_put_autosuspend(dev); +} + +static irqreturn_t omap2430_musb_interrupt(int irq, void *__hci) +{ +	unsigned long   flags; +	irqreturn_t     retval = IRQ_NONE; +	struct musb     *musb = __hci; + +	spin_lock_irqsave(&musb->lock, flags); + +	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); +	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); +	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); + +	if (musb->int_usb || musb->int_tx || musb->int_rx) +		retval = musb_interrupt(musb); + +	spin_unlock_irqrestore(&musb->lock, flags); + +	return retval; +} + +static int omap2430_musb_init(struct musb *musb) +{ +	u32 l; +	int status = 0; +	struct device *dev = musb->controller; +	struct omap2430_glue *glue = dev_get_drvdata(dev->parent); +	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); +	struct omap_musb_board_data *data = plat->board_data;  	/* We require some kind of external transceiver, hooked  	 * up through ULPI.  TWL4030-family PMICs include one,  	 * which needs a driver, drivers aren't always needed.  	 */ -	musb->xceiv = otg_get_transceiver(); -	if (!musb->xceiv) { +	if (dev->parent->of_node) { +		musb->phy = devm_phy_get(dev->parent, "usb2-phy"); + +		/* We can't totally remove musb->xceiv as of now because +		 * musb core uses xceiv.state and xceiv.otg. Once we have +		 * a separate state machine to handle otg, these can be moved +		 * out of xceiv and then we can start using the generic PHY +		 * framework +		 */ +		musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent, +		    "usb-phy", 0); +	} else { +		musb->xceiv = devm_usb_get_phy_dev(dev, 0); +		musb->phy = devm_phy_get(dev, "usb"); +	} + +	if (IS_ERR(musb->xceiv)) { +		status = PTR_ERR(musb->xceiv); + +		if (status == -ENXIO) +			return status; +  		pr_err("HS USB OTG: no transceiver configured\n"); -		return -ENODEV; +		return -EPROBE_DEFER;  	} -	musb_platform_resume(musb); +	if (IS_ERR(musb->phy)) { +		pr_err("HS USB OTG: no PHY configured\n"); +		return PTR_ERR(musb->phy); +	} +	musb->isr = omap2430_musb_interrupt; -	l = musb_readl(musb->mregs, OTG_SYSCONFIG); -	l &= ~ENABLEWAKEUP;	/* disable wakeup */ -	l &= ~NOSTDBY;		/* remove possible nostdby */ -	l |= SMARTSTDBY;	/* enable smart standby */ -	l &= ~AUTOIDLE;		/* disable auto idle */ -	l &= ~NOIDLE;		/* remove possible noidle */ -	l |= SMARTIDLE;		/* enable smart idle */ -	/* -	 * MUSB AUTOIDLE don't work in 3430. -	 * Workaround by Richard Woodruff/TI -	 */ -	if (!cpu_is_omap3430()) -		l |= AUTOIDLE;		/* enable auto idle */ -	musb_writel(musb->mregs, OTG_SYSCONFIG, l); +	status = pm_runtime_get_sync(dev); +	if (status < 0) { +		dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status); +		goto err1; +	}  	l = musb_readl(musb->mregs, OTG_INTERFSEL); @@ -239,87 +416,321 @@ int __init musb_platform_init(struct musb *musb, void *board_data)  			musb_readl(musb->mregs, OTG_INTERFSEL),  			musb_readl(musb->mregs, OTG_SIMENABLE)); -	if (is_host_enabled(musb)) -		musb->board_set_vbus = omap_set_vbus; -  	setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); +	if (glue->status != OMAP_MUSB_UNKNOWN) +		omap_musb_set_mailbox(glue); + +	phy_init(musb->phy); +	phy_power_on(musb->phy); + +	pm_runtime_put_noidle(musb->controller);  	return 0; + +err1: +	return status;  } -#ifdef CONFIG_PM -void musb_platform_save_context(struct musb *musb, -		struct musb_context_registers *musb_context) +static void omap2430_musb_enable(struct musb *musb)  { -	musb_context->otg_sysconfig = musb_readl(musb->mregs, OTG_SYSCONFIG); -	musb_context->otg_forcestandby = musb_readl(musb->mregs, OTG_FORCESTDBY); +	u8		devctl; +	unsigned long timeout = jiffies + msecs_to_jiffies(1000); +	struct device *dev = musb->controller; +	struct omap2430_glue *glue = dev_get_drvdata(dev->parent); +	struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); +	struct omap_musb_board_data *data = pdata->board_data; + +	switch (glue->status) { + +	case OMAP_MUSB_ID_GROUND: +		omap_control_usb_set_mode(glue->control_otghs, USB_MODE_HOST); +		if (data->interface_type != MUSB_INTERFACE_UTMI) +			break; +		devctl = musb_readb(musb->mregs, MUSB_DEVCTL); +		/* start the session */ +		devctl |= MUSB_DEVCTL_SESSION; +		musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); +		while (musb_readb(musb->mregs, MUSB_DEVCTL) & +				MUSB_DEVCTL_BDEVICE) { +			cpu_relax(); + +			if (time_after(jiffies, timeout)) { +				dev_err(dev, "configured as A device timeout"); +				break; +			} +		} +		break; + +	case OMAP_MUSB_VBUS_VALID: +		omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE); +		break; + +	default: +		break; +	}  } -void musb_platform_restore_context(struct musb *musb, -		struct musb_context_registers *musb_context) +static void omap2430_musb_disable(struct musb *musb)  { -	musb_writel(musb->mregs, OTG_SYSCONFIG, musb_context->otg_sysconfig); -	musb_writel(musb->mregs, OTG_FORCESTDBY, musb_context->otg_forcestandby); +	struct device *dev = musb->controller; +	struct omap2430_glue *glue = dev_get_drvdata(dev->parent); + +	if (glue->status != OMAP_MUSB_UNKNOWN) +		omap_control_usb_set_mode(glue->control_otghs, +			USB_MODE_DISCONNECT);  } -#endif -static int musb_platform_suspend(struct musb *musb) +static int omap2430_musb_exit(struct musb *musb)  { -	u32 l; +	del_timer_sync(&musb_idle_timer); -	if (!musb->clock) -		return 0; +	omap2430_low_level_exit(musb); +	phy_power_off(musb->phy); +	phy_exit(musb->phy); -	/* in any role */ -	l = musb_readl(musb->mregs, OTG_FORCESTDBY); -	l |= ENABLEFORCE;	/* enable MSTANDBY */ -	musb_writel(musb->mregs, OTG_FORCESTDBY, l); +	return 0; +} + +static const struct musb_platform_ops omap2430_ops = { +	.init		= omap2430_musb_init, +	.exit		= omap2430_musb_exit, + +	.set_mode	= omap2430_musb_set_mode, +	.try_idle	= omap2430_musb_try_idle, + +	.set_vbus	= omap2430_musb_set_vbus, + +	.enable		= omap2430_musb_enable, +	.disable	= omap2430_musb_disable, +}; + +static u64 omap2430_dmamask = DMA_BIT_MASK(32); + +static int omap2430_probe(struct platform_device *pdev) +{ +	struct resource			musb_resources[3]; +	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev); +	struct omap_musb_board_data	*data; +	struct platform_device		*musb; +	struct omap2430_glue		*glue; +	struct device_node		*np = pdev->dev.of_node; +	struct musb_hdrc_config		*config; +	int				ret = -ENOMEM; + +	glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); +	if (!glue) { +		dev_err(&pdev->dev, "failed to allocate glue context\n"); +		goto err0; +	} + +	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); +	if (!musb) { +		dev_err(&pdev->dev, "failed to allocate musb device\n"); +		goto err0; +	} + +	musb->dev.parent		= &pdev->dev; +	musb->dev.dma_mask		= &omap2430_dmamask; +	musb->dev.coherent_dma_mask	= omap2430_dmamask; -	l = musb_readl(musb->mregs, OTG_SYSCONFIG); -	l |= ENABLEWAKEUP;	/* enable wakeup */ -	musb_writel(musb->mregs, OTG_SYSCONFIG, l); +	glue->dev			= &pdev->dev; +	glue->musb			= musb; +	glue->status			= OMAP_MUSB_UNKNOWN; +	glue->control_otghs = ERR_PTR(-ENODEV); -	otg_set_suspend(musb->xceiv, 1); +	if (np) { +		struct device_node *control_node; +		struct platform_device *control_pdev; -	if (musb->set_clock) -		musb->set_clock(musb->clock, 0); -	else -		clk_disable(musb->clock); +		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); +		if (!pdata) { +			dev_err(&pdev->dev, +				"failed to allocate musb platform data\n"); +			goto err2; +		} + +		data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); +		if (!data) { +			dev_err(&pdev->dev, +				"failed to allocate musb board data\n"); +			goto err2; +		} + +		config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); +		if (!config) { +			dev_err(&pdev->dev, +				"failed to allocate musb hdrc config\n"); +			goto err2; +		} + +		of_property_read_u32(np, "mode", (u32 *)&pdata->mode); +		of_property_read_u32(np, "interface-type", +						(u32 *)&data->interface_type); +		of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps); +		of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits); +		of_property_read_u32(np, "power", (u32 *)&pdata->power); +		config->multipoint = of_property_read_bool(np, "multipoint"); + +		pdata->board_data	= data; +		pdata->config		= config; + +		control_node = of_parse_phandle(np, "ctrl-module", 0); +		if (control_node) { +			control_pdev = of_find_device_by_node(control_node); +			if (!control_pdev) { +				dev_err(&pdev->dev, "Failed to get control device\n"); +				ret = -EINVAL; +				goto err2; +			} +			glue->control_otghs = &control_pdev->dev; +		} +	} +	pdata->platform_ops		= &omap2430_ops; + +	platform_set_drvdata(pdev, glue); + +	/* +	 * REVISIT if we ever have two instances of the wrapper, we will be +	 * in big trouble +	 */ +	_glue	= glue; + +	INIT_WORK(&glue->omap_musb_mailbox_work, omap_musb_mailbox_work); + +	memset(musb_resources, 0x00, sizeof(*musb_resources) * +			ARRAY_SIZE(musb_resources)); + +	musb_resources[0].name = pdev->resource[0].name; +	musb_resources[0].start = pdev->resource[0].start; +	musb_resources[0].end = pdev->resource[0].end; +	musb_resources[0].flags = pdev->resource[0].flags; + +	musb_resources[1].name = pdev->resource[1].name; +	musb_resources[1].start = pdev->resource[1].start; +	musb_resources[1].end = pdev->resource[1].end; +	musb_resources[1].flags = pdev->resource[1].flags; + +	musb_resources[2].name = pdev->resource[2].name; +	musb_resources[2].start = pdev->resource[2].start; +	musb_resources[2].end = pdev->resource[2].end; +	musb_resources[2].flags = pdev->resource[2].flags; + +	ret = platform_device_add_resources(musb, musb_resources, +			ARRAY_SIZE(musb_resources)); +	if (ret) { +		dev_err(&pdev->dev, "failed to add resources\n"); +		goto err2; +	} + +	ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); +	if (ret) { +		dev_err(&pdev->dev, "failed to add platform_data\n"); +		goto err2; +	} + +	pm_runtime_enable(&pdev->dev); + +	ret = platform_device_add(musb); +	if (ret) { +		dev_err(&pdev->dev, "failed to register musb device\n"); +		goto err2; +	}  	return 0; + +err2: +	platform_device_put(musb); + +err0: +	return ret;  } -static int musb_platform_resume(struct musb *musb) +static int omap2430_remove(struct platform_device *pdev)  { -	u32 l; +	struct omap2430_glue		*glue = platform_get_drvdata(pdev); -	if (!musb->clock) -		return 0; +	cancel_work_sync(&glue->omap_musb_mailbox_work); +	platform_device_unregister(glue->musb); -	otg_set_suspend(musb->xceiv, 0); +	return 0; +} -	if (musb->set_clock) -		musb->set_clock(musb->clock, 1); -	else -		clk_enable(musb->clock); +#ifdef CONFIG_PM -	l = musb_readl(musb->mregs, OTG_SYSCONFIG); -	l &= ~ENABLEWAKEUP;	/* disable wakeup */ -	musb_writel(musb->mregs, OTG_SYSCONFIG, l); +static int omap2430_runtime_suspend(struct device *dev) +{ +	struct omap2430_glue		*glue = dev_get_drvdata(dev); +	struct musb			*musb = glue_to_musb(glue); -	l = musb_readl(musb->mregs, OTG_FORCESTDBY); -	l &= ~ENABLEFORCE;	/* disable MSTANDBY */ -	musb_writel(musb->mregs, OTG_FORCESTDBY, l); +	if (musb) { +		musb->context.otg_interfsel = musb_readl(musb->mregs, +				OTG_INTERFSEL); + +		omap2430_low_level_exit(musb); +	}  	return 0;  } - -int musb_platform_exit(struct musb *musb) +static int omap2430_runtime_resume(struct device *dev)  { +	struct omap2430_glue		*glue = dev_get_drvdata(dev); +	struct musb			*musb = glue_to_musb(glue); -	musb_platform_suspend(musb); +	if (musb) { +		omap2430_low_level_init(musb); +		musb_writel(musb->mregs, OTG_INTERFSEL, +				musb->context.otg_interfsel); +	} -	otg_put_transceiver(musb->xceiv);  	return 0;  } + +static struct dev_pm_ops omap2430_pm_ops = { +	.runtime_suspend = omap2430_runtime_suspend, +	.runtime_resume = omap2430_runtime_resume, +}; + +#define DEV_PM_OPS	(&omap2430_pm_ops) +#else +#define DEV_PM_OPS	NULL +#endif + +#ifdef CONFIG_OF +static const struct of_device_id omap2430_id_table[] = { +	{ +		.compatible = "ti,omap4-musb" +	}, +	{ +		.compatible = "ti,omap3-musb" +	}, +	{}, +}; +MODULE_DEVICE_TABLE(of, omap2430_id_table); +#endif + +static struct platform_driver omap2430_driver = { +	.probe		= omap2430_probe, +	.remove		= omap2430_remove, +	.driver		= { +		.name	= "musb-omap2430", +		.pm	= DEV_PM_OPS, +		.of_match_table = of_match_ptr(omap2430_id_table), +	}, +}; + +MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer"); +MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); +MODULE_LICENSE("GPL v2"); + +static int __init omap2430_init(void) +{ +	return platform_driver_register(&omap2430_driver); +} +subsys_initcall(omap2430_init); + +static void __exit omap2430_exit(void) +{ +	platform_driver_unregister(&omap2430_driver); +} +module_exit(omap2430_exit); diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h index 40b3c02ae9f..1b5e83a9840 100644 --- a/drivers/usb/musb/omap2430.h +++ b/drivers/usb/musb/omap2430.h @@ -10,7 +10,7 @@  #ifndef __MUSB_OMAP243X_H__  #define __MUSB_OMAP243X_H__ -#include <plat/usb.h> +#include <linux/platform_data/usb-omap.h>  /*   * OMAP2430-specific definitions diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index bde40efc704..159ef4be1ef 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -17,14 +17,24 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h> +#include <linux/err.h> +#include <linux/prefetch.h>  #include <linux/usb.h>  #include <linux/irq.h> +#include <linux/io.h>  #include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/usb/usb_phy_generic.h>  #include "musb_core.h" -static void tusb_source_power(struct musb *musb, int is_on); +struct tusb6010_glue { +	struct device		*dev; +	struct platform_device	*musb; +	struct platform_device	*phy; +}; + +static void tusb_musb_set_vbus(struct musb *musb, int is_on);  #define TUSB_REV_MAJOR(reg_val)		((reg_val >> 4) & 0xf)  #define TUSB_REV_MINOR(reg_val)		(reg_val & 0xf) @@ -33,7 +43,7 @@ static void tusb_source_power(struct musb *musb, int is_on);   * Checks the revision. We need to use the DMA register as 3.0 does not   * have correct versions for TUSB_PRCM_REV or TUSB_INT_CTRL_REV.   */ -u8 tusb_get_revision(struct musb *musb) +static u8 tusb_get_revision(struct musb *musb)  {  	void __iomem	*tbase = musb->ctrl_base;  	u32		die_id; @@ -50,12 +60,12 @@ u8 tusb_get_revision(struct musb *musb)  	return rev;  } -static int __init tusb_print_revision(struct musb *musb) +static void tusb_print_revision(struct musb *musb)  {  	void __iomem	*tbase = musb->ctrl_base;  	u8		rev; -	rev = tusb_get_revision(musb); +	rev = musb->tusb_revision;  	pr_info("tusb: %s%i.%i %s%i.%i %s%i.%i %s%i.%i %s%i %s%i.%i\n",  		"prcm", @@ -74,8 +84,6 @@ static int __init tusb_print_revision(struct musb *musb)  		TUSB_DIDR1_HI_CHIP_REV(musb_readl(tbase, TUSB_DIDR1_HI)),  		"rev",  		TUSB_REV_MAJOR(rev), TUSB_REV_MINOR(rev)); - -	return tusb_get_revision(musb);  }  #define WBUS_QUIRK_MASK	(TUSB_PHY_OTG_CTRL_TESTM2 | TUSB_PHY_OTG_CTRL_TESTM1 \ @@ -100,7 +108,7 @@ static void tusb_wbus_quirk(struct musb *musb, int enabled)  		tmp = phy_otg_ena & ~WBUS_QUIRK_MASK;  		tmp |= TUSB_PHY_OTG_CTRL_WRPROTECT | TUSB_PHY_OTG_CTRL_TESTM2;  		musb_writel(tbase, TUSB_PHY_OTG_CTRL_ENABLE, tmp); -		DBG(2, "Enabled tusb wbus quirk ctrl %08x ena %08x\n", +		dev_dbg(musb->controller, "Enabled tusb wbus quirk ctrl %08x ena %08x\n",  			musb_readl(tbase, TUSB_PHY_OTG_CTRL),  			musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE));  	} else if (musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE) @@ -109,7 +117,7 @@ static void tusb_wbus_quirk(struct musb *musb, int enabled)  		musb_writel(tbase, TUSB_PHY_OTG_CTRL, tmp);  		tmp = TUSB_PHY_OTG_CTRL_WRPROTECT | phy_otg_ena;  		musb_writel(tbase, TUSB_PHY_OTG_CTRL_ENABLE, tmp); -		DBG(2, "Disabled tusb wbus quirk ctrl %08x ena %08x\n", +		dev_dbg(musb->controller, "Disabled tusb wbus quirk ctrl %08x ena %08x\n",  			musb_readl(tbase, TUSB_PHY_OTG_CTRL),  			musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE));  		phy_otg_ctrl = 0; @@ -144,7 +152,7 @@ tusb_fifo_write_unaligned(void __iomem *fifo, const u8 *buf, u16 len)  }  static inline void tusb_fifo_read_unaligned(void __iomem *fifo, -						void __iomem *buf, u16 len) +						void *buf, u16 len)  {  	u32		val;  	int		i; @@ -166,13 +174,14 @@ static inline void tusb_fifo_read_unaligned(void __iomem *fifo,  void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf)  { +	struct musb *musb = hw_ep->musb;  	void __iomem	*ep_conf = hw_ep->conf;  	void __iomem	*fifo = hw_ep->fifo;  	u8		epnum = hw_ep->epnum;  	prefetch(buf); -	DBG(4, "%cX ep%d fifo %p count %d buf %p\n", +	dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n",  			'T', epnum, fifo, len, buf);  	if (epnum) @@ -187,7 +196,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf)  		/* Best case is 32bit-aligned destination address */  		if ((0x02 & (unsigned long) buf) == 0) {  			if (len >= 4) { -				writesl(fifo, buf, len >> 2); +				iowrite32_rep(fifo, buf, len >> 2);  				buf += (len & ~0x03);  				len &= 0x03;  			} @@ -215,11 +224,12 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf)  void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)  { +	struct musb *musb = hw_ep->musb;  	void __iomem	*ep_conf = hw_ep->conf;  	void __iomem	*fifo = hw_ep->fifo;  	u8		epnum = hw_ep->epnum; -	DBG(4, "%cX ep%d fifo %p count %d buf %p\n", +	dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n",  			'R', epnum, fifo, len, buf);  	if (epnum) @@ -233,7 +243,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)  		/* Best case is 32bit-aligned destination address */  		if ((0x02 & (unsigned long) buf) == 0) {  			if (len >= 4) { -				readsl(fifo, buf, len >> 2); +				ioread32_rep(fifo, buf, len >> 2);  				buf += (len & ~0x03);  				len &= 0x03;  			} @@ -261,31 +271,18 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)  static struct musb *the_musb; -#ifdef CONFIG_USB_GADGET_MUSB_HDRC -  /* This is used by gadget drivers, and OTG transceiver logic, allowing   * at most mA current to be drawn from VBUS during a Default-B session   * (that is, while VBUS exceeds 4.4V).  In Default-A (including pure host   * mode), or low power Default-B sessions, something else supplies power.   * Caller must take care of locking.   */ -static int tusb_draw_power(struct otg_transceiver *x, unsigned mA) +static int tusb_draw_power(struct usb_phy *x, unsigned mA)  {  	struct musb	*musb = the_musb;  	void __iomem	*tbase = musb->ctrl_base;  	u32		reg; -	/* -	 * 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. -	 */ -	if (musb->set_clock) { -		if (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.  	 * @@ -296,7 +293,7 @@ static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)  	 * The actual current usage would be very board-specific.  For now,  	 * it's simpler to just use an aggregate (also board-specific).  	 */ -	if (x->default_a || mA < (musb->min_power << 1)) +	if (x->otg->default_a || mA < (musb->min_power << 1))  		mA = 0;  	reg = musb_readl(tbase, TUSB_PRCM_MNGMT); @@ -309,14 +306,10 @@ static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)  	}  	musb_writel(tbase, TUSB_PRCM_MNGMT, reg); -	DBG(2, "draw max %d mA VBUS\n", mA); +	dev_dbg(musb->controller, "draw max %d mA VBUS\n", mA);  	return 0;  } -#else -#define tusb_draw_power	NULL -#endif -  /* workaround for issue 13:  change clock during chip idle   * (to be fixed in rev3 silicon) ... symptoms include disconnect   * or looping suspend/resume cycles @@ -348,13 +341,13 @@ static void tusb_set_clock_source(struct musb *musb, unsigned mode)   * USB link is not suspended ... and tells us the relevant wakeup   * events.  SW_EN for voltage is handled separately.   */ -void tusb_allow_idle(struct musb *musb, u32 wakeup_enables) +static void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)  {  	void __iomem	*tbase = musb->ctrl_base;  	u32		reg;  	if ((wakeup_enables & TUSB_PRCM_WBUS) -			&& (tusb_get_revision(musb) == TUSB_REV_30)) +			&& (musb->tusb_revision == TUSB_REV_30))  		tusb_wbus_quirk(musb, 1);  	tusb_set_clock_source(musb, 0); @@ -379,13 +372,13 @@ void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)  	reg |= TUSB_PRCM_MNGMT_PM_IDLE | TUSB_PRCM_MNGMT_DEV_IDLE;  	musb_writel(tbase, TUSB_PRCM_MNGMT, reg); -	DBG(6, "idle, wake on %02x\n", wakeup_enables); +	dev_dbg(musb->controller, "idle, wake on %02x\n", wakeup_enables);  }  /*   * Updates cable VBUS status. Caller must take care of locking.   */ -int musb_platform_get_vbus_status(struct musb *musb) +static int tusb_musb_vbus_status(struct musb *musb)  {  	void __iomem	*tbase = musb->ctrl_base;  	u32		otg_stat, prcm_mngmt; @@ -426,12 +419,12 @@ static void musb_do_idle(unsigned long _musb)  		if ((musb->a_wait_bcon != 0)  			&& (musb->idle_timeout == 0  				|| time_after(jiffies, musb->idle_timeout))) { -			DBG(4, "Nothing connected %s, turning off VBUS\n", -					otg_state_string(musb)); +			dev_dbg(musb->controller, "Nothing connected %s, turning off VBUS\n", +					usb_otg_state_string(musb->xceiv->state));  		}  		/* FALLTHROUGH */  	case OTG_STATE_A_IDLE: -		tusb_source_power(musb, 0); +		tusb_musb_set_vbus(musb, 0);  	default:  		break;  	} @@ -443,19 +436,14 @@ static void musb_do_idle(unsigned long _musb)  		if (is_host_active(musb) && (musb->port1_status >> 16))  			goto done; -#ifdef CONFIG_USB_GADGET_MUSB_HDRC -		if (is_peripheral_enabled(musb) && !musb->gadget_driver) +		if (!musb->gadget_driver) {  			wakeups = 0; -		else { +		} else {  			wakeups = TUSB_PRCM_WHOSTDISCON -					| TUSB_PRCM_WBUS +				| TUSB_PRCM_WBUS  					| TUSB_PRCM_WVBUS; -			if (is_otg_enabled(musb)) -				wakeups |= TUSB_PRCM_WID; +			wakeups |= TUSB_PRCM_WID;  		} -#else -		wakeups = TUSB_PRCM_WHOSTDISCON | TUSB_PRCM_WBUS; -#endif  		tusb_allow_idle(musb, wakeups);  	}  done: @@ -475,7 +463,7 @@ done:   * we don't want to treat that full speed J as a wakeup event.   * ... peripherals must draw only suspend current after 10 msec.   */ -void musb_platform_try_idle(struct musb *musb, unsigned long timeout) +static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout)  {  	unsigned long		default_timeout = jiffies + msecs_to_jiffies(3);  	static unsigned long	last_timer; @@ -486,7 +474,8 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)  	/* 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)); +		dev_dbg(musb->controller, "%s active, deleting timer\n", +			usb_otg_state_string(musb->xceiv->state));  		del_timer(&musb_idle_timer);  		last_timer = jiffies;  		return; @@ -496,14 +485,14 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)  		if (!timer_pending(&musb_idle_timer))  			last_timer = timeout;  		else { -			DBG(4, "Longer idle timer already pending, ignoring\n"); +			dev_dbg(musb->controller, "Longer idle timer already pending, ignoring\n");  			return;  		}  	}  	last_timer = timeout; -	DBG(4, "%s inactive, for idle timer for %lu ms\n", -		otg_state_string(musb), +	dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n", +		usb_otg_state_string(musb->xceiv->state),  		(unsigned long)jiffies_to_msecs(timeout - jiffies));  	mod_timer(&musb_idle_timer, timeout);  } @@ -515,11 +504,12 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)  				| TUSB_DEV_OTG_TIMER_ENABLE) \  		: 0) -static void tusb_source_power(struct musb *musb, int is_on) +static void tusb_musb_set_vbus(struct musb *musb, int is_on)  {  	void __iomem	*tbase = musb->ctrl_base;  	u32		conf, prcm, timer;  	u8		devctl; +	struct usb_otg	*otg = musb->xceiv->otg;  	/* HDRC controls CPEN, but beware current surges during device  	 * connect.  They can trigger transient overcurrent conditions @@ -531,10 +521,8 @@ static void tusb_source_power(struct musb *musb, int is_on)  	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);  	if (is_on) { -		if (musb->set_clock) -			musb->set_clock(musb->clock, 1);  		timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE); -		musb->xceiv->default_a = 1; +		otg->default_a = 1;  		musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;  		devctl |= MUSB_DEVCTL_SESSION; @@ -560,19 +548,17 @@ static void tusb_source_power(struct musb *musb, int is_on)  				musb->xceiv->state = OTG_STATE_A_IDLE;  			}  			musb->is_active = 0; -			musb->xceiv->default_a = 1; +			otg->default_a = 1;  			MUSB_HST_MODE(musb);  		} else {  			musb->is_active = 0; -			musb->xceiv->default_a = 0; +			otg->default_a = 0;  			musb->xceiv->state = OTG_STATE_B_IDLE;  			MUSB_DEV_MODE(musb);  		}  		devctl &= ~MUSB_DEVCTL_SESSION;  		conf &= ~TUSB_DEV_CONF_USB_HOST_MODE; -		if (musb->set_clock) -			musb->set_clock(musb->clock, 0);  	}  	prcm &= ~(TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN); @@ -581,8 +567,8 @@ static void tusb_source_power(struct musb *musb, int is_on)  	musb_writel(tbase, TUSB_DEV_CONF, conf);  	musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); -	DBG(1, "VBUS %s, devctl %02x otg %3x conf %08x prcm %08x\n", -		otg_state_string(musb), +	dev_dbg(musb->controller, "VBUS %s, devctl %02x otg %3x conf %08x prcm %08x\n", +		usb_otg_state_string(musb->xceiv->state),  		musb_readb(musb->mregs, MUSB_DEVCTL),  		musb_readl(tbase, TUSB_DEV_OTG_STAT),  		conf, prcm); @@ -594,21 +580,12 @@ static void tusb_source_power(struct musb *musb, int is_on)   *   * Note that if a mini-A cable is plugged in the ID line will stay down as   * the weak ID pull-up is not able to pull the ID up. - * - * REVISIT: It would be possible to add support for changing between host - * and peripheral modes in non-OTG configurations by reconfiguring hardware - * and then setting musb->board_mode. For now, only support OTG mode.   */ -int musb_platform_set_mode(struct musb *musb, u8 musb_mode) +static int tusb_musb_set_mode(struct musb *musb, u8 musb_mode)  {  	void __iomem	*tbase = musb->ctrl_base;  	u32		otg_stat, phy_otg_ctrl, phy_otg_ena, dev_conf; -	if (musb->board_mode != MUSB_OTG) { -		ERR("Changing mode currently only supported in OTG mode\n"); -		return -EINVAL; -	} -  	otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);  	phy_otg_ctrl = musb_readl(tbase, TUSB_PHY_OTG_CTRL);  	phy_otg_ena = musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE); @@ -616,33 +593,25 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)  	switch (musb_mode) { -#ifdef CONFIG_USB_MUSB_HDRC_HCD  	case MUSB_HOST:		/* Disable PHY ID detect, ground ID */  		phy_otg_ctrl &= ~TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;  		phy_otg_ena |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;  		dev_conf |= TUSB_DEV_CONF_ID_SEL;  		dev_conf &= ~TUSB_DEV_CONF_SOFT_ID;  		break; -#endif - -#ifdef CONFIG_USB_GADGET_MUSB_HDRC  	case MUSB_PERIPHERAL:	/* Disable PHY ID detect, keep ID pull-up on */  		phy_otg_ctrl |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;  		phy_otg_ena |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;  		dev_conf |= (TUSB_DEV_CONF_ID_SEL | TUSB_DEV_CONF_SOFT_ID);  		break; -#endif - -#ifdef CONFIG_USB_MUSB_OTG  	case MUSB_OTG:		/* Use PHY ID detection */  		phy_otg_ctrl |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;  		phy_otg_ena |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP;  		dev_conf &= ~(TUSB_DEV_CONF_ID_SEL | TUSB_DEV_CONF_SOFT_ID);  		break; -#endif  	default: -		DBG(2, "Trying to set mode %i\n", musb_mode); +		dev_dbg(musb->controller, "Trying to set mode %i\n", musb_mode);  		return -EINVAL;  	} @@ -666,18 +635,16 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)  {  	u32		otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);  	unsigned long	idle_timeout = 0; +	struct usb_otg	*otg = musb->xceiv->otg;  	/* ID pin */  	if ((int_src & TUSB_INT_SRC_ID_STATUS_CHNG)) {  		int	default_a; -		if (is_otg_enabled(musb)) -			default_a = !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS); -		else -			default_a = is_host_enabled(musb); -		DBG(2, "Default-%c\n", default_a ? 'A' : 'B'); -		musb->xceiv->default_a = default_a; -		tusb_source_power(musb, default_a); +		default_a = !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS); +		dev_dbg(musb->controller, "Default-%c\n", default_a ? 'A' : 'B'); +		otg->default_a = default_a; +		tusb_musb_set_vbus(musb, default_a);  		/* Don't allow idling immediately */  		if (default_a) @@ -688,9 +655,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)  	if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) {  		/* B-dev state machine:  no vbus ~= disconnect */ -		if ((is_otg_enabled(musb) && !musb->xceiv->default_a) -				|| !is_host_enabled(musb)) { -#ifdef CONFIG_USB_MUSB_HDRC_HCD +		if (!otg->default_a) {  			/* ? musb_root_disconnect(musb); */  			musb->port1_status &=  				~(USB_PORT_STAT_CONNECTION @@ -699,10 +664,9 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)  				| USB_PORT_STAT_HIGH_SPEED  				| USB_PORT_STAT_TEST  				); -#endif  			if (otg_stat & TUSB_DEV_OTG_STAT_SESS_END) { -				DBG(1, "Forcing disconnect (no interrupt)\n"); +				dev_dbg(musb->controller, "Forcing disconnect (no interrupt)\n");  				if (musb->xceiv->state != OTG_STATE_B_IDLE) {  					/* INTR_DISCONNECT can hide... */  					musb->xceiv->state = OTG_STATE_B_IDLE; @@ -710,19 +674,19 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)  				}  				musb->is_active = 0;  			} -			DBG(2, "vbus change, %s, otg %03x\n", -				otg_state_string(musb), otg_stat); +			dev_dbg(musb->controller, "vbus change, %s, otg %03x\n", +				usb_otg_state_string(musb->xceiv->state), otg_stat);  			idle_timeout = jiffies + (1 * HZ);  			schedule_work(&musb->irq_work);  		} else /* A-dev state machine */ { -			DBG(2, "vbus change, %s, otg %03x\n", -				otg_state_string(musb), otg_stat); +			dev_dbg(musb->controller, "vbus change, %s, otg %03x\n", +				usb_otg_state_string(musb->xceiv->state), otg_stat);  			switch (musb->xceiv->state) {  			case OTG_STATE_A_IDLE: -				DBG(2, "Got SRP, turning on VBUS\n"); -				musb_set_vbus(musb, 1); +				dev_dbg(musb->controller, "Got SRP, turning on VBUS\n"); +				musb_platform_set_vbus(musb, 1);  				/* CONNECT can wake if a_wait_bcon is set */  				if (musb->a_wait_bcon != 0) @@ -748,11 +712,11 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)  				 */  				if (musb->vbuserr_retry) {  					musb->vbuserr_retry--; -					tusb_source_power(musb, 1); +					tusb_musb_set_vbus(musb, 1);  				} else {  					musb->vbuserr_retry  						= VBUSERR_RETRY_COUNT; -					tusb_source_power(musb, 0); +					tusb_musb_set_vbus(musb, 0);  				}  				break;  			default: @@ -765,7 +729,8 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)  	if (int_src & TUSB_INT_SRC_OTG_TIMEOUT) {  		u8	devctl; -		DBG(4, "%s timer, %03x\n", otg_state_string(musb), otg_stat); +		dev_dbg(musb->controller, "%s timer, %03x\n", +			usb_otg_state_string(musb->xceiv->state), otg_stat);  		switch (musb->xceiv->state) {  		case OTG_STATE_A_WAIT_VRISE: @@ -776,7 +741,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)  			if (otg_stat & TUSB_DEV_OTG_STAT_VBUS_VALID) {  				if ((devctl & MUSB_DEVCTL_VBUS)  						!= MUSB_DEVCTL_VBUS) { -					DBG(2, "devctl %02x\n", devctl); +					dev_dbg(musb->controller, "devctl %02x\n", devctl);  					break;  				}  				musb->xceiv->state = OTG_STATE_A_WAIT_BCON; @@ -786,7 +751,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)  			} else {  				/* REVISIT report overcurrent to hub? */  				ERR("vbus too slow, devctl %02x\n", devctl); -				tusb_source_power(musb, 0); +				tusb_musb_set_vbus(musb, 0);  			}  			break;  		case OTG_STATE_A_WAIT_BCON: @@ -807,7 +772,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)  	return idle_timeout;  } -static irqreturn_t tusb_interrupt(int irq, void *__hci) +static irqreturn_t tusb_musb_interrupt(int irq, void *__hci)  {  	struct musb	*musb = __hci;  	void __iomem	*tbase = musb->ctrl_base; @@ -821,7 +786,7 @@ static irqreturn_t tusb_interrupt(int irq, void *__hci)  	musb_writel(tbase, TUSB_INT_MASK, ~TUSB_INT_MASK_RESERVED_BITS);  	int_src = musb_readl(tbase, TUSB_INT_SRC) & ~TUSB_INT_SRC_RESERVED_BITS; -	DBG(3, "TUSB IRQ %08x\n", int_src); +	dev_dbg(musb->controller, "TUSB IRQ %08x\n", int_src);  	musb->int_usb = (u8) int_src; @@ -830,7 +795,7 @@ static irqreturn_t tusb_interrupt(int irq, void *__hci)  		u32	reg;  		u32	i; -		if (tusb_get_revision(musb) == TUSB_REV_30) +		if (musb->tusb_revision == TUSB_REV_30)  			tusb_wbus_quirk(musb, 0);  		/* there are issues re-locking the PLL on wakeup ... */ @@ -842,7 +807,7 @@ static irqreturn_t tusb_interrupt(int irq, void *__hci)  			reg = musb_readl(tbase, TUSB_SCRATCH_PAD);  			if (reg == i)  				break; -			DBG(6, "TUSB NOR not ready\n"); +			dev_dbg(musb->controller, "TUSB NOR not ready\n");  		}  		/* work around issue 13 (2nd half) */ @@ -854,7 +819,7 @@ static irqreturn_t tusb_interrupt(int irq, void *__hci)  			musb->is_active = 1;  			schedule_work(&musb->irq_work);  		} -		DBG(3, "wake %sactive %02x\n", +		dev_dbg(musb->controller, "wake %sactive %02x\n",  				musb->is_active ? "" : "in", reg);  		/* REVISIT host side TUSB_PRCM_WHOSTDISCON, TUSB_PRCM_WBUS */ @@ -876,7 +841,7 @@ static irqreturn_t tusb_interrupt(int irq, void *__hci)  		u32	dma_src = musb_readl(tbase, TUSB_DMA_INT_SRC);  		u32	real_dma_src = musb_readl(tbase, TUSB_DMA_INT_MASK); -		DBG(3, "DMA IRQ %08x\n", dma_src); +		dev_dbg(musb->controller, "DMA IRQ %08x\n", dma_src);  		real_dma_src = ~real_dma_src & dma_src;  		if (tusb_dma_omap() && real_dma_src) {  			int	tx_source = (real_dma_src & 0xffff); @@ -884,7 +849,7 @@ static irqreturn_t tusb_interrupt(int irq, void *__hci)  			for (i = 1; i <= 15; i++) {  				if (tx_source & (1 << i)) { -					DBG(3, "completing ep%i %s\n", i, "tx"); +					dev_dbg(musb->controller, "completing ep%i %s\n", i, "tx");  					musb_dma_completion(musb, i, 1);  				}  			} @@ -911,7 +876,7 @@ static irqreturn_t tusb_interrupt(int irq, void *__hci)  	musb_writel(tbase, TUSB_INT_SRC_CLEAR,  		int_src & ~TUSB_INT_MASK_RESERVED_BITS); -	musb_platform_try_idle(musb, idle_timeout); +	tusb_musb_try_idle(musb, idle_timeout);  	musb_writel(tbase, TUSB_INT_MASK, int_mask);  	spin_unlock_irqrestore(&musb->lock, flags); @@ -926,7 +891,7 @@ static int dma_off;   * REVISIT:   * - Check what is unnecessary in MGC_HdrcStart()   */ -void musb_platform_enable(struct musb *musb) +static void tusb_musb_enable(struct musb *musb)  {  	void __iomem	*tbase = musb->ctrl_base; @@ -952,7 +917,7 @@ void musb_platform_enable(struct musb *musb)  	musb_writel(tbase, TUSB_INT_CTRL_CONF,  			TUSB_INT_CTRL_CONF_INT_RELCYC(0)); -	set_irq_type(musb->nIrq, IRQ_TYPE_LEVEL_LOW); +	irq_set_irq_type(musb->nIrq, IRQ_TYPE_LEVEL_LOW);  	/* maybe force into the Default-A OTG state machine */  	if (!(musb_readl(tbase, TUSB_DEV_OTG_STAT) @@ -970,7 +935,7 @@ void musb_platform_enable(struct musb *musb)  /*   * Disables TUSB6010. Caller must take care of locking.   */ -void musb_platform_disable(struct musb *musb) +static void tusb_musb_disable(struct musb *musb)  {  	void __iomem	*tbase = musb->ctrl_base; @@ -995,7 +960,7 @@ void musb_platform_disable(struct musb *musb)   * Sets up TUSB6010 CPU interface specific signals and registers   * Note: Settings optimized for OMAP24xx   */ -static void __init tusb_setup_cpu_interface(struct musb *musb) +static void tusb_setup_cpu_interface(struct musb *musb)  {  	void __iomem	*tbase = musb->ctrl_base; @@ -1022,7 +987,7 @@ static void __init tusb_setup_cpu_interface(struct musb *musb)  	musb_writel(tbase, TUSB_WAIT_COUNT, 1);  } -static int __init tusb_start(struct musb *musb) +static int tusb_musb_start(struct musb *musb)  {  	void __iomem	*tbase = musb->ctrl_base;  	int		ret = 0; @@ -1044,10 +1009,11 @@ static int __init tusb_start(struct musb *musb)  		goto err;  	} -	ret = tusb_print_revision(musb); -	if (ret < 2) { +	musb->tusb_revision = tusb_get_revision(musb); +	tusb_print_revision(musb); +	if (musb->tusb_revision < 2) {  		printk(KERN_ERR "tusb: Unsupported TUSB6010 revision %i\n", -				ret); +				musb->tusb_revision);  		goto err;  	} @@ -1091,17 +1057,16 @@ err:  	return -ENODEV;  } -int __init musb_platform_init(struct musb *musb, void *board_data) +static int tusb_musb_init(struct musb *musb)  {  	struct platform_device	*pdev;  	struct resource		*mem;  	void __iomem		*sync = NULL;  	int			ret; -	usb_nop_xceiv_register(); -	musb->xceiv = otg_get_transceiver(); -	if (!musb->xceiv) -		return -ENODEV; +	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); +	if (IS_ERR_OR_NULL(musb->xceiv)) +		return -EPROBE_DEFER;  	pdev = to_platform_device(musb->controller); @@ -1131,20 +1096,16 @@ int __init musb_platform_init(struct musb *musb, void *board_data)  	 */  	musb->mregs += TUSB_BASE_OFFSET; -	ret = tusb_start(musb); +	ret = tusb_musb_start(musb);  	if (ret) {  		printk(KERN_ERR "Could not start tusb6010 (%d)\n",  				ret);  		goto done;  	} -	musb->isr = tusb_interrupt; +	musb->isr = tusb_musb_interrupt; -	if (is_host_enabled(musb)) -		musb->board_set_vbus = tusb_source_power; -	if (is_peripheral_enabled(musb)) { -		musb->xceiv->set_power = tusb_draw_power; -		the_musb = musb; -	} +	musb->xceiv->set_power = tusb_draw_power; +	the_musb = musb;  	setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); @@ -1153,13 +1114,12 @@ done:  		if (sync)  			iounmap(sync); -		otg_put_transceiver(musb->xceiv); -		usb_nop_xceiv_unregister(); +		usb_put_phy(musb->xceiv);  	}  	return ret;  } -int musb_platform_exit(struct musb *musb) +static int tusb_musb_exit(struct musb *musb)  {  	del_timer_sync(&musb_idle_timer);  	the_musb = NULL; @@ -1169,7 +1129,113 @@ int musb_platform_exit(struct musb *musb)  	iounmap(musb->sync_va); -	otg_put_transceiver(musb->xceiv); -	usb_nop_xceiv_unregister(); +	usb_put_phy(musb->xceiv);  	return 0;  } + +static const struct musb_platform_ops tusb_ops = { +	.init		= tusb_musb_init, +	.exit		= tusb_musb_exit, + +	.enable		= tusb_musb_enable, +	.disable	= tusb_musb_disable, + +	.set_mode	= tusb_musb_set_mode, +	.try_idle	= tusb_musb_try_idle, + +	.vbus_status	= tusb_musb_vbus_status, +	.set_vbus	= tusb_musb_set_vbus, +}; + +static const struct platform_device_info tusb_dev_info = { +	.name		= "musb-hdrc", +	.id		= PLATFORM_DEVID_AUTO, +	.dma_mask	= DMA_BIT_MASK(32), +}; + +static int tusb_probe(struct platform_device *pdev) +{ +	struct resource musb_resources[3]; +	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev); +	struct platform_device		*musb; +	struct tusb6010_glue		*glue; +	struct platform_device_info	pinfo; +	int				ret = -ENOMEM; + +	glue = kzalloc(sizeof(*glue), GFP_KERNEL); +	if (!glue) { +		dev_err(&pdev->dev, "failed to allocate glue context\n"); +		goto err0; +	} + +	glue->dev			= &pdev->dev; + +	pdata->platform_ops		= &tusb_ops; + +	usb_phy_generic_register(); +	platform_set_drvdata(pdev, glue); + +	memset(musb_resources, 0x00, sizeof(*musb_resources) * +			ARRAY_SIZE(musb_resources)); + +	musb_resources[0].name = pdev->resource[0].name; +	musb_resources[0].start = pdev->resource[0].start; +	musb_resources[0].end = pdev->resource[0].end; +	musb_resources[0].flags = pdev->resource[0].flags; + +	musb_resources[1].name = pdev->resource[1].name; +	musb_resources[1].start = pdev->resource[1].start; +	musb_resources[1].end = pdev->resource[1].end; +	musb_resources[1].flags = pdev->resource[1].flags; + +	musb_resources[2].name = pdev->resource[2].name; +	musb_resources[2].start = pdev->resource[2].start; +	musb_resources[2].end = pdev->resource[2].end; +	musb_resources[2].flags = pdev->resource[2].flags; + +	pinfo = tusb_dev_info; +	pinfo.parent = &pdev->dev; +	pinfo.res = musb_resources; +	pinfo.num_res = ARRAY_SIZE(musb_resources); +	pinfo.data = pdata; +	pinfo.size_data = sizeof(*pdata); + +	glue->musb = musb = platform_device_register_full(&pinfo); +	if (IS_ERR(musb)) { +		ret = PTR_ERR(musb); +		dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); +		goto err3; +	} + +	return 0; + +err3: +	kfree(glue); + +err0: +	return ret; +} + +static int tusb_remove(struct platform_device *pdev) +{ +	struct tusb6010_glue		*glue = platform_get_drvdata(pdev); + +	platform_device_unregister(glue->musb); +	usb_phy_generic_unregister(glue->phy); +	kfree(glue); + +	return 0; +} + +static struct platform_driver tusb_driver = { +	.probe		= tusb_probe, +	.remove		= tusb_remove, +	.driver		= { +		.name	= "musb-tusb", +	}, +}; + +MODULE_DESCRIPTION("TUSB6010 MUSB Glue Layer"); +MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); +MODULE_LICENSE("GPL v2"); +module_platform_driver(tusb_driver); diff --git a/drivers/usb/musb/tusb6010.h b/drivers/usb/musb/tusb6010.h index 35c933a5d99..aec86c86ce3 100644 --- a/drivers/usb/musb/tusb6010.h +++ b/drivers/usb/musb/tusb6010.h @@ -12,14 +12,6 @@  #ifndef __TUSB6010_H__  #define __TUSB6010_H__ -extern u8 tusb_get_revision(struct musb *musb); - -#ifdef CONFIG_USB_TUSB6010 -#define musb_in_tusb()			1 -#else -#define musb_in_tusb()			0 -#endif -  #ifdef CONFIG_USB_TUSB_OMAP_DMA  #define tusb_dma_omap()			1  #else diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c index c061a88f2b0..3ce152c0408 100644 --- a/drivers/usb/musb/tusb6010_omap.c +++ b/drivers/usb/musb/tusb6010_omap.c @@ -11,20 +11,26 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/usb.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h>  #include <linux/slab.h> -#include <plat/dma.h> -#include <plat/mux.h> +#include <linux/omap-dma.h>  #include "musb_core.h" +#include "tusb6010.h"  #define to_chdat(c)		((struct tusb_omap_dma_ch *)(c)->private_data)  #define MAX_DMAREQ		5	/* REVISIT: Really 6, but req5 not OK */ +#define OMAP24XX_DMA_EXT_DMAREQ0	2 +#define OMAP24XX_DMA_EXT_DMAREQ1	3 +#define OMAP242X_DMA_EXT_DMAREQ2	14 +#define OMAP242X_DMA_EXT_DMAREQ3	15 +#define OMAP242X_DMA_EXT_DMAREQ4	16 +#define OMAP242X_DMA_EXT_DMAREQ5	64 +  struct tusb_omap_dma_ch {  	struct musb		*musb;  	void __iomem		*tbase; @@ -59,28 +65,6 @@ struct tusb_omap_dma {  	unsigned			multichannel:1;  }; -static int tusb_omap_dma_start(struct dma_controller *c) -{ -	struct tusb_omap_dma	*tusb_dma; - -	tusb_dma = container_of(c, struct tusb_omap_dma, controller); - -	/* DBG(3, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */ - -	return 0; -} - -static int tusb_omap_dma_stop(struct dma_controller *c) -{ -	struct tusb_omap_dma	*tusb_dma; - -	tusb_dma = container_of(c, struct tusb_omap_dma, controller); - -	/* DBG(3, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */ - -	return 0; -} -  /*   * Allocate dmareq0 to the current channel unless it's already taken   */ @@ -89,7 +73,7 @@ static inline int tusb_omap_use_shared_dmareq(struct tusb_omap_dma_ch *chdat)  	u32		reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP);  	if (reg != 0) { -		DBG(3, "ep%i dmareq0 is busy for ep%i\n", +		dev_dbg(chdat->musb->controller, "ep%i dmareq0 is busy for ep%i\n",  			chdat->epnum, reg & 0xf);  		return -EAGAIN;  	} @@ -143,7 +127,7 @@ static void tusb_omap_dma_cb(int lch, u16 ch_status, void *data)  	if (ch_status != OMAP_DMA_BLOCK_IRQ)  		printk(KERN_ERR "TUSB DMA error status: %i\n", ch_status); -	DBG(3, "ep%i %s dma callback ch: %i status: %x\n", +	dev_dbg(musb->controller, "ep%i %s dma callback ch: %i status: %x\n",  		chdat->epnum, chdat->tx ? "tx" : "rx",  		ch, ch_status); @@ -156,7 +140,7 @@ static void tusb_omap_dma_cb(int lch, u16 ch_status, void *data)  	/* HW issue #10: XFR_SIZE may get corrupt on DMA (both async & sync) */  	if (unlikely(remaining > chdat->transfer_len)) { -		DBG(2, "Corrupt %s dma ch%i XFR_SIZE: 0x%08lx\n", +		dev_dbg(musb->controller, "Corrupt %s dma ch%i XFR_SIZE: 0x%08lx\n",  			chdat->tx ? "tx" : "rx", chdat->ch,  			remaining);  		remaining = 0; @@ -165,13 +149,13 @@ static void tusb_omap_dma_cb(int lch, u16 ch_status, void *data)  	channel->actual_len = chdat->transfer_len - remaining;  	pio = chdat->len - channel->actual_len; -	DBG(3, "DMA remaining %lu/%u\n", remaining, chdat->transfer_len); +	dev_dbg(musb->controller, "DMA remaining %lu/%u\n", remaining, chdat->transfer_len);  	/* Transfer remaining 1 - 31 bytes */  	if (pio > 0 && pio < 32) {  		u8	*buf; -		DBG(3, "Using PIO for remaining %lu bytes\n", pio); +		dev_dbg(musb->controller, "Using PIO for remaining %lu bytes\n", pio);  		buf = phys_to_virt((u32)chdat->dma_addr) + chdat->transfer_len;  		if (chdat->tx) {  			dma_unmap_single(dev, chdat->dma_addr, @@ -209,7 +193,7 @@ static void tusb_omap_dma_cb(int lch, u16 ch_status, void *data)  		u16	csr;  		if (chdat->tx) { -			DBG(3, "terminating short tx packet\n"); +			dev_dbg(musb->controller, "terminating short tx packet\n");  			musb_ep_select(mbase, chdat->epnum);  			csr = musb_readw(hw_ep->regs, MUSB_TXCSR);  			csr |= MUSB_TXCSR_MODE | MUSB_TXCSR_TXPKTRDY @@ -264,7 +248,7 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,  	dma_remaining = TUSB_EP_CONFIG_XFR_SIZE(dma_remaining);  	if (dma_remaining) { -		DBG(2, "Busy %s dma ch%i, not using: %08x\n", +		dev_dbg(musb->controller, "Busy %s dma ch%i, not using: %08x\n",  			chdat->tx ? "tx" : "rx", chdat->ch,  			dma_remaining);  		return false; @@ -283,7 +267,7 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,  		sync_dev = chdat->sync_dev;  	} else {  		if (tusb_omap_use_shared_dmareq(chdat) != 0) { -			DBG(3, "could not get dma for ep%i\n", chdat->epnum); +			dev_dbg(musb->controller, "could not get dma for ep%i\n", chdat->epnum);  			return false;  		}  		if (tusb_dma->ch < 0) { @@ -326,7 +310,7 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,  	dma_params.frame_count	= chdat->transfer_len / 32; /* Burst sz frame */ -	DBG(3, "ep%i %s dma ch%i dma: %08x len: %u(%u) packet_sz: %i(%i)\n", +	dev_dbg(musb->controller, "ep%i %s dma ch%i dma: %08x len: %u(%u) packet_sz: %i(%i)\n",  		chdat->epnum, chdat->tx ? "tx" : "rx",  		ch, dma_addr, chdat->transfer_len, len,  		chdat->transfer_packet_sz, packet_sz); @@ -370,7 +354,7 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,  		dst_burst = OMAP_DMA_DATA_BURST_16;	/* 16x32 write */  	} -	DBG(3, "ep%i %s using %i-bit %s dma from 0x%08lx to 0x%08lx\n", +	dev_dbg(musb->controller, "ep%i %s using %i-bit %s dma from 0x%08lx to 0x%08lx\n",  		chdat->epnum, chdat->tx ? "tx" : "rx",  		(dma_params.data_type == OMAP_DMA_DATA_TYPE_S32) ? 32 : 16,  		((dma_addr & 0x3) == 0) ? "sync" : "async", @@ -525,7 +509,7 @@ tusb_omap_dma_allocate(struct dma_controller *c,  	/* REVISIT: Why does dmareq5 not work? */  	if (hw_ep->epnum == 0) { -		DBG(3, "Not allowing DMA for ep0 %s\n", tx ? "tx" : "rx"); +		dev_dbg(musb->controller, "Not allowing DMA for ep0 %s\n", tx ? "tx" : "rx");  		return NULL;  	} @@ -585,7 +569,7 @@ tusb_omap_dma_allocate(struct dma_controller *c,  		chdat->ch = -1;  	} -	DBG(3, "ep%i %s dma: %s dma%i dmareq%i sync%i\n", +	dev_dbg(musb->controller, "ep%i %s dma: %s dma%i dmareq%i sync%i\n",  		chdat->epnum,  		chdat->tx ? "tx" : "rx",  		chdat->ch >= 0 ? "dedicated" : "shared", @@ -598,7 +582,7 @@ tusb_omap_dma_allocate(struct dma_controller *c,  free_dmareq:  	tusb_omap_dma_free_dmareq(chdat); -	DBG(3, "ep%i: Could not get a DMA channel\n", chdat->epnum); +	dev_dbg(musb->controller, "ep%i: Could not get a DMA channel\n", chdat->epnum);  	channel->status = MUSB_DMA_STATUS_UNKNOWN;  	return NULL; @@ -611,7 +595,7 @@ static void tusb_omap_dma_release(struct dma_channel *channel)  	void __iomem		*tbase = musb->ctrl_base;  	u32			reg; -	DBG(3, "ep%i ch%i\n", chdat->epnum, chdat->ch); +	dev_dbg(musb->controller, "ep%i ch%i\n", chdat->epnum, chdat->ch);  	reg = musb_readl(tbase, TUSB_DMA_INT_MASK);  	if (chdat->tx) @@ -661,8 +645,7 @@ void dma_controller_destroy(struct dma_controller *c)  	kfree(tusb_dma);  } -struct dma_controller *__init -dma_controller_create(struct musb *musb, void __iomem *base) +struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *base)  {  	void __iomem		*tbase = musb->ctrl_base;  	struct tusb_omap_dma	*tusb_dma; @@ -680,7 +663,7 @@ dma_controller_create(struct musb *musb, void __iomem *base)  	tusb_dma = kzalloc(sizeof(struct tusb_omap_dma), GFP_KERNEL);  	if (!tusb_dma) -		goto cleanup; +		goto out;  	tusb_dma->musb = musb;  	tusb_dma->tbase = musb->ctrl_base; @@ -689,14 +672,12 @@ dma_controller_create(struct musb *musb, void __iomem *base)  	tusb_dma->dmareq = -1;  	tusb_dma->sync_dev = -1; -	tusb_dma->controller.start = tusb_omap_dma_start; -	tusb_dma->controller.stop = tusb_omap_dma_stop;  	tusb_dma->controller.channel_alloc = tusb_omap_dma_allocate;  	tusb_dma->controller.channel_release = tusb_omap_dma_release;  	tusb_dma->controller.channel_program = tusb_omap_dma_program;  	tusb_dma->controller.channel_abort = tusb_omap_dma_abort; -	if (tusb_get_revision(musb) >= TUSB_REV_30) +	if (musb->tusb_revision >= TUSB_REV_30)  		tusb_dma->multichannel = 1;  	for (i = 0; i < MAX_DMAREQ; i++) { @@ -721,6 +702,6 @@ dma_controller_create(struct musb *musb, void __iomem *base)  cleanup:  	dma_controller_destroy(&tusb_dma->controller); - +out:  	return NULL;  } diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c new file mode 100644 index 00000000000..f202e508846 --- /dev/null +++ b/drivers/usb/musb/ux500.c @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2010 ST-Ericsson AB + * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com> + * + * Based on omap2430.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/usb/musb-ux500.h> + +#include "musb_core.h" + +static struct musb_hdrc_config ux500_musb_hdrc_config = { +	.multipoint	= true, +	.dyn_fifo	= true, +	.num_eps	= 16, +	.ram_bits	= 16, +}; + +struct ux500_glue { +	struct device		*dev; +	struct platform_device	*musb; +	struct clk		*clk; +}; +#define glue_to_musb(g)	platform_get_drvdata(g->musb) + +static void ux500_musb_set_vbus(struct musb *musb, int is_on) +{ +	u8            devctl; +	unsigned long timeout = jiffies + msecs_to_jiffies(1000); +	/* HDRC controls CPEN, but beware current surges during device +	 * connect.  They can trigger transient overcurrent conditions +	 * that must be ignored. +	 */ + +	devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + +	if (is_on) { +		if (musb->xceiv->state == OTG_STATE_A_IDLE) { +			/* start the session */ +			devctl |= MUSB_DEVCTL_SESSION; +			musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); +			/* +			 * Wait for the musb to set as A device to enable the +			 * VBUS +			 */ +			while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) { + +				if (time_after(jiffies, timeout)) { +					dev_err(musb->controller, +					"configured as A device timeout"); +					break; +				} +			} + +		} else { +			musb->is_active = 1; +			musb->xceiv->otg->default_a = 1; +			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; +			devctl |= MUSB_DEVCTL_SESSION; +			MUSB_HST_MODE(musb); +		} +	} else { +		musb->is_active = 0; + +		/* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and jumping +		 * right to B_IDLE... +		 */ +		musb->xceiv->otg->default_a = 0; +		devctl &= ~MUSB_DEVCTL_SESSION; +		MUSB_DEV_MODE(musb); +	} +	musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); + +	/* +	 * Devctl values will be updated after vbus goes below +	 * session_valid. The time taken depends on the capacitance +	 * on VBUS line. The max discharge time can be upto 1 sec +	 * as per the spec. Typically on our platform, it is 200ms +	 */ +	if (!is_on) +		mdelay(200); + +	dev_dbg(musb->controller, "VBUS %s, devctl %02x\n", +		usb_otg_state_string(musb->xceiv->state), +		musb_readb(musb->mregs, MUSB_DEVCTL)); +} + +static int musb_otg_notifications(struct notifier_block *nb, +		unsigned long event, void *unused) +{ +	struct musb *musb = container_of(nb, struct musb, nb); + +	dev_dbg(musb->controller, "musb_otg_notifications %ld %s\n", +			event, usb_otg_state_string(musb->xceiv->state)); + +	switch (event) { +	case UX500_MUSB_ID: +		dev_dbg(musb->controller, "ID GND\n"); +		ux500_musb_set_vbus(musb, 1); +		break; +	case UX500_MUSB_VBUS: +		dev_dbg(musb->controller, "VBUS Connect\n"); +		break; +	case UX500_MUSB_NONE: +		dev_dbg(musb->controller, "VBUS Disconnect\n"); +		if (is_host_active(musb)) +			ux500_musb_set_vbus(musb, 0); +		else +			musb->xceiv->state = OTG_STATE_B_IDLE; +		break; +	default: +		dev_dbg(musb->controller, "ID float\n"); +		return NOTIFY_DONE; +	} +	return NOTIFY_OK; +} + +static irqreturn_t ux500_musb_interrupt(int irq, void *__hci) +{ +	unsigned long   flags; +	irqreturn_t     retval = IRQ_NONE; +	struct musb     *musb = __hci; + +	spin_lock_irqsave(&musb->lock, flags); + +	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); +	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); +	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); + +	if (musb->int_usb || musb->int_tx || musb->int_rx) +		retval = musb_interrupt(musb); + +	spin_unlock_irqrestore(&musb->lock, flags); + +	return retval; +} + +static int ux500_musb_init(struct musb *musb) +{ +	int status; + +	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); +	if (IS_ERR_OR_NULL(musb->xceiv)) { +		pr_err("HS USB OTG: no transceiver configured\n"); +		return -EPROBE_DEFER; +	} + +	musb->nb.notifier_call = musb_otg_notifications; +	status = usb_register_notifier(musb->xceiv, &musb->nb); +	if (status < 0) { +		dev_dbg(musb->controller, "notification register failed\n"); +		return status; +	} + +	musb->isr = ux500_musb_interrupt; + +	return 0; +} + +static int ux500_musb_exit(struct musb *musb) +{ +	usb_unregister_notifier(musb->xceiv, &musb->nb); + +	usb_put_phy(musb->xceiv); + +	return 0; +} + +static const struct musb_platform_ops ux500_ops = { +	.init		= ux500_musb_init, +	.exit		= ux500_musb_exit, + +	.set_vbus	= ux500_musb_set_vbus, +}; + +static struct musb_hdrc_platform_data * +ux500_of_probe(struct platform_device *pdev, struct device_node *np) +{ +	struct musb_hdrc_platform_data *pdata; +	const char *mode; +	int strlen; + +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); +	if (!pdata) +		return NULL; + +	mode = of_get_property(np, "dr_mode", &strlen); +	if (!mode) { +		dev_err(&pdev->dev, "No 'dr_mode' property found\n"); +		return NULL; +	} + +	if (strlen > 0) { +		if (!strcmp(mode, "host")) +			pdata->mode = MUSB_HOST; +		if (!strcmp(mode, "otg")) +			pdata->mode = MUSB_OTG; +		if (!strcmp(mode, "peripheral")) +			pdata->mode = MUSB_PERIPHERAL; +	} + +	return pdata; +} + +static int ux500_probe(struct platform_device *pdev) +{ +	struct resource musb_resources[2]; +	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev); +	struct device_node		*np = pdev->dev.of_node; +	struct platform_device		*musb; +	struct ux500_glue		*glue; +	struct clk			*clk; +	int				ret = -ENOMEM; + +	if (!pdata) { +		if (np) { +			pdata = ux500_of_probe(pdev, np); +			if (!pdata) +				goto err0; + +			pdev->dev.platform_data = pdata; +		} else { +			dev_err(&pdev->dev, "no pdata or device tree found\n"); +			goto err0; +		} +	} + +	glue = kzalloc(sizeof(*glue), GFP_KERNEL); +	if (!glue) { +		dev_err(&pdev->dev, "failed to allocate glue context\n"); +		goto err0; +	} + +	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); +	if (!musb) { +		dev_err(&pdev->dev, "failed to allocate musb device\n"); +		goto err1; +	} + +	clk = clk_get(&pdev->dev, NULL); +	if (IS_ERR(clk)) { +		dev_err(&pdev->dev, "failed to get clock\n"); +		ret = PTR_ERR(clk); +		goto err3; +	} + +	ret = clk_prepare_enable(clk); +	if (ret) { +		dev_err(&pdev->dev, "failed to enable clock\n"); +		goto err4; +	} + +	musb->dev.parent		= &pdev->dev; +	musb->dev.dma_mask		= &pdev->dev.coherent_dma_mask; +	musb->dev.coherent_dma_mask	= pdev->dev.coherent_dma_mask; + +	glue->dev			= &pdev->dev; +	glue->musb			= musb; +	glue->clk			= clk; + +	pdata->platform_ops		= &ux500_ops; +	pdata->config 			= &ux500_musb_hdrc_config; + +	platform_set_drvdata(pdev, glue); + +	memset(musb_resources, 0x00, sizeof(*musb_resources) * +			ARRAY_SIZE(musb_resources)); + +	musb_resources[0].name = pdev->resource[0].name; +	musb_resources[0].start = pdev->resource[0].start; +	musb_resources[0].end = pdev->resource[0].end; +	musb_resources[0].flags = pdev->resource[0].flags; + +	musb_resources[1].name = pdev->resource[1].name; +	musb_resources[1].start = pdev->resource[1].start; +	musb_resources[1].end = pdev->resource[1].end; +	musb_resources[1].flags = pdev->resource[1].flags; + +	ret = platform_device_add_resources(musb, musb_resources, +			ARRAY_SIZE(musb_resources)); +	if (ret) { +		dev_err(&pdev->dev, "failed to add resources\n"); +		goto err5; +	} + +	ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); +	if (ret) { +		dev_err(&pdev->dev, "failed to add platform_data\n"); +		goto err5; +	} + +	ret = platform_device_add(musb); +	if (ret) { +		dev_err(&pdev->dev, "failed to register musb device\n"); +		goto err5; +	} + +	return 0; + +err5: +	clk_disable_unprepare(clk); + +err4: +	clk_put(clk); + +err3: +	platform_device_put(musb); + +err1: +	kfree(glue); + +err0: +	return ret; +} + +static int ux500_remove(struct platform_device *pdev) +{ +	struct ux500_glue	*glue = platform_get_drvdata(pdev); + +	platform_device_unregister(glue->musb); +	clk_disable_unprepare(glue->clk); +	clk_put(glue->clk); +	kfree(glue); + +	return 0; +} + +#ifdef CONFIG_PM +static int ux500_suspend(struct device *dev) +{ +	struct ux500_glue	*glue = dev_get_drvdata(dev); +	struct musb		*musb = glue_to_musb(glue); + +	usb_phy_set_suspend(musb->xceiv, 1); +	clk_disable_unprepare(glue->clk); + +	return 0; +} + +static int ux500_resume(struct device *dev) +{ +	struct ux500_glue	*glue = dev_get_drvdata(dev); +	struct musb		*musb = glue_to_musb(glue); +	int			ret; + +	ret = clk_prepare_enable(glue->clk); +	if (ret) { +		dev_err(dev, "failed to enable clock\n"); +		return ret; +	} + +	usb_phy_set_suspend(musb->xceiv, 0); + +	return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(ux500_pm_ops, ux500_suspend, ux500_resume); + +static const struct of_device_id ux500_match[] = { +        { .compatible = "stericsson,db8500-musb", }, +        {} +}; + +static struct platform_driver ux500_driver = { +	.probe		= ux500_probe, +	.remove		= ux500_remove, +	.driver		= { +		.name	= "musb-ux500", +		.pm	= &ux500_pm_ops, +		.of_match_table = ux500_match, +	}, +}; + +MODULE_DESCRIPTION("UX500 MUSB Glue Layer"); +MODULE_AUTHOR("Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>"); +MODULE_LICENSE("GPL v2"); +module_platform_driver(ux500_driver); diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c new file mode 100644 index 00000000000..9aad00f11bd --- /dev/null +++ b/drivers/usb/musb/ux500_dma.c @@ -0,0 +1,412 @@ +/* + * drivers/usb/musb/ux500_dma.c + * + * U8500 DMA support code + * + * Copyright (C) 2009 STMicroelectronics + * Copyright (C) 2011 ST-Ericsson SA + * Authors: + *	Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com> + *	Praveena Nadahally <praveen.nadahally@stericsson.com> + *	Rajaram Regupathy <ragupathy.rajaram@stericsson.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> +#include <linux/pfn.h> +#include <linux/sizes.h> +#include <linux/platform_data/usb-musb-ux500.h> +#include "musb_core.h" + +static const char *iep_chan_names[] = { "iep_1_9", "iep_2_10", "iep_3_11", "iep_4_12", +					"iep_5_13", "iep_6_14", "iep_7_15", "iep_8" }; +static const char *oep_chan_names[] = { "oep_1_9", "oep_2_10", "oep_3_11", "oep_4_12", +					"oep_5_13", "oep_6_14", "oep_7_15", "oep_8" }; + +struct ux500_dma_channel { +	struct dma_channel channel; +	struct ux500_dma_controller *controller; +	struct musb_hw_ep *hw_ep; +	struct dma_chan *dma_chan; +	unsigned int cur_len; +	dma_cookie_t cookie; +	u8 ch_num; +	u8 is_tx; +	u8 is_allocated; +}; + +struct ux500_dma_controller { +	struct dma_controller controller; +	struct ux500_dma_channel rx_channel[UX500_MUSB_DMA_NUM_RX_TX_CHANNELS]; +	struct ux500_dma_channel tx_channel[UX500_MUSB_DMA_NUM_RX_TX_CHANNELS]; +	void *private_data; +	dma_addr_t phy_base; +}; + +/* Work function invoked from DMA callback to handle rx transfers. */ +static void ux500_dma_callback(void *private_data) +{ +	struct dma_channel *channel = private_data; +	struct ux500_dma_channel *ux500_channel = channel->private_data; +	struct musb_hw_ep       *hw_ep = ux500_channel->hw_ep; +	struct musb *musb = hw_ep->musb; +	unsigned long flags; + +	dev_dbg(musb->controller, "DMA rx transfer done on hw_ep=%d\n", +		hw_ep->epnum); + +	spin_lock_irqsave(&musb->lock, flags); +	ux500_channel->channel.actual_len = ux500_channel->cur_len; +	ux500_channel->channel.status = MUSB_DMA_STATUS_FREE; +	musb_dma_completion(musb, hw_ep->epnum, ux500_channel->is_tx); +	spin_unlock_irqrestore(&musb->lock, flags); + +} + +static bool ux500_configure_channel(struct dma_channel *channel, +				u16 packet_sz, u8 mode, +				dma_addr_t dma_addr, u32 len) +{ +	struct ux500_dma_channel *ux500_channel = channel->private_data; +	struct musb_hw_ep *hw_ep = ux500_channel->hw_ep; +	struct dma_chan *dma_chan = ux500_channel->dma_chan; +	struct dma_async_tx_descriptor *dma_desc; +	enum dma_transfer_direction direction; +	struct scatterlist sg; +	struct dma_slave_config slave_conf; +	enum dma_slave_buswidth addr_width; +	dma_addr_t usb_fifo_addr = (MUSB_FIFO_OFFSET(hw_ep->epnum) + +					ux500_channel->controller->phy_base); +	struct musb *musb = ux500_channel->controller->private_data; + +	dev_dbg(musb->controller, +		"packet_sz=%d, mode=%d, dma_addr=0x%llu, len=%d is_tx=%d\n", +		packet_sz, mode, (unsigned long long) dma_addr, +		len, ux500_channel->is_tx); + +	ux500_channel->cur_len = len; + +	sg_init_table(&sg, 1); +	sg_set_page(&sg, pfn_to_page(PFN_DOWN(dma_addr)), len, +					    offset_in_page(dma_addr)); +	sg_dma_address(&sg) = dma_addr; +	sg_dma_len(&sg) = len; + +	direction = ux500_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; +	addr_width = (len & 0x3) ? DMA_SLAVE_BUSWIDTH_1_BYTE : +					DMA_SLAVE_BUSWIDTH_4_BYTES; + +	slave_conf.direction = direction; +	slave_conf.src_addr = usb_fifo_addr; +	slave_conf.src_addr_width = addr_width; +	slave_conf.src_maxburst = 16; +	slave_conf.dst_addr = usb_fifo_addr; +	slave_conf.dst_addr_width = addr_width; +	slave_conf.dst_maxburst = 16; +	slave_conf.device_fc = false; + +	dma_chan->device->device_control(dma_chan, DMA_SLAVE_CONFIG, +					     (unsigned long) &slave_conf); + +	dma_desc = dmaengine_prep_slave_sg(dma_chan, &sg, 1, direction, +					     DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +	if (!dma_desc) +		return false; + +	dma_desc->callback = ux500_dma_callback; +	dma_desc->callback_param = channel; +	ux500_channel->cookie = dma_desc->tx_submit(dma_desc); + +	dma_async_issue_pending(dma_chan); + +	return true; +} + +static struct dma_channel *ux500_dma_channel_allocate(struct dma_controller *c, +				struct musb_hw_ep *hw_ep, u8 is_tx) +{ +	struct ux500_dma_controller *controller = container_of(c, +			struct ux500_dma_controller, controller); +	struct ux500_dma_channel *ux500_channel = NULL; +	struct musb *musb = controller->private_data; +	u8 ch_num = hw_ep->epnum - 1; + +	/* 8 DMA channels (0 - 7). Each DMA channel can only be allocated +	 * to specified hw_ep. For example DMA channel 0 can only be allocated +	 * to hw_ep 1 and 9. +	 */ +	if (ch_num > 7) +		ch_num -= 8; + +	if (ch_num >= UX500_MUSB_DMA_NUM_RX_TX_CHANNELS) +		return NULL; + +	ux500_channel = is_tx ? &(controller->tx_channel[ch_num]) : +				&(controller->rx_channel[ch_num]) ; + +	/* Check if channel is already used. */ +	if (ux500_channel->is_allocated) +		return NULL; + +	ux500_channel->hw_ep = hw_ep; +	ux500_channel->is_allocated = 1; + +	dev_dbg(musb->controller, "hw_ep=%d, is_tx=0x%x, channel=%d\n", +		hw_ep->epnum, is_tx, ch_num); + +	return &(ux500_channel->channel); +} + +static void ux500_dma_channel_release(struct dma_channel *channel) +{ +	struct ux500_dma_channel *ux500_channel = channel->private_data; +	struct musb *musb = ux500_channel->controller->private_data; + +	dev_dbg(musb->controller, "channel=%d\n", ux500_channel->ch_num); + +	if (ux500_channel->is_allocated) { +		ux500_channel->is_allocated = 0; +		channel->status = MUSB_DMA_STATUS_FREE; +		channel->actual_len = 0; +	} +} + +static int ux500_dma_is_compatible(struct dma_channel *channel, +		u16 maxpacket, void *buf, u32 length) +{ +	if ((maxpacket & 0x3)		|| +		((unsigned long int) buf & 0x3)	|| +		(length < 512)		|| +		(length & 0x3)) +		return false; +	else +		return true; +} + +static int ux500_dma_channel_program(struct dma_channel *channel, +				u16 packet_sz, u8 mode, +				dma_addr_t dma_addr, u32 len) +{ +	int ret; + +	BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || +		channel->status == MUSB_DMA_STATUS_BUSY); + +	if (!ux500_dma_is_compatible(channel, packet_sz, (void *)dma_addr, len)) +		return false; + +	channel->status = MUSB_DMA_STATUS_BUSY; +	channel->actual_len = 0; +	ret = ux500_configure_channel(channel, packet_sz, mode, dma_addr, len); +	if (!ret) +		channel->status = MUSB_DMA_STATUS_FREE; + +	return ret; +} + +static int ux500_dma_channel_abort(struct dma_channel *channel) +{ +	struct ux500_dma_channel *ux500_channel = channel->private_data; +	struct ux500_dma_controller *controller = ux500_channel->controller; +	struct musb *musb = controller->private_data; +	void __iomem *epio = musb->endpoints[ux500_channel->hw_ep->epnum].regs; +	u16 csr; + +	dev_dbg(musb->controller, "channel=%d, is_tx=%d\n", +		ux500_channel->ch_num, ux500_channel->is_tx); + +	if (channel->status == MUSB_DMA_STATUS_BUSY) { +		if (ux500_channel->is_tx) { +			csr = musb_readw(epio, MUSB_TXCSR); +			csr &= ~(MUSB_TXCSR_AUTOSET | +				 MUSB_TXCSR_DMAENAB | +				 MUSB_TXCSR_DMAMODE); +			musb_writew(epio, MUSB_TXCSR, csr); +		} else { +			csr = musb_readw(epio, MUSB_RXCSR); +			csr &= ~(MUSB_RXCSR_AUTOCLEAR | +				 MUSB_RXCSR_DMAENAB | +				 MUSB_RXCSR_DMAMODE); +			musb_writew(epio, MUSB_RXCSR, csr); +		} + +		ux500_channel->dma_chan->device-> +				device_control(ux500_channel->dma_chan, +					DMA_TERMINATE_ALL, 0); +		channel->status = MUSB_DMA_STATUS_FREE; +	} +	return 0; +} + +static void ux500_dma_controller_stop(struct ux500_dma_controller *controller) +{ +	struct ux500_dma_channel *ux500_channel; +	struct dma_channel *channel; +	u8 ch_num; + +	for (ch_num = 0; ch_num < UX500_MUSB_DMA_NUM_RX_TX_CHANNELS; ch_num++) { +		channel = &controller->rx_channel[ch_num].channel; +		ux500_channel = channel->private_data; + +		ux500_dma_channel_release(channel); + +		if (ux500_channel->dma_chan) +			dma_release_channel(ux500_channel->dma_chan); +	} + +	for (ch_num = 0; ch_num < UX500_MUSB_DMA_NUM_RX_TX_CHANNELS; ch_num++) { +		channel = &controller->tx_channel[ch_num].channel; +		ux500_channel = channel->private_data; + +		ux500_dma_channel_release(channel); + +		if (ux500_channel->dma_chan) +			dma_release_channel(ux500_channel->dma_chan); +	} +} + +static int ux500_dma_controller_start(struct ux500_dma_controller *controller) +{ +	struct ux500_dma_channel *ux500_channel = NULL; +	struct musb *musb = controller->private_data; +	struct device *dev = musb->controller; +	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); +	struct ux500_musb_board_data *data; +	struct dma_channel *dma_channel = NULL; +	char **chan_names; +	u32 ch_num; +	u8 dir; +	u8 is_tx = 0; + +	void **param_array; +	struct ux500_dma_channel *channel_array; +	dma_cap_mask_t mask; + +	if (!plat) { +		dev_err(musb->controller, "No platform data\n"); +		return -EINVAL; +	} + +	data = plat->board_data; + +	dma_cap_zero(mask); +	dma_cap_set(DMA_SLAVE, mask); + +	/* Prepare the loop for RX channels */ +	channel_array = controller->rx_channel; +	param_array = data ? data->dma_rx_param_array : NULL; +	chan_names = (char **)iep_chan_names; + +	for (dir = 0; dir < 2; dir++) { +		for (ch_num = 0; +		     ch_num < UX500_MUSB_DMA_NUM_RX_TX_CHANNELS; +		     ch_num++) { +			ux500_channel = &channel_array[ch_num]; +			ux500_channel->controller = controller; +			ux500_channel->ch_num = ch_num; +			ux500_channel->is_tx = is_tx; + +			dma_channel = &(ux500_channel->channel); +			dma_channel->private_data = ux500_channel; +			dma_channel->status = MUSB_DMA_STATUS_FREE; +			dma_channel->max_len = SZ_16M; + +			ux500_channel->dma_chan = +				dma_request_slave_channel(dev, chan_names[ch_num]); + +			if (!ux500_channel->dma_chan) +				ux500_channel->dma_chan = +					dma_request_channel(mask, +							    data ? +							    data->dma_filter : +							    NULL, +							    param_array ? +							    param_array[ch_num] : +							    NULL); + +			if (!ux500_channel->dma_chan) { +				ERR("Dma pipe allocation error dir=%d ch=%d\n", +					dir, ch_num); + +				/* Release already allocated channels */ +				ux500_dma_controller_stop(controller); + +				return -EBUSY; +			} + +		} + +		/* Prepare the loop for TX channels */ +		channel_array = controller->tx_channel; +		param_array = data ? data->dma_tx_param_array : NULL; +		chan_names = (char **)oep_chan_names; +		is_tx = 1; +	} + +	return 0; +} + +void dma_controller_destroy(struct dma_controller *c) +{ +	struct ux500_dma_controller *controller = container_of(c, +			struct ux500_dma_controller, controller); + +	ux500_dma_controller_stop(controller); +	kfree(controller); +} + +struct dma_controller *dma_controller_create(struct musb *musb, +					void __iomem *base) +{ +	struct ux500_dma_controller *controller; +	struct platform_device *pdev = to_platform_device(musb->controller); +	struct resource	*iomem; +	int ret; + +	controller = kzalloc(sizeof(*controller), GFP_KERNEL); +	if (!controller) +		goto kzalloc_fail; + +	controller->private_data = musb; + +	/* Save physical address for DMA controller. */ +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	if (!iomem) { +		dev_err(musb->controller, "no memory resource defined\n"); +		goto plat_get_fail; +	} + +	controller->phy_base = (dma_addr_t) iomem->start; + +	controller->controller.channel_alloc = ux500_dma_channel_allocate; +	controller->controller.channel_release = ux500_dma_channel_release; +	controller->controller.channel_program = ux500_dma_channel_program; +	controller->controller.channel_abort = ux500_dma_channel_abort; +	controller->controller.is_compatible = ux500_dma_is_compatible; + +	ret = ux500_dma_controller_start(controller); +	if (ret) +		goto plat_get_fail; +	return &controller->controller; + +plat_get_fail: +	kfree(controller); +kzalloc_fail: +	return NULL; +}  | 
